Because I apparently never learn, I am back to trying to get my board to run at 20 MHz. I can sure live with millis() and delay() being wrong. That's super easy to code around. The problem I am having though is that baud rates are wrong.
So I took a peek in to HardwareSeial.cpp to see what I can do. I confess, I'm not very clear on how the baud rate parts work. But, looking at the begin method, its clear it does some math to come up with the baud_setting varible. So I tried to modify the code to produce the same result for a 20 MHz crystal as it would for a 16 MHz one, and that was easy. Too bad it didn't work. I changed:
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
[/code}
To this:
[code]
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 5 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 10 / baud - 1) / 2;
}
I also changed the code above it that selected which method to use, but for now, that should not be a big deal. With these changes, the math works out the same with the new value for F_CPU.
So then, can anyone suggest a reason it didn't work?
Thanks...
Jim
[/code]
The problem I am having though is that baud rates are wrong.
Are you certain?
I vaguely recall working through that code on paper and reaching the conclusion that it works reasonably well for clock speeds at or above 8 MHz.
Yes, I see data corruption at 19,200. I have a device that I read data from at that baud rate, and with the 16 MHz crystal it works well, with the 20MHz crystal its no good at all. Similar issue with talking to the boot loader. I found a spread sheet on AVR Freaks that calculates baud rate sttings, now I just need to figure out where to put the numbers. off tot he data sheet...
BTW, i am able to talk to my device by telling my Arduino compatible board (at 20 MHz) to use a baud rate of 18500. It then talks to a 19,200 device fine.
Does the "boards.txt" entry for your board have the correct processor speed?
This problem...
BTW, i am able to talk to my device by telling my Arduino compatible board (at 20 MHz) to use a baud rate of 18500. It then talks to a 19,200 device fine.
...seems suspiciously like at 20 MHz board running a sketch compiled to run at 16 MHz.
I appreciate your comments, but the boards.txt file is set correctly. I fixed the problem.
Basically, there is a lot of code in hardwareSerial.cpp, in the begin() method, that tries to decide how to set up the baud rate. I refer to this:
uint16_t baud_setting;
bool use_u2x;
// U2X mode is needed for baud rates higher than (CPU Hz / 16)
if (baud > F_CPU / 16) {
use_u2x = true;
} else {
// figure out if U2X mode would allow for a better connection
// calculate the percent difference between the baud-rate specified and
// the real baud rate for both U2X and non-U2X mode (0-255 error percent)
uint8_t nonu2x_baud_error = abs((int)(255-((F_CPU/(16*(((F_CPU/8/baud-1)/2)+1))*255)/baud)));
uint8_t u2x_baud_error = abs((int)(255-((F_CPU/(8*(((F_CPU/4/baud-1)/2)+1))*255)/baud)));
// prefer non-U2X mode because it handles clock skew better
use_u2x = (nonu2x_baud_error > u2x_baud_error);
}
if (use_u2x) {
*_ucsra = 1 << _u2x;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
*_ucsra = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
*_ubrrh = baud_setting >> 8;
*_ubrrl = baud_setting;
I will study the data sheet a bit more when I am more awake, but rather than go through all that I replaced that code with this code:
#define BAUD_PRESCALE (((F_CPU / (baud * 16L))) -1)
*_ubrrh = BAUD_PRESCALE >> 8;
*_ubrrl = BAUD_PRESCALE;
That code is based on the instructions in the data sheet. A quick look at the replaced code makes me think there is a subtle bug, but when I am more awake I'll double check.
I was having the same issue in the boot loader code.
Anyhow, my app is now talking to the 19,200 baud device with no errors, even when set to, believe it or not, 19200. So I am happy. Big improvement. Next step, get that bootloader working with no verification errors.
The last step will be getting millis() and delay() to work correctly. With a 20 MHz crystal, a delay of 939 causes a 1 second delay. The math does not work out exactly right for that so I need to dig deep and figure out why that's happening. I looked into changing wiring.h, but that's not going to work. The clockCyclesPerMicrosecond is currently set correctly for a 20MHz board (appropriately enough, to 20).
Last time I looked at millis() there was a bit of asm in there, and that's not my best skill. So I'll dig in another time, but soon. For now, I just use some macros to define a 1 second delay as 939.
SImple sketch to "detect baudrates" might be usefull.
Set the serial monitor @1200 baud and run the sketch to detect at which speed meaningfull chars come out.
long baudrate = 800;
void setup()
{
Serial.begin(1200);
Serial.println("start");
}
void loop()
{
if (baudrate <= 1600)
{
Serial.begin(1200);
Serial.print(baudrate);
Serial.print(" : ");
delay(100);
Serial.begin(baudrate);
Serial.print(baudrate);
delay(100);
Serial.begin(1200);
Serial.println();
delay(100);
baudrate+=10;
}
}
(off topic)
An experiment with this sketch indicates that ~5% deviation still works, so in theory one could let the Arduino send the data 5% faster (buffer empty faster)...
Well if the system clock is a multiple of 1.8432MHz then there should be 0% error. But of course 20 does not qualify. Neither does 16 for that matter.
To find an idea of the error:
System clock == 7372800Hz
BaudValue = (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
BaudValue = (7372800 / (9600 * 16) - 1)
BaudValue = (7372800 / 153600 - 1)
BaudValue = (48 - 1)
BaudValue = 47
If 47 had a remainder, like 47.1, then that .1 represents the error, in this case about 2%. Any more than that is a bad idea. With a 20 MHz clock, a nice speed is 115,200. My needed speed of 19,200 is pretty nice as well, with a baud value of 64.1042. Just tolerable error.
I am going to hit the sack and let this thing collect data all night, hopefully there won't be any errors. If there are, I may need to pick a slightly slower crytal, like 18.432 MHz. At that point I may as well stay at 16MHz.
Oh, I set the boot loader baud rate to 115,200 but I still get verification errors. I'll have to get to the bottom of that.