Trying To Understand Teensy2.0++ Timers

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

I'm fooling around with my new Teensy2.0++ and trying to learn how to play with interrupts. I want to make the LED toggle at 1Hz (one second on, one second off). I've tried following Dean's tutorial and the datasheet, but I'm having some trouble, the LED is toggling, but at much longer than 1Hz, which makes me think I'm missing something. Here's my code:

#include 
#include 
#include 

ISR(TIMER1_COMPA_vect)
{
	PORTD ^= (1 << 6);
}

void init (void)
{	
	/**** Clock Settings ****/
	// Enable Clock Change
	CLKPR = (1 << CLKPCE);
	// Set Clock Prescaler to 0x00 (16 Mhz)
	CLKPR = 0x00;
	
	/**** Peripheral Initialization ****/
	/* Timer 1 - 1 Second Interrupt Generator */
	// Set CTC Mode & prescaler to 256
	TCCR1B |= (1 << WGM12 | 1 << CS12 | 0 << CS11 | 0 << CS10);
		
	// Set Output Compare Channel A for 1 Hz @ 16 MHz / 256
	OCR1A = 62499;
	
	TIMSK1 |= (1 << OCIE1A);
	
	PRR0 = 0x00;
	
	/**** GPIO Initialization ****/
	// LED
	DDRD |= (1<<6);
	
	
	/**** Enable Interrupts ****/
	sei();
}

int main(void)
{
	init();
	
    while(1)
    {
		
    }
}

I'd like to be running at 16Mhz, so I think I've done my math right, but I'm not certain. Changing the value in OCR1A doesn't seem to do anything to the toggle speed, which makes me think I'm totally missing something here, but I'm not sure. Any thoughts?

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

Quote:
but at much longer than 1Hz,

It would help if you could tell us what the actual toggle period that you have.

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

If by "much longer" you mean 8 times what it should be, then it is likely because your CKDIV8 fuse is set.

Regards,
Steve A.

The Board helps those that help themselves.

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

Errrmmmm... Have you checked to make sure the teensy bootloader has returned the timer config registers back to their default values?

You can check that the clock is correctly being set to 16MHz by toggling a different LED inside of the while loop in main() with a delay_ms(500) or something similar (make sure you set F_CPU correctly, though).

- S

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

Quote:

I want to make the LED toggle at 1Hz (one second on, one second off).

That isn't 1Hz, that is 0.5Hz.

1Hz would be 0.5s on, 0.5s off.

A "cycle" only completes when you've got back to where you started.

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

I haven't measured the time with a stopwatch yet, but about 8 seconds longer sounds right. However, if I change the OCR1A value, the period doesn't seem to change.

I don't have any extra LEDs at the moment, but I can definitely try getting that set up.

I feel like I'm missing something obvious here, but I double checked Dean's tutorial & the Teensy website, and I don't see what's missing. It's almost like the clock is running slow (should CKDIV8 matter if I change the prescaler?) and then it's like Timer1 is not being set properly, but I don't really understand why not.

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

Err...so I might be an idiot.

I had assumed that interrupts were disabled by default, but perhaps not? On a whim, I added a

cli();

to the top of my init() function, and now everything is working as expected.

*sigh*

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

But in that compiler interrupts ARE disabled by default?!?

However does this chip have a bootloader that actually launches this code you have written. If so it sounds like that may be doing an SEI and then forgetting to set things back to default (CLI) before it enters the application program. That's pretty naughty! I wonder what else they have left in a non-default state?

If the source of the bootloader is available I'd take a look through and see if there any other nasty gotchas.

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

So I'm using a Teensy++ 2.0, from http://pjrc.com/teensy/index.html. Paul's developed the "HalfKay" bootloader, which takes up a tiny amount of EEPROM space (512B), but is unfortunately closed source. It is USB enabled (USB HID) which I'm guessing means it's using interrupts, but it's hard to tell.

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

I guess this is just one of the compromises of squeezing something like that into 0.5KB. A decent bootloader should force a watchdog reset before entering the app to be sure of a "clean machine" but I guess there just wasn't room for things like that.

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

Quote:

I had assumed that interrupts were disabled by default, but perhaps not? On a whim, I added a
Code:
cli();
to the top of my init() function, and now everything is working as expected.

*sigh*


Quote:

But in that compiler interrupts ARE disabled by default?!?

OK, I'll bite: Whether interrupts are on or off when the init() is run, then what difference would it make? There might be a spurious interrupt that fires, but what would it matter?

That said, CLKPR work has a 4-cycle limitation. So if the spurious interrupt hits at that time then the clock prescaler may be off.

Other than that, can you tell me which part(s) of init() might not be happy if interrupts are globally enabled?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

The only thing I can think of is CLKPR being cut in half, and not being set properly. There's literally no other interrupts set, what you see above is all of the code, there's nothing else.

One other thing that occurred to me, my computer was rebooted overnight. It's possible that there was a stale file handle that the Teensy loader app (Paul's custom equivalent to FLIP) was using to flash? Seems unlikely, but I've seen odder things before :/.

clawson,

The HalfKay bootloader is both awesome and insanely annoying. It's definitely a tradeoff, but for my purposes it's pretty nice, usually. As soon as I add my own buttons to my breadboarded circuit. Since the only button on the Teensy++ just resets it into the bootloader...

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

Quote:

The only thing I can think of is CLKPR being cut in half, and not being set properly.

Doesn't the GCC have a "safe" version of CLKPR setting? "clock_prescale_set()"?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

theusch wrote:
Doesn't the GCC have a "safe" version of CLKPR setting? "clock_prescale_set()"?

I'm not familiar with that, but it does look like that function (macro?) exists.

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

Quote:

I'm not familiar with that

which is why God invented user manuals:

http://www.nongnu.org/avr-libc/u...

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

clawson wrote:
which is why God invented user manuals:

http://www.nongnu.org/avr-libc/u...

Well, and it's nice that you're helping to inform us stupidheads about such nice things! :lol:

Thanks Clawson, I was not aware of that website, which will certainly make things easier!

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

Quote:

I was not aware of that website, which will certainly make things easier!

Well there *should* be a copy of those same HTML pages installed on your HDD along with the avr-gcc (in ./doc/) but atmel forgot it in AS6.