AnsweredAssumed Answered

Why are the first 2 bytes in each SPI transmission with DMA controller erroneous?

Question asked by arnold_w on Mar 16, 2016
Latest reply on Mar 18, 2016 by arnold_w
I'm working with the Discovery Development Board and I am trying to use the DMA-controller with my SPI-bus in order to support 5-byte continuous transfers. I have assigned SPI1 as my master and SPI2 as my slave and connected wires in between and I have verified using a logic analyzer that my master is working properly. My slave, on the other hand, is not working properly. My slave can successfully receive what the master is sending, but the first 2 bytes of what the slave sends to the master are always wrong. The slave should be sending a counting sequence

[0, 1, 2, 3, 4]
[5, 6, 7, 8, 9]
[10, 11, 12, 13, 14]
[15, 16, 17, 18, 19]... etc,
but on the logic analyzer I can see that the slave is actually sending

[0, 0, 2, 3, 4]
[0, 1, 7, 8, 9]
[5, 6, 12, 13, 14]
[10, 11, 17, 18, 19]

Thus, the first two byte in each transmission are wrong. Does anybody know why? I get no error codes or error interrupts.

SPI_HandleTypeDef hspi2;
DMA_HandleTypeDef hdma_spi2_tx;
DMA_HandleTypeDef hdma_spi2_rx;
 
void initializeSpi2controlPins(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    __SPI2_CLK_ENABLE();
 
    /***************************************************
    *****************  SPI MISO  ***********************
    ***************************************************/
    GPIO_InitStructure.Pin       = GPIO_PIN_2;
    GPIO_InitStructure.Mode      = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Speed     = GPIO_SPEED_FAST;
    GPIO_InitStructure.Pull      = GPIO_NOPULL;
    GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
 
    /***************************************************
    *****************  SPI MOSI  ***********************
    ***************************************************/
    GPIO_InitStructure.Pin       = GPIO_PIN_3;
    GPIO_InitStructure.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStructure.Speed     = GPIO_SPEED_FAST;
    GPIO_InitStructure.Pull      = GPIO_NOPULL;
    GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStructure);
 
    /***************************************************
    *****************  SPI CLK  ************************
    ***************************************************/
    GPIO_InitStructure.Pin       = GPIO_PIN_10;
    GPIO_InitStructure.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStructure.Speed     = GPIO_SPEED_FAST;
    GPIO_InitStructure.Pull      = GPIO_NOPULL;
    GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
 
    /***************************************************
    *****************  SPI NSS  ************************
    ***************************************************/
    GPIO_InitStructure.Pin       = GPIO_PIN_9;
    GPIO_InitStructure.Mode      = GPIO_MODE_AF_OD;
    GPIO_InitStructure.Speed     = GPIO_SPEED_FAST;
    GPIO_InitStructure.Pull      = GPIO_NOPULL;
    GPIO_InitStructure.Alternate = GPIO_AF5_SPI2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
}
 
 
#define DMA_RECEIVE_BUFFER_SIZE  5
uint8_t receiveDMAbuffer[DMA_RECEIVE_BUFFER_SIZE];
uint8_t transmitDMAbuffer[DMA_RECEIVE_BUFFER_SIZE];
 
void enableSpi2module(void)
{
    __DMA1_CLK_ENABLE();
    hspi2.Instance                        = SPI2;
    hspi2.Init.Mode                       = SPI_MODE_SLAVE;
    hspi2.Init.Direction                  = SPI_DIRECTION_2LINES;
    hspi2.Init.DataSize                   = SPI_DATASIZE_8BIT;
    hspi2.Init.CLKPolarity                = SPI_POLARITY_HIGH;
    hspi2.Init.CLKPhase                   = SPI_PHASE_2EDGE;
    hspi2.Init.NSS                        = SPI_NSS_HARD_INPUT;
    hspi2.Init.FirstBit                   = SPI_FIRSTBIT_MSB;
    hspi2.Init.TIMode                     = SPI_TIMODE_DISABLED;
    hspi2.Init.CRCCalculation             = SPI_CRCCALCULATION_DISABLED;
    hspi2.Init.CRCPolynomial              = 10;
 
    hdma_spi2_rx.Instance                 = DMA1_Stream3;
    hdma_spi2_rx.Init.Channel             = DMA_CHANNEL_0;
    hdma_spi2_rx.Init.Direction           = DMA_PERIPH_TO_MEMORY;
    hdma_spi2_rx.Init.PeriphInc           = DMA_PINC_DISABLE;
    hdma_spi2_rx.Init.MemInc              = DMA_MINC_ENABLE;
    hdma_spi2_rx.Init.MemBurst            = DMA_MBURST_SINGLE;
    hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_rx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    hdma_spi2_rx.Init.Mode                = DMA_CIRCULAR;
    hdma_spi2_rx.Init.Priority            = DMA_PRIORITY_LOW;
    hdma_spi2_rx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_spi2_rx);
 
    __HAL_LINKDMA(&hspi2, hdmarx, hdma_spi2_rx);
 
    hdma_spi2_tx.Instance                 = DMA1_Stream4;
    hdma_spi2_tx.Init.Channel             = DMA_CHANNEL_0;
    hdma_spi2_tx.Init.Direction           = DMA_MEMORY_TO_PERIPH;
    hdma_spi2_tx.Init.PeriphInc           = DMA_PINC_DISABLE;
    hdma_spi2_tx.Init.MemInc              = DMA_MINC_ENABLE;
    hdma_spi2_tx.Init.MemBurst            = DMA_MBURST_SINGLE;
    hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
    hdma_spi2_tx.Init.MemDataAlignment    = DMA_MDATAALIGN_BYTE;
    hdma_spi2_tx.Init.Mode                = DMA_CIRCULAR;
    hdma_spi2_tx.Init.Priority            = DMA_PRIORITY_LOW;
    hdma_spi2_tx.Init.FIFOMode            = DMA_FIFOMODE_DISABLE;
    HAL_DMA_Init(&hdma_spi2_tx);
 
    __HAL_LINKDMA(&hspi2, hdmatx, hdma_spi2_tx);
 
    /* Disable the selected SPI peripheral */
    __HAL_SPI_DISABLE(&hspi2);
 
    HAL_StatusTypeDef status = HAL_SPI_Init(&hspi2);
    if (status == HAL_ERROR)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Init status HAL_ERROR");
    }
    else if (status == HAL_BUSY)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Init status HAL_BUSY");
    }
    else if (status == HAL_TIMEOUT)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Init status HAL_TIMEOUT");
    }
 
 
    /* DMA interrupt init */
    HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
    HAL_NVIC_SetPriority(DMA1_Stream4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
 
    status = HAL_SPI_TransmitReceive_DMA(&hspi2, transmitDMAbuffer, receiveDMAbuffer, DMA_RECEIVE_BUFFER_SIZE);
    if (status == HAL_ERROR)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Receive_DMA status HAL_ERROR");
    }
    else if (status == HAL_BUSY)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Receive_DMA status HAL_BUSY");
    }
    else if (status == HAL_TIMEOUT)
    {
        UART4_TransmitNullTerminatedString((uint8_t*) "\r\nHAL_SPI_Receive_DMA status HAL_TIMEOUT");
    }
}
 
 
void loadTransmitBuffer(uint8_t* bytesToTransmit)
{
    (void) memcpy (transmitDMAbuffer, bytesToTransmit, DMA_RECEIVE_BUFFER_SIZE);
}
 
 
void DMA1_Stream3_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_spi2_rx);
}
 
 
void DMA1_Stream4_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&hdma_spi2_tx);
}
 
 
void HAL_SPI_RxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_RxHalfCpltCallback");
    UART4_WaitForTransmitToFinish();
}
 
 
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_TxCpltCallback");
    UART4_WaitForTransmitToFinish();
}
 
 
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_RxCpltCallback");
    UART4_WaitForTransmitToFinish();
}
 
 
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_TxRxCpltCallback");
    UART4_WaitForTransmitToFinish();
}
 
 
void HAL_SPI_ErrorCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_ErrorCallback");
    UART4_WaitForTransmitToFinish();
}
 
 
void HAL_SPI_TxHalfCpltCallback(SPI_HandleTypeDef *hspi)
{
    UART4_TransmitNullTerminatedString((uint8_t*)"\r\nHAL_SPI_TxHalfCpltCallback");
    UART4_WaitForTransmitToFinish();
}

If I modify the loadTransmitBuffer-function to the following, then the problem with the first byte in each transmission disappears, but the second byte is still wrong (changing the SPI to 16-bit mode didn't help):

void loadTransmitBuffer(uint8_t* bytesToTransmit)
{
    (void) memcpy (transmitDMAbuffer, bytesToTransmit, DMA_RECEIVE_BUFFER_SIZE);
    SPI2->DR = ((((uint16_t)bytesToTransmit[1]) << 8) & 0xFF00) + bytesToTransmit[0];
}

Outcomes