- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have the PSoC 4 BLE system connected via SPI to a device. That device has a "Who Am I" register at 0x0f that will reply with the value 0x6a if read correctly.
I have used a SCB dialog to create a SPI master, Sub mode: Motorola CLK CPHA=1, CPOL=1
Data Rate: 1Mbps
Rx & Tx data bits 16
Transfer Separation: Separated
Rx & Tx Buffer Size: 8
No Interrupts
I have written the code to just query that register to prove that the SPI bus works. When the register is read correctly a LED connected to Pin 2 is turned on.
What I found was that I had to put a while loop to continuously read the SPI bus to get the correct value. In fact I had to read the bus 9 times first and then on the 10th time the value returned was correct.
Here is the code:
static uint8_t readTheRegByUart(uint8_t theRegAddr) {
uint8_t theRegValue = 0;
uint16_t theReadCmd = 0x8000;
/* read the register */
theReadCmd |= (uint16_t)((uint16_t)theRegAddr << 8);
SPI_SpiUartWriteTxData(theReadCmd);
while(SPI_SpiUartGetRxBufferSize() > 0) {
theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff);
}
return theRegValue;
}
int main(void) {
uint8_t theValue;
CyGlobalIntEnable; /* Enable global interrupts. */
SPI_Start();
while((theValue = readTheRegByUart(0x0f)) != 0x6a);
Pin_2_Write(0);
for (;;)
{
;
}
}
Am I running into a buffering issue from the Rx FIFO in the SPI implementation? Is using the "Uart" version of the SPI code wrong?
Any insights would be helpful.
Cheers!!
Solved! Go to Solution.
- Labels:
-
BLE
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SPI_SpiUartWriteTxData(theReadCmd);
while(SPI_SpiUartGetTxBufferSize() > 0); // Not needed
while(SPI_SpiUartGetRxBufferSize() == 0); // needed to blocking wait for char ready
while(SPI_SpiUartGetRxBufferSize() > 0) // Not needed{
theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff); // This is what you want...
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Between these lines
SPI_SpiUartWriteTxData(theReadCmd);
while(SPI_SpiUartGetRxBufferSize() > 0) {
you should wait for SPI write is completed.
For every bit (byte) the SPI interface gets, one bit (byte) is returned immediately. When the very first byte is sent, the interface does not "know" yet what to answer, so a dummy byte is returned which should be skipped.
SPI has no read command, so you must send dummy bytes to retrieve the information wanted.
A pitfall is the select line, which is automatically taken low when a byte is sent. When the buffer is empty it is taken high again. This can lead to interface errors when the byte sequence is not provided fast enough resulting in ss-line glitches.
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Bob,
Thanks for replying. I stuck this line in as you suggested:
while(SPI_SpiUartGetTxBufferSize() > 0);
However no joy.
If I'm sending "0x8f00" I'm assuming I should get something like 0x??6a" back. Where the 0x8f is the slave devices read command of it's ID register. What would be read back is "0x6a" (Slaves ID register contents) not so? In other words I send 2 bytes I immediately receive 2 bytes of data that are the effect of the sent 2 bytes which are commands to the slave device.
Cheers!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Instead of
while(SPI_SpiUartGetTxBufferSize() == 0);
look at the SPI status / status register / bits. The SPI component thells you when a transfer is in progress. Even when the TX FIFO is empty it might take a (little) while until the data is available in the RX FIFO.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hli,
In fact "SPI_SpiUartGetTxBufferSize()" is a call to the following code:
#define SPI_GET_TX_FIFO_ENTRIES (SPI_TX_FIFO_STATUS_REG & \
SPI_TX_FIFO_STATUS_USED_MASK)
So it does what you are describing.
Cheers!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Me again...
Perhaps I've solved this myself but I hate the solution...
Essentially I just added a wait until I saw that data was received...
uint8_t theRegValue = 0;
uint16_t theReadCmd = 0x8000;
SPI_SpiUartClearRxBuffer();
/* read the register */
theReadCmd |= (uint16_t)((uint16_t)theRegister << 8);
SPI_SpiUartWriteTxData(theReadCmd);
while(SPI_SpiUartGetTxBufferSize() > 0);
while(SPI_SpiUartGetRxBufferSize() == 0);
while(SPI_SpiUartGetRxBufferSize() > 0) {
theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff);
}
return theRegValue;
I don't like having a blocking read in the code but I'm wondering if this is a typical solution to using SPI in this environment?
Cheers!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
SPI_SpiUartWriteTxData(theReadCmd);
while(SPI_SpiUartGetTxBufferSize() > 0); // Not needed
while(SPI_SpiUartGetRxBufferSize() == 0); // needed to blocking wait for char ready
while(SPI_SpiUartGetRxBufferSize() > 0) // Not needed{
theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff); // This is what you want...
Bob
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks Bob.
that works.
Have a great New Year!!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks, I'll do my very best 😉
Bob