Close

ATtiny13

A project log for Nyan Board

A small ATtiny85 board playing the Nyan Cat tune.

dehipudeʃhipu 11/28/2016 at 08:043 Comments

I'm still waiting for my chips, but @davedarko has a bunch of ATtiny13s handy, and he reports that there is a small problem: ATtiny13 doesn't have Timer1. A quick look at the datasheet confirms that -- so I will need to use Timer0 instead. However, there are two problems with that. First, Timer0 cannot directly control the PB4 pin that I used for the piezo on the boards, and second, its prescaler is not nearly as accurate, so I can't use it for selecting octaves. But let's try and see what we can do.

The first problem is simple: I undusted my old trusty time machine, went back a week, and modified the original board design, to make one of the cats (the middle right one) different from others -- it has piezo on pin PB0, and separate LEDs on PB3 and PB4, so it can blink its eyes independently.

The second one is a bit worse -- we will have to compromise. I'm setting the prescaler to a static value, and I'm shifting the timer counters right by the octave number -- this way the higher the octave, the smaller the numbers -- so higher frequency. (You may remember from your music lessons, that each octave has twice the frequency of the previous one). The problem with this is that I lose accuracy at the higher frequencies. Oh well. Also, I had to switch the chip to 1Mhz, because then I can get the prescaler at the right spot.

The end result isn't bad, and it's only 2 bytes larger than the ATtiny85 version (because I now blink the other eye too, otherwise it would have been smaller). Here it is:

void play(const byte *notes, byte length) {
    union {
        struct {
            unsigned int tone: 3;
            unsigned int octave: 2;
            unsigned int length: 1;
        } note;
        byte raw;
    } note;

    while (length --> 0) { // "Goes to 0" operator.
        note.raw = pgm_read_byte_near(notes++);
        if (note.note.octave) {
            TCCR0B = 2; // Pre-scaler /64
            OCR0A = pgm_read_byte_near(FREQ + note.note.tone) >> (note.note.octave - 1);
        }
        if (note.note.length) {
            _delay_ms(220);
            TCCR0B = 0;
            _delay_ms(30);
        } else {
            _delay_ms(110);
            TCCR0B = 0;
            _delay_ms(15);
        }
        PORTB ^= 1<<3 | 1<<4;
    }
}

int main() {
    DDRB = 1<<0 | 1<<3 | 1<<4; // Output pins PB0, PB3, PB4.
    TCCR0A |= 1<<COM0A0 | 1<<WGM01; // Enable output on PB0 and set CTC mode.
    PORTB ^= 1<<4; // Close one eye, so they blink one at a time.
    play(INTRO_NOTES, 26);
    while(1) {
        play(MELODY_NOTES, 216);
    }
}

Discussions

davedarko wrote 11/28/2016 at 15:20 point

TCCR0B = 2;


TCCR0B = 4;

It's compiled with 9600000 cpu speed, default internal freq of the attiny13a.

  Are you sure? yes | no

deʃhipu wrote 11/28/2016 at 15:27 point

Thanks for testing, I guess there are more differences in there with the ATtiny85. I will have to experiment once my chips arrive. Sorry for it not working out of the box, it worked on the ATtiny85, I promise!

  Are you sure? yes | no

davedarko wrote 11/28/2016 at 15:32 point

oh don't apologise! that's pretty impressive for a shot in the dark :) looking forward for that update!

  Are you sure? yes | no