Ich habe einen ATMega88A, der so konfiguriert ist, dass er mit einem internen 8-MHz-Takt läuft:
lfuse = 0xE2
hfuse = 0xDF
efuse = 0x01
F_CPU defined as 8000000
Dies wird in der 'realen Welt' durch Blinken einer LED mit _delay_ms(1000) bestätigt. Es ist ~ 1 Sek., nicht 8 Sek. oder 1/8 Sek.
Ich habe versucht, den SPI so einzustellen, dass er mit Fosc/2 läuft, indem ich nur SPI2X auf 1 gesetzt habe. (SPR1, SPR0 werden initialisiert und sollten auf 0 bleiben.) Dies sollte zu einer SPI-Geschwindigkeit von 4 MHz führen.
Ich habe den Timer auf eine 256-fache Vorskalierung eingestellt.
Ich versuche, 5000 Bytes über SPI zu senden. (Es ist kein Gerät angeschlossen, es werden nur Bits aus dem Port verschoben.) Der Timer wird vor der Übertragung auf Null gesetzt und der Wert wird nach der Übertragung als LEDs angezeigt.
Das Senden eines Bits über einen 4-MHz-SPI sollte 1/4000000 = 250 ns dauern, ein Byte 8 * 250 ns = 2 us, 5000 Byte 2 us * 5000 = 10 ms .
Aus meinem Timer geht jedoch hervor: Die Systemuhr beträgt 8 MHz, also beträgt die Periode 1/8000000 = 125 ns, der Timer-Prescaler von 256 bedeutet einen Timer-Tick von 125 ns * 256 = 32 us .
Wie ist die Wirklichkeit schneller als die Theorie?
Der Kicker? Das Kommentieren SPSR = (1 << SPI2X);
hat keinen Einfluss auf den Wert, der in den Timer-LEDs angezeigt wird.
Beispielcode:
#include <avr/io.h>
#include <util/delay.h>
#define set_output(portdir,pin) portdir |= (1<<pin)
void init() {
// Set MOSI, SCK, SS as Output
set_output(DDRB, DDB5);
set_output(DDRB, DDB3);
set_output(DDRB, DDB2);
// Enable SPI, Set as Master, Set CPOL & CPHA to 1 (SPI mode 3)
SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);
SPSR = (1 << SPI2X); // Enable SPI clock doubler
DDRD = 0xff; // Set PORTD as output
TCCR1B |= (1 << CS12); // Setup Timer with 256 prescaling
}
int main(void) {
unsigned int i;
init();
TCNT1 = 0; // Zero the timer
for (i = 0; i < 5000; i++) {
SPDR = 0; // Load data into the SPI data reg
while (!(SPSR) & (1 << SPIF)); // Wait until transmission complete
}
PORTD = (unsigned char) TCNT1; // Display the timer on PORTD
for (;;) {}
return 0;
}
Einige Probleme, die ich getestet habe:
if (SPSR & (1<<SPI2X))
true zurückgibt.-O3
und -Os
, aber großer Anstieg des Timerwerts für -O0
.Werde ich verrückt?
BEARBEITEN: Der Teil des fehlerhaften Codes, wie unten beantwortet, wurde von mir ohne Überprüfung von hier aus nachlässig kopiert.
Bist du sicher, dass die Zeile while (!(SPSR) & (1 << SPIF));
richtig ist? Ich vermute vermeintliche Funktionalität:while (!(SPSR & (1 << SPIF)));
PeterJ
Adam Griffin