Forum: Mikrocontroller und Digitale Elektronik STM32F4: Frage zur SPI


von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich hätte da mal eine Frage zur SPI, ohne das jetzt durch Messungen zu 
unterlegen habe ich mal "ausprobiert".

Zwei Routinen, eine Transfer und eine die nur sendet.

SPI_SendByte funktioniert in der Kommunikation mit einem Gerät, welches 
mehrere Bytes empfängt NUR dann, wenn  ich

while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));

als Blocker einfüge. Obwohl nur gesendet wird muss ich warten, bis das 
Receive Bit gesetzt wurde. Das Abfragen des BSY Bit allein genügt nicht, 
dann fehlen Zyklen.

Ich habe die SPI als "Master_2_Lines MISO/MOSI" konfiguriert. D.h. nicht 
als "1 Line MOSI". Aber eigentlich dürfte das keinen Unterschied machen, 
ich hole das DR Register sowieso nicht lesend ab.

Kann mir jemand erklären warum das so ist?

PS: Ich möchte eigentlich für alles, wo nur gesendet wird auch die 
passende Konfiguration verwenden, ebenso bei Transfers mit Empfang. Muss 
ich da jedesmal den Initstruct vor jedem Datensatz neu aufrufen, um die 
SPI neu zu konfugurieren? Bisschen heftig...

Gruss,
Christian


1
/* ------ SPI Low Level: Ein 8 Bit Datenwort senden und holen ------- */
2
uint8_t SPI_TransferByte(uint8_t data)
3
{
4
    uint8_t val;
5
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));       // Warte bis TXE (SPI ist frei)
6
    SPI_I2S_SendData(SPI1, data);                                // Byte senden...
7
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));      // Warte bis Byte empfangen worden
8
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
9
    val = SPI_I2S_ReceiveData(SPI1);
10
    return  val;                            // Wert abholen...
11
}
12
13
/* ------ SPI Low Level: Ein 8 Bit Datenwort senden ------- */
14
void SPI_SendByte(uint8_t data)
15
{
16
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE));       // Warte bis TXE (SPI ist frei)
17
    SPI_I2S_SendData(SPI1, data);                                // Byte senden...
18
    while(!SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE));      // Warte bis Byte empfangen worden
19
    while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_BSY));
20
}

von Jim M. (turboj)


Lesenswert?

Christian J. schrieb:
> Obwohl nur gesendet wird muss ich warten, bis das
> Receive Bit gesetzt wurde. Das Abfragen des BSY Bit allein genügt nicht,
> dann fehlen Zyklen.

Cortex M4 hat Schreibpuffer. Bei ungünstigem Takverhältnis könnte das 
Status Register gelesen werden bevor die Transaktion gestartet wurde, 
dann wäre der Status "noch nicht busy" - und die Busy Schleife 
terminiert. Eventuell reicht ein __DMB(); zur Behebung des Problems.

Damit das RXNE Bit korrekt funktioniert muss man IMHO am Schluss des 
Sendens ebenfalls ein (dummy) Read auf das SPI Datenregister machen. 
Ansonsten wird das ja gar nicht zurückgesetzt. Da Du auch auf BUSY 
testest, wird dieses Problem IMO aber maskiert.

von Christian J. (Gast)


Lesenswert?

Jim M. schrieb:
> Bei ungünstigem Takverhältnis könnte das
> Status Register gelesen werden bevor die Transaktion gestartet wurde,

Tja... da frage ich mich so ein wenig, ob es irgendwo die 
hochoffizielle, richtige und bombensichere SPI Routine gibt. Das Thema 
dürften ja schon tausende Programmierer bearbeitet haben.

__DMB() ist doch ein Memory Blocker, das TX_DR ist aber ein Register. 
Das sind doch zwei Paar Schuhe, oder?

Manual:
"A continuous transmit stream can be maintained if the next data to be 
transmitted is put in the Tx buffer once the transmission is started. 
Note that TXE flag should be ‘1 before any attempt to write the Tx 
buffer is made."

Ok, reicht aber nicht aus, RXNE und/oder BSY Flag müssen ebenfalls 
abgefragt werden, damit ein nachfolgender CE_HIGH Deselect nicht die 
letzten Takte abschneidet.

Hat mal jemand die der CubeMX zur Hand?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.