Strange STM32F777 SPI behaviour - Page 1
Forum section: electronics / general

author: Enceladus
author_rank: Contributor
timestamp: June 06, 2024, 12:39:52 am
content: Hello! I've been having issues with the SPI on STM32F777 microcontroller. Basically I need to read the data from the external ADC fast so I'm using bare registers for receiving while CubeMX is generating the SPI initialisation.So the SPI configuration looks like this:spi4_init.pngand the initialisation code is:Code:void MX_SPI4_Init(void){hspi4.Instance = SPI4;hspi4.Init.Mode = SPI_MODE_MASTER;hspi4.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;hspi4.Init.DataSize = SPI_DATASIZE_16BIT;hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;hspi4.Init.NSS = SPI_NSS_SOFT;hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi4.Init.TIMode = SPI_TIMODE_DISABLE;hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi4.Init.CRCPolynomial = 7;hspi4.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;hspi4.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;if (HAL_SPI_Init(&hspi4) != HAL_OK){Error_Handler();}}Please note that the data size is 16 bit and the SPI mode is Receive Only Master.So here is the code I'm using to receive the 16 bit:Code:uint16_t tmp = 0;// select the AD4100GPIOE->BSRR |= 0x100000;// enable SPISPI4->CR1 |= SPI_CR1_SPE;// set the FIFO threshold to 1/2 of the buffer (16 bit)CLEAR_BIT(SPI4->CR2, SPI_RXFIFO_THRESHOLD);// wait for RXNE to set (Rx buffer is not empty)while (!(SPI4->SR & SPI_SR_RXNE));// copy data from the registertmp = *(volatile uint16_t *)&SPI4->DR;// disable SPISPI4->CR1 &= (~SPI_CR1_SPE);// deselect the AD4100GPIOE->BSRR |= 0x0010;Because the mode of the SPI is receive master only I don't need to send dummy data (though I tried, it didn't help) as it outputs CLK as soon as the SPI is enabled.The problem is that for some reason the first read clocks more than 16 pulses and then the following reads set the SPI_SR_RXNE too early and the CS goes high before 16 CLK cycles are finished. Please see the images below:RigolDS1.pngRigolDS0.pngI've tried to clear the FIFO but it didn't help:Code:uint8_t emp = 0;while ((SPI4->SR & SPI_SR_FRLVL) != SPI_FRLVL_EMPTY)emp = *(volatile uint8_t *)&SPI4->DR;I would wait for the BSY flag but according to errata 2.15.1https://www.st.com/resource/en/errata_sheet/es0334-stm32f76xxx-and-stm32f77xxx-device-errata-stmicroelectronics.pdfthere is a bug that wouldn't allow me to do so (I've tried, it freezes in the endless waiting for the BSY flag to be released).What could possibly cause such behaviour and are there any workarounds? Thank you!

author: Enceladus
author_rank: Contributor
timestamp: June 06, 2024, 01:23:51 am
content: OK, seems that I've found what's going on. I've changed the mode from Read Only Master to Full-Duplex Master. In this regime the CLK is only generated when I'm sending something, so I have to send a dummy uint16 to generate 16 CLK pulses:Code:// send dummy data*(volatile uint16_t*)&SPI4->DR = tmp;while (!((SPI4->SR) & (1 << 1)));Now everything works fine and SPI_SR_RXNE flag is being set properly (when 16 bit were received). Looks like the Read Only Master is only to be used with circular DMA...

author: aliarifat794
author_rank: Regular Contributor
timestamp: June 06, 2024, 06:11:35 am
content: You can modify your code like this:Code:void MX_SPI4_Init(void){hspi4.Instance = SPI4;hspi4.Init.Mode = SPI_MODE_MASTER;hspi4.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;hspi4.Init.DataSize = SPI_DATASIZE_16BIT;hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;hspi4.Init.NSS = SPI_NSS_SOFT;hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi4.Init.TIMode = SPI_TIMODE_DISABLE;hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi4.Init.CRCPolynomial = 7;hspi4.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;hspi4.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;if (HAL_SPI_Init(&hspi4) != HAL_OK){Error_Handler();}}uint16_t Read_SPI4_Data(void){uint16_t tmp = 0;// select the AD4100 (assuming active low)GPIOE->BSRR |= 0x100000; // Set pin low (assuming bit 20 corresponds to CS)// enable SPISPI4->CR1 |= SPI_CR1_SPE;// set the FIFO threshold to 1/2 of the buffer (16 bit)SET_BIT(SPI4->CR2, SPI_RXFIFO_THRESHOLD);// small delay to ensure SPI is readyfor(volatile int i = 0; i < 10; i++);// wait for RXNE to set (Rx buffer is not empty)while (!(SPI4->SR & SPI_SR_RXNE));// copy data from the registertmp = *(volatile uint16_t *)&SPI4->DR;// disable SPISPI4->CR1 &= (~SPI_CR1_SPE);// deselect the AD4100GPIOE->BSRR |= 0x0010; // Set pin high (assuming bit 4 corresponds to CS)return tmp;}