Das EEPROM ist nur Mittel zum Zweck. Durch Schreiben ins EEPROM kommt man an den internen 1MHz RC-Oszillator:
Zitat von
AVR-Manual
The calibrated Oscillator is used to time the EEPROM accesses. Table 1 lists the typical programming time for EEPROM access from the CPU.
Number of Calibrated RC Oscillator Cycles(1): 8448
Note (1): Uses 1 MHz clock, independent of CKSEL Fuse settings.
Allzu genau wird das aber nicht. Hier mal als C-Funktion für Mega8:
Code:
#include <avr/io.h>
#include <avr/eeprom.h>
#define EEPROM_CYCLES 8448
#undef EEPROM_CYCLES
#define EEPROM_CYCLES 8241 /* nach-kalibriert */
#define EEPROM_LOOP_CYCLES 5
// Ergibt Oszillator-Frequenz in kHz
uint16_t get_fosc()
{
uint16_t fosc;
// EE-Adresse setzen, Datum lesen...
eeprom_read_byte ((uint8_t*) 0);
fosc = -1;
// ...und wieder schreiben
__asm__ volatile (
"in __tmp_reg__, __SREG__" "\n\t"
"cli" "\n\t"
"sbi %2-0x20, 2" "\n\t"
"sbi %2-0x20, 1" "\n\t"
"0:" "\n\t"
"adiw %0, 1 ; 2 cycles" "\n\t"
"sbic %2-0x20, 1 ; 1 cycle" "\n\t"
"rjmp 0b ; 2 cycles" "\n\t"
"out __SREG__, __tmp_reg__"
: "=w" (fosc)
: "0" (fosc), "M" (&EECR)
);
// vermeidet Division
const uint32_t x = (EEPROM_CYCLES/2 + 0x10000*EEPROM_LOOP_CYCLES*1000)/EEPROM_CYCLES;
return (x*fosc) >> 16;
}
Mit einem 16MHz-Quarz erhalte ich damit ca 15.600 kHz, zu ungenau für eine UART-Initialisierung.
Wenn ich das Verfahren einmal mir einem 16MHz-Quarz kalibriere, dann wird es um einiges genauer (8241 für EEPROM_CYCLES):
22.1184MHz ............. 22110 kHz
18 MHz .................... 17971 kHz
16 MHz .................... 15998 kHz
10 MHz .................... 9978 kHz
7.3728 MHz .............. 7361 kHz
Das sind Fehler von weniger als 0.2%, damit wäre es genau genug für den UART.
Ein Ersatz für Auto-Baud ist das allerdings nicht. Wenn Daten mit variablen Baudraten reinkommen, hilt das auch nix...
Woher die Abweichung von über 3% bei dem im Manual angegebenen Wert von 8448 kommt...keine Ahnung. Ebenso, wie groß die Temperaturdrift ist und die Spannungs- und Altersabgängigkeit.
Lesezeichen