cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 SPI port

dwooller
Associate II
Posted on February 06, 2012 at 18:02

I am trying to interface with an SPI port device which requires a 24bit transfer, I have successfully managed to achieve this using the example code and standard peripheral library but I am seeing gaps between byte transfers. It appears that these are down to the software waiting for a receive byte prior to sending the next byte in the tx data packet. the code used is as follows:

/**

  * @brief  write data width bytes from SPI interface.

  * @param  passed address & data  

  * @retval None

  */

void Cspi::write(uint8_t address, uint16_t data )

{

uint8_t * txdata = (uint8_t*)&data;

uint16_t dummy = 0;

   /* Transfer procedure */

    if (Spi_port == SPI1) {

        GPIO_WriteBit( Spi_gpio,SPI1_PIN_NSS,Bit_RESET );      // drive the CS line low

    }else{

        GPIO_WriteBit( Spi_gpio,SPI2_PIN_NSS,Bit_RESET );      // drive the CS line low

    }

    

      

    

    /* Wait for SPIy Tx buffer empty */

    while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_TXE) == RESET);

    /* Send SPI address */

    SPI_I2S_SendData(Spi_port, address);

    

    while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_RXNE) == RESET);

    dummy = SPI_I2S_ReceiveData(Spi_port);      /* Read SPI received data */

    for (int8_t x = 1; x >= 0 ; x-- ) {

        while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_TXE) == RESET);

        /* Send SPI data high */

        SPI_I2S_SendData(Spi_port, txdata[x]);

    

        while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_RXNE) == RESET);

        dummy = SPI_I2S_ReceiveData(Spi_port);  /* Read SPI received data */

    }

    

    if (Spi_port == SPI1) {

        GPIO_WriteBit( Spi_gpio, SPI1_PIN_NSS,Bit_SET );      // drive the CS line high

    }else{

        GPIO_WriteBit( Spi_gpio, SPI2_PIN_NSS,Bit_SET );      // drive the CS line high

    }

when trying to use the BSY flag to determine if the last byte has been sent instead of the receive flag, the CS line goes high before the last byte has been sent. The state of the BSY flag is a bit vague in the data sheet but it appears to be cleared after the byte has been loaded into the TX buffer not when the TX buffer has completed its output. Is this correct or have I missed something?

Any help would be appreciated

Thanks

dwooller

#spi-serial-port #spi
6 REPLIES 6
Posted on February 06, 2012 at 19:04

Well I'd probably wait for TXE before driving the chip select low.

You'd wait on RXNE to detect that the last bit has exited, and the last receive bit had come in. But you need to be sure that RXNE has been cleared, because the bit may be high from some previous data you have failed to clear from the DR. You also need to try a less serialized approach. ie make a loop which identifies both when you need to stuff data into the transmit register, and read data from the receive register. The current implementation looks to stall the transfers in the most inopportune manner. If you are just throwing away the receive data, then don't bother to wait for it. After you have posted the final byte, do a final read against the DR, and spin on RXNE before de-asserting CS. Something along the lines of :

void Cspi::write(uint8_t address, uint16_t data )
{
uint8_t * txdata = (uint8_t*)&data;
/* Transfer procedure */
/* Wait for SPIy Tx buffer empty */
while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_TXE) == RESET);
if (Spi_port == SPI1) {
GPIO_WriteBit( Spi_gpio,SPI1_PIN_NSS,Bit_RESET ); // drive the CS line low
}else{
GPIO_WriteBit( Spi_gpio,SPI2_PIN_NSS,Bit_RESET ); // drive the CS line low
}
/* Send SPI address */
SPI_I2S_SendData(Spi_port, address);
for (int8_t x = 1; x >= 0 ; x-- ) {
while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_TXE) == RESET);
/* Send SPI data high */
SPI_I2S_SendData(Spi_port, txdata[x]);
}
SPI_I2S_ReceiveData(Spi_port); /* Clear pending RXNE*/
while (SPI_I2S_GetFlagStatus(Spi_port, SPI_I2S_FLAG_RXNE) == RESET);
if (Spi_port == SPI1) {
GPIO_WriteBit( Spi_gpio, SPI1_PIN_NSS,Bit_SET ); // drive the CS line high
}else{
GPIO_WriteBit( Spi_gpio, SPI2_PIN_NSS,Bit_SET ); // drive the CS line high
}
}

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
dwooller
Associate II
Posted on February 07, 2012 at 12:18

jpeacock2399
Associate II
Posted on February 07, 2012 at 16:14

When you are finished with the bus transaction you need to wait on the TXE flag before deasserting the chip select, to make sure the last bit has been shifted out.  If you see the chip select deasserted early it's because you are looking at the gap between buffer empty to transmit empty.

  Jack Peacock

Posted on February 07, 2012 at 17:25

When you are finished with the bus transaction you need to wait on the TXE flag before deasserting the chip select, to make sure the last bit has been shifted out. If you see the chip select deasserted early it's because you are looking at the gap between buffer empty totransmit empty.


 Unless I'm mistaken the TXE goes high before, or proximate, to the time the FIRST bit is transmitted. The last bit of the prior byte, but not the last byte in the buffer pending transmission.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
dwooller
Associate II
Posted on February 08, 2012 at 12:06

Posted on February 08, 2012 at 13:44

What is the behaviour of the BSY flag, from my tests here it appears to be de-asserted before the TX has been shifted out.

That would appear to deviate from the documented behaviour. I have no data for this.


Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..