Der folgende Code konfiguriert und aktiviert SPI2 als Slave auf meiner STM32F303RE-Karte , schreibt 0xAA-, 0xBB-, 0xCC-, 0xDD- Bytes in das DR- Register und macht eine Weile eine Schleife (1) :
/* Enable clocks for GPIOB (SPI2 pins) and SPI2 peripheral. */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
/* SPI pin mappings. */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_5); /* SPI2_NSS */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource13, GPIO_AF_5); /* SPI2_SCK */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_5); /* SPI2_MISO */
GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_5); /* SPI2_MOSI */
GPIO_InitTypeDef gpio_init_struct =
{
.GPIO_Mode = GPIO_Mode_AF,
.GPIO_OType = GPIO_OType_PP,
.GPIO_PuPd = GPIO_PuPd_DOWN,
.GPIO_Speed = GPIO_Speed_50MHz
};
/* SPI NSS pin configuration. */
gpio_init_struct.GPIO_Pin = GPIO_Pin_12;
GPIO_Init(GPIOB, &gpio_init_struct);
/* SPI SCK pin configuration. */
gpio_init_struct.GPIO_Pin = GPIO_Pin_13;
GPIO_Init(GPIOB, &gpio_init_struct);
/* SPI MISO pin configuration. */
gpio_init_struct.GPIO_Pin = GPIO_Pin_14;
GPIO_Init(GPIOB, &gpio_init_struct);
/* SPI MOSI pin configuration. */
gpio_init_struct.GPIO_Pin = GPIO_Pin_15;
GPIO_Init(GPIOB, &gpio_init_struct);
SPI_InitTypeDef spi_init_struct =
{
.SPI_Direction = SPI_Direction_2Lines_FullDuplex,
.SPI_Mode = SPI_Mode_Slave,
.SPI_DataSize = SPI_DataSize_8b,
.SPI_CPOL = SPI_CPOL_Low,
.SPI_CPHA = SPI_CPHA_1Edge,
.SPI_NSS = SPI_NSS_Hard,
.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2,
.SPI_FirstBit = SPI_FirstBit_MSB,
.SPI_CRCPolynomial = 7
};
SPI_I2S_DeInit(SPI2);
SPI_Init(SPI2, &spi_init_struct);
SPI_CalculateCRC(SPI2, DISABLE);
SPI_TIModeCmd(SPI2, DISABLE);
SPI_NSSPulseModeCmd(SPI2, DISABLE);
SPI_Cmd(SPI2, ENABLE);
SPI_SendData8(SPI2, (uint8_t) 0xAA);
SPI_SendData8(SPI2, (uint8_t) 0xBB);
SPI_SendData8(SPI2, (uint8_t) 0xCC);
SPI_SendData8(SPI2, (uint8_t) 0xDD);
while(1) { }
Bei einem Master, der 2 Bytes pro Chip-Select anfordert , erhält der Master:
0xAA 0xBB
0xCC 0xDD
0xAA 0xAA -----> TXFIFO should be empty here, why not "0x00 0x00"?
0xAA 0xAA
0xAA 0xAA
0xAA 0xAA
0xAA 0xAA
0xAA 0xAA
0xAA 0xAA
......... (0xAA 0xAA infinite times)
Ich hätte erwartet, dass der Master "0x00 0x00" erhält, nachdem TXFIFO leer wird . Warum erhalte ich stattdessen kontinuierlich " 0xAA 0xAA "? Im Handbuch konnte ich nichts finden, was auf ein solches Verhalten hindeuten würde.
AKTUALISIERUNG 1
Warten Sie, bis die Transaktionen kurz vor dem while(1) abgeschlossen sind , und schreiben Sie danach Nullen auf den SPI , wie folgt:
while(SPI_GetTransmissionFIFOStatus(SPI2) != SPI_TransmissionFIFOStatus_Empty) { }
while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) != RESET) { }
#define ZEROS_CNT (1)
for(int i = 0; i < ZEROS_CNT; i++)
SPI_SendData8(SPI2, 0);
while(1) { }
rendert das folgende Master-Verhalten für verschiedene Werte von ZEROS_CNT:
ZEROS_CNT = 0 => master receives after TXFIFO is empty: 0xAA infinitely
ZEROS_CNT = 1 => master receives after TXFIFO is empty: 0x00 1 times, followed by 0xBB infinitely
ZEROS_CNT = 2 => master receives after TXFIFO is empty: 0x00 2 times, followed by 0xCC infinitely
ZEROS_CNT = 3 => master receives after TXFIFO is empty: 0x00 3 times, followed by 0xDD infinitely
ZEROS_CNT >= 4 => master receives after TXFIFO is empty: 0x00 infinitely
Es sieht so aus, als ob das SPI-Peripheriegerät eine Art Verlauf dessen hat, was in das TXFIFO geschrieben wurde, und wenn es leer wird, sendet es Bytes aus diesem Verlauf.
AKTUALISIERUNG 2
Es verhält sich gleich, unabhängig davon, wie viele Bytes der Master in einem einzelnen Chip-Select anfordert. Ich habe versucht, 1, 2, 4 und 5 @ gleichzeitig anzufordern.
Ich habe das herausgefunden und beschlossen, diese Antwort umfassender zu machen, indem ich einige Animationen erstellt habe. Zunächst einmal gibt es 2 Tatsachen zu beachten, die die Logik hinter dem Verhalten von TXFIFO bestimmen:
RXFIFO verhält sich höchstwahrscheinlich genauso.
Der in C# geschriebene Algorithmus für push/pop lautet wie folgt:
public class TXFIFO
{
public byte[] data;
byte push_position = 1;
byte occupied = 0;
public TXFIFO()
{
data = new byte[4];
}
public byte Push(byte v)
{
// write
data[push_position - 1] = v;
// push_position
if (push_position < 4) push_position++;
else push_position = 1;
// occupied
if (occupied < 4) occupied++;
return v;
}
public byte Pop()
{
// read
if (occupied == 0) return data[0];
byte v = data[0];
// rotate left once
for (int i = 1; i < 4; i++)
data[i - 1] = data[i];
data[3] = v;
//push_position
if (push_position > 1) push_position--;
else push_position = 4;
//occupied
if (occupied > 0) occupied--;
return v;
}
public byte GetOccupied()
{
return occupied;
}
}
Und hier sind 5 Animationen, die die ursprünglich beschriebenen ZEROS_CNT- Szenarien veranschaulichen (siehe UPDATE 1 der Frage ). Beachten Sie, dass ich , um den Punkt klarer zu machen, anstatt Nullen einzufügen , hier 0x01-0x02-..to..-ZEROS_CNT -Werte eingefügt habe.
ZEROS_CNT = 0:
ZEROS_CNT = 1:
ZEROS_CNT = 2:
ZEROS_CNT = 3:
ZEROS_CNT = 4:
ZEROS_CNT = 5:
...usw...
Wie bereits in der Frage erwähnt, würde eine Problemumgehung für das Senden von 0x00 bei leerem TXFIFO darin bestehen, das SPI- Peripheriegerät deaktiviert zu lassen , wenn TXFIFO leer ist, bis neue Daten in DR geschrieben werden , was ich schließlich tat, nachdem ich verstanden hatte, was los ist .
Die Werte nach dem 4. Byte stammen nicht aus dem TX-Puffer des Slaves. Untersuchen Sie das SPI-Blockdiagramm. Sie werden ursprünglich als Speicherauszugsdaten vom Master gesendet, wenn der SCI durchlaufen wird, und sie kehren vom Schieberegister des Slaves zurück und erscheinen als gültige Daten. Wenn der Master Daten abruft, wird erwartet, dass dies überschrieben wird, in diesem Fall jedoch nicht, da der Slave keine Daten in den TX-Puffer drückt und das Schieberegister geladen wird.
Wladimir Cravero
Zuzu Corneliu
Wladimir Cravero
Zuzu Corneliu
dom
Zuzu Corneliu
dom
Zuzu Corneliu
Zuzu Corneliu
dom
Wladimir Cravero
Zuzu Corneliu