2022-02-26 11:44 AM
Master: STM32L476RG on Nucleo board
Slave: M95M01-A125, 1 Mbit serial SPI bus EEPROM
I set up a SPI driver to study details how registers work and the data is out and in transmitted. The data flow works fine looking at the logic analyzer window. In this case I asked the slave for its ID to have a simple task to start. I used a relatively slow speed on the SPI bus to avoid any problems with data loss or funny results.
Right now I cannot see the received bytes in my array, which is prepared to collect the data in the transmit function call. I had a look at the HAL driver supplied by ST. Right now I have no clue what is going on. I send and receive 1 Byte at a time. Here is the code of my transmit function, which sends and receives: (For the 16 bit I still have sending only.)
void SPI_TransmitData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint8_t *pRxBuffer, uint32_t Len)
{
uint32_t temp;
SPI_ClearRXFIFO(SPI2);
while(Len > 0)
{
while( !(pSPIx->SPIx_SR & (1 << SPI_SR_TXE))) // polling call, space for watchdog stuff
{
;
}
if((pSPIx->SPIx_CR2 & (0xF << SPI_CR2_DS)) == 0xF) // 0xF stands for 16 bit data size
{
// load the data into data register DR. Here: 2 choices only: 16 or 8 bit
pSPIx->SPIx_DR = *((uint16_t *) pTxBuffer);
(uint16_t *) pTxBuffer++;
// read the data from the DR to RxBuffer
*(uint16_t*)pRxBuffer = (pSPIx->SPIx_DR);
Len--;
Len--;
(uint16_t *) pRxBuffer++;
}else // 8 bit data size
{
(*(uint8_t*)&(pSPIx->SPIx_DR)) = *pTxBuffer; // typecasting is essential! - Look for data packing in ref man
*(uint8_t*)pTxBuffer = *(uint8_t*)&(pSPIx->SPIx_DR);
temp = (pSPIx->SPIx_SR & (0x3 << SPI_SR_FRLVL));
(void)temp;
pRxBuffer++;
pTxBuffer++;
Len--;
}
}
}
When I stepped through the code, I saw the received data in the DR register in the SFR tab (after sending in line 25). The moment I did one more step the content disappeared. That gave me the sign, I wouldn't be able to collect the data to assign it to the "pRxBuffer in the upcoming step.... But that maybe a feature of the IDE in debug mode.
Secondly, I checked the 2 FRLVL bits in SR. They showed up fine telling me, I have received a byte. But same like the content of DR: One more step and everything shows 0. The RxBuffer contains only 0x00.
Next step was I had a look at the SPI HAL driver by ST. I found code to for the RXNE flag and the RXFIFO threashold. Why that in a non interrupt based function? It says in the HAL_SPI_TransmitReceive function:
/* Wait until RXNE flag is reset */
if ((__HAL_SPI_GET_FLAG(hspi, SPI_FLAG_RXNE)) && (hspi->RxXferCount > 0U))
{
if (hspi->RxXferCount > 1U)
{
*((uint16_t *)hspi->pRxBuffPtr) = (uint16_t)hspi->Instance->DR;
hspi->pRxBuffPtr += sizeof(uint16_t);
hspi->RxXferCount -= 2U;
if (hspi->RxXferCount <= 1U)
{
/* Set RX Fifo threshold before to switch on 8 bit data size */
SET_BIT(hspi->Instance->CR2, SPI_RXFIFO_THRESHOLD);
}
}
else
{
(*(uint8_t *)hspi->pRxBuffPtr) = *(__IO uint8_t *)&hspi->Instance->DR;
hspi->pRxBuffPtr++;
hspi->RxXferCount--;
}
/* Next Data is a Transmission (Tx). Tx is allowed */
That lead me to init the SPIx_CR2 register Bit 12 FRXTH: FIFO reception threshold to 1 for my 8-bit transmission. Before and after I could see changing the bits 10:9 FRLVL[1:0]: FIFO reception level in SR. It does not make sense to me, as I am in a blocking mode, but I gave it a try. The array for the received data shows 0x00.
Can anybody see what I did wrong?
2022-02-26 12:24 PM
Use receivetransmit functions. Wait for rxne which confirm all spi clocks have been generated. Use dma to be more efficient. Also some SPI do care if DR is read/written as 8 or 16 bit chunks.
2022-02-26 01:39 PM
> while( !(pSPIx->SPIx_SR & (1 << SPI_SR_TXE)))
This is nonsense. If you want to check for the flag:
while(!(pSPIx->SPIx_SR & SPI_SR_TXE))
...well actually in this case it works, but only because SPI_SR_TXE = 1. If you take another example:
> if((pSPIx->SPIx_CR2 & (0xF << SPI_CR2_DS)) == 0xF)
This one does not work. SPI_CR2_DS = 0xF << 8 = 3840. And 0xF << 3840 isn't allowed. You want this:
> if((pSPIx->SPIx_CR2 & SPI_CR2_DS) == 0xFU << SPI_CR2_DS_Pos)
You have this error in a few places.
2022-02-27 01:53 AM
Hi TDK,
`> while( !(pSPIx->SPIx_SR & (1 << SPI_SR_TXE)))
This is nonsense.
Well, I would not agree. You may not imagine the macro standing behind SPI_SR_TXE, which is used in my code.
#define SPI_SR_TXE 1
and same for your 2nd example
#define SPI_CR2_DS 8
As written before, all the data exchange on MOSI and MISO works fine. The way I coded may not be the MISRA way. I am a beginner in embedded programming. The course I took part may have left a few gaps to fill.
2022-02-27 06:26 AM
2022-02-27 11:48 AM
> I saw the received data in the DR register in the SFR tab (after sending in line 25). The moment I did one more step the content disappeared.
Debugging is intrusive - reading DR by debugger both moves the data through FIFO and clears status flags.
JW
2022-02-28 04:11 AM
Thank you for this valuable information! Now I am curious, where I will find the information "in the toolchain" about registers read, when using (no) breakpoints (in general or whenever). :smiling_face_with_smiling_eyes:
2022-02-28 06:32 AM
Toolchains probably don't document absence of SFR reading i.e. description under what conditions a toolchain does *not* read SFRs. Usually, toolchains don't read SFR unless they are actively displayed. And even when displayed, they usually don't read them while program is running unless a special "live display" or similarly tagged mode is switched on.
The exact behaviour is of course toolchain-dependent.
JW