SPI using PSoC 4 SCB 4.0

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
CaHi_1120211
Level 1
Level 1
First like received Welcome!

I'm trying to use an SPI master interface on a project with a CYBLE-022001-00.  Using PSoC Creator 4.1, the only SPI block available is V4.0.

The example provided uses V2.5, which apparently has a completely different API.

Because of pinout issues, I have to use firmware-driven slave selects, and I need to determine when the transfer is complete so I can release the slave select.  I only need to send data out, no need for anything coming back.

The examples and all the discussions I can find here all refer to using SPI_ReadTxStatus(), but that's not available with the V4.0 API.

Basically, I need to do this (from other threads on this board):

    SS_Write(0);                //SS low --> Communication between Master and Slave starts

    SPI_WriteTxData(value);    /* Send data byte */

    while (!(SPI_ReadTxStatus() & SPI_STS_SPI_DONE));

    SS_Write(1);                // Transfer to slave is done

The problem is that SPIM_ReadTxStatus() no longer exists.

How do you check the transmit status with the V4.0 API?

I've tried using the

    SPI_SpiUartWriteTxData(value);

    while (!SPI_SpiIsBusBusy());  // wait for transfer to start

    while (SPI_SpiIsBusBusy());  // wait for transfer to end

    SS_Write(1);                // Transfer to slave is done

but it occasionally hangs on the first while - if the timer interrupt routine happens to fall while it's in that loop, then by the time it comes back from the ISR, the entire transfer is over so the SPI bus is not busy again - forever!

I don't want to disable interrupts for that period because it can be up to 2 SCLK clocks after you write data before the , according to the data sheet for the SCB:

"SPI Master does not assign slave select line immediately after the first word is written into TX FIFO. It takes up to 2 SCLK clocks to assign slave select. Until this happens the bus considered not busy."

Any insights would be greatly appreciated!

0 Likes
1 Solution

Hi (op) Carlos,

With SPI_SpiIsBusBusy being not available i meant you can't use it because you are not using the embedded /SS pin of the component, from the SPI SCB datasheet:

spi_state.png

So using the number of bytes on the Tx Buffer to determine when the transfer was completed seems the way to go. If you solve your issue let us know.

Regards,

Carlos.

View solution in original post

0 Likes
6 Replies
RyanZhao
Moderator
Moderator
Moderator
250 sign-ins First question asked 750 replies posted

Hi Carlos,

SPI v2.5 uses UDB instead of SCB block.

Regarding of SCB SPI, recommend to refer to SCB_SpiCommMaster code example.

Thanks,

Ryan

0 Likes

Hi Ryan,

Thanks for the pointer to that example - I had not found it.

However, the example uses the built-in slave select, so it is not concerned with tight timing of transmitted bytes.  Since I cannot use the built-in slave select, I need to know when the transmitted byte is actually complete so I can clear the slave select manually.

In the device at the other end of the SPI connection, the trailing edge of slave select is what actually stores the value into the slave, so I don't want to leave slave select active for an arbitrarily long period.  I really do need to know when the physical transfer has been completed.

Thanks,

Carlos

0 Likes

Hi Carlos,

I assume you are using the SPI based on the SCB block, if i remember correctly the SPI_SpiIsBusBusy function is not available because you are not using the embedded /SS pin, so i do as follows:

    SS_Write(0);

    SPI_SpiUartWriteTxData(NRF_W_REGISTER_CMD | reg);

    SPI_SpiUartWriteTxData(data);

    while (SPI_SpiUartGetRxBufferSize() != 2) {}

    SS_Write(1);

You can see i wait for the Rx FIFO to have the same number of bytes i written to the SPI Slave, in this case i wait until the Rx FIFO have 2 bytes (this of course only works if you are using the MISO line of the SPI, this worked for me so far).

I haven't test this, but maybe replace the   while(SPI_SpiUartGetRxBufferSize() != 2){} for   while (SPI_SpiUartGetTxBufferSize() != 0) {}, so you wait until the Tx FIFO gets empty (aka all bytes have been transmitted).

Let me know if it works for you.

Regards,

(another) Carlos

0 Likes

Hi Carlos,

Yes, I'm using the SCB version of the SPI - it's the only one available for the part I'm using.  And the SPI_SpiIsBusBusy() function IS available, but it doesn't show the bus busy immediately after the call to SPI_SpiUartWriteTxData().  The active status won't show for up to 2 SPI clock cycles after you write the data according to the data sheet, so it looks like the SPI transfer is complete even before it starts.

I'm not using the MISO line at all, just writing a single byte out to each of two digital pots.

I tried your last suggestion, but the TxBufferSize apparently goes to 0 immediately, before the BusBusy status becomes active:

OFST_CSL_Write(0);

SPI_SpiUartWriteTxData(offset);

while (SPI_SpiUartGetTxBufferSize() != 0) { }

while (SPI_SpiIsBusBusy()) { }

OFST_CSL_Write(1);

So the CS goes away before the clock actually even starts toggling.  Good thought, but didn't work.

I had not tried your first approach, since I didn't know whether the RX buffer status would be updated.  I have the MISO pin is "removed" from the symbol and therefore not connected to anything.  I just tried it and apparently, it does still get updated.  Seems like it could be a waste of CPU cycles since I said I wasn't using it, but it does make sense from the hardware perspective - the shift register is still there, it's just that the input is unconnected.  Anyway, I tried this:

SPI_SpiUartClearRxBuffer();

OFST_CSL_Write(0);

SPI_SpiUartWriteTxData(offset);

while (SPI_SpiUartGetRxBufferSize() == 0) { }

OFST_CSL_Write(1);

This DOES appear to work, I'll do some more testing, but I think my problem is solved. 

Thanks!

(op) Carlos

Hi (op) Carlos,

With SPI_SpiIsBusBusy being not available i meant you can't use it because you are not using the embedded /SS pin of the component, from the SPI SCB datasheet:

spi_state.png

So using the number of bytes on the Tx Buffer to determine when the transfer was completed seems the way to go. If you solve your issue let us know.

Regards,

Carlos.

0 Likes

I stuck with this code:

SPI_SpiUartClearRxBuffer(); 

OFST_CSL_Write(0); 

SPI_SpiUartWriteTxData(offset); 

while (SPI_SpiUartGetRxBufferSize() == 0) { } 

OFST_CSL_Write(1); 

It's been working fine that way.  I ran it in a tight loop for hours without any errors.

Thanks!

(op) Carlos

0 Likes