Unknown failure trying to make the MCU pause.

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

I am trying to create a sub-routine that is functionally identical to _delay_ms(). I am already using Timer0 for switch debouncing and it seems to interfere with _delay_ms().

Since I am using Timer2 to track a time interval for another purpose I want to employ it to create a delay sub-routine. I've set the timer2 interrupt to track time in seconds. getTimeOfTimer2() will return the total time in seconds since the AVR was turned on. pauseTheSystem() is intended to take a number in milliseconds and pause the MCU for that duration of time.

In this example I am trying to use my delay sub-routine to blink an LED.

My problem is once the program enters the do while loop the MCU hangs (LEDs won't blink). For some reason that I just don't understand it is unable to make the while comparison (I think). To make things even more mysterious if I add either a UART or LCD printf statement inside the do while loop the program will execute properly.

Does anyone have an idea as to what the problem might be? I've been staring at this for days and I am out of ideas. Thanks.

#define F_CPU  1000000

#include 
#include 
#include 

#define TIMER2_COUNTER_LIMIT	250

void pauseTheSystem(float);
float getTimeOfTimer2(void);

volatile unsigned int timeUnit = 0;
volatile unsigned int milliSeconds = 0;
volatile unsigned int seconds = 0;

ISR(TIMER2_OVF_vect)	
{
	++timeUnit;

	if(timeUnit >= 4){
		milliSeconds++;
		timeUnit = 0;

		if(milliSeconds >= 1000)
		{
			seconds++;
			milliSeconds = 0;
		}
	}
}

int main(void)
{
	TIMSK |= (1 << TOIE2);
	OCR2 = TIMER2_COUNTER_LIMIT;
	TCNT2 = 0;
	TCCR2 |= (1 << CS20);

	sei();

	DDRB = 0xff;
	PORTB = 0xff;

	while (1)
	{
		PORTB &= ~(1<<PORTB0);

		pauseTheSystem(500);

		PORTB = 0xff;

		pauseTheSystem(500);		
	}

}

float getTimeOfTimer2(void)
{
	return (float)seconds + (float)milliSeconds/1000;
}

void pauseTheSystem(float pauseMilliSeconds)
{
	float stopTime = getTimeOfTimer2() + pauseMilliSeconds/1000;

	float currentTime = 0;
	
	do
	{
		currentTime = getTimeOfTimer2();

		//For some reason this will only work if there is a printf statment here

	}while(stopTime > currentTime);
}

Using:
ATmega16
AVR Studio 4.14
GCC Compiler
STK500
Windows 2000

Last Edited: Tue. Apr 27, 2010 - 06:30 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm staring at this

while(stopTime < currentTime)

, thinking you want ">" rather than "<" there..

I'd get rid of the floats.

You could simplify the pausing, removing some of the arithmetic:

unsigned long timeRemaining = pauseMilliSeconds/1000; 
while (timeRemaining--);

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Yes you are correct I mistyped "<" when I copied the code over. The problem persists with ">" in the while condition.

I've updated the original code I posted.

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

Quote:

Yes you are correct I mistyped "<" when I copied the code over.

Argghhhh! Why in the sake of do you type the code into AVRfreaks. For the whole time of the existence of the World Wide Web I have not encountered one computer/OS that does not have a copy/paste function.

It is sooo darn meaningless to read, and find faults in, code that has been typed into the forum post. It is a waste of time. Mine, not yours, so that may be the reason for you not caring.

I will not allocate more time to look at your random key-presses in posts. I'm out.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

My favourite topic raises it's ugly head here - atomicity. seconds and milliseconds are integers so there two reads need to be done for each. What happens if your timer2_ovf interrupt kicks in between? In order to do a valid read of te time, you need to disable interrupts, copy seconds and milliseconds into another set of variables, re-enable interrupts then do your calc with the copies. Only then can you ensure that you have read the variables atomically. Otherwise it will work "most of the time".

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

Why would seconds (0..59) be stored in an unsigned int (0..65535) anyway?

BTW if you do have an int that only ever counts 0..59 so all activity is isolated to the low byte then are there really atomicity problems? Discuss.

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

The compiler could be optimizing your code out. I've had this happen to me a couple times.
I'm not saying it's that necessarily...but can't hurt to make sure. The compiler tends to be a little overaggressibve sometimes and optimize out statements. Make sure you can set a breakpoint on the currentTime = getTimeOfTimer2(); part when its running...if it complains "Can't bind breakpoint to code" or something similar then thats your problem.

The print statement would force the compiler to include the code.

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

RabidCicada you were correct. The compiler was optimizing out the do while loop. I made the two variables "currentTime" and "stopTime" volatile global variables and the program executed as expected.

My embedded programing coworker said that if you declare the variables as volatile global variables your compiler would not be allowed to optimize the statements out.

Worked like a charm.

Updated Code:

#define F_CPU  1000000

#include 
#include 
#include 

#define TIMER2_COUNTER_LIMIT   250

void pauseTheSystem(float);
float getTimeOfTimer2(void);

volatile unsigned int timeUnit = 0;
volatile unsigned int milliSeconds = 0;
volatile unsigned int seconds = 0;

volatile float currentTime = 0;
volatile float stopTime = 0;

ISR(TIMER2_OVF_vect)   
{
   ++timeUnit;

   if(timeUnit >= 4){
      milliSeconds++;
      timeUnit = 0;

      if(milliSeconds >= 1000)
      {
         seconds++;
         milliSeconds = 0;
      }
   }
}

int main(void)
{
   TIMSK |= (1 << TOIE2);
   OCR2 = TIMER2_COUNTER_LIMIT;
   TCNT2 = 0;
   TCCR2 |= (1 << CS20);

   sei();

   DDRB = 0xff;
   PORTB = 0xff;

   while (1)
   {
      PORTB &= ~(1<<PORTB0);

      pauseTheSystem(500);

      PORTB = 0xff;

      pauseTheSystem(500);      
   }
}

float getTimeOfTimer2(void)
{
   return (float)seconds + (float)milliSeconds/1000;
}

void pauseTheSystem(float pauseMilliSeconds)
{
   stopTime = getTimeOfTimer2() + pauseMilliSeconds/1000;

   currentTime = 0;
   
   do
   {
      currentTime = getTimeOfTimer2();

   }while(stopTime > currentTime);
} 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You haven't fixed the atomicity issues! If you find you occasionally get weird time values, then you'll know why.