ATMEGA32-ISR won't change my global variable

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

Hello newbie here, what i think my code should do :

i  connected a push button to PIND3, and when i press it pulls it low, i think this should set the timer0 on release of the button then the ISR should fire after 16 ms, and PORTC0 becomes high which should make test=0xff; then when it returns it makes PORTC1 high .

 

what i'm getting:

when i release the switch the PORTC0 becomes high and LED turns on but the other led connected to PORTC1 is not on, which makes me think the variable didn't change.

 

#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
volatile uint8_t test=0x00;

ISR(TIMER0_OVF_vect){
	TCCR0=0X00;
	TCNT0=0X00;
	PORTC|=(1<<0);
	test=0xff;
	reti();
}
int main(void)
{MCUCSR|=(1<<JTD);
	MCUCSR|=(1<<JTD);
	DDRC=0XFF;
	DDRD&=~(1<<3);
	PORTD|=(1<<3);
	TIMSK|=(1<<TOIE0);
	sei();
    
    while (1) 
    {
		if(!(PIND&(1<<3))){
			TCNT0=0X00;
			TCCR0=(1<<CS01)|(1<<CS00);
    }
	if(test==0xFF){
		PORTC|=(1<<1);
	}
}

}

thanks in advance.

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

garmoosh wrote:
ISR should fire ... then when it returns
And that's the problem, it does not return to where it should return to.

Remove the "reti()" in the ISR!

Stefan Ernst

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

sternst wrote:
Remove the "reti()" in the ISR!
You may then want to read the manual:

 

http://nongnu.org/avr-libc/user-...

 

In the description of reti() it tells you:

This should be the last command executed before leaving an ISR defined with the ISR_NAKED attribute.

Maybe there is not enough emphasis there but the further implication is "but do NOT use it unless ISR_NAKED is being used"

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

oh i get it now, so i needn't even use reti() and the program returns to where it should automatically , it works fine now. but i thought reti would just pop the address from the stack and return the program to where it was before it was interrupted. If i used reti() without ISR_NAKED then what does this reti() actually do? where does it put my program. sorry for my bad english.

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

garmoosh wrote:
but i thought reti would just pop the address from the stack
It does pop the topmost bytes from the stack. At the point it is executed in your code those topmost bytes are saved register contents. So the "address" it returns to is junk.

Stefan Ernst

Last Edited: Tue. Jul 10, 2018 - 01:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Without the ISR_NAKED, there is more then just the return address on the stack (i.e. saved registers) so the added reti will be popping register contents instead of the return address and returning to who knows where!

 

 

Jim

 

Click Link: Get Free Stock: Retire early!

share.robinhood.com/jamesc3274

 

 

 

Last Edited: Tue. Jul 10, 2018 - 12:59 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

garmoosh wrote:

...i thought reti would just pop the address from the stack and return the program to where it was before it was interrupted.

 

It does BUT, on entry to the ISR, the compiler will have made changes to other registers and possibly to the stack which do not get undone because your reti causes an immediate return to the interrupted location.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

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

Part of what you get when you use ISR() is a RETI rather than a RET anyway. But what you can't "see" is the fact at that the start of the ISR() the compiler also PUSH's anything that may be touched by the code that follows and, at the end, before it gets to the provided RETI it POPs those things back. When you use the "reti()" macro you just cause a RETI before it's done all the POPs. Here's an example:

D:\atmel_avr\avr8-gnu-toolchain\bin>type avr.c
#include <avr/interrupt.h>

int main(void) {
}

ISR(INT0_vect) {
    PORTB = 0x55;
}

ISR(INT1_vect) {
    PORTB = 0xAA;
    reti();
}
D:\atmel_avr\avr8-gnu-toolchain\bin>avr-gcc -mmcu=atmega16 -Os -g avr.c -o avr.elf

D:\atmel_avr\avr8-gnu-toolchain\bin>avr-objdump -S avr.elf

avr.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0c 94 2a 00     jmp     0x54    ; 0x54 <__ctors_end>
   4:   0c 94 36 00     jmp     0x6c    ; 0x6c <__vector_1>
   8:   0c 94 44 00     jmp     0x88    ; 0x88 <__vector_2>
   c:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  10:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  14:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  18:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  1c:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  20:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  24:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  28:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  2c:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  30:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  34:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  38:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  3c:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  40:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  44:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  48:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  4c:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>
  50:   0c 94 34 00     jmp     0x68    ; 0x68 <__bad_interrupt>

00000054 <__ctors_end>:
  54:   11 24           eor     r1, r1
  56:   1f be           out     0x3f, r1        ; 63
  58:   cf e5           ldi     r28, 0x5F       ; 95
  5a:   d4 e0           ldi     r29, 0x04       ; 4
  5c:   de bf           out     0x3e, r29       ; 62
  5e:   cd bf           out     0x3d, r28       ; 61
  60:   0e 94 53 00     call    0xa6    ; 0xa6 <main>
  64:   0c 94 54 00     jmp     0xa8    ; 0xa8 <_exit>

00000068 <__bad_interrupt>:
  68:   0c 94 00 00     jmp     0       ; 0x0 <__vectors>

0000006c <__vector_1>:
#include <avr/interrupt.h>

int main(void) {
}

ISR(INT0_vect) {
  6c:   1f 92           push    r1
  6e:   0f 92           push    r0
  70:   0f b6           in      r0, 0x3f        ; 63
  72:   0f 92           push    r0
  74:   11 24           eor     r1, r1
  76:   8f 93           push    r24
    PORTB = 0x55;
  78:   85 e5           ldi     r24, 0x55       ; 85
  7a:   88 bb           out     0x18, r24       ; 24
}
  7c:   8f 91           pop     r24
  7e:   0f 90           pop     r0
  80:   0f be           out     0x3f, r0        ; 63
  82:   0f 90           pop     r0
  84:   1f 90           pop     r1
  86:   18 95           reti

00000088 <__vector_2>:

ISR(INT1_vect) {
  88:   1f 92           push    r1
  8a:   0f 92           push    r0
  8c:   0f b6           in      r0, 0x3f        ; 63
  8e:   0f 92           push    r0
  90:   11 24           eor     r1, r1
  92:   8f 93           push    r24
    PORTB = 0xAA;
  94:   8a ea           ldi     r24, 0xAA       ; 170
  96:   88 bb           out     0x18, r24       ; 24
    reti();
  98:   18 95           reti
  9a:   8f 91           pop     r24
  9c:   0f 90           pop     r0
  9e:   0f be           out     0x3f, r0        ; 63
  a0:   0f 90           pop     r0
  a2:   1f 90           pop     r1
  a4:   18 95           reti

000000a6 <main>:
#include <avr/interrupt.h>

int main(void) {
}
  a6:   08 95           ret

000000a8 <_exit>:
  a8:   f8 94           cli

000000aa <__stop_program>:
  aa:   ff cf           rjmp    .-2             ; 0xaa <__stop_program>

INT0_vect is done properly. So there is the prologue that PUSH's registers then the write of 0x55 to PORTB then the POPs before the RETI.

 

But look at what happened to INT1_vect with the reti() inserted. It cuts off the extra POPs/RETI so they become unreachable.

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

okey i understand what you mean, thanks everyone for your help.

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

mark one of the posts as the solution so others will know that there is an answer to your question.

 

Jim

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

jgmdesign wrote:
mark one of the posts as the solution 

For detailed instructions on how to do that, see Tip #5

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...