I wish to read a SPI slave device. Here's what I thought the procedure would be like :


  1. SPI_Write(slave_address)
  2. SPI_Write(register)
  3. SPI_Write(0x00) //dummy byte
  4. data = SPI_Read()


However, this doesn't work. To make it work, here's what I have to follow:


  1. SPI_Write(slave_address)
  2. temp = SPI_Read()
  3. SPI_Write(register)
  4. temp = SPI_Read()
  5. SPI_Write(0x00) //dummy byte
  6. data = SPI_Read()


Why do I have to read the data on MISO line even when I know there will be nothing desirable?

PS: The SPI Read() and Write() functions are just my own implementations, nothing particular to a single MCU.

Edit : As requested, I am providing some details on the MCUs.

I am using two MCUs - STM32F303VCT and TI TIVA123GH6PM. Both the MCUs require me to follow the said procedure.

Here's my implementation of SPI transmit & receive function on STM32

uint8_t SPI_rdwr(uint8_t data)
    *(__IO uint8_t *)&SPI1->DR = data;              //send data
    while(!(SPI1->SR & SPI_SR_TXE));                // wait till TX buffer is empty
    while(SPI1->SR & SPI_SR_BSY);                  // wait if SPI line is busy
    while(!(SPI1->SR & SPI_SR_RXNE));               //wait till RX buffe is NOT empty                   

    return *(__IO uint8_t *)&SPI1->DR;          //return data if data received on MISO line
  • 8
    \$\begingroup\$ Whether it works or not depends on the MCU and the SPI implementation it has and the code you wrote to use it. Would you disclose what MCU you are using to answer this? \$\endgroup\$
    – Justme
    Jan 25, 2021 at 18:42
  • 1
    \$\begingroup\$ It may be that SPI_Read is what clocks the READ data into the CPU ... thereby also clocking the WRITE data out to the peripheral. If so, omitting it won't work. \$\endgroup\$
    – user16324
    Jan 25, 2021 at 19:07
  • 3
    \$\begingroup\$ Or the SPI hardware has a read buffer that can receive e.g. one byte and will not update from the shift register unless read. We don't know unless @Luffy provides us with the exact MCU make/model and provides code to see what is wrong. \$\endgroup\$
    – Justme
    Jan 25, 2021 at 19:25
  • 2
    \$\begingroup\$ Then my guess is: if the receive buffer is full you get a fault condition which stops SPI. \$\endgroup\$
    – user253751
    Jan 25, 2021 at 20:08
  • 1
    \$\begingroup\$ @Luffy But your spi_rdwr does not match what you asked first. It is up to the slave how it works, but your rdwr should work just fine for full-duplex operation, and in fact STM32 SPI requires you read the receive buffer or it won't update with the received data. The rdwr now transmits and receives one byte. And you don't mention with what slave you communicate with, so I can't tell you if the protocol is correct or not. \$\endgroup\$
    – Justme
    Jan 25, 2021 at 20:43

1 Answer 1


Why does 4 wire SPI read operation need me to read MISO line on every transmit operation?


  1. For performance reasons, the HAL implementers wrote SPI_Write without the "wait for transmit register empty" loop built in, but SPI_Read has such a loop. In that case, issuing writes without reads would overrun the buffer. Your implementation also wastes time in that loop - once you can read, you can write, too; or

  2. The hardware abstraction library (HAL) you're using configures the silicon to work that way, when the silicon doesn't require it to be so,

  3. and perhaps you're not configuring the HAL to do it the way you want, in case the HAL supported it (and necessarily also the silicon); or

  4. perhaps you're not configuring the silicon to do the "right" thing when the silicon allows that; or

  5. the silicon is designed to work that way and no other way.

I don't recall the details of SPI implementation on the chips you're using, but:

  1. Some SPI implementations can have the receiver switched off, and thus reads won't be necessary since that function will be disabled.

  2. SPI can be probably used with DMA, thus you won't care about the overhead of doing the reads too much.

  3. Even if you do it in software, the reads may be cheap. Not using the HAL would probably help with that too, although be sure to compile the code in optimized release configuration, and audit the assembly to confirm that it doesn't do anything unnecessary. Even your hand-written code does unnecessary things.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.