I am using the Arduino Uno at 11.0592MHz. I recognized that the delayMicroseconds() function is about 27% to fast. The reason is, that the code in wiring.c assumes that the clock peed is now 8MHz.
Now I try to fix it. I found different posts but I am not sure what is the most Arduino compatible way. What can you recommend?
Multiply the variable "us" in wiring.c with 1.27 if the F_CPU is 11.0592MHz? Easy but only affects delayMicroseconds and not millis(), micros(), delay(), etc.
pro.name=Arduino Pro or Pro Mini (3.3V, 8 MHz) w/ ATmega168
pro.upload.protocol=arduino
pro.upload.maximum_size=14336
pro.upload.speed=19200
pro.bootloader.low_fuses=0xc6
pro.bootloader.high_fuses=0xdd
pro.bootloader.extended_fuses=0x00
pro.bootloader.path=atmega
pro.bootloader.file=ATmegaBOOT_168_pro_8MHz.hex
pro.bootloader.unlock_bits=0x3F
pro.bootloader.lock_bits=0x0F
pro.build.mcu=atmega168
pro.build.f_cpu=8000000L
pro.build.core=arduino
pro.build.variant=standard
I would hope it would be a simple job of altering the _cpu= setting in the boards.txt but suspect someone will (politely) tell us why this is not so. You may run into issues if your using Serial though as I think the baud rate settings expect either 8 or 16 MHz.
The timing functions are wrong as weel (about 27.6%) because they are also only written for 8MHz, 16Mhz and 20MHz. The file which is needed here is the following file: hardware/arduino/cores/arduino/wiring.c
Then later in the delaymicrosecond() the bit shifts for the "us" variable.
/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
// calling avrlib's delay_us() function with low values (e.g. 1 or
// 2 microseconds) gives delays longer than desired.
//delay_us(us);
#if F_CPU >= 20000000L
// for the 20 MHz clock on rare Arduino boards
// for a one-microsecond delay, simply wait 2 cycle and return. The overhead
// of the function call yields a delay of exactly a one microsecond.
__asm__ __volatile__ (
"nop" "\n\t"
"nop"); //just waiting 2 cycle
if (--us == 0)
return;
// the following loop takes a 1/5 of a microsecond (4 cycles)
// per iteration, so execute it five times for each microsecond of
// delay requested.
us = (us<<2) + us; // x5 us
// account for the time taken in the preceeding commands.
us -= 2;
#elif F_CPU >= 16000000L
// for the 16 MHz clock on most Arduino boards
// for a one-microsecond delay, simply return. the overhead
// of the function call yields a delay of approximately 1 1/8 us.
if (--us == 0)
return;
// the following loop takes a quarter of a microsecond (4 cycles)
// per iteration, so execute it four times for each microsecond of
// delay requested.
us <<= 2;
// account for the time taken in the preceeding commands.
us -= 2;
#else
// for the 8 MHz internal clock on the ATmega168
// for a one- or two-microsecond delay, simply return. the overhead of
// the function calls takes more than two microseconds. can't just
// subtract two, since us is unsigned; we'd overflow.
if (--us == 0)
return;
if (--us == 0)
return;
// the following loop takes half of a microsecond (4 cycles)
// per iteration, so execute it twice for each microsecond of
// delay requested.
us <<= 1;
// partially compensate for the time taken by the preceeding commands.
// we can't subtract any more than this or we'd overflow w/ small delays.
us--;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
"brne 1b" : "=w" (us) : "0" (us) // 2 cycles
);
}
A short comment to the baud rate. Some UART devices needs 115200baud. This is not really nice at 16MHz because the error rate is too high. So I am using 11.0592MHz. Here a graphic from the ATmega328 datasheet:
I found a nice post about the topic of the millis function and the prescale. Still I don't know how to fix the issue for the 11.0592MHz. But this post is nice.
From the delaymicroseconds function you see, that a Arduino with a FCPU of 11.0592MHz uses the 8MHz delays. So 27.6% to fast.
The wiring.c part of the Arduino core makes a bunch of assumptions:
The clock rate is evenly divisible by 1,000,000.
The microsecond per clock overflow modulo 1000 is divisible by 8. This results in a value below 125 so the overflow accumulator fits in 8 bits.
I think the only way to make the Arduino core work with all clock rates is to do a major re-write of the wiring.c file.
For some things you can use routines from the AVR LibC:
// Helper macros for baud rate calculations
#include <util/setbaud.h>
// Delays in milliseconds and microseconds
#include <util/delay.h>
void _delay_ms[/iurl] (double __ms);
void _delay_us(double __us);
// Delays in clock cycles
#include <util/delay_basic.h>
void _delay_loop_1(uint8_t __count);
void _delay_loop_2(uint16_t __count);