cancel
Showing results for 
Search instead for 
Did you mean: 

Moving from HAL (working) to LL (issue), SPI always receive 255

Adrian94
Associate

Hello everyone,

I am facing an issue during migration from HAL libraries to LL. I need to increase performance of my code and better understand STM peripherals.

My MCU is STM32F746 on a custom board.

CubeMX configuration for SPI1 is the same for HAL && LL version. There was a DMA stream for SPI which I used later on to talk to ADC, I tried to leave it and remove it for LL version but had no affect on solving the issue.

The code is as follows, an initialization generated from CubeMX and part of my code:

/**
  * @brief SPI1 Initialization Function
  * @param None
  * @retval None
  */
static void MX_SPI1_Init(void)
{
 
  /* USER CODE BEGIN SPI1_Init 0 */
 
  /* USER CODE END SPI1_Init 0 */
 
  LL_SPI_InitTypeDef SPI_InitStruct = {0};
 
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
 
  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SPI1);
 
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOB);
  /**SPI1 GPIO Configuration
  PA5   ------> SPI1_SCK
  PB4   ------> SPI1_MISO
  PB5   ------> SPI1_MOSI
  */
  GPIO_InitStruct.Pin = ADC_SCK_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(ADC_SCK_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = ADC_MISO_Pin;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(ADC_MISO_GPIO_Port, &GPIO_InitStruct);
 
  GPIO_InitStruct.Pin = LL_GPIO_PIN_5;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_5;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
  /* USER CODE BEGIN SPI1_Init 1 */
 
  /* USER CODE END SPI1_Init 1 */
  /* SPI1 parameter configuration*/
  SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
  SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
  SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
  SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_LOW;
  SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
  SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
  SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2;
  SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;
  SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
  SPI_InitStruct.CRCPoly = 7;
  LL_SPI_Init(SPI1, &SPI_InitStruct);
  LL_SPI_SetStandard(SPI1, LL_SPI_PROTOCOL_MOTOROLA);
  LL_SPI_DisableNSSPulseMgt(SPI1);
  /* USER CODE BEGIN SPI1_Init 2 */
 
  /* USER CODE END SPI1_Init 2 */
}

After I initialize an ADC, I wrote some hardtyped code to debug this case:

volatile uint8_t response = 0;
 
/* ADC init, nothing but GPIO writes */
 
// Run ADC, 5 ms delay for internal init according to datasheet
LL_GPIO_SetOutputPin(ADC_RESET_GPIO_Port, ADC_RESET_Pin);
vTaskDelay(5);
 
// Quater threshold for 1 byte / 8 bits
LL_SPI_SetRxFIFOThreshold(SPI1, LL_SPI_RX_FIFO_TH_QUARTER);
 
// Enable SPI
LL_SPI_Enable(SPI1);
 
// Wait until SPI is ready
while (LL_SPI_IsActiveFlag_BSY(SPI1));
 
// CS down
LL_GPIO_ResetOutputPin(ADC_CS_GPIO_Port, ADC_CS_Pin);
 
// Wait for transmit buffer empty and transmit data
while (!LL_SPI_IsActiveFlag_TXE(SPI1));
LL_SPI_TransmitData8(SPI1, 0xAA);
 
// Wait for received data and dummy read
while(!LL_SPI_IsActiveFlag_RXNE(SPI1));
LL_SPI_ReceiveData8(SPI1);
 
// Wait for transmit buffer empty and write dummy data
while (!LL_SPI_IsActiveFlag_TXE(SPI1));
LL_SPI_TransmitData8(SPI1, 0x55);
 
// Wait for received data and read response
while(!LL_SPI_IsActiveFlag_RXNE(SPI1));
response = LL_SPI_ReceiveData8(SPI1);
 
// CS up
LL_GPIO_SetOutputPin(ADC_CS_GPIO_Port, ADC_CS_Pin);

This code procudes such a waveform:

0693W000007EDPtQAO.pngLow signal integrity is a result of poor probing technique, with proper measurement it is all right. As you can see, there is data output from ADC (slave) on MISO and MCU (master) should read 0x81.

I can switch back my code to HAL version and it comes back to work. I tried many other options like replacing LL_SPI_IsActiveFlag_TXE with LL_SPI_IsActiveFlag_BSY (I know it is not recommended), dummy read after LL_SPI_Enable, double write with LL_SPI_RX_FIFO_TH_HALF and LL_SPI_ReceiveData16 (returns 0xFFFF).. I have analyzed HAL libraries code and it is basically 2 days after debugging that I have to ask for an advice.

Can you help me with this issue?

1 ACCEPTED SOLUTION

Accepted Solutions

Read out and check/post SPI and related GPIO registers content.

JW

View solution in original post

2 REPLIES 2

Read out and check/post SPI and related GPIO registers content.

JW

Thank you @Community member​ for investigating the problem.

I wrote some code to fetch all SPI and related GPIO registers and during that I have discovered that at some point after I cloned my HAL-based project, the CubeMX swapped MISO pin back to it's default assigment. I thought it might happen when I migrated project to newer version of CubeMX, but I failed to reproduce it. Thus I had no clue how it might happen. I was not experimenting with pin assigments since I designed hardware.. like months ago.

Changing it back fixed the problem. Shame on me. Thanks to you for forcing me to check those GPIOs (and oh God, it was very close to miss the thing again..).

If anyone is still curious about SPI registers, here it is:

// Enable SPI
LL_SPI_Enable(SPI1);
 
// Wait until SPI is ready
while (LL_SPI_IsActiveFlag_BSY(SPI1));
 
// SPI registers
regRead = SPI1->CR1; 		// 0x0345
regRead = SPI1->CR2; 		// 0x1700
regRead = SPI1->SR; 		// 0x0002
regRead = SPI1->DR; 		// 0x0000
regRead = SPI1->CRCPR; 		// 0x0007
regRead = SPI1->RXCRCR; 	// 0x0000
regRead = SPI1->I2SCFGR; 	// 0x0000
regRead = SPI1->I2SPR; 		// 0x0002

Thank you again and now the posted code seems to work as expected!

Have a nice day.

Yours

Adrian