EmbeddedRelated.com
Forums

global jumps and stack

Started by Arnim Zichner February 10, 2004
Hello!

I'm programming two ATmega162s which should do some communication via their
USART-interfaces. I'm using the C-programming language with the CodeVision
AVR Compiler. I preferred C, because I do not have too much experience in
programming in assembly language and to this point everything worked pretty
good. But sadly a serious problem occured:

My Programm runs in an endless loop ("main-loop"), getting chars from the
usart0 and putting them to usart1. This procedure is regulary (each 200ms)
interrupted by Timer-Interrupt1 (CTC-mode), which puts a certain ping-signal
('*****') to usart1 and then starts Timer2(CTC-mode aswell), which
Interrupts after 2ms. Within these two milliseconds 5 respond-chars should
be received on usart1 in the main-loop. If  not a certain PIN gets pulled
down for some short time.

So far so good this seems to me to be a good idea. The Problem is, that
TimerInterrupt1 would return to the main-loop, waiting for characters on
usart0. In the case that at that time no char would arrive at usart0, the
programm woulf be blocked by the corresponding getchar()-routine. So I put a
longjump into the interrupt-routine1 to get to  another place in the
main-loop, where the ATmega then should wait for the ping-response at
usart1. This all works, but it only works for 230 times receiving 'regular'
characters on usart0 and putting them to usart1.

I suspect the stack of growing and growing,  because the jump-operations,
and I tested this. The Stack grows from somewhere 1275 to 837 and then the
program hangs itself up. It would be nice, if someone could help me with
that jump things....


Bye

Arnim


Here are the corresponding code excerpts:


....

#include <mega162.h>
#include <delay.h>
#include <setjmp.h>

// Alphanumeric LCD Module functions
#asm
   .equ __lcd_port=0x1B
#endasm
#include <lcd.h>
#include <stdlib.h>

....

//global vars
char trans;
char pingsent;
char pongreceived = 0;
char mode;

//debugging-vars
int i = 0;
int j = 0;
int count_t1 = 0;
int count_t2 = 0;
char a[6], b[6], c[6];
int count_reset = 0;

//Processor-states according sot setjmp.h
jmp_buf cpu_state;

//Functions
char sendping(void);
char receivepong(void);


....


interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
count_t1+=1;
LED0_AN;
mode=PING;
pingsent = sendping();
TCCR2=0x0F; //start timer 2
LED0_AUS;
//Longjump back to the main-loop
longjmp(cpu_state, 1);
}

// Timer 2 output compare interrupt service routine
//2ms
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
 count_t2+=1;
 TCCR2=0x00; //stop itself
 TCNT2=0x00; //block next ctc-match
 if(pongreceived){
  pongreceived = 0;
 } else {
  LED1_AN; //self-defined LED-ON
  delay_ms(10);
  LED1_AUS; //self-defined LED-OFF

}
}//Interrupt Timer2

char sendping(){
   int i;
 for(i=0;i<5;i++)putchar1('*');
   return 1;
}//send

char receivepong(){
   char c;
   int i;
   for(i=0; i<5; i++){
    c = getchar1();
   }//rof

   return 1;
}//receivepong





.....


void main(void)
{

...

//endless-loop / main-loop
while (1)
      {

      if (setjmp(cpu_state)==0)
       {
       /*
       //Some debugging-output to display
       i+=1;
       lcd_gotoxy(0,0);
       itoa(i,a);
       lcd_puts(a);
       */
       lcd_gotoxy(5,0);
   lcd_putsf("TIM2:");
       itoa(count_t2,b);
       lcd_puts(b);
       lcd_gotoxy(5,1);
   lcd_putsf("TIM1:");
       itoa(count_t1,a);
       lcd_puts(a);

       trans = getchar();
       putchar1(trans);
       }
  else
   {
   /*
   //Some debugging-output to display
   j+=1;
       lcd_gotoxy(0,1);
       itoa(j,b);
       lcd_puts(b);
       */
       lcd_gotoxy(5,1);
   lcd_putsf("TIM1:");
       itoa(count_t1,a);
       lcd_puts(a);
       lcd_gotoxy(5,0);
   lcd_putsf("TIM2:");
       itoa(count_t2,b);
       lcd_puts(b);

   pongreceived = receivepong();
   }
      };//while1
}//main


Arnim Zichner <zichner@tuhh.de> wrote:

[...]
> So far so good this seems to me to be a good idea. The Problem is, that > TimerInterrupt1 would return to the main-loop, waiting for characters on > usart0. In the case that at that time no char would arrive at usart0, the > programm woulf be blocked by the corresponding getchar()-routine.
You can't use exclusive busy-waiting in a multi-input situation like that. You'll have to put non-blocking versions of getchar() to *both* serial ports into the waiting loop. I.e. instead of the main loop being while (1) { c = getchar(usart0); /* do something with it */ } it'll have to become something like this: while (1) { if (peekchar(usart0)) { c = getchar(usart0); /* do something with it */ } if (status_waiting_for_int2 && peekchar(usart1)) { c = getchar(usart1); /* do something with it */ } } -- Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de) Even if all the snow were burnt, ashes would remain.
"Arnim Zichner" <zichner@tuhh.de> wrote in message
news:c0b0br$15f5ej$1@uni-berlin.de...
> Hello! > >So I put a > longjump into the interrupt-routine1 to get to another place in the > main-loop, where the ATmega then should wait for the ping-response at > usart1. This all works, but it only works for 230 times receiving
'regular'
> characters on usart0 and putting them to usart1. > > I suspect the stack of growing and growing, because the jump-operations, > and I tested this. The Stack grows from somewhere 1275 to 837 and then the > program hangs itself up. It would be nice, if someone could help me with > that jump things.... > > > Bye > > Arnim
Using setjmp and longjmp is asking for trouble. Putting the longjmp in an interrupt routine is asking for even more trouble (like you've got). The pair are designed to work together only when the function with the longjmp has been called (directly or indirectly) from the one with the setjmp. Although you could regard the interrupt as a "function call", the stack frame is likely to be somewhat different (all those extra pushes and pops) - hence the problem. My only advice would be *never* to use these things. Redesign your program as if you'd never heard of them. -- Peter Bushell http://www.software-integrity.com/
"Arnim Zichner" <zichner@tuhh.de> wrote in message
news:c0b0br$15f5ej$1@uni-berlin.de...
> > So far so good this seems to me to be a good idea. The Problem is, that > TimerInterrupt1 would return to the main-loop, waiting for characters on > usart0. In the case that at that time no char would arrive at usart0, the > programm woulf be blocked by the corresponding getchar()-routine. So I put
a
> longjump into the interrupt-routine1 to get to another place in the > main-loop, where the ATmega then should wait for the ping-response at > usart1. This all works, but it only works for 230 times receiving
'regular'
> characters on usart0 and putting them to usart1.
I strongly suggest you revise your code such that the interrupts only communicate with the main loop via data. Set a request flag in the interrupt, and act on it and clear it in the main loop. Steve http://www.fivetrees.com http://www.sfdesign.co.uk