Skip to main content
Breakthecake
Associate II
Feb 26, 2022 7:44 PM UTC
Question

SPI communication using own driver for blocking call: Transmit/receive works fine, but I cannot get the data into the RxData array for later use.

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?

This topic has been closed for replies.

7 replies

S.Ma
Principal
Feb 26, 2022 8:24 PM UTC

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.

TDK
Feb 26, 2022 9:39 PM UTC

> 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.

"If you feel a post has answered your question, please click ""Accept as Solution""."
Breakthecake
Associate II
Feb 27, 2022 9:53 AM UTC

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.

TDK
Feb 27, 2022 2:26 PM UTC
Ah okay. Those are standard definitions in the CMSIS header files. It’ll make your code more readable if you use those instead. Should be in stm32l486.h.
"If you feel a post has answered your question, please click ""Accept as Solution""."
waclawek.jan
Super User
Feb 27, 2022 7:48 PM UTC

> 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

Breakthecake
Associate II
Feb 28, 2022 12:11 PM UTC

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:

waclawek.jan
Super User
Feb 28, 2022 2:32 PM UTC

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