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.png
and the initialisation code is:
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:
uint16_t tmp = 0;
// select the AD4100
GPIOE->BSRR |= 0x100000;
// enable SPI
SPI4->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 register
tmp = *(volatile uint16_t *)&SPI4->DR;
// disable SPI
SPI4->CR1 &= (~SPI_CR1_SPE);
// deselect the AD4100
GPIOE->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.png
RigolDS0.png
I've tried to clear the FIFO but it didn't help:
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.1
https://www.st.com/resource/en/errata_sheet/es0334-stm32f76xxx-and-stm32f77xxx-device-errata-stmicroelectronics.pdf there 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!