- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.