SPI slow because gaps between data

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

cross mob
zoli
Level 1
Level 1
First like received First reply posted First question asked

Hello,

What would be the issue with SPI setup because there is a big gap/delay between data while I would like to send it continuously?

The source code is simple:

void send_packet(void) {
    uint8_t i;
    for(i=0; i<82; i++) {
        SPI_IR_WriteTxData(0xAAAA);
    }

}

As on the attached picture it is sending two 16 bit data continuously and then there is a 2.6ms delay before the next group of data.

2022-03-20 01_45_35-Window.png2022-03-20 02_07_52-Configure 'SPI_IR'.png2022-03-20 02_08_06-Configure 'SPI_IR'.png

Thanks!

0 Likes
1 Solution
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

zoli,

moto is correct.   Use of SPI_IR_PutArray(const uint8/uint16 buffer[], uint8 byteCount) would be much better for your needs.

 

uint16 data_ary[82] = {0xAAAA, 0xAAAA, ... };
void send_packet(void)
{
   SPI_IR_PutArray(data_ary, sizeof(data_ary));
}

 

The use of SPI_IR_WriteTxData()  implied you are sending on element at a time via CPU intervention which could take some time between sending more elements from your array.

Using SPI_IR_PutArray() tries to find the most efficient (time and/or CPU) method of sending the elements. 

In your configuration, you allocated 82 16-bit elements for your Tx buffer.  Since the component only has a 4-byte deep FIFO, it allocates RAM scratchpad of 82*2 bytes.  The SPI_IR_PutArray() will copy the data from the array you pass to this RAM scratchpad.

It then allocates and initializes an internal interrupt to efficiently manage the RAM scratchpad buffer. 

Len_CONSULTRON_0-1647788038484.png

Additionally it enables the "Tx FIFO Not Full" interrupt to cause the Tx interrupt.

Len_CONSULTRON_1-1647788119997.png

When this interrupt occurs, it checks that the Tx FIFO status is "Not Full" and then moves data from the RAM scratchpad to the Tx FIFO until it is full.

The Tx interrupt will again trigger when the next data is transferred to the serial buffer which makes the "TX FIFO Not Full".  This pattern will repeat until all the data is transferred.

As long as there is data in the FIFO and in the serial output buffer, the transmission of SPI data should be continuous without breaks and the /CS line should be low for the entire transmission.

Additional Note:

Since you allocated 82 elements as the SPI TX buffer, when you execute  the SPI_IR_PutArray() API call with same number of bytes as your RAM scratchpad, it will copy all the bytes from your data array in the arguments to the RAM scratchpad and then exit the call immediately.  In this case, it is a non-blocking call.   All transferring will occur at interrupt-level.

If you want to allow the  SPI_IR_PutArray() API call as a blocking call, you could allocate only the 4-byte FIFO in the TX buffer.  It will not allocate a RAM scratchpad or enable the Tx interrupt.

In this case, when executing the SPI_IR_PutArray() API call, your code will fill the FIFO and start the transmission and wait in the API call.  It will poll the TX FIFO status and place data in the FIFO when it becomes "Not Full" until ALL the data is transferred

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
8 Replies
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

I wonder if you can try 

void SPI_IR_PutArray(const uint8/uint16 buffer[], uint8 byteCount)

Or you might need to consider using DMA

moto

0 Likes
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

zoli,

moto is correct.   Use of SPI_IR_PutArray(const uint8/uint16 buffer[], uint8 byteCount) would be much better for your needs.

 

uint16 data_ary[82] = {0xAAAA, 0xAAAA, ... };
void send_packet(void)
{
   SPI_IR_PutArray(data_ary, sizeof(data_ary));
}

 

The use of SPI_IR_WriteTxData()  implied you are sending on element at a time via CPU intervention which could take some time between sending more elements from your array.

Using SPI_IR_PutArray() tries to find the most efficient (time and/or CPU) method of sending the elements. 

In your configuration, you allocated 82 16-bit elements for your Tx buffer.  Since the component only has a 4-byte deep FIFO, it allocates RAM scratchpad of 82*2 bytes.  The SPI_IR_PutArray() will copy the data from the array you pass to this RAM scratchpad.

It then allocates and initializes an internal interrupt to efficiently manage the RAM scratchpad buffer. 

Len_CONSULTRON_0-1647788038484.png

Additionally it enables the "Tx FIFO Not Full" interrupt to cause the Tx interrupt.

Len_CONSULTRON_1-1647788119997.png

When this interrupt occurs, it checks that the Tx FIFO status is "Not Full" and then moves data from the RAM scratchpad to the Tx FIFO until it is full.

The Tx interrupt will again trigger when the next data is transferred to the serial buffer which makes the "TX FIFO Not Full".  This pattern will repeat until all the data is transferred.

As long as there is data in the FIFO and in the serial output buffer, the transmission of SPI data should be continuous without breaks and the /CS line should be low for the entire transmission.

Additional Note:

Since you allocated 82 elements as the SPI TX buffer, when you execute  the SPI_IR_PutArray() API call with same number of bytes as your RAM scratchpad, it will copy all the bytes from your data array in the arguments to the RAM scratchpad and then exit the call immediately.  In this case, it is a non-blocking call.   All transferring will occur at interrupt-level.

If you want to allow the  SPI_IR_PutArray() API call as a blocking call, you could allocate only the 4-byte FIFO in the TX buffer.  It will not allocate a RAM scratchpad or enable the Tx interrupt.

In this case, when executing the SPI_IR_PutArray() API call, your code will fill the FIFO and start the transmission and wait in the API call.  It will poll the TX FIFO status and place data in the FIFO when it becomes "Not Full" until ALL the data is transferred

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
zoli
Level 1
Level 1
First like received First reply posted First question asked

Thanks for the answers.

The reason I didn't consider SPI_IR_PutArray() is it is calling the same SPI_IR_WriteTxData() function kind a similar way as I did. So I can't see a reason why it would be any faster, but I will try it now.

void SPI_IR_PutArray(const uint16 buffer[], uint8 byteCount) {
    uint8 bufIndex;
    bufIndex = 0u;
    while(byteCount > 0u) {
        SPI_IR_WriteTxData(buffer[bufIndex]);
        bufIndex++;
        byteCount--;
    }
}

0 Likes
lock attach
Attachments are accessible only for community members.

zoli,

Interesting ...

Question: Why are you creating your own SPI_IR_PutArray() function call since this API function already exists?

I've created a VERY simple project to dump 82 16bit elements through the SPI Master.

I used a SPI Master component with 82 16-bit words.

I ran the code with your original send_packet() function listed in the first post.

Here's a scope pic of the results:

Len_CONSULTRON_1-1647868229930.png

 

No issue.  No data gaps between Tx data transmissions.

I changed your send_packet() function to the SPI_IR_PuttArray() API call that comes with the component.  I get the EXACT SAME results.  No issue.  No gaps.

I've attached my program I used for your review. 

 

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Len,

"Question: Why are you creating your own SPI_IR_PutArray()...?"

No, I didn't created a new one. I just copied the generated code to show it is using the same function in a loop.

I really appreciate your detailed answers, and as you mentioned 82*2 bytes FIFO is a software resource so I tested with the 4 words long FIFO. And it is solved the issue.

So if I'm using only the hardware (4*2 bytes) FIFO there is no gap between data anymore.
It is also means I have to read out RX register after every data sending, and I can't get data in one packet at the end, but it is not a drawback.

void read_packet(void) {
    uint8_t i;
    for(i=0; i<82; i++) {
        SPI_IR_WriteTxData(0xAAAA);
        packet_buffer[i] = SPI_IR_ReadRxData();
    }
}

I have checked your project also and the only difference is the SPI speed.
I'm using 20 MHz and you have used 1 MHz. Maybe in 1 MHz SPI the software FIFO speed limitation is not an issue.

2022-03-20 20_49_13-PicoScope 6.png

 

 

zoli
Level 1
Level 1
First like received First reply posted First question asked

So SPI_IR_PutArray() is even slower to send 82 times 16 bit data.
On pictures the SPI_IR_PutArray() vs my for loop.

 2022-03-20 20_20_54-PicoScope 6.png2022-03-20 20_12_29-PicoScope 6.png

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Surprisingly you are right!
I have confirmed same result with my CY8CKIT-059.

So I'm sorry, I was wrong.  m(_ _)m

BTW, by writing "slow", how fast do you need to send these 82 x 16 bits?
Or is/are the gap between the data problem for your application?

moto

0 Likes

Moto,

Thanks for your help! The solution was so simple, just use 4 words long FIFO (see above).
The fast speed is important, because I'm on to read out thermal image sensor, and there is a big amount of data coming often.