cancel
Showing results for 
Search instead for 
Did you mean: 

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.

Breakthecake
Associate II

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?

7 REPLIES 7
S.Ma
Principal

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
Guru

> 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

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.

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

> 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

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

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