SPI slave and DMA question

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

cross mob
Anonymous
Not applicable

I am using PSoC3 at the SPI slave end and SPI master is a ARM9 processor. I need to consistantly exchange block of data to PSoC3 through the SPI, so I set up the DMA on PSoC3 side. In my test program, I find SPI slave return data is shifted by one byte. For example, in PSoC3, I initialize spitxdata = i + 10; but on the SPI master side, at the very first time, it receive data SpiReturn[0] = 0; SpiReturn[1] = 10; SpiReturn[2] = 11......and the next round, it will assign SpiReturn[0] = 49, then SpiReturn[1] = 10.... It seems Spi slave Tx does not put the tx data after receiving the first byte? Any suggestions?

   

Here is some more details about my program. SPIS Rx/Tx buffer size = 4, only selected Interrupt On Tx FIFO Not Full and Interrupt On Rx FIFO Not Empty, rx_interrupt output connects to DMA_RX_S drq and tx_interrupt connects to DMA_TX_S drq, both DMA has hardware request set to level

   

 

   

Attached is the related code.

   

 

   

Thanks in advance for any suggestion!

0 Likes
1 Solution
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        After reading deeper into the SPI Slave data sheet, I have an idea what might happen. Basically when you start the TX buffer is empty (nothing is loaded into A0 so there is nothing to transmit). Now when the master starts to write, it asserts SS and starts sending. In that moment, the SPI Slave sees that the TX buffer is empty, creates an IRQ and the the DMA fills in the first byte. But that is then too late to send it out, so it will get send only the second time. You can test that by adding an ISR to the tx_interrupt line. It should fire after the SPI has been initialized, and before the master sends for the first time. If it doesn't, then my idea above is correct. (Or you route it to a pin and check with a logic analyzer when interrupts are generated) If this is what happens, then you would just need to create the first DMA request manually (with CyDMAChSetRequest).   

View solution in original post

0 Likes
14 Replies
Anonymous
Not applicable

 sorry about the second post. the website told me it was a bad link, so I clicked "post again". Admin please remove other duplicated post. thanks

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

 somehow, the attachment did not show up. Here goes again.

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored

Can you post your complete project  so we can look at it? E.g. how the DMA gets triggered, and how SPI is set up... The reason might be just something not related to your setup code.

   

Also, did you try to just use a SPI buffer of 40 bytes? Then the component should do all the work for you...

   

lastly, your receive DMA handling looks strange. There is a second TD in the DMA which just copies the first byte of the receive buffer to itself, over and over... (or actually it might do even stranger things given that the SRC base address is set to the peripherals instead of sRAM)

0 Likes
Anonymous
Not applicable

 The original project has lots of unrelated stuff, so let me try to make a new test version and post it later. But it is still not easy for you to test because my SPI master is a ARM 9 processor on a different board. 

   

For the test, I do set up entire 40 bytes both on master side and slave side. It is just the first byte is always zero, and the last byte of the first transfer from slave will show up as the first byte in 2nd transfer from master, so it is shifted by one.

   

And for the last part, I know it is strange, I got the example code from our support FAE, (he is on vacation now). In his email: It moves the first byte from first location of the buffer to the exact place, which does nothing. But, in the process of moving from the beginning of the buffer to the beginning of the buffer, it essentially resets the pointer for the DMA. So when the next SPI packet arrives, the first byte will go to rxBuffer[0].

   

I don't completely unstand the logic, but the example project have two TDs at both Tx and Rx side, I changed Tx side to one TD, it still works, but when I changed Rx side, all the sudden, I only got the same byte over and over, so I changed it back to two TDs.

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        To the second DMA TD: OK, I understand. This is quite a neat solution to reset the DMA - otherwise this would have to be done in software AFAICS. To the SPI problem: can you observe the SPI transaction with a logic analyzer? (When I understand you right the problematic data is not on the PSoC side, but observed on the master side, right?) That way you can find out whether the PSoC is transmitting the data at the wrong place or not. This actually might be quite normal: when the master starts transmitting its data, it also is starting to receive data. But the first byte is only received fully when the first byte has been transmitted also fully. So it might be that the receive process on your master then puts the data to the second byte in the buffer. What kind of MCU is you master exactly?   
0 Likes
Anonymous
Not applicable

 SPI master is Atmel AT91SAM9261. 

   

Before using DMA, I used to load SPI slave manually with SPSI_WriteByteZero(data), so I am very sure the master will correctly receive each byte in this case. The master side is still sending each byte separately but eventually will use DMA as well. That's after I get SPI slave side working first.

0 Likes
Anonymous
Not applicable

 I added a line right after SPIS_Start

   

SPIS_WriteTxDataZero(0x55);

   

so now the first byte I am getting at the master side is 0x55, then the second byte and beyond are the bytes I set up in s_txBuffer at the PSoC3 side. So it looks like the problem is still at the PSoC3 side and it is not loading the first byte into the register to prepare for the SPI transfer

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        But the question remains: do you know who is the culprit? Does the PSoC, when using DMA, really send out the bytes one too late (and with a leading zero especially)? Did you try to use a 40 byte SPI buffer, so the component does everything on its own )that way you won't need DMA at all)?   
0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        After reading deeper into the SPI Slave data sheet, I have an idea what might happen. Basically when you start the TX buffer is empty (nothing is loaded into A0 so there is nothing to transmit). Now when the master starts to write, it asserts SS and starts sending. In that moment, the SPI Slave sees that the TX buffer is empty, creates an IRQ and the the DMA fills in the first byte. But that is then too late to send it out, so it will get send only the second time. You can test that by adding an ISR to the tx_interrupt line. It should fire after the SPI has been initialized, and before the master sends for the first time. If it doesn't, then my idea above is correct. (Or you route it to a pin and check with a logic analyzer when interrupts are generated) If this is what happens, then you would just need to create the first DMA request manually (with CyDMAChSetRequest).   
0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        Stupid editor 😞 Does anybody know how to add paragraph breaks with this "small box editor"?   
0 Likes
ETRO_SSN583
Level 9
Level 9
250 likes received 100 sign-ins 5 likes given

I have found that if you delete all history in your browser, when the small

   

box shows up, then close the browser, reopen, small box goes away.

   

 

   

Regards, Dana.

0 Likes
Anonymous
Not applicable

 so I added a isr line to the tx_interrupt, and wrote some dummy code in the isr routine and set a break point. well the break point did not trigger. So that means it did not load the first byte?

   

I added CyDmaChSetRequest(S_TxChannel, CPU_REQ) into my Dma_S_Tx_Configuration, right after CyDmaChSetInitialTd and this time, the data on master side does not shift by one, it misses the first byte entirely, but the second byte is the second byte slave sends. So I guess it is a little bit better. 

   

When I manually request first DMA, it loads data, but does it push it all the way to SPIS register to be ready to send off?

0 Likes
Anonymous
Not applicable

 with first manually DMA request and manually load first byte with SPIS_WriteByteZero(s_txBuffer[0]); I can finally have the correct data at the master side. 

   

Still like to know if there is any less clumsy solution.

0 Likes
HeLi_263931
Level 8
Level 8
100 solutions authored 50 solutions authored 25 solutions authored
        When I read the data sheet correctly (look at the function description) the "FIFO not full" state gets triggered when the accumulator gets set (A0). Starting the first DMA transaction manually writes only to the FIFO register, which might also be one byte to late. You might want to open a support case with Cypress about this, to get clarification of the actual behavior. Or you can try the solution with the 40 bytes TX buffer as suggested before - this doesn't use the DMA at all but an internal ISR to feed the SPI.