High res software timer for freq generator... weird problem!

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

So I'm attempting to do what could quite possibly be the simplest thing ever, but I am getting very weird results that have been driving me mad for the past 24 hours, so I'm hoping you all might see something that I'm missing!

I'm using an ATtiny45 (running off the internal 8 MHz oscillator) to do some frequency shifting and I'm getting some weird glitching issues where I get output transitions at weird times randomly. In an effort to debug the problem, I've rolled the code back to an incredibly simple situation: generating a single custom square wave using a high res timer, and I still get glitches! (All verified on a scope).

I'm using a 32-bit overflow counter as the high resolution software counter:

volatile unsigned long overflowCounter = 0;

The Timer0 overflow ISR looks like:

ISR( TIM0_OVF_vect)
{
  overflowCounter++;
}

The main loop to generate a simple 50% duty cycle square wave of frequency 100 Hz is:

unsigned char currentPinState;
unsigned char lastPinState = 0;  // set last pin state as low

int main ( void )
{
  DDRB |= (1 << 0);  // set PORTB 0 to output                 
  PORTB &= ~(1 << 0);  // set PORTB 0 initially low             

  while ( 1 )
  {
    // get current pin state
    currentPinState = PORTB & (1 << 0);

    if ( currentPinState )  // pin is high
    {
      if ( overflowCounter >= 50UL )  // 5 ms passed
      {
        PORTB &= ~(1 << 0);  // generate falling edge
      }
    }
    else  // pin is low
    {
      if ( overflowCounter >= 100UL )  // 10 ms passed
      {
        PORTB |= (1 << 0);  // generate rising edge
        overflowCounter = 0;  // reset counter to 0
      }
    }
	
    lastPinState = currentPinState;  // record pin state
  }

  return 0;   
}

The problem is that while I get a nice 50% duty cycle 100 Hz wave a lot of the time, I also seem to get random glitches where I get an early positive edge transition. The high period always seems to be correct, but the low period is sometimes too short, and when it IS too short, it's always the same too-short length (it doesn't appear to randomly vary all over the place).

So am I missing something? All other interrupts are disabled, no WDT, etc. This is the only code running in the micro. The chip is not resetting unintentionally, and all glitching is verified on a scope. I verified that the ISR is executing every 100 us by toggling a line and watching it on the scope.

I can only assume that there is something up with the initialization of overflowCounter to 0, or with the comparison to the constants. But since overflowCounter is volatile, it shouldn't be a problem, correct? Any ideas? I don't know what else to do at this point for debugging other than investing in a DebugWire interface. Thanks!

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

Remember that overflowcounter is actually four
memory locations, which all need to be touched
by your ISR. If the interrupt fires in the middle of
the main loop reading out parts of that variable,
you'll get inconsistent results.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.

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

Hi Jorg,

I was worried about such problems, but I thought that declaring the variable as volatile somehow magically took care of such issues. I guess this is not the case (I should read up some on voltatile...)?

You are indeed correct, as I just tried disabling interrupts before I read overflowCounter in the main loop and re-enabling afterwards, and sure enough the glitch is gone. I swear I tried this before in debugging but I must have missed some references to the counter somewhere in the main loop since it glitched less often but still gitched.

Thanks Jorg, you're the man as usual! :D Much appreciated.

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

Hmm so volatile is apparently just there to prevent accesses to the variable to be optimized out in certain cases.

So basically it's safe to read an 8-bit variable outside an ISR without turning off interrupts, but for larger variables that take multiple instructions to read and compare interrupts need to be turned off to prevent possible write during read scenarios. Am I close on this? :)

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

Exactly, on both items.

Jörg Wunsch

Please don't send me PMs, use email if you want to approach me personally.