[TUT] [C] Newbie's Guide to AVR Timers

Go To Last Post
482 posts / 0 new

Pages

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

Post your code.

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

Following is the code that i tried to run on atmega8:

#include  
#include  

int main (void) 
{ 
   DDRB |= (1 << 0); // Set LED as output 
   PORTB=0X00;

   TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode 

   TIMSK |= (1 << OCIE1A); // Enable CTC interrupt 

   sei(); //  Enable global interrupts 

   OCR1A   = 31250; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 256 

   TCCR1B |= (1 << CS12) ; // Start timer at Fcpu/256 

   for(;;) 
   { 

   } 
} 

ISR(TIMER1_COMPA_vect) 
 {
   PORTB ^= (1 << 0); // Toggle the LED 
 }

Following is what i get when i do make all:

> "make.exe" all
avr-gcc -g -Wall -O2 -mmcu=atmega8 -c -o interrupt.o interrupt.c
interrupt.c:26: warning: return type defaults to `int'
interrupt.c: In function `ISR':
interrupt.c:28: warning: control reaches end of non-void function
avr-gcc -g -Wall -O2 -mmcu=atmega8 -Wl,-Map,interrupt.map -o interrupt.elf interrupt.o -lm
avr-objdump -h -S interrupt.elf > interrupt.lst
avr-objcopy -j .text -j .data -O ihex interrupt.elf interrupt.hex
avr-objcopy -j .text -j .data -O binary interrupt.elf interrupt.bin
avr-objcopy -j .text -j .data -O srec interrupt.elf interrupt.srec
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex interrupt.elf interrupt_eeprom.hex
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O binary interrupt.elf interrupt_eeprom.bin
avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O srec interrupt.elf interrupt_eeprom.srec

> Process Exit Code: 0

Kindly guide!!

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

There's one more doubt.

In the tutorial the following code is given as

TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64

But I feel it should rather be:

TCCR1B |= ((1 << CS10) & (1 << CS11)); // Start timer at Fcpu/64

because both the bits need to be set simultaneously.

Both codes are working well on the hardware but I cant figure out how is it possible??

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

nupurnsit!

When the compiler shows the warnings you see for the ISR() then this is a strong indication that your compiler is quite old. What version of avr-gcc are you using? (Ok, ok, it's actually mostly about the version of avr-libc but the compiler version will normally hint about the age of the complete tool chain.)

Start a command prompt, go to the directory that contains avr-gcc.exe and do this:

C:\somewhere...\> avr-gcc --version

copy the version information and post paste it in a post here.

Or if you have installed avr-gcc through WinAVR , just tell us the version of WinAVR.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"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

Quote:

because both the bits need to be set simultaneously.

Time to get a good book on Boolean algebra methinks.

(with & the two single bits in different positions cancel and the result is always 0)

Maybe start with the "101" thread in this forum?

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

i have installed avr-gcc 3.4.3 using winavr version 20050214.

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

nupurnsit wrote:
i have installed avr-gcc 3.4.3 using winavr version 20050214.

Then there's your problem. ISR did not exist 4 years ago - back then the now deprecated SIGNAL and INTERRUPT were being used.

I gotta ask though what on earth possessed you to install a FOUR year old version??

Suggest you pick up and install 20081205

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

Hey thanx.
the code worked with the new version of winavr.

Actually i was working wid an institution and the old version was available with them. As i had no idea about the new versions of winavr, so i worked with the old one.

But anyway thanx again...

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

Thank you very much !

Your job is great. I am starting with microcontrollers, specially Mega8 and Mega16. I was searching for a good tutorial, when I have found this one.

It is the best !

I am anxiously waiting for a PWM tutorial :)

Rio de Janeiro - Brazil
Avr Studio 4.16
Assembler Code Only.
Protoboard Hardware
PC Parallel Ponyprog
Atmega8 / Atmega16
Crystal 11.0592MHz

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

Thank you very much for that great tutorial! It helped me so much. But I found this equation in the ATMega 128 datasheet (page 125, CTC Mode)

fOCnA = fclk / 2*N*(1+OCRnA)

Where fclk is the CPU clock and N the pre-scaler. If I get it right you get the following equation after re-arranging:

OCRnA = (fclk/2*N*fOCnA) -1

Lets say your CPU is clocked with 16MHz and your desired frequency is 20kHz it should look like this:

OCRnA = (16MHz/2*8*20kHz)-1

which results in 49. So with a pre-scaler of 8 you get 20kHz on OC1A if you load 49 into OCR1A. I checked the result with a scope so it works that way. If I'd use your equation I'd receive 100 (OCR1A=16MHz/8/20kHz)which would result in half of the frequency I need. Am I getting something wrong here?

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

The equation that Dean gave is for the frequency of the timer compares (and it is incorrect in that it should subtract 1, so the value would be 99, not 100). Your equation is for the frequency of a toggled pin. The value of the pin is changed on each compare, so it takes two compares to create a complete cycle on the pin.

Regards,
Steve A.

The Board helps those that help themselves.

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

IC. Thank you very much for clearing things up! :)

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

Hello there,

I just would like to thank the author for this great tutorial!

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

I am using AVR162. I have problem using one of the codes in tutorial...

#include 
#include 
#include 

#define F_CPU 1000000UL 	// system frequency at 1MHz


int main (void)
{
	DDRB = 0XFF;

	PORTB = 0x00;
	TCCR1B |= (1 << CS10); // Set up timer
	TCNT1 =0;			   // reset time value
	while(1)
	{
		if (TCNT1 >=5)     // toggle PORTB3 at every 5 clock cycle
		{
			PORTB ^= ( 1  << 3);
			TCNT1= 0;		// reset time value
		}
	}

}

This is the code designed to toggle PORTB3 at every 5 clock of 1MHz. But I got 10 clock toggling instead... Can someone please point me out? Many thanks

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

As you toggle the bit it takes two toggles to produce one complete cycle - hence the /2 effect

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

How long do you think that it takes to do the code within the while loop? Just the code after the 'if' to determine if the timer has gone 5 clocks will take a minimum of 6 cycles, plus 2 more for the while loop.

Regards,
Steve A.

The Board helps those that help themselves.

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

Actually timer interrupts are easier than you think:
http://blog.stranadurakov.com/20...

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

I thought it would be helpful to include a table of the bit definitions to set the prescaler values.

Prescaler Table
-------------------------------------
CSx2 CSx1 CSx0
   0    0    0      Timer Stopped
   0    0    1      System Clock/1 (Equal to System Clock)
   0    1    0      System Clock/8
   0    1    1      System Clock/64
   1    0    0      System Clock/256
   1    0    1      System Clock/1024
   1    1    0      External Pin T0, counts a falling edge
   1    1    1      External Pin T0, counts a rising edge
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi abcminiuser,

first of all thanks for the tutorial. I have an question about the value of the target timer count. If let say i'm using 4Mhz xtal(external), so how is the calculation for the value for target timer count?

thank you.

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

I put the calculation into a spreadsheet - helps a lot. You can enter your desired frequency and the system clock and you get the countmode, togglemode and if you can use 8 or 16 bit as well as the variation so you can chose the closest value. Hope you can need it.

Attachment(s): 

Last Edited: Mon. May 11, 2009 - 08:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

lostchild wrote:
I put the calculation into a spreadsheet - helps a lot. You can enter your desired frequency and the system clock and you get the countmode, togglemode and if you can use 8 or 16 bit as well as the variation so you can chose the closest value. Hope you can need it.

What did you use to zip this up? Winzip gives this error message.

xtracting to "C:\projects\AIRSOFT\"
Use Path: yes Overlay Files: no
skipping: Atmel_Timer_Prescaler.ods unsupported compression method 12
skipping: Atmel_Timer_Prescaler.xls unsupported compression method 12
error: no files were found - nothing to do

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

Extracts ok with 7-zip
/Lars

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

Lajon wrote:
Extracts ok with 7-zip
/Lars

I'm using Winzip 8.0 currently, not sure why that doesn't work.

I downloaded 7-zip and in fact works just fine.

Thanks

Last Edited: Fri. May 8, 2009 - 05:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well neither WinRAR now Windows Vista can unzip the files either. I'd suggest you turn the candle down a bit inside WinZip to make a more widely compatible .zip file.

(by the way, what does this offer that avrcalc doesn't already do?)

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

clawson: it was compressed with 7zip and included an Open Office as well as a Microsoft Excel Spreadsheet. I reduced it to the Microsoft Excel Sheet since OO can handle both. Well, to be honest I did not know about avrcalc - I apologize for that! One reason to chose the spreadsheet might be that you use it on every operating system?! I don't know if it works on every system, I work with a German Windows XP and a German Open Office installation.

I'm sorry for people not being able to open the archive. I edited the post above.

Josef

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

I read this tutorial last and it's an EXCELLENT one! Totally helpful! Great job and THANK YOU!

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

indeed, very good tutorial!

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

Hi,

When somebody would like to see all possible
frequencies for his/her uC crystal, please
see this: http://sebastianpawlak.com/index...

Regards,
CypressValley

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

Quote:

Firstly, we need to start the timer at the top of our main routine, so that it will start counting. To do this, we need to supply the timer with a clock; as soon as it is clocked it will begin counting in parallel with the AVR's CPU core (this is called asynchronous operation).

Isn't that called synchronous?

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

Quote:

Isn't that called synchronous?

Oops! Quite right - I'll correct that.

- Dean :twisted:

Make Atmel Studio better with my free extensions. Open source and feedback welcome!

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

Really, thank you very much.
Very useful and perfectly illustrated and simplified.

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

Question - Alot of clock projects with the AVR use 32.768Khz crystals... Why is that?

This guide is awesome though, I like the explanation. I never knew it had a timer system :)

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

Quote:
Alot of clock projects with the AVR use 32.768Khz crystals... Why is that?

Divide 32,768 by powers of 2 (2, 4, 8, 16, etc.) and see what you get. Keep going until you get to 32,768 :-) .

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

SteveN wrote:
Quote:
Alot of clock projects with the AVR use 32.768Khz crystals... Why is that?

Divide 32,768 by powers of 2 (2, 4, 8, 16, etc.) and see what you get. Keep going until you get to 32,768 :-) .

THAT IS SOOOOO COOOL! That makes sense. Thanks :)

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

Wow, this tutorial was incredible.

I feel like I'm actually starting to get the hang of this stuff and I pretty much owe it all to you Dean. Thanks so much.

-apc

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

Thanks so much for the tutorial :)

One question though, what is the best method for producing accurate long delays? I'm building an intervalometer for a camera and it's very important that the delays are dead on.

The delays i need are user defined and i think it'll be up to one hour (any longer than that and i think the batteries in the SLR would be an issue - and if you're doing 3 hours between shots, why not do every half hour and make the movie frame rate better!).

I also need to make some very accurate small delays (in the order of a few hundred us), but this has been fairly well documented i think.

Basically i'm a bit lost on how to proceed, i'm comfortable just using _delay_ms(), but i don't know how accurate that is. Various solutions have involved writing assembly code to base the timings precisely using clock cycles, but whether there's a simpler method...?

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

Quote:

it's very important that the delays are dead on.

What does "dead on" mean. One second, or one femtosecond, or what? State your requirement on precision needed.

You will never get better precision than the precision of the clock source you are using. Eg a crystal will give you about 20 - 50 ppm errors.

Personally, I'd go fo a timer that interrupts with the precision needed, eg once every millisecond. I'd count milliseconds, and let the main loop do whatever needss to be doen at the appropriate times.

If the timer interrupts every millisecond, and the AVR runs at e 8 MHz you have 8000 clocks between each interrupt. Should be plenty of time to both handle the interrupt (which is just basically an increment of a variable), and running the main loop (which 1. picks the variable value from the ISR and then zeroes it, 2. adds that value to the millisecond count, and 3. examines if the millisecond count has reache a value that warrants any action and if so executes that action).

If your system will be exposed to variations in supply voltage, tempereature etc then a separate RTC chip which can compensate for such variations might be an option.

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"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

The issue is that it's likely to be outside at night where the temperature could drop anywhere from 10 to 20 degrees and over a long period of time (say 10-30 minutes) all the little errors in the timers add up :P Of course i could just insulate the box - but i'll worry about that later!

Dead on, hah, sorry about that, i should be in Physics mode with ± errors at the ready. I mean, i don't want to do a 5 minute interval and find it's 20 seconds out.

I found a pretty good piece of code that i've bodged into mine - http://www.shapeshifter.se/2009/... - which uses what seems to be the standard watch crystal + TIMER2 setup.

So, i think for the moment i'm ok, just have to sort out some pesky compile errors... something about undefined symbols (which is confusing because all the files are linked), but that's another topic.

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

Quote:

Dead on, hah, sorry about that, i should be in Physics mode with ± errors at the ready.

Still nothing about what accuracy you actually need.

Quote:

i don't want to do a 5 minute interval and find it's 20 seconds out.

20/300 is 6.7 percent. You will get 50 ppm, ie about 1300 times better than that, with a crystal. Or if you like, 50 ppm error of 5 minutes is 0.03 seconds.

Now please tell us if this is enough for you or you need something better. As for now you merely say something like it should be "dead on" and we have no way of giving good advice for such a weak requirement specification.

Quote:

all the little errors in the timers add up

If we are talking about a hardware Timer/Counter (which was what I suggested) then the error you will get is from the clock source proper (eg the crystal). There will be no additional error introduced if you code the application right.

Are we maybe seeing a misconcetion here? That "servicing" the timer interrupts will "stel" time that will add errors to the mesurement of time. If so, then this will not happend.

The Interrupt Service Routine (ISR) gets activated each time the timer reaches a specified value. Lets asume that you have the hardware timer set up so that you get an interrupt every millisecond. In the ISR you simply set a flag that a millisecond timer event has occured, nothing more.

Please note that while this happends the timer continues ticking. Set up correctly it will just wrap from the interrupt trigging value back to zero, and keep on counting. This means that while the AVR CPU is handling the interrupt the timer has already started counting for the next millisecond event. In essence, you have some parallell proessing going on.

The ISR and the main loop needs to communicate over this flag, so it needs the volatile attribute. The flag and the ISR would look something like this:

volatile unsigned char millisecondFlag;

ISR(theTimerEvent)
{
   millisecondFlag++;
}

When the ISR has finished it's trivial work it ends, and the CPU continues to execute where it was before the interrupt. In my sketch above that is the main loop of the program, and if you want it to do something every second, it would go something like this:

int main(void)
{
   // A variable to keep count of milliseconds passed
   unsigned long millisecondsPassed = 0;
   // Set up the timer
   SetupTimer();

   // Main loop
   while (1)
   {
      // Handle if the timer has passed another millisecond
      if (millisecondFlag > 0)
      {
         millisecondsPassed += millisecondFlag;
         millisecondFlag = 0;
      }

      // Handle if 1 second has passed
      if (millisendsPassed >= 1000)
      {
         millisecondsPassed = 0;
         DoSomething();
      }
   }

   return 0;
}

Thats it. As the ISR is triggered every millisend, and we run the AVR at 8 MHz, this means thet there will be 8000 CPU cycles between every interrupt. There will be plenty of cycles to service the interrupt (which might take something like 25 or 50 cycles) and execute the loop hundreds of times. There is no risk that the timer will overrun the application. There will be no accumulated error apart from the error of the AVR clock source (eg the crystal).

The above is sketchy. There are some practical measures that has to be taken, eg asuring that access to shared variables are atomic.

Back to the accuracy: Although the above will contain no accumulative error, there are no guarantees that the execution of DoSomething() will happen on "a specific predictable millisecond every time". This is why you need to tell us more about what accuracy and precision you need. If you cant specify that in a numerical manner, but merely have "dead on" then in some sense you really don't know what you are doing and need to get back to thinking and analyzing the requirements.

You can never get "dead on". For an event occuring after 30 seconds of timing, how much is it allowed to miss that "absolute time". A microsecond? A millisecond? A second?

"He used to carry his guitar in a gunny sack, or sit beneath the tree by the railroad track. Oh the engineers would see him sitting in the shade, Strumming with the rhythm that the drivers made. People passing by, they would stop and say, "Oh, my, what that little country boy could play!" [Chuck Berry]

 

"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

I realise you can't be exact, as i said, the perils of being a Physicist and dealing with errors has hammered that home enough times.

However i don't really have an "exact" requirement for accuracy. I understand you need something a bit more concrete, but for the moment the requirement is "accurate enough to take photos at precise intervals without being a seconds out after a number of minutes" so i reasoned, go for as good as i can get and then i can possibly get it to do other things besides count intervals between firing shutters.

But lets just clarify this and say a millisecond is suitable accuracy.

As i said, i've now made a rough outline of the code using the link above. My loop is something like this:

else
			{	
				/* clear the LCD and start the real time clock */
				lcd_clrscr();
				lcd_puts("Taking Photos...\n");
				_delay_ms(50);
				clock_start();
				/* while the terminate button isn't pressed */
				while(!is_shoot_pressed == 1)
				{
					/* seconds is the number of seconds passed since we started */
					seconds = clock_seconds();
					/* if the elapsed time is greater than the shooting interval */
					if ( seconds >= shootinterval )
					{
					/* reset the timer */
					global_system_ticks = 0;
					/* display the shot count */
					shotcount++;
					lcd_puts("Shot:");
					lcd_gotoxy(6,2);
					lcd_putc(shotcount);
					_delay_ms(50);
					}
				}
				/* stop the clock */
					clock_stop();
				/* go back to the interval menu */
			}

There should be a "shoot" command in there somewhere, but i haven't quite worked out how to implement it yet.

I did wonder whether it was going to be an issue using delay in conjunction (required for the LCD), but then i realised that the interrupt would sort itself out anyway and i could call a few commands without worrying about it.

The number of seconds is calculated by the number of ticks passed (i.e. interrupts every 1/32 of a second - accurate enough i think). The timer is cleared after each interval to save bothering about working out multiples. ClockStart(); and ClockSto(); are pretty simple functions that set up the timer to run off the watch crystal and clock stop just sets all the timer control bits to zero.

(TCCR2B |= ~(1 << CS21);)

I've yet to try it out, but i think it'll work.

Thanks for all your help (and for putting up with my vagueness!).

EDIT:

Ah, i remember why it needs to be very accurate. The IR remote needs to send a signal with accurate delays for on/off. The sequence is:

- Wait for a start pulse (2000 usec)
- There must be no pulse for 27830 usec (pause)
- Receive a pulse (390 usec)
- Pause (1580 usec)
- Receive a second pulse (410 usec)
- Longer pause (3580 usec)
- Receive the last pulse (400 usec)

Each "on" pulse needs to be modulated at 39000kHz ish.

UPDATE: I think the solution to sending the modulated signal is just to include some assembly code. It works by itself so in theory calling it as a function inside a C file would work?

Of course this now means that i have to use an 8MHz crystal for the clock, so my timer script goes out the window. But i think _delay_ms(); will be good enough for photo intervals.

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

would just like to post a thank you to dean. Your tutorial has really helped me get started with my AVR, and not having a finished PWM tutorial actually encouraged me to open up my datasheet and figure it out myself :)

cheers.

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

This is my first official tutorial on AVR and it really opened me to this exciting world of microcontrollers. Really, learned a lot. Thanks Dean, for putting such time and effort in this excellent tutorial. By the way, you should write a book man, I'll surely buy it.

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

Just got thru your tutorial Dean and wanted to thank you heaps. It made learning the basics about timers a breeze.

Keep up the great work.

Craig

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

My question is in regards to "Part Four - The CTC Timer Mode" I have tried this and the LED stays on all the time, no toggle. The previous examples worked fine. I have copied and pasted his code directly, and still not toggle. I am using the stk500 @ 1MHz with an ATMEGA16 and Os Optimization. Any ideas?

#include

int main (void)
{
DDRB |= (1 << 0); // Set LED as output

TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
OCR1A = 15624; // Set CTC compare value to 1Hz at 1MHz AVR clock, with a prescaler of 64

TCCR1B |= ((1 << CS10) | (1 << CS11)); // Start timer at Fcpu/64

for ( ;; )
{
if (TIFR & (1 << OCF1A))
{
PORTB ^= (1 << 0); // Toggle the LED

TIFR = (1 << OCF1A); // clear the CTC flag (writing a logic one to the set flag clears it)
}
}
}

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

Man!!! Your tutorials are good, when is the book coming :P i will be your customer!

Mark
Germany

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

Beautiful! Very roundabout, but that turns out to be an effective way to teach something this convoluted. :^)

All the other tutorials, articles and things I read trying to avoid brute forcing my way through the datasheets and headers didn't get me a single working ISR. I still don't completely grok avr's timer system but I do have a cylon light in my atmega8515 here that I've walked through to. And that's a great start.

I'd buy your book too :)

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

Great tutorial. I was able to do some of it, but I was hoping that someone else's implementation was available.
Are there any libraries available for timers? I'm looking for something that will just let me time signals without having to program it from scratch. I'm using the ATmega128.

This is what I'd like to do:

while(1)
{
  if (trigger)
  {
     send_signal();
  }

}

an example trigger/signal could be 1 for 100us, 0 for 50us, 1 for 150us, 0 for 200us. So I would use a timer to test for the trigger, and then again to send the signal. And since the trigger/signal wouldn't be perfect I would need to be able to set a tolerance in us or %.

Thanks,

Waspinator

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

I have a question about CTC mode. If I change the OCR value in the interrupt will it cause any problems.

I am trying to control a servo (more accurately than PWM will give me) by setting two interrupts. The first is for the high period .9ms + 0 to 1.2 ms followed by 2.2ms - .9ms + 0 to 1.2ms. I am also using a second timer to get the update frequency of about 50 Hz.

I think the math works out to me being able to control 8 servo channels this way.

In general it works out to be something like this


volatile unsigned char s_num;
volatile unsigned char state;
volatile unsigned int s_0high, s_0low;
volatile unsigned int s_1high, s_1low;
.......

50hz timer interrupt
{
     calculate high and low as values for OCR for each servo;
     //s_n high and low will change in a feedback loop
     state = 0;
     s_num = 0;
     force compare on the timer; //cause the timer interrupt to fire!

     return;
}    

servo_timer_ISR()
{
  switch(state)
  {
    case 0:
      switch(s_num)
          //UPDATE OCR to the correct s_Nhigh value
          //UPDATE the correct servo control pin to high
      state = 1;
      break;

    case 1:
      switch(s_num)
          //UPDATE OCR to the correct s_Nlow value
          //UPDATE the correct servo control pin to low
      state = 0;
      ++s_num;
      break;
  }

  //invalid servo number results in no changes to outputs

  return;
}

So 50 times a second I start a chain of updates to each servo over a fixed period of time. The update frequency is fixed since:

time high + time low = 2.2 mS
50 Hz = 20mS period;
2.2mS * 8 < 20 mS

Will this work or am I doomed to fail?

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

Quote:
I have a question about CTC mode. If I change the OCR value in the interrupt will it cause any problems.

In CTC mode the OCR register is not double buffered, so you have to be careful when setting it as it may be hit twice within one PWM period.
Quote:
I am trying to control a servo (more accurately than PWM will give me) by setting two interrupts.

And why do you think that this method would be more accurate? Certainly you can do more servos with one AVR this way, but I doubt that you will gain anything in accuracy (and might even lose accuracy).

Regards,
Steve A.

The Board helps those that help themselves.

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

Koshchi wrote:
Quote:
I have a question about CTC mode. If I change the OCR value in the interrupt will it cause any problems.

In CTC mode the OCR register is not double buffered, so you have to be careful when setting it as it may be hit twice within one PWM period.
Quote:
I am trying to control a servo (more accurately than PWM will give me) by setting two interrupts.

And why do you think that this method would be more accurate? Certainly you can do more servos with one AVR this way, but I doubt that you will gain anything in accuracy (and might even lose accuracy).

The general idea being I can change OCR long before the timer gets close to its new or old value. I realize there is very little safety factor on the low pulse side but I can set a dead period of a few hundred uS between channels.

maybe:

0 to (900 + x) uS must be high
(900 +x) to 2500 uS must be low (could be 2100 but gives a bit of dead time if at max position)

next servo:
same as first but with 2500 uS offset on each value

The whole point is that use PWM give me a handful of valid values as the usable duty cycle is only a 10% range. Thus 90% of the possible duty cycle values of the PWM are useless. If I can take the 1.2mS interval into N (256) discrete time units, I can accurately control the servo to that many positions.

Pages