STM32G030 SPI master read issue
I use in my project stm32g030f6p6 to communicate with ADXL345 by 4-wire SPI. I have no problem with transmition, yet with reading I run into serious problem, that doesn't mentioned in Errata.
My SPI configuraton is CPOL 1, CPHA 1, speed 1MHz.
I use Logic-U analizer and ADXL345 for sure respond right, but I receive wrong data, usualy from 1 to 2 bytes.
Only one solution is while reading procedure before togling NSS pin twice read SPI_DR in tthat case RX FiFo is cleared and I receive right data.
I can't understand why I should have done it even once, why it isn't mentioned in Errata.
I also tried to set RXONLY bit right after sending register address and clear it after receiving last byte, but permantely SPI send extra byte it's register address with cleared 7th bit, nor clearing SPE bit neither reading DR doesn't help.
Thus, I wonder what I did wrang If I did of course, and what the solution ST offer.
Here it's part of my code for reading data from register
#define CAST_IO8(x) *((__IO uint8_t *)&x)
#define CAST_IO16(x) *((__IO uint16_t *)&x)
typedef struct {
pinDef_TypeDef nss;
uint32_t cr1;
uint32_t cr2;
bool halfDuplex;
bool hardwareNSS;
} spi_t;
// Array to store configuration of 'n' devices for both SPI interfaces
static spi_t spi_unit[2][4];
// Array of the pointers to current device for both SPI interfaces
static spi_t* spi[2];
/****************************************************************/
/****************************************************************/
static uint8_t getBusID (SPI_TypeDef* pBus)
{
switch ((uint32_t)pBus) {
case (uint32_t)SPI1: return 0;
case (uint32_t)SPI2: return 1;
}
return 0xff; // Error
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline void SPI_ClearDR(SPI_TypeDef* pBus)
{
limited_while (0xffff, !(pBus->SR & SPI_SR_RXNE));
(void)CAST_IO8(pBus->DR);
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline void SPI_WriteDR(SPI_TypeDef* pBus, uint8_t data)
{
limited_while (0xffff, !(pBus->SR & SPI_SR_TXE));
CAST_IO8(pBus->DR) = data;
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline uint8_t SPI_ReadDR(SPI_TypeDef* pBus, uint8_t busId)
{
if (!spi[busId]->halfDuplex) {
limited_while (0xffff, !(pBus->SR & SPI_SR_TXE));
CAST_IO8(pBus->DR) = 0;
}
limited_while (0xffff, !(pBus->SR & SPI_SR_RXNE));
return CAST_IO8(pBus->DR);
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline void SPI_SwitchToRX(SPI_TypeDef* pBus, uint8_t busId)
{
if (spi[busId]->halfDuplex) pBus->CR1 &=~SPI_CR1_BIDIOE;
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline void SPI_SwitchToTX(SPI_TypeDef* pBus, uint8_t busId)
{
if (spi[busId]->halfDuplex) pBus->CR1 |= SPI_CR1_BIDIOE;
}
/****************************************************************/
/****************************************************************/
__attribute__((always_inline))
static inline void SPI_NSS_set(SPI_TypeDef* pBus, uint8_t state)
{
uint8_t bus = getBusID(pBus);
// Check state for the part of the transaction
switch (state) {
// It's end of the transaction - Wait till it's done
case true: limited_while (0xffff, pBus->SR & SPI_SR_BSY); break;
// It's start of the transaction - Clear DR.
// I don't know why I has to do it twice, yet it's only one way to read right data!
case false: (void)CAST_IO16(pBus->DR); (void)CAST_IO16(pBus->DR); break;
}
// It's hardware NSS mode there's nothing to do
if (spi[bus]->hardwareNSS) return;
GPIOx_Write(spi[bus]->nss.GPIO, spi[bus]->nss.pin, state);
}
/****************************************************************/
/* The function for reading data from register in Master mode */
/* ============================================================ */
/* pBus - SPI bus (SPI1 / SPI2) */
/* addr - register address to read data */
/* data - pointer to array to write read data */
/* len - bytes to read */
/****************************************************************/
void SPI_MasterReadDataFromReg (SPI_TypeDef* pBus, uint8_t addr, uint8_t* data, size_t len)
{
uint8_t bus = getBusID(pBus);
SPI_NSS_set(pBus, 0);
SPI_WriteDR(pBus, addr);
SPI_ClearDR(pBus);
// Switch to read mode
SPI_SwitchToRX(pBus, bus);
// Read received data
while(len--) *(data++) = SPI_ReadDR(pBus, bus);
// Switch to transmit mode
SPI_SwitchToTX(pBus, bus);
SPI_NSS_set(pBus, 1);
}
