AnsweredAssumed Answered

STM32F373 - SPI + DMA - Data corruptions

Question asked by marcotte.alexand.001 on Sep 9, 2014

Hi,

I’m using a STM32F373

I want to read the data from an accelerometer (H3LIS33DL) with the SPI and DMA.

When I try to read multiple bytes (>2), sometime I got a corruption problem; the data is anormaly shifted in my destination data buffer.

Example: I should alway read 0xFF as the first byte, but sometime this is the second or the third byte in my buffer 

When I’m reading the accelerometer data by a polling method, there is no probleme at all

I can observe on the oscilloscope that the SPI signals are alway correct. It looks like there is no hardware problem. 

I followed the STM32 reference manual SPI-DMA guide (start and stop a transfer).

There is a notice in the errata about the SPI multi-packet, but I had some trouble to correctly understand.

Your help is greatly appreciated.

Alex

/******************************************************************************/

void initSpi(void)

{

  SPI_InitTypeDef                    SPI_InitHandler;

  GPIO_InitTypeDef                   GPIO_InitHandler;

  DMA_InitTypeDef                    DMA_InitHandler;

  TIM_TimeBaseInitTypeDef       TIM_InitHandler;

  NVIC_InitTypeDef                   NVIC_InitHandler;

  

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB |

                        RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD | 

                        RCC_AHBPeriph_DMA1, ENABLE);

  

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 | RCC_APB1Periph_TIM7, ENABLE);

  

  GPIO_InitHandler.GPIO_Pin      = MOSI_PIN | MISO_PIN;

  GPIO_InitHandler.GPIO_Mode     = GPIO_Mode_AF;

  GPIO_InitHandler.GPIO_Speed    = GPIO_Speed_Level_3;

  GPIO_InitHandler.GPIO_OType    = GPIO_OType_PP;

  GPIO_InitHandler.GPIO_PuPd     = GPIO_PuPd_NOPULL;

  GPIO_Init(MOSI_PORT, &GPIO_InitHandler);

  GPIO_InitHandler.GPIO_Pin      = SCK_PIN;

  GPIO_Init(SCK_PORT, &GPIO_InitHandler);

  GPIO_InitHandler.GPIO_Pin      = CS_PIN;

  GPIO_InitHandler.GPIO_Mode     = GPIO_Mode_OUT;

  GPIO_Init(CS_PORT, &GPIO_InitHandler);

  

  GPIO_PinAFConfig(MOSI_PORT, MOSI_PIN_SRC, GPIO_AF_5);

  GPIO_PinAFConfig(MISO_PORT, MISO_PIN_SRC, GPIO_AF_5);

  GPIO_PinAFConfig(SCK_PORT , SCK_PIN_SRC , GPIO_AF_5);

  

  SPI_InitHandler.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;

  SPI_InitHandler.SPI_CPHA                   = SPI_CPHA_2Edge;

  SPI_InitHandler.SPI_CPOL                        = SPI_CPOL_High;

  SPI_InitHandler.SPI_CRCPolynomial          = NOT_DEFINED;

  SPI_InitHandler.SPI_DataSize               = SPI_DataSize_8b;

  SPI_InitHandler.SPI_Direction                   = SPI_Direction_2Lines_FullDuplex;

  SPI_InitHandler.SPI_FirstBit                    = SPI_FirstBit_MSB;

  SPI_InitHandler.SPI_Mode                        = SPI_Mode_Master;

  SPI_InitHandler.SPI_NSS                         = SPI_NSS_Soft;

  SPI_Init(SPI2, &SPI_InitHandler);

  SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_ERR, ENABLE);

  

  DMA_InitHandler.DMA_BufferSize                     = NOT_DEFINED;

  DMA_InitHandler.DMA_DIR                            = DMA_DIR_PeripheralDST;

  DMA_InitHandler.DMA_M2M                            = DMA_M2M_Disable;

  DMA_InitHandler.DMA_MemoryBaseAddr        = NOT_DEFINED;

  DMA_InitHandler.DMA_MemoryDataSize         = DMA_MemoryDataSize_Byte;

  DMA_InitHandler.DMA_MemoryInc                      = DMA_MemoryInc_Enable;

  DMA_InitHandler.DMA_Mode                           = DMA_Mode_Normal;

  DMA_InitHandler.DMA_PeripheralBaseAddr     = (uint32_t)(&SPI2->DR);

  DMA_InitHandler.DMA_PeripheralDataSize      = DMA_PeripheralDataSize_Byte;

  DMA_InitHandler.DMA_PeripheralInc                  = DMA_PeripheralInc_Disable;

  DMA_InitHandler.DMA_Priority                       = DMA_Priority_Low;

  DMA_Init(DMA_SPI_TX, &DMA_InitHandler);

  DMA_InitHandler.DMA_DIR                       = DMA_DIR_PeripheralSRC;

  DMA_InitHandler.DMA_Priority                  = DMA_Priority_High;

  DMA_Init(DMA_SPI_RX, &DMA_InitHandler);

  DMA_ITConfig(DMA_SPI_RX, DMA_IT_TC, ENABLE);

  

  TIM_InitHandler.TIM_Prescaler               = 7199;

  TIM_InitHandler.TIM_CounterMode          = TIM_CounterMode_Down;

  TIM_InitHandler.TIM_Period               = NOT_DEFINED;

  TIM_InitHandler.TIM_ClockDivision           = 0;

  TIM_TimeBaseInit(TIM7, &TIM_InitHandler);

  TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);

  TIM_ClearFlag(TIM7, TIM_FLAG_Update);

  TIM_ClearITPendingBit(TIM7, TIM_IT_Update);

  DBGMCU_APB1PeriphConfig(DBGMCU_TIM7_STOP, ENABLE);

  

  NVIC_InitHandler.NVIC_IRQChannelCmd                   = ENABLE;

  NVIC_InitHandler.NVIC_IRQChannelPreemptionPriority    = 0;

  NVIC_InitHandler.NVIC_IRQChannelSubPriority           = 1;

  NVIC_InitHandler.NVIC_IRQChannel                      = SPI2_IRQn;

  NVIC_Init(&NVIC_InitHandler);

  NVIC_InitHandler.NVIC_IRQChannel                   = DMA1_Channel4_IRQn;

  NVIC_Init(&NVIC_InitHandler);

  NVIC_InitHandler.NVIC_IRQChannel                = TIM7_IRQn;

  NVIC_Init(&NVIC_InitHandler);

}

/******************************************************************************/

void startSpiTransfer(SpiTransceiverHandler *pSpiTransfer)

{

  assert_param(pSpiTransfer != NULL);

  assert_param(pSpiTransfer->len != 0);

  assert_param(pSpiTransfer->pTxData != NULL);

  assert_param((pSpiTransfer->pRxData != NULL) || (pSpiTransfer->operation == SPI_WRITE));

  

  pSpiTransceiver = pSpiTransfer;

  

  DMA_ClearITPendingBit(DMA1_IT_TC4);

  DMA_ClearITPendingBit(DMA1_IT_TC5);

  

  DMA_SPI_TX->CNDTR     = (uint16_t)(pSpiTransceiver->len);

  DMA_SPI_TX->CMAR     = (uint32_t)(pSpiTransceiver->pTxData);

  DMA_SPI_RX->CNDTR      = (uint16_t)(pSpiTransceiver->len);

  DMA_SPI_RX->CMAR     = (uint32_t)(pSpiTransceiver->pRxData);

  

  if(pSpiTransceiver->timeoutMs > 0){

    TIM7->CNT = pSpiTransceiver->timeoutMs;

    TIM_Cmd(TIM7, ENABLE);

  }

  else{

    TIM_Cmd(TIM7, DISABLE);

  }

  

  pSpiTransceiver->Flag.isTransferInProgress = TRUE;

  

  assertChipSelect(TRUE);

  

  DMA_Cmd(DMA_SPI_RX, ENABLE);

  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, ENABLE);

  SPI_Cmd(SPI2, ENABLE);

  DMA_Cmd(DMA_SPI_TX, ENABLE);

}

/******************************************************************************/

void stopSpiTransfer(void)

{

  volatile uint8_t dummyRead;

  

  assertChipSelect(FALSE);

  

  /* Disabling DMA procedure */

  SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx | SPI_I2S_DMAReq_Rx, DISABLE);

  

  /* Disabling SPI procedure */ 

  while(SPI_GetTransmissionFIFOStatus(SPI2) != 0);

  while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET);

  SPI_Cmd(SPI2, DISABLE);

  while(SPI_GetReceptionFIFOStatus(SPI2) != SPI_ReceptionFIFOStatus_Empty){

    dummyRead = SPI2->DR;

  }

  

  DMA_Cmd(DMA_SPI_TX, DISABLE);

  DMA_Cmd(DMA_SPI_RX, DISABLE);

  

  TIM_Cmd(TIM7, DISABLE);

  

  pSpiTransceiver->Flag.isTransferInProgress = FALSE;

}

/******************************************************************************/

void DMA_SPI_RX_ISR(void)

{

  if(DMA_GetITStatus(DMA1_IT_TC4) == SET){

    DMA_ClearFlag(DMA1_FLAG_TC4);

    stopSpiTransfer();

    if(pSpiTransceiver->operation == SPI_READ){

      pSpiTransceiver->Flag.isDataAvailable = TRUE; 

    }

  }

}

/******************************************************************************/

void TIM7_IRQHandler(void)

{

  if(TIM_GetITStatus(TIM7, TIM_IT_Update) == SET){

    TIM_ClearFlag(TIM7, TIM_FLAG_Update);

    if(pSpiTransceiver->Flag.isTransferInProgress == TRUE){

      //assert_param(0);

      stopSpiTransfer();

      pSpiTransceiver->Flag.isTimeoutErrorOccured = TRUE;

    }

  }

}

/******************************************************************************/

Outcomes