Ich verwende STM32F051R8T6 auf STM32F0-Discovery-Board und M25P80-Flash-IC als Peripheriegerät. Ich habe das SPI in 3-Zeilen (+ 1 Software-Chip-Select-Zeile) im Vollduplex-Modus konfiguriert und verwende Polling zum Senden und Empfangen von Daten. Ich hatte viele Probleme damit, SPI richtig zum Laufen zu bringen, und alles lief darauf hinaus, dass diese Reihe von Tests nacheinander ausgeführt wurden, die einen Fehler aufdeckten, den ich nicht erklären kann.
Schritt 1: Fordern Sie eine Signatur vom Peripheriegerät an. Signatur ist 0x13, funktioniert 99% der Zeit.
Schritt 2: Aktivieren Sie das Schreiben an das Peripheriegerät, indem Sie ihm einen Befehl ausgeben.
Schritt 3: Lesen Sie den Inhalt des Statusregisters, um sicherzustellen, dass der vorherige Befehl durchgekommen ist.
Da das Peripheriegerät im Vollduplexmodus arbeitet, aber Daten niemals gleichzeitig in beide Richtungen gesendet werden, muss der Eingangspuffer die gleichen Abmessungen wie der Ausgangspuffer haben, und in ihn geschriebene Daten haben einen gewissen Versatz.
Problem entsteht im letzten Schritt. Wenn nur ein einzelnes Byte gelesen werden soll, registriert SPI keine Daten, die an es gesendet werden! Wenn mehr Bytes angefordert werden (durch Verwendung von 1 + X als viertem Funktionsparameter), sieht der Inhalt des Eingangspuffers wie folgt aus:
@ 1 + 3:
0x00 0x00 0x02 0x13
@ 1 + 4:
0x00 0x00 0x02 0x13 0x00
@ 1 + 5:
0x00 0x00 0x02 0x13 0x02 0x00
@ 1 + 6:
0x00 0x00 0x02 0x13 0x02 0x00 0x02
@ 1 + 7:
0x00 0x00 0x02 0x13 0x02 0x00 0x02 0x02
Und hier sind die Signale auf der MISO-Leitung (rot) und SCK (gelb) beim Lesen von insgesamt 1 + 3 Bytes. Das erste Paket ist der zweite Schritt. Vom Flash-IC wird erwartungsgemäß nichts übertragen. Zweites Paket ist Schritt Nr. 3. Peripherie ist während des ersten Bytes still und gibt dann 0x02 auf allen folgenden Bytes aus, aber nur das dritte Byte wird erfolgreich gelesen. Und dann liest es die Bytes 4 und 6 nicht (alle weiteren Bytes werden korrekt gelesen).
Ich weiß also nicht, wie ich erklären soll, dass die gelesenen Daten nicht vollständig dem entsprechen, was ich auf dem Oszilloskop sehe. Und das Seltsamste ist - im dritten Schritt wird ein 0x13-Byte gelesen! Wenn der erste Schritt entfernt wird, wird dieses Byte als 0x00 gelesen. Scheint eine Speicherbeschädigung auf STM32-Seite zu sein, aber ich kann keinen Grund dafür finden, da Puffer mit memset() bereinigt werden und der interne Puffer von SPI mit HAL_SPI_FlushRxFifo(&hspi1) geleert wird.
Hier ist der Code:
uint8_t command;
uint8_t inBuffer[16];
uint8_t outBuffer[16];
/* Step 1: Check if IC is alive */
{
memset(inBuffer, 0x00, 16);
memset(outBuffer, 0x00, 16);
command = OPCODE_RES;
outBuffer[0] = command;
spi_select(M25P80);
HAL_SPI_TransmitReceive(&hspi1, outBuffer, inBuffer, (1 + 3) + 1, TIMEOUT);
spi_deselect(M25P80);
HAL_SPI_FlushRxFifo(&hspi1);
}
for (volatile uint32_t i = 0; i < 200; i++);
/* Step 2: Enable writing */
{
memset(inBuffer, 0x00, 16);
memset(outBuffer, 0x00, 16);
command = OPCODE_WREN;
outBuffer[0] = command;
spi_select(M25P80);
HAL_SPI_Transmit(&hspi1, outBuffer, 1, TIMEOUT);
spi_deselect(M25P80);
HAL_SPI_FlushRxFifo(&hspi1);
}
for (volatile uint32_t i = 0; i < 200; i++);
/* Step 3: Make sure writing is enabled */
{
memset(inBuffer, 0x00, 16);
memset(outBuffer, 0x00, 16);
command = OPCODE_RDSR;
outBuffer[0] = command;
spi_select(M25P80);
HAL_SPI_TransmitReceive(&hspi1, outBuffer, inBuffer, 1 + 1, TIMEOUT);
spi_deselect(M25P80);
HAL_SPI_FlushRxFifo(&hspi1);
}
Einige Details zur SPI-API von STM. In einem Anruf wie:
HAL_SPI_TransmitReceive(&hspi1, outBuffer, inBuffer, (1 + 3) + 1, TIMEOUT);
&hspi1 - peripheral handle containing its settings and configurations
outBuffer - pointer to a memory location with data to be sent
inBuffer - pointer to a memory location to which received data is written
(1 + 3) + 1 - number of bytes to receive/transmit;
in this case 1 - command byte, 3 - dummy bytes, 1 - received signature byte
TIMEOUT - a value in the range of 10000 which indicates at which point transmission must be
aborted if failed to finish
EDIT 1: SPI-Initialisierungscode, wie von STM32CubeMx generiert:
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLED;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLED;
HAL_SPI_Init(&hspi1);
EDIT 2: Jetzt, wo ich die Geschwindigkeit auf 488 b / s gesenkt habe, funktioniert alles einwandfrei. Ich bleibe noch eine Weile bei diesem Hack.
Meiner Meinung nach sollten Sie die Standard Peripheral Library für STM verwenden, da sie stabiler ist und Sie nicht die Low-Level-Sachen verbirgt, die Ihnen eine kontrollierbarere Umgebung bieten. Außerdem müssen Sie beim CS-Pin-Timing vorsichtig sein, viele Geräte müssen halten diesen Wert eine Weile, bis Sie die Übertragung starten.
Befehle, Adressen oder Eingangsdaten werden an der ansteigenden Flanke des Takteingangs zwischengespeichert, während Ausgangsdaten an der abfallenden Flanke des Takteingangs herausgeschoben werden.
Versuchen
hspi1.Init.CLKPhase = SPI_PHASE_2EDGE;
Das Datenblatt für Ihr Gerät sagt "und Ausgangsdaten sind ab der fallenden Flanke von C verfügbar." Ich glaube, das ist, wo Sie das einstellen würden.
bitsmack
Bruce Abbott
andrej
andrej
FRob