Hallo,
ich habe eine Frage zum SPI "transmission complete"
µC ist ein ATmega2560
Die Timer ISR wird aller 5ms aufgerufen.
Es sollen 2 Bytes für zwei kaskadierte Schieberegister zyklisch
übertragen werden.
Im Hauptprogramm wird testweise eine laufende LED erzeugt.
Mein Verständnis zum SPIF Flag.
Das wird entweder gelöscht mit aktivierten SPIE Interrupt. Nutze ich
nicht.
Oder es wird gelöscht wenn etwas neues ins SPDR Register geschrieben
wird.
Die Logik bestätigt sich eigentlich mit Code (a).
SPDR wird beschrieben, es wird gewartet bis das Byte raus ist und dann
wird das zweite Byte übertragen und gewartet bis das raus ist. Ein Byte
raustakten dauert ca. 2,5µs.
Jetzt dachte ich mir, warum die letzten 2,5µs unnötig warten, wenn neue
Daten erst wieder nach 5ms rausgehen. Lasse ich nun das letzte warten
auf das SPIF Flag weg, funktioniert alles nicht mehr wie gewollt. Ich
verstehe nicht warum. Weil nicht einmal das erste warten wie vorher
abläuft. Was es aber laut meiner Logik nachwievor müsste. Nur das zweite
warten düfte alleine wegfallen. Effekt ist das die laufende LED auf
beiden Schieberegister parallel läuft.
Wo ist mein Denkfehler?
zum Bild a
1
ISR(TIMER1_COMPB_vect) //
2
{
3
const uint16_t tcount = 10000; // aller 5ms
4
5
/* vom Schieberegister ins Ausgaberegister übernehmen */
6
shift_Latch_ON;
7
shift_Latch_OFF;
8
9
uint8_t LSB = value & 0xFF;
10
uint8_t MSB = value >> 8;
11
12
debugLED30_ON;
13
SPDR = LSB; // Start transmission
14
while (!(SPSR & (1 << SPIF))) // wait for transmission complete
15
;
16
debugLED30_OFF;
17
18
debugLED30_ON;
19
SPDR = MSB; // Start transmission
20
while (!(SPSR & (1 << SPIF))) // wait for transmission complete
21
;
22
debugLED30_OFF;
23
24
OCR1B += tcount;
25
}
zum Bild b
1
ISR(TIMER1_COMPB_vect) //
2
{
3
const uint16_t tcount = 10000; // aller 5ms
4
5
/* vom Schieberegister ins Ausgaberegister übernehmen */
6
shift_Latch_ON;
7
shift_Latch_OFF;
8
9
uint8_t LSB = value & 0xFF;
10
uint8_t MSB = value >> 8;
11
12
debugLED30_ON;
13
SPDR = LSB; // Start transmission
14
while (!(SPSR & (1 << SPIF))) // wait for transmission complete
> Oder es wird gelöscht wenn etwas neues ins SPDR Register geschrieben wird.
Schon, aber vorher muss SPSR gelesen werden:
'Alternatively, the SPIF bit is cleared by first reading the SPI Status
Register with SPIF set, then accessing the SPI Data Register(SPDR).'
Veit D. schrieb:> Wo ist mein Denkfehler?
Beim zweiten und allen folgenden Interrupts tritt folgende
Sequenz auf:
// rem: Vorgeschichte
SPDR = MSB; // Start transmission
// aktueller Interrupt
SPDR = LSB; // Start transmission
etc.
Das heisst das Datenregister wird kurz hintereinander zweimal
beschrieben, was natürlich Käse ist. Das SPI ist ja mit
dem ersten Byte noch nicht fertig.
Wohl doch nicht, das geht beim allerersten Byte schief.
Nun, vor dem SPDR=LSB muss irgendwie SPSR gelesen werden (ohne dass
der C-Compiler es wegoptimiert).
Hallo,
die blaue Linie ist die debugLED30 in der ISR. Zeigt das warten an.
Oh man okay, ich habe das überlesen weil der Registername nur
ausgeschrieben im Text steht. Nicht nochmal in Klammern wie das (SPDR).
Wenn ich nun vorm ins SPDR schreiben das SPIF Flag abfrage funktioniert
es wie gewünscht. In der main() beschreibe ich SPDR mit einem leeren
Byte. :-)
Danke.
1
ISR(TIMER1_COMPB_vect)//
2
{
3
constuint16_ttcount=10000;// aller 5ms
4
5
/* vom Schieberegister ins Ausgaberegister übernehmen */
6
shift_Latch_ON;
7
shift_Latch_OFF;
8
9
uint8_tLSB=value&0xFF;
10
uint8_tMSB=value>>8;
11
12
while(!(SPSR&(1<<SPIF)))// wait for transmission complete
13
;
14
SPDR=LSB;// Start transmission
15
16
while(!(SPSR&(1<<SPIF)))// wait for transmission complete
Hallo,
eigentlich sollte das auch ohne das einmalige beschreiben von SPDR
funktionieren. Wenn ich statt dessen in main() nun SPSR = (1<<SPIF) o.a.
probiere, sollte es die gleiche Wirkung haben. Hat es jedoch nicht. Es
ist auch egal ob ich value und data volatile mache. Funktioniert nur mit
einmaligen SPDR = data. Verstehe ich nicht. Es geht doch nur darum das
SPIF einmal gesetzt wird um zu simulieren das eine Übertragung fertig
ist.
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
#include<util/atomic.h>
4
#include<util/delay.h>
5
6
7
#define NOP __asm__ __volatile__ ("nop")
8
9
#ifndef sbi
10
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // setzt das angegebene Bit
11
#endif
12
#ifndef cbi
13
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // löscht das angegebene Bit
Veit D. schrieb:> Es sollen 2 Bytes für zwei kaskadierte Schieberegister zyklisch> übertragen werden.
Da bietet sich eine der 4 UARTs im SPI-Mode geradezu an. Die sind
nämlich gepuffert, d.h. man kann 2 Bytes hintereinander ins
Senderegister schreiben.
SPSR = (1<<SPIF) o.a.
Natürlich geht das nicht, im Datenblatt ist SPIF als 'R'= readonly
angegeben. Es wird also nur von der Hardware gesetzt/rückgesetzt.
Hallo,
das mit dem read only habe ich nun auch gerade erst gelesen, peinlich.
Hatte noch diverse Tests gemacht mit Register beschreiben und auslesen
und mich gewundert das alles auf 0 bleibt. Immer wieder das klein
Gedruckte. :-)
Danke fürs mitdenken usw.
UART im SPI Mode werde ich probieren. Danke für den Hinweis.
Hi
>UART im SPI Mode werde ich probieren. Danke für den Hinweis.
Das funktioniert aber nicht mit dem Arduino Mega2560. Da fehlen die
CLK-Leitungen der UARTS.
MfG Spess
Hallo,
musste ich vorhin leider auch feststellen, alle XCKn Pins der USARTs
sind nicht rausgeführt. Ich habe jedoch noch ein ATtiny841 Eigenbauboard
zum "spielen" frei.
Veit D. schrieb:> Mein Verständnis zum SPIF Flag.> Das wird entweder gelöscht mit aktivierten SPIE Interrupt. Nutze ich> nicht.> Oder es wird gelöscht wenn etwas neues ins SPDR Register geschrieben> wird.
Falsch. Was richtig ist, steht im Datenblatt. Wer hätte das gedacht...
Zitat:
> SPIF is cleared by hardware when executing the corresponding interrupt> handling vector. Alternatively, the SPIF bit is cleared by first reading the SPI> Status Register with SPIF set, then accessing the SPI Data Register SPDR)
Übersetzt (den Interrupt-Teil mal weggelassen):
Du musst erst das Statusregister lesen, dann prüfen, ob darin SPIF
gesetzt ist und dann auf das SPI-Datenregister zugreifen (egal ob
schreibend oder lesend).
Der Knackpunkt ist die Abfolge der Registerzugriffe und die Einhaltung
der Bedingung.