cancel
Showing results for 
Search instead for 
Did you mean: 

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

arnold_w
Senior
Posted on March 16, 2016 at 10:52

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 theloadTransmitBuffer-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];
}

4 REPLIES 4
shingadaddy
Senior
Posted on March 16, 2016 at 20:31

I've got similar results like this if the numbers were defined in a buffer as ASCII

Then SIZEOF returns a count that includes the AUTO ADDED NUL on an ascii buffer.

That usually can throw sizing, indexing, offsets and counting functionality out of whack.

Just something maybe to check??

arnold_w
Senior
Posted on March 17, 2016 at 09:21

I never use SIZEOF, my buffer size is always hardcoded to 5 bytes so that can't be the problem. Thanks for your suggestion, though.

arnold_w
Senior
Posted on March 18, 2016 at 09:54

I've narrowed down the problem and it kind of makes sense that the first byte is wrong (I don't understand why the 2nd byte is wrong, though). Since the SPI is a slave, it must pre-fetch the first byte in order to always be ready to transmit and changing the data in the DMA-buffer doesn't change that pre-fetched byte. So, my question is rather, how do I tell my SPI module to invalidate what it has already pre-fetched and go grab new, fresh data from the DMA-buffer?

arnold_w
Senior
Posted on March 18, 2016 at 16:53

I finally got it working. In order to make the SPI-module fetch new data from the DMA-controller I almost reinitialise the whole SPI-module and DMA-controller again... This is pretty crazy and I wish there was a better way, but for now I'm just happy it's working at all.

static SPI_HandleTypeDef hspi2;
static DMA_HandleTypeDef hdma_spi2_tx;
static DMA_HandleTypeDef hdma_spi2_rx;
#define DMA_RECEIVE_BUFFER_SIZE 5
static uint8_t receiveDMAbuffer[DMA_RECEIVE_BUFFER_SIZE];
static uint8_t transmitDMAbuffer[DMA_RECEIVE_BUFFER_SIZE];
void initSpi2(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/***************************************************
***************** 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);
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;
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_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_NORMAL;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
}
static void shutDownSpi2(void)
{
HAL_NVIC_DisableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_DisableIRQ(DMA1_Stream4_IRQn);
HAL_DMA_DeInit(&hdma_spi2_rx);
HAL_DMA_DeInit(&hdma_spi2_tx);
__HAL_SPI_DISABLE(&hspi2);
__DMA1_CLK_DISABLE();
__SPI2_CLK_DISABLE();
}
static HAL_StatusTypeDef setupSpi1moduleForTransfer(void)
{
HAL_StatusTypeDef status;
shutDownSpi2();
__DMA1_CLK_ENABLE();
__SPI2_CLK_ENABLE();
status = HAL_DMA_Init(&hdma_spi2_rx);
if (status != HAL_OK)
{
shutDownSpi2();
return status;
}
status = HAL_DMA_Init(&hdma_spi2_tx);
if (status != HAL_OK)
{
shutDownSpi2();
return status;
}
__HAL_LINKDMA(&hspi2, hdmarx, hdma_spi2_rx);
__HAL_LINKDMA(&hspi2, hdmarx, hdma_spi2_rx);
__HAL_LINKDMA(&hspi2, hdmatx, hdma_spi2_tx);
status = HAL_SPI_Init(&hspi2);
if (status != HAL_OK)
{
shutDownSpi2();
return status;
}
HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn);
HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
status = HAL_SPI_TransmitReceive_DMA(&hspi2, transmitDMAbuffer, receiveDMAbuffer, DMA_RECEIVE_BUFFER_SIZE);
if (status != HAL_OK)
{
shutDownSpi2();
return status;
}
return HAL_OK;
}
HAL_StatusTypeDef prepareTransferSpi2(uint8_t* bytesToTransmit)
{
uint16_t i;
for (i = 0; i < DMA_RECEIVE_BUFFER_SIZE; i++)
{
transmitDMAbuffer[i] = bytesToTransmit[i];
}
return setupSpi1moduleForTransfer();
}
void DMA1_Stream3_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi2_rx);
}
void DMA1_Stream4_IRQHandler(void)
{
HAL_DMA_IRQHandler(&hdma_spi2_tx);
}
void SPI2_IRQHandler(void)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

SPI2_IRQHandler'');
UART4_WaitForTransmitToFinish();
}
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
UART4_TransmitNullTerminatedString((uint8_t*)''

HAL_SPI_TxRxCpltCallback'');
UART4_WaitForTransmitToFinish();
uint16_t i;
UART4_TransmitNullTerminatedString((uint8_t*) ''

Slave received the following in the receive DMA buffer: '');
for (i = 0; i < DMA_RECEIVE_BUFFER_SIZE; i++)
{
UART4_TransmitNullTerminatedString((uint8_t*) ''

0x'');
UART4_TransmitHexNumberAsASCII((uint32_t)receiveDMAbuffer[i]);
}
}