cancel
Showing results for 
Search instead for 
Did you mean: 

STM32CubeF4 - SPI Receiver doesn't work under HAL...

Zaher
Senior II
Posted on March 14, 2017 at 17:04

Hello everyone!

I was forced to move my project to HAL Libs for bunch of reasons beyond the scope of this discussion, and ever since, I ran into problems getting the SPI to work properly. I spent a tremendous time trying to get acquainted with the Std Periph Lib from ST, and I have been able to build several projects under that lib, until that TROUBLESOME HAL thing came out and changed everything, for the worst, in fact! I guess I'm not alone in reporting tons of bugs and issues moving from Std Periph Libs to HAL (Hell Always, not Hardware Abstraction Layer). 

Well, getting down to the problem, part of my project is to control a dSPIN device over SPI. I had a working code based on the Std.Periph.Libs and built with the AC6/GCC tools, where everything worked out as expected. I've been able to write and read the registers from the device, however, trying to do the same thing with HAL, keeping all settings for the SPI, RCC, GPIO has failed for no obvious reason. 

My problem lies in the receiving part of the SPI. Usually, the master sends a byte and the slave, dSPIN, sends response of 1~3 bytes long, depending on the command received. At the beginning, I noticed that there's no data being received by the master, STM32F429ZIT. The RXNE flag is never set and the program stuck in a while loop waiting for the RXNE flag forever. I tried everything possible, switched to another GPIO/SPI port, changed RCC settings, but all of that did not help in getting the response from the dSPIN/Slave. After almost two weeks of painful work modifying my code dozens of times, I managed to find out that the 2-Line Duplex mode was the reason the RX part did not work, thus the RXNE flag kept cleared. Although the same SPI configurations (2-Line Duplex) did the job very well for the old project that I built with the Std.PeriphLibs under the Eclipse-Based IDE. Now, after changing the SPI configurations from 2-Line to 1-Line, I started to receive data and the RXNE flag is set with each byte received, however, the data received seems to be a garbage and not related to any response from the dSPIN. I found out that others had similar issue with different series of STM32, and Flushing the RX FIFO is all they needed to get the correct data, but I believe the flushing function,RX_FIFO_flush

()

, is not available for the STM32F4 series. 

Below are some snippets from my project source code that had to do with the SPI:

/* SPI4 init function */

static void MX_SPI4_Init(void)

{

hspi4.Instance = SPI4;

hspi4.Init.Mode = SPI_MODE_MASTER;

hspi4.Init.Direction = SPI_DIRECTION_1LINE;

hspi4.Init.DataSize = SPI_DATASIZE_8BIT;

hspi4.Init.CLKPolarity = SPI_POLARITY_HIGH;

hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;

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;

if (HAL_SPI_Init(&hspi4) != HAL_OK)

{

Error_Handler();

}

}

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)

{

GPIO_InitTypeDef GPIO_InitStruct;

if(hspi->Instance==SPI4)

{

/* USER CODE BEGIN SPI4_MspInit 0 */

/* USER CODE END SPI4_MspInit 0 */

/* Peripheral clock enable */

__HAL_RCC_SPI4_CLK_ENABLE();

/**SPI4 GPIO Configuration

PE2 ------> SPI4_SCK

PE5 ------> SPI4_MISO

PE6 ------> SPI4_MOSI

*/

GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_5|GPIO_PIN_6;

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_SPI4;

HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);

/* USER CODE BEGIN SPI4_MspInit 1 */

/* USER CODE END SPI4_MspInit 1 */

}

}

And here's my write function that write/reads a byte over SPI to/from a dSPIN slave:

/**

* @brief Transmits/Receives one byte to/from dSPIN over SPI.

* @param Transmited byte

* @retval Received byte

*/

uint8_t dSPIN_Write_Byte(uint8_t byte)

{

uint8_t Shifting_Byte = 0x00;

uint8_t Rx_Buffer[12] = 0;

uint8_t receivedbyte = 0;

uint8_t *Rx_Ptr;

/* nSS signal activation - low */

HAL_GPIO_WritePin(dSPIN_CS_GPIO_Port, dSPIN_CS_Pin, GPIO_PIN_RESET);

/* SPI byte send */

//HAL_Delay(10); /** Allow some time for CS **/

HAL_SPI_Transmit(&hspi4, (uint8_t*) &byte, 1, 100);

//HAL_SPI_TransmitReceive(&hspi4, (uint8_t*)&byte, Rx_Buffer, 1, 100);

/* Wait for SPIx Busy flag */

while(__HAL_SPI_GET_FLAG(&hspi4, SPI_FLAG_BSY) != RESET);

/* nSS signal deactivation - high */

HAL_GPIO_WritePin(dSPIN_CS_GPIO_Port, dSPIN_CS_Pin, GPIO_PIN_SET);

//HAL_SPI_Receive(&hspi4, &Rx_Buffer[0], 1, 100); /* Version 1 */

//HAL_SPI_Receive(&hspi4, (uint8_t*)&Resp, 1, 100); /* Version 2 */

//HAL_SPI_TransmitReceive(&hspi4, (uint8_t*)&Shifting_Byte,(uint8_t*) &receivedbyte, 1, 100); /* Version 3 */

HAL_SPI_Transmit(&hspi4, (uint8_t*) &Shifting_Byte, 2, 100);

//HAL_SPI_Receive(&hspi4, &receivedbyte, 1, 100 ); /* Version 4 */

//HAL_SPI_Receive(&hspi4, Rx_Ptr, 1, 100 ); /* Version 5 */

HAL_SPI_Receive(&hspi4, &Rx_Buffer[0], 1, 100 ); /* Version 6 */

/* Wait for SPIx Busy flag */

while(__HAL_SPI_GET_FLAG(&hspi4, SPI_FLAG_RXNE) != RESET);

//return Rx_Buffer[0];

//return (uint8_t)receivedbyte;

//return (uint8_t)*Rx_Ptr;

return Rx_Buffer[0];

}

As you can see above, I tried it in multitude of ways, but still can't get the correct response from the dSPIN. 

Hope someone has the solution for this! 

Regards,

Zaher

14 REPLIES 14
T J
Lead
Posted on March 25, 2017 at 02:14

to receive a byte you have to clock it, to clock the receiver, you have to send a byte.

void quickSendReceive8SPI(SPI_HandleTypeDef *hspi){
 while( !( hspi->Instance->SR & SPI_FLAG_TXE));
 
 *((__IO uint8_t *)&hspi->Instance->DR) = TxSPIByte; // force the SPI to transceive 8 bit
 while( !( hspi->Instance->SR & SPI_FLAG_TXE));
 while( ( hspi->Instance->SR & SPI_FLAG_BSY));
 while( ( hspi->Instance->SR & SPI_FLAG_RXNE))
 RxSPIByte1 = hspi->Instance->DR; // empty DR fifo, we only want the last byte
}�?�?�?�?�?�?�?�?�?�?

as you can see here, I am clocking out TxSPIByte, to clock in data, if there is some earlier data in the Rx buffer (usually double or tripled buffered) then the final byte received is left in RxSPIByte1

Posted on March 25, 2017 at 19:52

Just a quick update, the RXNE flag sets now as I send a new byte to the slave. The slave responds with 0x00 for most commands received, except those required to read parameters from the internal registers. Well, that was on the old version of the project I built with SPL. 

As far as I remember, I tried everything possible, even the Send_Receive in order to clock data into the receiver. But I might have missed something in the receiving sequence. Now, cancelling all 'receive' functions from my old SPL code, I still get bytes shifted out of the slave's shift register as the RXNE flag sets with each byte sent to the device. That was only by calling the 

SPI_I2S_SendData function. With that being said, all shifted bytes were detected at the master side. Now, if the HAL_SPI receives only by calling Send_Receive, then I believe I have to look back at my code to see if there's something I can do. 

Thank you again!

Zaher

Posted on March 25, 2017 at 21:23

To make things easier, SPI specific, and apart from my own dSPIN/Slave device, here's what I have found so far:

- Code built with SPL: Sending several bytes over SPI to my slave has always returned a response byte from the slave and the RXNE flag sets.

-Code built with HAL: Doing the same thing with HAL_SPI_Transmit or HAL_SPI_TransmitReceive has no effect whatsoever on the receiving of data and RXNE flag is always cleared! 

Tried with both pointers, casting to pointers, non has solved the issue! 

I'm almost giving up on this. The problem is I can't go back to SPL for the entire project, as the majority of the modules in the project are built with HAL. 

Thanks again,

Zaher

Zaher
Senior II
Posted on March 26, 2017 at 06:23

Finally, I came up with a solution that has worked out flawlessly and the code obviously compiles/runs much faster than ever. 

While it might be a stupid workaround for some, I'm pretty confident many others out there are looking for such a solution. It is not only for SPI, it could be done with any other peripheral, too. Well, I often had the idea of mixing HAL libraries with SPL and Googling it has not revealed much, except the fact that many are trying to do it somehow. Yes, I did it! 

I've been playing around this for the past 8 hours, and now my code compiles and runs smoothly without any issue. I can now use the same code I have written for SPL with the very same SPL-based SPI functions. I can now send and receive data to my dSPIN as expected. 

What I did is creating an object file for the SPI-related modules in the SPL-based project, and had those linked/added to my HAL-Based project. Finally, I have modified the code again to work with the old-fashioned, yet very efficient and easy to handle, SPI functions, and now everything works out perfectly!

It's a lot of fun to have some parts of the project built with the SPL, while still enjoy the CubeMx Initialization code generator, as well as the other modules needed in the project.

So, it is not 'impossible' to get them both working in the same project. Just create pre-compiled object files out of your SPL-based project for the modules concerned, and with some tweaking, your ready to utilize SPL functions in HAL projects, like I did successfully! 

I hope someone finds this helpful!

Thanks,

Zaher

Posted on March 26, 2017 at 10:28

Interesting. This stretched can become a linkable library...