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

cross mob
pblemel
Level 4
Level 4
25 replies posted 25 sign-ins First like received

Hello, everyone!

Although this is more of a PDL question than a PSoC question, I'm moving this question here, since I'm working with the PSoC 6. 

Using the PDL, can a single SPI transaction be split into two calls to Cy_SCB_SPI_Transfer(), such that the slave device sees one continuous transaction?

Take for example a command 0x01 that returns 16 x 2-byte words of data.  Using a single transaction works:

 

uint8_t buff[33], result[33];
buff[0] = 0x01;  // Command
buff[1] ... buff[32] = 0; // Dummy bytes to shift in the data.

Cy_SCB_SPI_Transfer(SCB, buff, result, 33, context);

 

The data is all received, but the 32 byte result is byte-aligned starting at result[1] because of the full-duplex transfer.  I ideally, I want the result at result[0] and need to discard the first full-duplex transfer. 

To align the result, I think I need to split this into two calls. Naively, I tried:

 

uint8_t cmd = 0x01;  // Command
uint16_t result[16];

Cy_SCB_SPI_Transfer(SCB, &cmd, NULL, 1, context);
while (Cy_SCB_SPI_IsBusBusy(SCB))
    ;
Cy_SCB_SPI_Transfer(SCB, NULL, &result, 32, context);

 

But I suspect that the PDL treats the second call as it's own transaction and I don't get the data back from the chip. 

Is there a way to discard the full-duplex result of the command byte so that only the bytes returned from the chip end up in the result array?  If so, what calls do I need to make and in what order?

Thanks,
Peter

0 Likes
1 Solution
RodolfoGL
Employee
Employee
250 solutions authored 250 sign-ins 5 comments on KBA

We are trying to leverage the PDL functions as it is, without customization.

But you could implement what you need by adding a new variable the SPI context structure indicating if it is the first byte, then modify the HandleReceive() implementation in the cy_scb_spi.c to discard the first byte.

Using DMA is also another way to solve this. You can setup one DMA to write the command (0x01) and ZEROs to the TX FIFO. The other DMA is setup to read the RX FIFO. You can set the first transfer of this DMA to do a dummy transfer and the rest goes to your result array.

View solution in original post

0 Likes
6 Replies
RodolfoGL
Employee
Employee
250 solutions authored 250 sign-ins 5 comments on KBA

I think this sequence of commands might work for you:

Cy_SCB_SPI_Write(SCB, 0x01);
Cy_SCB_SPI_Transfer(SCB,NULL,result,32,context);

 

0 Likes

Rodolfo,

Thanks for the suggest, but it unfortunately doesn't work.

Unless I've made some error, when I write and read in the same call to

 

Cy_SCB_SPI_Transfer(SCB, buff, result, 33, context);

 

I get correct data back from the chip (but byte aligned at result[1]).  Using my initial attempt and/or your suggestion, the data returned is all zeros. What I assume is happening is that when the first write completes, chip select goes high and the slave thinks the read is terminated. When it goes low again for the read, the slave is expecting the first byte to be the register/command. That's complete speculation on my part. I did try to step through the low-level code, but the interrupt handling is difficult for me to follow.

Thanks,

Peter

0 Likes
RodolfoGL
Employee
Employee
250 solutions authored 250 sign-ins 5 comments on KBA

Oh, I see the problem. You might need to use the low level APIs to get this done then. 

If you don't mind to have a blocking function, you can implement something like this:

Cy_SCB_SPI_Write(SCB, 0x1); // Command data
for (int i = 0; i < 32; i++)
{
    Cy_SCB_SPI_Write(SCB, 0x0); // Dummy data
}
// Wait till TX FIFO is empty
while ((Cy_SCB_SPI_GetTxFifoStatus(SCB) & CY_CB_SPI_TX_EMPTY) == 0);

Cy_SCB_SPI_Read(SCB); // Discard first word
Cy_SCB_SPI_ReadArray(SCB, result, 32);

If you want a non-blocking function, then you setup the SPI TX Interrupt to trigger when TX is empty, then call the two SPI read functions above.

This method will work as long you read less than 64 words.

0 Likes

Rodolfo,

Thanks for the reply. The problem is that this chip (ADXL372) stores 512 bytes of event data that needs to be read and processed on interrupt. The only solution that I have so far is reading the data into a temporary array and then copying it to the final array (shifting everything down by a byte). 

So, that one extra byte in the beginning of the data caused by a full duplex read is extremely expensive. Data gets shifted into the RX buffer, copied into a temporary array, and then copied again into the final array - plus the extra expense of a 513 byte temporary array on the stack on a device where memory is at a premium.  

I have read a bit about using DMA, which could at least get rid of the copy from the RX buffer to the temporary array. Maybe I could set up the DMA pointer to ensure that the received data is word aligned,

 

uint16_t buff[513]; // Ensures word alignment
uint8_t *base = (uint8_t *) buff;
... Make dma point to &base[1], which would put the dummy 
... byte at base[0] and 1st data byte at base[1] ...
... then ...
uint16_t *data = &buff[1]; // Alias to the 1st valid data word  
Operate on the data in "data".

 

Thanks again,
Peter

0 Likes
RodolfoGL
Employee
Employee
250 solutions authored 250 sign-ins 5 comments on KBA

We are trying to leverage the PDL functions as it is, without customization.

But you could implement what you need by adding a new variable the SPI context structure indicating if it is the first byte, then modify the HandleReceive() implementation in the cy_scb_spi.c to discard the first byte.

Using DMA is also another way to solve this. You can setup one DMA to write the command (0x01) and ZEROs to the TX FIFO. The other DMA is setup to read the RX FIFO. You can set the first transfer of this DMA to do a dummy transfer and the rest goes to your result array.

0 Likes

But you could implement what you need by adding a new variable the SPI context structure indicating if it is the first byte, then modify the HandleReceive() implementation in the cy_scb_spi.c to discard the first byte.

I don't know how to add things to the SPI context structure, but I'm willing to learn.

0 Likes