cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC 4 MCU

Anonymous
Not applicable

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!!

0 Likes
Reply
1 Solution
JoMe_264151
Expert II

  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

View solution in original post

0 Likes
Reply
8 Replies
JoMe_264151
Expert II

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

0 Likes
Reply
Anonymous
Not applicable

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!!

0 Likes
Reply
HeLi_263931
Honored Contributor II

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.

0 Likes
Reply
Anonymous
Not applicable

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!!

0 Likes
Reply
Anonymous
Not applicable

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!!

0 Likes
Reply
JoMe_264151
Expert II

  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

View solution in original post

0 Likes
Reply
Anonymous
Not applicable

Thanks Bob.

   

that works.

   

Have a great New Year!!

0 Likes
Reply
JoMe_264151
Expert II

Thanks, I'll do my very best 😉

   

 

   

Bob

0 Likes
Reply