AnsweredAssumed Answered

STM32F3 SPI over DMA receive issues

Question asked by G S on Jan 8, 2018
Latest reply on Jan 18, 2018 by G S

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

Outcomes