Help With a simple Assembly program that uses external interrupts

Go To Last Post
13 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello to everyone in this forum. I am a beginner at learning assembly programming. My question is regarding the following assembly code that was written for ATmega328P using Atmel studio. Whenever the PD2 is low, output at PB5 is toggled.

 

.ORG 0
    JMP MAIN
.ORG 0x02
    JMP EX0_ISR

MAIN:    
        LDI R20,HIGH(RAMEND)
        OUT SPH,R20
        LDI R20,LOW(RAMEND)
        OUT SPL,R20
        LDI R20,0x2
        STS EICRA,R20
        SBI DDRB,5
        SBI PORTD,2
        LDI R20,1<<INT0
        OUT EIMSK,R20
        SEI
        

HERE:    JMP HERE

EX0_ISR:    
        IN R21,PORTB
        LDI R22,(1<<5)
        EOR R21,R22
        OUT PORTB,R21
        RETI

 

 

I uploaded this to AVR controller and now I having bouncing(occasionally more than one input is taken) issues with the switch. I am aware that the two solutions are either using a capacitor or using a delay. I would really appreciate if someone here could help with implementing a delay to this program.

 

Thank you very much for your time and attention.

This topic has a solution.
Last Edited: Fri. Sep 6, 2019 - 08:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In your case, putting a delay inside the ISR is the easiest solution (though not a good idea in general - ISRs should be short and fast as a rule).

 

A second approach, and more in keeping with the way ISRs are commonly used, is to have the ISR simply set a flag (a single byte) which the main loop reads "often" (meaning, often enough that you meet your responsiveness requirements - for switching an LED, that might be 50 ms - any longer and the delay might become noticeable and annoying to users).  So when your main loop reads the flag set, it toggles the LED and sets a delay during which it no longer looks at the flag.  At the end of the delay, clear the flag (which the ISR may have tried to set a few more times) and begin watching for the flag again.  A good range of switch debounce delays is perhaps 10 to 25 ms.  That should take care of all but the most pathological of switches, and throw out those bad ones anyway!

 

EDIT: the simplest delay would use the SBIW instruction, but that is limited to only a few register pairs.  Another option is to use the registers you've already used (r21, r22) such as (in pseudo-code)

 

L1: dec r21  ; LSB of your delay count

      bne L1

      dec r22  ; MSB of your delay count

      bne L1

Last Edited: Fri. Sep 6, 2019 - 06:10 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much for the help kind sir. Is that bne or brne? And where should I insert this L1 coding block in the ISR?

 

 

Last Edited: Fri. Sep 6, 2019 - 06:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

esavrperson wrote:

Thank you very much for the help kind sir. Is that bne or brne? And where should I insert this L1 coding block in the ISR?

That's why I said it was pseudo-code - I didn't want to look up the actual instructions. :)

 

I'd put the delay right before the reti in the ISR.  If you put it in the main code, it would be after you detect the flag is set (and then you could use sbiw instead, just a bit cleaner).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello Again Sir, I used the knowledge I have and created this little assembly loop to create a delay. Is this something that will work? Thank you very much for the help thus far good sir.

 

.ORG 0
    JMP MAIN
.ORG 0x02
    JMP EX0_ISR

MAIN:    LDI R20,HIGH(RAMEND)
        OUT SPH,R20
        LDI R20,LOW(RAMEND)
        OUT SPL,R20
        LDI R20,0x2
        STS EICRA,R20
        SBI DDRB,5
        SBI PORTD,2
        LDI R20,1<<INT0
        OUT EIMSK,R20
        SEI
        

HERE:    JMP HERE

 

EX0_ISR:
        IN R21,PORTB
        LDI R22,(1<<5)
        EOR R21,R22
        OUT PORTB,R21
        
L1:       LDI R24,200
            LDI R25,0
            SUB R24,R25    
            BREQ L2
            DEC R24    
            RJMP L1

 

L2:       RETI

        

Last Edited: Fri. Sep 6, 2019 - 07:31 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

L1:       LDI R24,200
            LDI R25,0
            SUB R24,R25    
            BREQ L2
            DEC R24    
            RJMP L1

 

No, this won't work.  First, you're jumping back to your initialization code, not your loop code.  Second, your loop is wrong.

 

Try this

 

            LDI R24,200
            LDI R25,0
L1:       DEC R25    ;assuming R25 holds your LSB
            BRNE L1
            DEC R24    
            BRNE L1

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

You are probably better off designing software first rather than rushing to implementation then trying to shoe-horn in bits that don't really fit.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

kk6gm wrote:

Quote:

 

 

            LDI R24,200
            LDI R25,0
L1:       DEC R25    ;assuming R25 holds your LSB
            BRNE L1
            DEC R24    
            BRNE L1

 

 

 

Thank you for the quick reply sir.

 

EX0_ISR:
        IN R21,PORTB
        LDI R22,(1<<5)
        EOR R21,R22
        OUT PORTB,R21
        
        LDI R24,200
        LDI R25,0
L1:     DEC R25    
        BRNE L1
        DEC R24    
        BRNE L1

        RETI

 

After the modifying the code like above the bouncing still occurs. I assume the delay caused by the loop is not enough to prevent the bouncing? 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The delay is about 200 * 256 * 3 (clock cycles per inner loop) * clock cycle time, or very roughly, 10 ms for the numbers you've used.  It's possible that the interrupt hardware flags another interrupt while you're in the delay, in which case you need to clear the interrupt flag just before the reti (after the delay), by clearing INT0 in EIFR.  The bit is cleared by writing a '1' to it, not a '0'.

 

I say it is -possible- that this is your problem, because the data sheet does not say when the hardware clears INT0, but my guess is that it happens at the beginning of the interrupt response.

 

Or, as I mentioned, don't delay in the ISR, but in the main code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried adding the loop you wrote after the main tag, before SEI and after SEI. Bouncing kept occurring. At this point I think I should use capacitor to accomplish my objective. Thank you verymuch, I learned a lot from this conversation. Good day to you and best of luck with everything:) 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

STOP

 

before you go even one code line further, at least give some names to your registers ...use those instead & save yourself from code blindness...do not use r-numbers in your code

 

.def dog = r16

.def frog= r17

.def cat = r18

 

 

   ldi dog, 0xFE

   ldi cat,  0xED

  mov frog, cat

  add dog, frog

  cp cat, dog

  brlo bark

  rjmp meow

    

versus

   ldi r16,0xFE

   ldi r18,0xED

  mov r17,r18

  add r16,r17

  cp r18,r16

  brlo bark

  rjmp meow

 

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Sat. Sep 7, 2019 - 12:20 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

esavrperson wrote:
At this point I think I should use capacitor to accomplish my objective

I think that would be a mistake.  99+% of debouncing is done in software, not in hardware.  You should work at it until you get it figured out,

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

make 100% sure you have this type of code at the beginning & end of any IRQ you write

 

 

TIM0_COMPA:    push ZL        ;save ZL register during interrupt
            in ZL, sreg    ;save CPU status bits during interrupt
            push ZL
            push ZH



exit_irq:    pop ZH
            pop ZL
            out sreg, ZL    ;return with pre-interrupt status bits
            pop ZL        ;return ZL to pre-interrupt value
            reti            ;return from timer0 compareA interrupt routine

 

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!