2018-01-08 01:05 PM
Hello everyone,
I am using the STM32F303VC, trying to interface to a SPI EEPROM over DMA and having some issues on the reception of the data. The DMA is set up as full duplex, and I can see the transmissions and response fine when looking at the signals using a logic analyzer. The issue is in the DMA receive buffer. For some reason, the receive buffer is not showing the correct data. It appears that there's potentially some alignment issues, since I am seeing some of the correct values, just not so much in the right order. For example, I am
sending the following:
1.
MOSI: 0x06
MISO: 0xFF
2.
MOSI: 0x05 0xFF
MISO: 0xFF 0x02
3.
MOSI: 0x05 0xFF 0xFF 0xFF 0xFF
0xFF
0xFF
0xFF
MISO: 0xFF 0x02
0x02
0x02
0x02
0x02
0x02
0x02
0x02
And these are the contents of the receive buffer for each of the above cases
1. 0x00 (expected 0xFF)
2. 0x02 0x00 (expected 0xFF, 0x02)
3. 0x02 0xFF, 0x02, 0xFF, 0x02, 0x02, 0x02, 0x02 (expected 0xFF, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02)
Here's my initialization code, and function calls:
// Define for SPI DMA channels
#define EEPROM_SPI_DMA_RX_CHANNEL DMA1_Channel4 /* SPI2 RX DMA is handled by DMA 1 Channel 4 */
#define EEPROM_SPI_DMA_TX_CHANNEL DMA1_Channel5 /* SPI2 TX DMA is handled by DMA 1 Channel 5 */
void EEPROM_Initialize(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
// SPI CS, SCK, MISO and MOSI peripheral clock enable
RCC_AHBPeriphClockCmd(EEPROM_SPI_CLK | EEPROM_SPI_CS_GPIO_CLK | EEPROM_SPI_SCK_GPIO_CLK |
EEPROM_SPI_MISO_GPIO_CLK | EEPROM_SPI_MOSI_GPIO_CLK , ENABLE);
// Enable DMA1 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// SPI Perihperal clock enable
RCC_APB1PeriphClockCmd(EEPROM_SPI_CLK, ENABLE);
// Configure SPI pins: CS
GPIO_InitStructure.GPIO_Pin = EEPROM_SPI_CS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(EEPROM_SPI_CS_GPIO, &GPIO_InitStructure);
GPIO_SetBits(EEPROM_SPI_CS_GPIO, EEPROM_SPI_CS_PIN); // Drive CS high
// Configure SPI pins: SCK
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // Now that CS GPIO has been initialized to Mode: OUT, change GPIO Mode to AF
GPIO_InitStructure.GPIO_Pin = EEPROM_SPI_SCK_PIN;
GPIO_Init(EEPROM_SPI_SCK_GPIO, &GPIO_InitStructure);
// Configure SPI pins: MISO
GPIO_InitStructure.GPIO_Pin = EEPROM_SPI_MISO_PIN;
GPIO_Init(EEPROM_SPI_MISO_GPIO, &GPIO_InitStructure);
// Configure SPI pins: MOSI
GPIO_InitStructure.GPIO_Pin = EEPROM_SPI_MOSI_PIN;
GPIO_Init(EEPROM_SPI_MOSI_GPIO, &GPIO_InitStructure);
// Configure alternate function to SPI related GPIOs to act as SPI peripheral
GPIO_PinAFConfig(EEPROM_SPI_SCK_GPIO, EEPROM_SPI_SCK_PIN_SOURCE, EEPROM_SPI_SCK_AF);
GPIO_PinAFConfig(EEPROM_SPI_MISO_GPIO, EEPROM_SPI_MISO_PIN_SOURCE, EEPROM_SPI_MISO_AF);
GPIO_PinAFConfig(EEPROM_SPI_MOSI_GPIO, EEPROM_SPI_MOSI_PIN_SOURCE, EEPROM_SPI_MOSI_AF);
// Configure SPI
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(EEPROM_SPI, &SPI_InitStructure);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // Enable DMA1 clock
DMA_DeInit(EEPROM_SPI_DMA_TX_CHANNEL); // Reset DMA1 channe1 to default values;
DMA_DeInit(EEPROM_SPI_DMA_RX_CHANNEL); // Reset DMA1 channe1 to default values;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // M2M Disabled- Peripheral mode (requires timer trigger)
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // Normal mode
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; // Medium priority
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // Memory to Peripheral
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // 8-bit Register
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // Always write to same register
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&EEPROM_SPI->DR; // Output data for SPI peripheral
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // 8-bit array
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // Increment through array
DMA_InitStructure.DMA_MemoryBaseAddr = 0; // Initialize later
DMA_InitStructure.DMA_BufferSize = 1; // Initialize later
DMA_Init(EEPROM_SPI_DMA_TX_CHANNEL, &DMA_InitStructure); // Initialize TX DMA
// Initialize RX DMA
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // Peripheral to Memory
DMA_Init(EEPROM_SPI_DMA_RX_CHANNEL, &DMA_InitStructure); // Initialize RX DMA
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
void EEPROM_SPITransaction(uint8_t* commandData, uint8_t commandLength, const uint8_t* responseData, uint8_t responseLength)
{
DMA_SetCurrDataCounter(EEPROM_SPI_DMA_TX_CHANNEL, commandLength);
DMA_SetCurrDataCounter(EEPROM_SPI_DMA_RX_CHANNEL, responseLength);
// Configure the peripheral base address
EEPROM_SPI_DMA_TX_CHANNEL->CMAR = (uint32_t)commandData;
EEPROM_SPI_DMA_RX_CHANNEL->CMAR = (uint32_t)responseData;
/* The Data transfer is performed in the SPI using Direct Memory Access */
/* Enable DMA SPI TX Stream */
DMA_Cmd(EEPROM_SPI_DMA_TX_CHANNEL, ENABLE);
/* Enable DMA SPI RX Stream */
DMA_Cmd(EEPROM_SPI_DMA_RX_CHANNEL, ENABLE);
// Assert the CS
EEPROM_CS_Low();
/* Enable SPI DMA TX Requsts */
SPI_I2S_DMACmd(EEPROM_SPI, SPI_I2S_DMAReq_Tx, ENABLE);
/* Enable SPI DMA RX Requsts */
SPI_I2S_DMACmd(EEPROM_SPI, SPI_I2S_DMAReq_Rx, ENABLE);
/* Enable the SPI peripheral */
SPI_Cmd(EEPROM_SPI, ENABLE);
/* Waiting the end of Data transfer */
volatile unsigned int timeoutCounter = 0;
while ((DMA_GetFlagStatus(DMA1_FLAG_TC5)==RESET) && (timeoutCounter < EEPROM_TIMEOUT))
{
timeoutCounter++;
}
timeoutCounter = 0;
while ((DMA_GetFlagStatus(DMA1_FLAG_TC4)==RESET) && (timeoutCounter < EEPROM_TIMEOUT))
{
timeoutCounter++;
}
/* Clear DMA Flags */
DMA_ClearFlag(DMA1_FLAG_GL4 | DMA1_FLAG_HT4 | DMA1_FLAG_TC4 | DMA1_FLAG_GL5 | DMA1_FLAG_HT5 | DMA1_FLAG_TC5);
/* Disable DMA SPI TX Stream */
DMA_Cmd(EEPROM_SPI_DMA_TX_CHANNEL,DISABLE);
/* Disable DMA SPI RX Stream */
DMA_Cmd(EEPROM_SPI_DMA_RX_CHANNEL,DISABLE);
/* Disable SPI DMA TX Requsts */
SPI_I2S_DMACmd(EEPROM_SPI, SPI_I2S_DMAReq_Tx, DISABLE);
/* Disable SPI DMA RX Requsts */
SPI_I2S_DMACmd(EEPROM_SPI, SPI_I2S_DMAReq_Rx, DISABLE);
/* Disable the SPI peripheral */
SPI_Cmd(EEPROM_SPI, DISABLE);
// Release the CS
EEPROM_CS_High();
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?
I'm driving my head against the wall on this one
:(
#spi #spi-dma #spi_rx #dma-spi-rx-receive #dma #stm32f32018-01-09 10:13 PM
Start a simple program with nothing else just the SPI.
Try to receive data without DMA, in a polled loop. Are they received correctly?
With DMA, try more varying data. Fill the buffer with a distinctively different pattern to see, where the received data start and whether the number of received data matches the number of transmitted data. Maybe you can disconnect the EEPROM and loop back MOSI to MISO.
JW
2018-01-09 10:43 PM
As SPI Master, I don't check for completion of the DMA TX, only on the completion of the DMA RX, then wait for SPI BUSY to be done and raise the NSS. For other first byte issue, it's probably configuring and sequencing. DMA RX settings should be initialized first, then DMA TX next (event that triggers the SPI clock generation)
2018-01-18 05:46 AM
Thanks for the replies!
It seems that the issue was resolved after adding the RX FIFO threshold to quarter full:
SPI_RxFIFOThresholdConfig(EEPROM_SPI,SPI_RxFIFOThreshold_QF);
Makes sense since I'm doing byte-wide transactions.