2021-07-23 03:26 AM
I have been trying to establish an SPI communication using STM32F7 microcontroller using Low level drivers in STM32CubeMX. I am facing issue Reading from the DR register. I need to read 8-bits but the values are getting stored as 16-bits. Also the DR register is getting update only after transmitting the command 3 times.
This is the SPI driver which I have written.
void SPITransmitData(char *p8Data, int i16Length)
{
while(SET == LL_SPI_IsActiveFlag_BSY(SPI2);
do
{
while(RESET == LL_SPI_IsActiveFlag_TXE(SPI2);
LL_SPI_TransmitData8(SPI2, *p8Data++);
i16Length--;
}while(i16Length != 0);
while(SET == LL_SPI_GetTxFIFOLevel(SPI2);
while(SET == LL_SPI_GetRxFIFOLevel(SPI2);
LL_SPI_ClearFlag_OVR(SPI2);
return;
}
void SPIReceiveData(char *p8Data, int i16Length)
{
do
{
LL_SPI_SetRxFIFOThreshold(SPI2, LL_SPI_RX_FIFO_TH_QUARTER);
while(RESET == LL_SPI_IsActiveFlag_TXE(SPI2);
LL_SPI_TransmitData8(SPI2, (uint8_t)*(p8Data+i16Count));
while(RESET == LL_SPI_IsActiveFlag_RXNE(SPI2);
*(p8Data+i16Count) = (uint8_t)(LL_SPI_ReceiveData16(SPI2);
i16Count += 1;
i16Length--;
}while(i16Length != 0);
while(SET == LL_SPI_GetTxFIFOLevel(SPI2);
while(SET == LL_SPI_GetRxFIFOLevel(SPI2);
return;
}
Please can anyone help.
-Regards
2021-07-23 07:33 AM
> I need to read 8-bits but the values are getting stored as 16-bits.
> *(p8Data+i16Count) = (uint8_t)(LL_SPI_ReceiveData16(SPI2);
Use LL_SPI_ReceiveData8 instead of LL_SPI_ReceiveData8.
Note also that, as written, that line won't compile. It amazes me the amount of "copy/paste errors" when users post code here.
> while(RESET == LL_SPI_IsActiveFlag_TXE(SPI2);
> while(RESET == LL_SPI_IsActiveFlag_RXNE(SPI2);
These lines also will not compile as-written since the parentheses are not balanced.
2021-07-25 10:37 PM
Thank you for the reply.
I apologise for the parentheses. It might have missed while coping. This will be taken care of in future. But I confirm that there are not compilation error in the code.
I tried using LL_SPI_ReceiveData8, but it is always reading 0x00. I observed that the data is being read as MSB for the 16-bit register. I had to do (uint8_t)((LL_SPI_ReceiveData16(SPI2)>>8); in order to read it properly. And that too after sending same command thrice.
Could you please tell if I am missing any settings. Below are the SPI settings which I have done.
LL_SPI_InitTypeDef SPI_InitStruct = {0};
SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;
SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;
SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_8BIT;
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;
SPI_InitStruct.ClockPolarity=LL_SPI_POLARITY_HIGH;
SPI_InitStruct.ClockPhase=LL_SPI_PHASE_2EDGE;
LL_SPI_Disable(SPI2);
LL_SPI_Init(SPI2, &SPI_InitStruct);
LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);
LL_SPI_EnableNSSPulseMgt(SPI2);
LL_SPI_Enable(SPI2);
2021-07-29 04:15 AM
Hi,
Can anyone please tell where I am going wrong in? Why am I not able to read data?
2022-06-23 05:11 AM
I had a similar issue reading the DR register correctly.
Here's the settings I had:
LL_SPI_InitTypeDef SPI_InitStruct = {0};
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_HIGH;
SPI_InitStruct.ClockPhase = LL_SPI_PHASE_2EDGE;
SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;
SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV16;
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);
I was careful to keep the FRXTH bit of SPIx_CR2 register in line with the call made to read the data from the DR register (LL_SPI_ReceiveData8 and LL_SPI_ReceiveData16) but when invoking the LL_SPI_ReceiveData8 function, the returned value was always garbage although I could see that the register value was correct by stepping with the debugger. After a while of hair pulling, I tried to create a temporary variable and read the register like so:
volatile uint8_t *const spiDR8Bits = (volatile uint8_t*) &SPI1->DR;
uint8_t receivedByte = *spiDR8Bits;
This worked !
I think the issue had to do with the compiler not generating the correct instructions but It's no clear to me why and how.
I noticed that the LL_SPI_TransmitData8 and LL_SPI_TransmitData16 functions were defined like this:
__STATIC_INLINE void LL_SPI_TransmitData8(SPI_TypeDef *SPIx, uint8_t TxData)
{
#if defined (__GNUC__)
__IO uint8_t *spidr = ((__IO uint8_t *)&SPIx->DR);
*spidr = TxData;
#else
*((__IO uint8_t *)&SPIx->DR) = TxData;
#endif /* __GNUC__ */
}
__STATIC_INLINE void LL_SPI_TransmitData16(SPI_TypeDef *SPIx, uint16_t TxData)
{
#if defined (__GNUC__)
__IO uint16_t *spidr = ((__IO uint16_t *)&SPIx->DR);
*spidr = TxData;
#else
SPIx->DR = TxData;
#endif /* __GNUC__ */
}
But the LL_SPI_ReceiveData8 and LL_SPI_ReceiveData16 functions didn't make a distinction on the compiler so I finally created my own inline functions to read the DR register like this:
static inline uint8_t SPI_ReceiveData8(SPI_TypeDef *SPIx)
{
#if defined (__GNUC__)
volatile uint8_t *spidr = ((volatile uint8_t*) &SPIx->DR);
return *spidr;
#else
return (*((volatile uint8_t *)&SPIx->DR));
#endif /* __GNUC__ */
}
static inline uint16_t SPI_ReceiveData16(SPI_TypeDef *SPIx)
{
#if defined (__GNUC__)
volatile uint16_t *spidr = ((volatile uint16_t*) &SPIx->DR);
return *spidr;
#else
return (*((volatile uint16_t*) &SPIx->DR));
#endif /* __GNUC__ */
}
2022-06-23 07:12 AM
The SPI data register indeed is sensitive to the write width (8 vs 32 bits).
In your example this does a 8-bit read
volatile uint8_t *spidr = ((volatile uint8_t*) &SPIx->DR);
return *spidr;
This should do a 8-bit write:
*((volatile uint8_t *)&SPIx->DR) = TxData;
but this won't do a 16-bit read (can you see why?)
return (uint16_t)(READ_REG(SPIx->DR));
2022-06-23 07:25 AM
@Pavel A.
"but this won't do a 16-bit read (can you see why?)"
return (uint16_t)(READ_REG(SPIx->DR));
I meant :
return (*((volatile uint16_t *)&SPIx->DR));
2022-06-23 11:57 AM
OK then