1
votes

I'm learning assembler AVR and found it confusing, this simple program below is using two timers, TIMER1 is used to make "OC1" to vibrate at certain frequency (CTC and toggles OC1), TIMER0 is used to start an interrupt at certain intervals, this interrupt is loading bytes from SRAM and modifies the OCR1AL to change frequency. (to play a melody) Everything works ok only at specific TIMER1 intervals, when i change the OCR0 to longer or shorter intervals some notes are missing, any idea why ? Another problem is the last note that is stored to the memory is not being loaded as the first one by the interrupt, i have to store one extra (empty or whatever value) to match the st Z+ with ld -Z. What i do wrong ? Thanks

the chip im using is the Atmega32a

/*
 * Melody.asm
 *
 *  Created: 03/04/14 8:17:54 PM
 *   Author: Michal
 */ 

    .equ MelodyStartAddr = 0x0301
    .equ NoteC1 = 0xEF // C
    .equ NoteD1 = 0xD4 // D
    .equ NoteE1 = 0xBD // E
    .equ NoteF1 = 0xB3 // F - 5 698 Hz
    .equ NoteG1 = 0x9F // G
    .equ NoteA1 = 0x8E // A
    .equ NoteH1 = 0x7E // H
    .equ NoteC2 = 0x77 // C

.def Temp = r16
.def TempH = r17
.def Zero = r0
.def Max = r1

//.cseg
.org 0x000
    rjmp Start1
.org 0x014 
    jmp ChangeNote


Start1:
    sei

        ldi Temp, HIGH(RAMEND)
        out SPH, Temp
        ldi Temp, LOW(RAMEND)
        out SPL, Temp

        ldi Temp, 0b11111111            // 
        out DDRD, Temp

        ldi YH, HIGH(MelodyStartAddr)
        ldi YL, LOW(MelodyStartAddr)

        ldi Temp, 0x00      // END
        st Z+, Temp

        ldi Temp, NoteE1
        st Z+, Temp
        ldi Temp, NoteE1
        st Z+, Temp

        ldi Temp, NoteE1
        st Z+, Temp
        ldi Temp, NoteE1
        st Z+, Temp

        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteG1

        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp

        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp

        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteF1
        st Z+, Temp
        ldi Temp, NoteG1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp
        ldi Temp, NoteC2
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp
        ldi Temp, NoteA1
        st Z+, Temp
        ldi Temp, NoteC2
        st Z+, Temp
        ldi Temp, NoteC2
        st Z+, Temp
        ldi Temp, NoteC2
        st Z+, Temp

        ldi Temp, NoteC2        // This is the extra Note that is not loaded in the interrupt 
        st Z+, Temp


        // ************* TIMER 1 ***********************    

        ldi Temp, 0b01000000 //  toggle oc1
        out TCCR1A, Temp

        ldi Temp, 0b00001010 //  WGM11, prescaler x8
        out TCCR1B, Temp

        ldi Temp, 0x00
        out OCR1AH, Temp

        //********** TIMER 0*******************************
        ldi Temp, 0b00011101            // 0b00011011 x64
        OUT TCCR0, Temp

        ldi Temp, 0xea              // Speed Works with 0xef, but not with 0xaf or 0xff or 0xea, any idea ?
        out OCR0, Temp

        ldi Temp, 0b00000010
        OUT TIMSK, Temp

Loop: 
nop
    rjmp Loop


ChangeNote:
        push Temp
        in Temp, SREG
        push Temp

        ldi Temp, 0x00
        out OCR1AH, Temp
        ld Temp, -Z
        cpi Temp, 0x00
        breq StopPlaying

        out OCR1AL, temp

        pop Temp
        out SREG, Temp
        pop Temp

    reti

StopPlaying:
    ldi Temp, 0x00
    out TIMSK, Temp
    ldi Temp, 0b00000000 //  toggle oc1
    out TCCR1A, Temp
ret


Delay:
    clr R1
    ldi TempH, 0xaf
    mov R2, TempH
    DelayLoop:
    dec R1
    brne DelayLoop
    clr R1
    dec R2
    brne DelayLoop

ret
2

2 Answers

0
votes

Why are you loading offset of memory buffer to Y register but then using Z register to store and load the melody?

ldi YH, HIGH(MelodyStartAddr)
ldi YL, LOW(MelodyStartAddr)
...
st Z+, Temp
...
ld Temp, -Z
0
votes

After reasonably thorough inspection of your code I too fail to see what the issue is with the timer ISR. Should actually work. If it works in the simulator you might have some sort of hardware problem.

On a side note: You're not initializing OCR1AL (though that should be 0 after reset anyway).

As to your second question:

i have to store one extra (empty or whatever value) to match the st Z+ with ld -Z

You shouldn't have to do that.

st Z+, Temp
ld Temp, -Z

will store Temp and retrieve the stored value immediately. Z+ is "post-increment", which means Temp is stored to Z and then Z is incremented. -Z is "pre-decrement", where Z is decremented and then the value is retrieved from the location Z now points to.