Stolperstein beim STM32F051 und SPI

OP #3240771
Lesenswert?

Servus Allerseits

Nach mehreren Stunden Fehlersuche:
Der STM32F051 hat ein SPI-FIFO, weshalb, falls man mit 8-bit arbeitet, 
die Abfrage des RXNE Bits nicht greift.
Deshalb muss im CR2 Register unbedingt FRXTH (FIFO reception threshold) 
gesetzt werden.
1
//=================================
2
// SetSpi
3
//=================================
4
void MySpi_1::SetSpi( void )
5
{
6
  SPI_InitTypeDef  SPI_InitStructure;
7

8
  SPI_I2S_DeInit(SPI1);
9
  SPI_InitStructure.SPI_Mode      = SPI_Mode_Master;
10
  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
11
  SPI_InitStructure.SPI_DataSize  = SPI_DataSize_8b;
12
  SPI_InitStructure.SPI_CPOL      = SPI_CPOL_Low;  
13
  SPI_InitStructure.SPI_CPHA      = SPI_CPHA_1Edge;
14
  SPI_InitStructure.SPI_NSS       = SPI_NSS_Soft;
15
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;  // prescaler: 2, 4, 8, 16, 32, 64, 128, 256
16
  SPI_InitStructure.SPI_FirstBit  = SPI_FirstBit_MSB;
17
  SPI_InitStructure.SPI_CRCPolynomial = 7;
18
  SPI_Init(SPI1, &SPI_InitStructure);
19

20
  // Bei 8-Bit Transfer nicht vergessen!
21
  SPI_RxFIFOThresholdConfig(SPI1, SPI_RxFIFOThreshold_QF);  // SPI1->CR2 |= SPI_CR2_FRXTH;
22

23
  SPI_Cmd(SPI1, ENABLE);
24
}
25

26

27
//=================================
28
// Send
29
//=================================
30
uint8_t MySpi_1::Send( uint8_t data)
31
{
32
  uint32_t spi_base_adr;
33

34
  spi_base_adr = (uint32_t)SPI1 + 0x0C;
35
  *(volatile uint8_t *) spi_base_adr = data;   // SPI_SendData8(SPI1, data);
36

37
  while((SPI1->SR & SPI_I2S_FLAG_RXNE) == RESET);  // 0: RxBuffer is empty
38
  return *(volatile uint8_t *) spi_base_adr;   // SPI_ReceiveData8(SPI1);
39
}
Gast #4805658
Lesenswert?

Mehmet K. schrieb:
> Nach mehreren Stunden Fehlersuche:
> Der STM32F051 hat ein SPI-FIFO, weshalb, falls man mit 8-bit arbeitet,
> die Abfrage des RXNE Bits nicht greift.
> Deshalb muss im CR2 Register unbedingt FRXTH (FIFO reception threshold)
> gesetzt werden.

Ebenfalls nach stundenlanger Fehlersuche:
Scheinbar existiert ein ähnliches Problem beim STM32F446.
Hier gibs es aber kein FRXTH-Bit mehr (ich habe auch kein Äquivalent 
gefunden).

Was funktioniert:
Auf RXNE warten und das Datenregister zweimal auslesen.

Was auch funktioniert:
Bevor das Dummybyte ins Datenregister geschrieben wird, muß erst das 
Datenregister und anschließend das Statusregister gelesen werden.
Damit wird lt. Datenblatt das 'Overrun flag' zurückgesetzt:
1
Clearing the OVR bit is done by a read access to the SPI_DR
2
register followed by a read access to the SPI_SR register.
#4809015
Lesenswert?

So sieht der Spaß bei mir aus. Läuft hervorragend.
Ist natürlich jetzt die Frage, wie man das ganze umsetzen möchte. Für 
die paar SPI-Geräte die ich nur einmal initialisiere, brauche ich 
zumindest keine großen Verrenkungen machen.
1
uint8_t spi_rw(uint8_t byte) {
2
  SPI2->DR = byte;
3
  while(!(SPI2->SR & SPI_SR_TXE));
4
  while(!(SPI2->SR & SPI_SR_RXNE));
5
  return SPI2->DR;
6
}
Edit: Datenblatt gelesen...
1
  while(SPI2->SR & SPI_SR_BSY);
nur zum deaktivieren vom SPI prüfen.
Muss ich jetzt in der Tat nochmal checken.
#5045413
Lesenswert?

Rainer S. schrieb:
> Bin gerade dabei den STM32F051 zu programmieren.
> Habe alles oben schon ausprobiert.
>
> Der Controller sendet 2 mal anstatt einmal.
>
> Bei 8 Bit werden trotzdem die ganzen 16 Bit gesendet.

Nein, Du musst es bloss richtig machen und nur 8 Bit ins 
SPI-Datenregister schreiben, etwa so (bin ich aber auch schonmal drauf 
'reingefallen!):

*(uint8_t *)SPI->DR = data;

Dann gibt es auch nur 8 Clocks/Byte.
#5045455
Lesenswert?

Thomas E. schrieb:
> Nein, Du musst es bloss richtig machen

Danke, funktioniert. Da wäre ich jetzt so gut wie nie drauf gekommen.

Zumal es beim STM32F411 hier bereits so funktioniert, dass ich das 
komplette 16 Bit Datenregister beschreiben kann. Die Datasize wird ja im 
CR2 definiert.

Bei dem SPI Datenregister im Referenzhandbuch vom STM32F051 (Seite 807) 
steht auch nix davon.

http://www.st.com/content/ccc/resource/technical/document/reference_manual/c2/f8/8a/f2/18/e6/43/96/DM00031936.pdf/files/DM00031936.pdf/jcr:content/translations/en.DM00031936.pdf

Oder was bedeutet: "The Rx threshold setting must always
correspond with the read access currently used."

Da steht noch: "Unused bits are ignored when writing to the register, 
and read as zero when the register is read."

Weshalb nur schwer vermittelbar ist, dass man explizit nur das Lobyte 
beschreiben soll, damit der 8 Bit Modus reibungslos funktioniert.

Bei den Codeschnipseln S. 975 steht was von unit8_t davor.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren