2

I'm programming an Arduino Nano so I belive that this question should be qualified for this SE.

I am trying to dim up an LED using a for loop in AVR assembly.

My problem is that the cycle is repeated twice before ending, while it is suppose to end after the first cycle.

A cycle is when the red_loop is repeated 256 times (to dim the led up). At that point, the value should overflow causing the variable to go back to 0. The code should stop there, but mysteriously, it does another cycle and then it stops.

Does anyone know why?

Here is my code :

.org 0x000

ldi r16, 0b111
out ddrb, r16

ldi r16, 0xff
out portb, r16

ldi r16, 0

; ff00 pin
; ff01 value
; ff02 led

ldi r16, 0b000
sts $ff00, r16

ldi r16, 0
sts $ff01, r16

red:
    ldi r16, 0b001
    sts $ff00, r16

red_loop:
    rcall pwm

    lds r16, $ff01
    inc r16
    sts $ff01, r16
    cpi r16, 0
    brne red_loop

end:
    rjmp end

pwm:
    ldi r24, 190

pwm_pre_loop:
    ldi r17, 0

pwm_loop:
    lds r16, $ff01
    cp r17, r16
    brge off

    cp r17, r16
    brlo on

pwm_loop_check:
    inc r17
    cpi r17, 0
    brne pwm_loop

    inc r24

    cpi r24, 0
    brne pwm_pre_loop

    ret

on:
    lds r16, $ff00

    sbrc r16, 0
    cbi portb, 0

    sbrc r16, 1
    cbi portb, 1

    sbrc r16, 2
    cbi portb, 2

    rjmp pwm_loop_check

off:
    lds r16, $ff00

    sbrc r16, 0
    sbi portb, 0

    sbrc r16, 1
    sbi portb, 1

    sbrc r16, 2
    sbi portb, 2

    rjmp pwm_loop_check
  • you did not say what cycle means, so i am assuming that it means red_loop ..... are you sure that the red_loop repeats only two times?.... i am not very familiar with avr assembly instructions, but it looks like the red_loop repeats a lot more than two times – jsotola Oct 7 '18 at 18:02
  • 1
    AVR asembly is not Arduino – Juraj Oct 7 '18 at 18:35
  • 1
    What kind of Arduino is that? Unless you have something like 64K of SRAM, $ff00 is going to be out of range. – Edgar Bonet Oct 7 '18 at 19:55
  • I suggest re-writing this code in C and taking a look at the assembly output of the compiler as a reference. Also, it might be a good idea to feed this into a simulator. E.g. avr-asm-tutorial.net/avr_sim/index_en.html – ex-punctis Oct 7 '18 at 20:59
  • 1
    @Juraj I am programming an Arduino Nano, so this question should be qualified for this site. – Dat Ha Oct 7 '18 at 21:04
2

The problem is that the register r17, which you use as a PWM timing ramp, overflows twice every time you enter pwm_pre_loop:

  • when you increments it past 127, it overflows to −128
  • when you increment it past 255, it overflows to 0.

When using a counter the way you are using r17 here, you usually have it overflow only once per cycle: either you consider it holds a signed number which overflows from 127 to −128, or you consider it holds an unsigned number which overflows from 255 to 0. I guess the latter is more common. Your code is confused about that register's signedness:

  • The instruction brge (named “Branch if Greater or Equal (Signed)” in the instruction set datasheet) tests the S (sign flag) bit of the status register, which is useful for signed comparisons.

  • The instruction brlo (“Branch if Lower (Unsigned)”) tests the carry flag, which is used for unsigned comparisons.

You should decide once on the signedness of the counter, and then use it consistently. Since here unsigned makes more sense, you can just replace brge by brsh (“Branch if Same or Higher (Unsigned)”).

Or better yet, remove the second test, which is redundant:

pwm_loop:
    lds r16, value
    cp r17, r16
    brsh off  ; if (r17 >= r16) goto off;
    rjmp on   ; else goto on;

Note by the way that you can name your RAM variables. And you can use some of the other available registers instead of the RAM.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.