cancel
Showing results for 
Search instead for 
Did you mean: 

When will the SPI_SR_RXNE bit be set to 0?

MMust.5
Senior II
I'm using SPI on STM32F407VGT6 
This is the code I use to check the state of the SPI_SR_RXNE bit:
This is the code for the LIS3DSH accelerometer, when I send data to the accelerometer in response the accelerometer sends data to the Microcontroller.
This code is working, with this code I am getting data from accelerometer.
You can use other code to check the SPI_SR_RXNE status, it doesn't matter.

 

int main()
{
    uint8_t Read_Out_X_Y_Z_REG_Address=0xA8;
    uint8_t Out_X_Y_Z_Data_Separate[6]={0};
    int16_t Out_X_Y_Z_Data_RESULT[3]={0};

    
SPI1->CR1  |= SPI_CR1_SPE; 
uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = address;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);
    
while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;  //STARTING HERE I COMMENT THE CODE FOR THE EXPERIMENT.
while((SPI1->SR & SPI_SR_RXNE)); 
while((SPI1->SR & SPI_SR_BSY) != RESET);
    
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = 0;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_RXNE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_SET); //Chip Select
}

 

The Reference Manual says: Clearing of the RXNE bit is performed by reading the SPI_DR register.
So after this code the RXNE bit will be cleared?

 

uint8_t result;
result=SPI1->DR;

 

It's hard for me to imagine that the SPI_DR register keeps track of when SPI_DR will be read. 
When I say "reading SPI_DR " I mean this:

 

result=SPI1->DR;

 

I cut the code above to check the state of the SPI_SR_RXNE bit.

 

SPI1->CR1  |= SPI_CR1_SPE; 
uint8_t address=0x8F; //Register address+read
uint8_t result;
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_3, GPIO_PIN_RESET); //Chip Select
while(!(SPI1->SR & SPI_SR_TXE));
SPI1->DR = address;
while(!(SPI1->SR & SPI_SR_TXE));
while((SPI1->SR & SPI_SR_BSY) != RESET);

while((SPI1->SR & SPI_SR_RXNE));
//result=SPI1->DR; //DEACTIVATED

 

Maybe under "reading the DR register" in Reference Manual there is meaning something else?
For example, transferring data to the SPI1->DR register? 
I don't clear the SPI_SR_RXNE bit myself, but SPI_SR_RXNE clears itself without reading the SPI1->DR register.
tim.png
Maybe I'm wrong, but in my opinion clearing SPI_SR_RXNE signals the transfer of data to the SPI1->DR register, and not reading SPI1->DR. 
Do the same experiment for yourself, send something to the RX buffer, DO NOT READ SPI_DR REGISTER and look at the state of the SPI_SR_RXNE bit. 
 
It’s very important for me to know, the code algorithm depends on it.
 
If you follow my logic that SPI_SR_RXNE is cleared after the data is transferred to SPI1->DR, then the data should be received like this:

 

while((SPI1->SR & SPI_SR_RXNE));
result=SPI1->DR;
while((SPI1->SR & SPI_SR_BSY) != RESET);

 

But if this is not the case, then my code for receiving data will be incorrect.
1 ACCEPTED SOLUTION

Accepted Solutions
TDK
Guru

> But the RX buffer and SPI1->DR are not the same thing.

Maybe at some technical standpoint they are not the same since SPI->DR is a hardware interface, but for the purposes of reading data, they are effectively the same.

When RXNE is asserted, there is data in the RX buffer. The RX buffer is read by reading SPI->DR, which clears RXNE. There is no intermediate step or race condition here.

Not seeing any contradictions in the RM.

In the last figure, at the green arrow, RXNE transitions from 1 to 0 when the 0xA1 value is read from SPI->DR. RXNE goes back to 1 when the next data (0xA2) is available to be read.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

7 REPLIES 7
TDK
Guru

Reading SPI->DR does in fact clear RXNE just as the RM says. Note that reading it from your debugger still counts as reading it, which is likely why you saw it was cleared despite not reading it in code.

The RM has explicit step by step instructions for operation SPI in register mode. I'd recommend following those.

Note that you can queue 2 bytes to be sent before the first byte is received.

TDK_0-1698018709134.png

> It's hard for me to imagine that the SPI_DR register keeps track of when SPI_DR will be read. 

You should think of SPI->DR as a hardware interface, not just a register in memory. The SPI peripheral has an internal state machine that respond to reads and writes to this interface appropriately. That's why reads always show incoming data and writes always send data out.

If you feel a post has answered your question, please click "Accept as Solution".

pr.pngWhile the RX buffer is full, the SPI_SR_RXNE bit is 1.
The instruction in the image above suggests reading data from the SPI1->DR register while the RX buffer is full.

But the RX buffer and SPI1->DR are not the same thing.

Let's say a situation occurs when the RX buffer is full, I read the SPI1->DR data, but the data from the RX buffer has not yet reached the SPI1->DR register.

It seems strange to me that there is no indicator indicating that data has reached the SPI1->DR register from the RX buffer.

PortA8.png

With the TX buffer everything happens logically.
I need to wait until the TX buffer is empty and after that I need to fill the SPI_DR register.
Therefore the description is suitable: write SPI_DR.

PortA3.png
But with the RX buffer, I don’t see the logic, as I described above.
The RX buffer is full, but for some reason it is necessary to read SPI_DR, although the data is not in the SPI_DR register, but in the RX buffer.

---

TDK
Guru

> But the RX buffer and SPI1->DR are not the same thing.

Maybe at some technical standpoint they are not the same since SPI->DR is a hardware interface, but for the purposes of reading data, they are effectively the same.

When RXNE is asserted, there is data in the RX buffer. The RX buffer is read by reading SPI->DR, which clears RXNE. There is no intermediate step or race condition here.

Not seeing any contradictions in the RM.

In the last figure, at the green arrow, RXNE transitions from 1 to 0 when the 0xA1 value is read from SPI->DR. RXNE goes back to 1 when the next data (0xA2) is available to be read.

If you feel a post has answered your question, please click "Accept as Solution".

My last drawing was wrong, I deleted it)
>but for the purposes of reading data, they are effectively the same.

Ok, are SPI_DR and RX buffer the same thing if the purpose is reading?

Maybe you know where I can read this from official sources?

I can’t understand why SPI_DR and RX buffer are the same thing if they are physically located in different parts of the microcontroller.

5269dee283754cdbb18f14874e20cf92.jpg

238152409-d59e00dc-b22c-4697-af4a-2c835039616a.png

The image shows that RX buffer and RX Data are different parts of the Microcontroller even for reading.

Transferring data from different parts of the Microcontroller takes a certain time.

The RX buffer is full, but we are reading RX Data Register, I don’t understand.

Again, think of SPI->DR as an interface, not a memory location. It's not a memory location. Nothing is stored there. When the CPU gets a write to SPI->DR instruction, it puts that data into the TX buffer. When it gets a read instruction, it gets data from the RX buffer.

If you feel a post has answered your question, please click "Accept as Solution".