2012-02-06 09:02 AM
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 #spi2012-02-06 10:04 AM
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
}
}
2012-02-07 03:18 AM
2012-02-07 07:14 AM
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 Peacock2012-02-07 08:25 AM
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.
2012-02-08 03:06 AM
2012-02-08 04:44 AM
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.