I am running my Digispark (bootloader v. 1.06; same behavior in 1.02) connected to a USB port, so it is running at 16.5MHz, and apparently it is, except the software thinks it's still running at 16MHz. To wit, timing loops run faster than they should by a factor of 16.5/16. In particular, the microseconds counted by micros() are too short by that factor. To prove my point, i wrote this program:
// Check whether a DigiSpark is actually running calibrated.
//
// Pin 0: output: what should be a 50 or 60 Hz, 25% DC signal.
// Pin 1: output: 0 if uncalibrated, and a 50% DC PWM signal if calibrated.
// Pin 2: input: 0 to select 50Hz, 1 to select 60Hz
// Pin 5: input: xor to the value of is_calibrated.
// From https://digistump.com/wiki/digispark/tricks
#include <avr/boot.h>
byte read_factory_calibration(void) {
byte SIGRD = 5; // for some reason this isn't defined...
byte value = boot_signature_byte_get(1);
return value;
}
boolean is_clock_calibrated(void) {
// TODO(ji): verify that this should indeed be a not-equals comparison,
// since OSCCAL is 165 (meaning 16.5MHz, perchance? Or is it simply 0xA5,
// which is a nice palindromic binary number? (10100101)
return read_factory_calibration() != OSCCAL;
}
inline void sethi(int p) {
digitalWrite(p, HIGH);
}
inline void setlo(int p) {
digitalWrite(p, LOW);
}
inline unsigned long delay_to(unsigned long us) {
unsigned long usr;
while ((usr = micros()) < us) {
;
}
return usr;
}
void setup() {
pinMode(0, OUTPUT);
pinMode(1, OUTPUT);
pinMode(2, INPUT);
pinMode(5, INPUT);
setlo(0);
setlo(1);
bool is_calibrated = is_clock_calibrated();
if (is_calibrated) {
analogWrite(1, 128);
}
unsigned long us0 = micros();
unsigned long us1;
for (;;) {
sethi(0);
delay_to(us0 + 4200); // ~25% duty cycle
setlo(0);
unsigned long us_final;
if (is_calibrated ^ ((bool)digitalRead(5))) {
if (digitalRead(2)) { // 60Hz
us_final = us0 + 16667;
} else { // 50Hz
us_final = us0 + 20000;
}
} else {
if (digitalRead(2)) { // 60Hz
us_final = us0 + 17188;
} else { // 50Hz
us_final = us0 + 20625;
}
}
us0 = delay_to(us_final);
}
}
void loop() {
}
As you can see, by changing the values of pins 2 and 5 I can select 50/60Hz, and either assume that the board is indeed calibrated properly, or compensate for the fact that it thinks it is running at 16MHz but it is really running at 16.5MHz.
The attachments show the four screen captures corresponding to these settings. The measurements are within the error margin of the scope.
Why is device thinking it's running at 16MHz?