cancel
Showing results for 
Search instead for 
Did you mean: 

SPI reliability problem when transferring large amount of data

RMlad
Associate

I'm building SPI slave based on STM32F750V8T6 MCU and I'm having problem loosing sync between master and slave. When I run test that is sending sync bytes, slave receive data from master, sync again and slave is returning data after some time master ends up receiving sync bytes not the message that has been sent.

I have tried lowering speed, adding delays between syncs.

Master SPI config:

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

slave SPI init

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_SLAVE;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 7;
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
  {
    Error_Handler();
  }

master sync

uint8_t txackbytes = SPI_MASTER_SYNBYTE;
  rxackbytes = 0x00;
  do
  {
    SPI_TASK(HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)&txackbytes, (uint8_t *)&rxackbytes, 1, HAL_MAX_DELAY))
  }while(rxackbytes != SPI_SLAVE_SYNBYTE);

slave sync

  uint8_t txackbyte = SPI_SLAVE_SYNBYTE;
  uint8_t rxackbyte = 0x00;
  do
  {
    SPI_TASK(HAL_SPI_TransmitReceive(&hspi1, (uint8_t *)&txackbyte, (uint8_t *)&rxackbyte, 1, HAL_MAX_DELAY))
  } while (rxackbyte != SPI_MASTER_SYNBYTE);

master while(1)

HAL_GPIO_WritePin(SPI_SS_GPIO_Port,SPI_SS_Pin,GPIO_PIN_RESET);
 
    Master_Synchro();
    SPI_TASK(HAL_SPI_Transmit(&hspi1, (uint8_t*)&porukaSize, 2, 50));
 
    Master_Synchro();
    SPI_TASK(HAL_SPI_Transmit(&hspi1, poruka, porukaSize, 50));
 
    Master_Synchro();
    SPI_TASK(HAL_SPI_Receive(&hspi1, aRxBuffer, porukaSize, 50));
 
    HAL_GPIO_WritePin(SPI_SS_GPIO_Port,SPI_SS_Pin,GPIO_PIN_SET);
 
    if(strcmp(poruka, aRxBuffer) != 0)
      flag = 0;
 
    if (flag){
      broj_uspeha++;
    }
    memset(aRxBuffer, 0, sizeof(aRxBuffer));

slave while(1)

if(!HAL_GPIO_ReadPin(SPI_SS_GPIO_Port,SPI_SS_Pin)){
 
      Slave_Synchro();
      SPI_TASK(HAL_SPI_Receive(&hspi1, (uint8_t*)&aRxBufferSize, 2, 50));
 
      Slave_Synchro();
      SPI_TASK(HAL_SPI_Receive(&hspi1, aRxBuffer, aRxBufferSize, 50));
 
      memcpy(aTxBuffer, aRxBuffer, sizeof(aRxBuffer));
 
      Slave_Synchro();
      SPI_TASK(HAL_SPI_Transmit(&hspi1, aTxBuffer, aRxBufferSize, 50));
 
      memset(aRxBuffer, 0, sizeof(aRxBuffer));
      memset(aTxBuffer, 0, sizeof(aTxBuffer));
    }

3 REPLIES 3
S.Ma
Principal

Seems you don't use NSS SPI signal between chips?

I2C bus is an NSS embedded in the clock data stream with START (falling edge) and STOP (rising edge) to synchronise data and make sure bytes are not misplaced.

For the slave SPI, do use DMA with cyclical buffer in RAM.

When NSS toggles, get EXTI interrupt to notify that the transmission is completed or about to start, and prepare your DMA pointers for it.

We are using SPI_NSS_SOFT for slave select, with DMA we are having even bigger problem. When using DMA the first sync-send-receive is failure.

S.Ma
Principal

Implement EXTI interrupt on NSS GPIO both rise and fall edge at least for the slave function.

Use it to initialize the DMA (at fall edge if length known at last minute, at rise edge otherwise).