cancel
Showing results for 
Search instead for 
Did you mean: 

SPI Slave transmit has extra byte at times

MPatt.11
Associate II

0690X000006DCWkQAO.jpg0690X000006DCWfQAO.jpg0690X000006DCWaQAO.jpgI have two STM32F7 processors set up in SPI Master/Slave configuration. When the slave wants to transmit data to the master, it issues an interrupt and the master reads 4 bytes. The first two are the number of data bytes to read, the second two is a command code. The master waits for a go-ahead interrupt, then reads the rest of the bytes.

At times, I'm seeing the first byte of the 4-byte transfer duplicated in the data transfer - thus shifting the bytes by one, and adding one byte to the transfer. This may make more sense by looking at the captures from the logic analyzer. I am using HAL_SPI_Transmit_IT to the master, and HAL_SPI_Receive_IT on the master side to receive the bytes.

The transfer rate is 14 MHz. Slowing the clock down makes no difference.

Using SPI_NSS_PULSE_DISABLE or SPI_NSS_PULSE_ENABLE does not help

On the Master side, using SPI_NSS_HARD_OUTPUT or generating the NSS signal manually makes no difference.

The only thing that seems to help is enforcing a minimum transfer rate of 2ms. In other words, the slave needs to wait 2ms minimum between transfers.

Slave initialization:

/* SPI Port for communications with Master processor
 **/
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
  GPIO_InitTypeDef GPIO_InitStruct;
  if(hspi->Instance==SPI1)
  {
    /* Peripheral clock enable */
    __HAL_RCC_SPI1_CLK_ENABLE();
  
    /**SPI1 GPIO Configuration    
    PA4     ------> SPI1_NSS
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    GPIO_InitStruct.Pin = SPI_CS_IN_Pin|SPI_CLK_IN_Pin|SPI_MISO_Pin|SPI_MOSI_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
 
    /* SPI1 interrupt Init */
    HAL_NVIC_SetPriority(SPI1_IRQn, 1, 0);   
    HAL_NVIC_EnableIRQ(SPI1_IRQn);
  }
}
 
 
 
/* SPI1 init function */
void MX_SPI1_Init(void)
{
  /* SPI1 parameter configuration*/
  SPI_SLAVE_1.Instance = SPI1;
  SPI_SLAVE_1.Init.Mode = SPI_MODE_SLAVE;
  SPI_SLAVE_1.Init.Direction = SPI_DIRECTION_2LINES;
  SPI_SLAVE_1.Init.DataSize = SPI_DATASIZE_8BIT;
  SPI_SLAVE_1.Init.CLKPolarity = SPI_POLARITY_LOW;
  SPI_SLAVE_1.Init.CLKPhase = SPI_PHASE_1EDGE;
  SPI_SLAVE_1.Init.NSS = SPI_NSS_HARD_INPUT;
  SPI_SLAVE_1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  SPI_SLAVE_1.Init.TIMode = SPI_TIMODE_DISABLE;
  SPI_SLAVE_1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  SPI_SLAVE_1.Init.CRCPolynomial = 7;
  SPI_SLAVE_1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
  SPI_SLAVE_1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
  if (HAL_SPI_Init(&SPI_SLAVE_1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}

Has anyone seen similar issues with the SPI Slave transfer?

Mark

11 REPLIES 11
S.Ma
Principal

I've spent 6 months playing around various SPI with Master - Slave STM32, what I learnt :

  • There are different generations of SPI, the 8 or 16 bit old one, the 4..16 bit one, the 32 bit hidden TX/RX FIFO and the H7 one (so far)
  • SPI is the potentially highest 1 bit serial bus datarate in an MCU and deserves DMA use
  • NSS is manually operated on the master side, HW used on the slave side to Hi-Z the pins when not selected
  • The protocol should be carefully done to try to avoid interrupts during the SPI exchange
  • Always think bi-directional = receive/transmit
  • Full HW slaves (ADC, DAC, Memories) are usually half duplex, with write, dummy byte (if latency to turnaround from write to read), then read
  • Robustness (buy a cheap headphone, which will break within weeks and add plastic trash) : Don't expect the transmitter data lenght, use DMA in cyclic mode and use EXTI on NSS to get told there is something in your mailbox... = buffers. The master needs to provide enough time (MCU=SW=Delay) for the slaves to pump the data away and get ready for the next. Add extra margin as in real world, application are having many interrupts firering anytime and extending lags of others. In technical term is the hunt for WCET value.
  • You want your protocol to survive glitches, incorrect transmittion, survive ESD shocks and still operating properly overnight.
  • Reset the slave SPI once the NSS goes high, and reconfigure it. The HW FIFO slave TX classical issue is there and was mentionned in this post. Won't reexplain it every time it pops in this forum.
  • In the protocol, it is a good idea to have the packet length (receive or transmit) and even an error / overrun bit

Good luck !

History : RS232, then SPI 4 wires, then SPI 3 wires, then I2C (1982)

Nice list, @S.Ma​ !

> There are different generations of SPI,

... and we still hold our breath until ST kindly supplies us with the list of IP versions used in various STM32 (sub)families... see @Nikita91​ 's Idea... oh wait, Ideas gone thanks to the ST's neglect and salesforce's incompetence...

> the 4..16 bit one, the 32 bit hidden TX/RX FIFO

Is there a 4..16 bit SPI without the FIFO out there?

JW