NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » Help with delay_us using a 9.216mhz crystal
September 10, 2012 by akschu ![]() |
Hello Fellow Nerds, I have a project that I want to run at 9.216 because I want it to be solid at the various serial baud rates, and it needs to run on 3.3v (which the atmel can't do at 14.7mhz) The issue is that my code does some things with timing, but of course my delay_us doesn't work correctly anymore. I've changed it to something like this (sorry don't have the code directly in front of me):
The idea is that I can figure out how much time a nop takes then convert that into us and do some rounding to come reasonably close. The issue is that I need to use a 32-bit int because when I use a 16 bit the conversion is greater than 1 and then I have the possibility of foo being greater than 16-bits. When I convert to 32-bit foo is less than 1 because it takes longer for the micro to convert everything. The issue is that this isn't all that accurate because of the overhead. So what can I do to get a more accurate delay? Can you Nerd Kit Dudes post something on timing and how to run at different speeds and get accurate delay_us? thanks, schu |
---|---|
September 10, 2012 by pcbolt ![]() |
@ akschu In the NK "delay.c" file you'll see that they set the number of NOP statements to 9 for 1 uSec using a 14 Mhz oscillator. For a 9 Mhz clock, you'd have to use 6 NOPs. You could just copy the NK file, alter it to 6 NOPs and save it as some other name ("delay9.c"). You'd have to do the same for "delay.h" but without any alterations. |
September 10, 2012 by akschu ![]() |
That doesn't work for some reason. Here is what I have for delay.c:
And using the blinking led code:
That should give me 500ms on and 500ms off, but it doesn't. My saleae logic analyzer is showing me that it's on then off for 542.7ms which is almost 10% off. And this is with 3 NOPs. Any other ideas? schu |
September 11, 2012 by Noter ![]() |
Maybe one of the timers will work for you, interrupt or pwm. Here's an interrupt example. For 1ms pulse I would use a smaller scaler to improve accuracy.
|
September 11, 2012 by bretm ![]() |
If you're on Windows, Nerdkits is based on WinAVR. With that library you can use _delay_us instead of Nerdkit's delay_us. Other host platforms probably support the same or similar. The _delay_us function is more accurate than the Nerdkit's version. The reason Nerdkits have delay_us is that it supports variable delays. Since you just want a constant delay, _delay_us will work just fine. Just be sure to #define FPU with the correct value. _delay_us also supports floating-point values, and the math is done at compile-time so it doesn't pull in floating-point support libraries which would take a lot of program space. See this library article for more information. |
September 11, 2012 by akschu ![]() |
Actually, I do need it to be variable, it's just not variable right now because I haven't implemented the part of the code that will change the pwm output. I don't need it to be dead accurate, but I do want it within 2-3% which I should be able to do. schu |
September 11, 2012 by pcbolt ![]() |
schu - With 9.216 Mhz, the execution time per machine code step should be 108.5 ns. By your code above that would mean the machine code to jump to the "delay" function, set up the stack, start the "for" loop and execute 3 NOPs must be 10 machine code operations. That would give you a clock of 1.085 uSec for each uSec you want. That 8.5% error is exactly what you are seeing with 500 mSec vs. 542.7 mSec. Using 2 NOP's should be closer 0.9766 uSec per uSec or 2.34%. If you test this, please let me know how it went. |
September 11, 2012 by akschu ![]() |
I get 488.4ms with two nops. I need to read a lot more about machine operations. Do you have any books or links for me to read through. I really need to understand this stuff so that my project can be reliable. schu |
September 11, 2012 by pcbolt ![]() |
schu - Looks like you are within the 3% margin. That's pretty good. You can always modify your time variable to take into account the slight difference. As far as books/links go, I would actually start with the datasheet for the ATmega 168 in the section on the instruction set. Then write some simple code in C, compile it and check out the *.ass file output. To do this type...
It will show you the machine code instructions used to generate a .hex file (before final linking I think). Here "filename" should be replaced by the name of the program you are interested in. The problem with books and website in regards to machine code is that it's hard to generalize machine-specific instruction sets and what works for some does not work for others. The ATmega is a whole different animal than what you might encounter. |
September 11, 2012 by Rick_S ![]() |
Noter!! Are you back??? !! |
September 11, 2012 by Noter ![]() |
Hi Rick! Yep, looks like I'll be around a while longer! |
September 11, 2012 by Ralphxyz ![]() |
Wow Paul, great to see you. Ralph |
September 11, 2012 by sask55 ![]() |
I agree! It is great to see a post from you Noter. You where such a big help to me with my fridge control project. You are one of major contributors to this forum. I hope to see many more of your informative and interesting posts from you in the future. Darryl |
Please log in to post a reply.
Did you know that any circuit of voltage sources and resistors can be simplified to a "Thevenin" equivalent circuit? Learn more...
|