I'm hoping someone can explain this behavior
K64 SPI set for 8 bit transfers, FIFO disabled, fed by DMA
Before the SPI process takes place -- as a note -- the CMD 16 bits of the SPI's Push Register is zero (0).
DMA is set for 8 bit transfers.
No CMD pushed into the SPI by the application.
The SPI transfer is started by setting DMA_SSRT
The Source pointer of the DMA channel is pointing to memory which holds an array of bytes increasing by 1.
Data array === 0,1,2,3,4,5 ..... 255
I use a logic probe to capture the actual SPI data and clock coming off the K64
Data on MOSI line is ==== 0,1,3,4,5 ... 255
Notice byte three (3) of the input data (byte value 2) is eaten and never appears on the MOSI line out of the K64.
NXP/Freescale has never really published good documentation on using DMA with SPI and only pushing DATA - never the upper 16 bits of COMMAND.
Is there any published documentation that can explain this behavior?
Any ideas as to why byte 3 is ALWAYS eaten and never appears on the output?
Note: the rest of the data is always transferred - independent of number of bytes -- the behavior is only at the start of the transfer and always byte 3
Thanks.
Joe
Mike
Never mind - I solved it.
It turn out the issue was me -- I think I was attempting to start the DMA twice
Code that causes the issue ... from above
SPI1_RSER = My_SPI_RSER; // spi serviced by dma
DMA_SSRT = DMA_SSRT_SSRT(12); // start transfer
Turns out the DMA transfer is NOT started with the write to DMA_SSRT but starts with the write to SPI1_RSER
SPI1_RSER = My_SPI_RSER; // spi serviced by dma
//DMA_SSRT = DMA_SSRT_SSRT(12); // start transfer
By removing the DMA_SSRT line -- all is correct and now well understood.
Thanks for helping.
Joe
Hi Joe,
Thank you let us know the root cause.
best regards,
Mike
Mike
Link below is the most basic - bare-metal implementation of the test to illustrate the issue.
I use Crossworks as my development IDE so I don't think you can outright use the project but there are only a couple of files required to import the test into your own development IDE.
I am running on a Custom K64 board that has a 25mhz oscillator. Clocks.c is used to set the CPU clock to 120mhz. Your implementation will change depending on the board you use to test and what crystal/oscillator is driving it.
By default the SPI Push register comes up as Zero so there is no need to prime the upper 16 bits for command.
Thanks for taking the time to investigate this.
As a side note - in the process of checking out this implementation I set my break point inside the actual Perform_SPI_Xfer() and the output did NOT show the missing third byte.
That is a puzzle!!!
Since the real application does not pause keep your break point at the actual call to Perform_SPI_Xfer() and let you logic probe capture the output -- no DMA errors, and byte 3 is missing.
Found out where the DMA error came from you earlier noted -- if you set break points within Perform_SPI_Xfer() you can cause the DMA error to set.
Thanks.
Joe
Mike:
I will create a bare-bones project that demonstrates the issue.
It may take me a day or two to accomplish.
Thanks.
Joe
Thank you, Joe.
Mike:
I can't explain that DMA error.
I can tell you that I just ran the test above (code cycles every 25 msec writing out the test data) for the last hour with no DMA errors yet every run byte 3 of the input stream is missing from the output stream.
Thanks.
Joe
Hi Joe,
Thanks.
Could you post your test project here?
If not possible, just post SPI0 and eDMA related code.
I will do a test on my site with FRDM-K64F board next week.
best regards,
Mike
Thanks for looking into this Mike
Below is a snap shot just before kicking off the SPI-DMA transfer.
You can see the SPI code in the editor window, the array of data to be transferred in the bottom memory window, and all the SPI1 registers just prior to starting the process
Here is the capture of that SPI transfer - notice that the output goes 0,1,3,4.
The third byte should be 2 but its 3
I've attached pictures of the DMA registers for your review.
I've also included the complete logic probe capture should you want to dig into it further.
Thanks again.
Joe
http://www.joehinkle.com/download/SPI Capture.logicdata
http://www.joehinkle.com/download/DMA20.png
http://www.joehinkle.com/download/DMA21.png
http://www.joehinkle.com/download/DMA22.png
http://www.joehinkle.com/download/DMA23.png
http://www.joehinkle.com/download/DMA24.png
https://community.nxp.com/thread/joehinkle.com/download/SPI Capture.logicdata
Hi Joe,
From the DMA register value, I could find there with error at channel 13:
The error type is a source read bus error.
From your DMA initialization code, what's the "dword" definition?
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Mike
Early on in the application I write a 32 bit zero to the push register to properly load the upper 16 bits.
Since only DMA loads the SPI after the initial 32 bit zero is pushed -- the upper 16 bits never change.
I manually set and clear the SPI chip select since it is normally in the upper 16 bits of the SPI Push register -- but I keep that at zero.
Thanks for thinking some more on this issue.
Joe
Hi Joe,
Do you have recorded the SPI communication signals?
With the SPI_TX signal we could analyze the actual communication behavior.
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi,
From the posted code, I don't find there with any code to write the SPIx_PUSHR high 16-bit command filed.
Could you probe the SPI communication signals?
If there with chip select signal asserted during SPI communication?
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
If it is helpful -
Here is my DMA and SPI setup.
[CODE]
********************************************
DMA
********************************************
DMA_CERQ = DMA_CERQ_CERQ(13) ; // now disable chan13 for triggers
DMA_TCD13_SOFF = 1; // 1 byte move address offset
DMA_TCD13_ATTR = DMA_ATTR_SMOD(0) | DMA_ATTR_SSIZE(0) | DMA_ATTR_DMOD(0) | DMA_ATTR_DSIZE(0); // no circular addressing S&D, 8 bit S&D
DMA_TCD13_NBYTES_MLNO = 1; // 8bit sample every minor loop
DMA_TCD13_NBYTES_MLOFFNO = 1;
DMA_TCD13_NBYTES_MLOFFYES = 1;
DMA_TCD13_SLAST = 0; // not needed -- IRQ will set new start
DMA_TCD13_DOFF = 0; // no offset - always spi xmit
DMA_TCD13_DLASTSGA = 0; // no final last adjustment ( does not move )
DMA_TCD13_CSR = DMA_CSR_INTMAJOR_MASK ; // interrupt when done
DMA_TCD13_DADDR = (dword)&SPI0_PUSHR;
********************************************
SPI
******************************************
SPI0_SR = 0xffff0000; // clear all pending status flags
SPI0_MCR = SPI_MCR_MSTR_MASK | // master mode
SPI_MCR_DIS_TXF_MASK |
SPI_MCR_CLR_RXF_MASK | SPI_MCR_CLR_TXF_MASK | // // clr both FIFO's .. debug
SPI_MCR_PCSIS(0); // no chip selects
My_SPI_RSER = SPI_RSER_TFFF_RE_MASK | SPI_RSER_TFFF_DIRS_MASK; // xmit avail dma flag
SPI0_CTAR0 = SPI_CTAR_FMSZ(7) | // Data is 8 bits
SPI_CTAR_DBR_MASK | // double clock speed so baud is 12mhz
SPI_CTAR_CPOL_MASK | // Clock Polarity HI at Idle
SPI_CTAR_CPHA_MASK | // Clock Phase - out on leading edge, in on falling
SPI_CTAR_PCSSCK(0) | // delay prescaler - CS and Clock Edge
SPI_CTAR_PASC(0) | // delay prescaler - last clk edge and CS off
SPI_CTAR_PDT(0) | // delay prescaler between CS off and CS on -- between frames
SPI_CTAR_PBR(2) | // Bard Rate .. 2 == divide by 5 ... 60/5 = 12
SPI_CTAR_CSSCK(0) | // actual delay between CS and first clk edge
SPI_CTAR_ASC(0) | // actual delay last clk and CS off
SPI_CTAR_DT(0) | // actual delay between frames
SPI_CTAR_BR(0); // baud rate scaler ... 12 / 2 = 6
DMA_TCD13_SADDR = (dword)Work.Data;
DMA_TCD13_CITER_ELINKNO = NumberOfBytes;
DMA_TCD13_BITER_ELINKNO = NumberOfBytes;
SPI0_MCR |= SPI_MCR_CLR_TXF_MASK; // clear any waiting data
DMA_SERQ = DMA_SERQ_SERQ(13) ; // now enable chan13 for triggers
SPI0_RSER = My_SPI_RSER;
DMA_SSRT = DMA_SSRT_SSRT(13); // start transfer
[/CODE]
Thanks for the reply but I don't think your statement addresses the issue.
Please see post https://community.nxp.com/thread/381726
That's on a K80 but I suspect the SPI and DMA cells are the same on a K64
As I said in the post, the upper 16 bits of the push register are zero and I agree - they are passed to the SPI as a command. A SPI command of zero (0) does not affect or explain the third byte missing from the output steam.
I've been using this SPI DMA combination for a while now. I have a work-around that provides the first 3 bytes of the input with known data and the receiver ignores the first two bytes it receives.
I was hoping a long term Freescale engineer was still around that could explain why this occurs.
Hi,
Please check below description about SPIx_PUSHR register write requirement:
When you are using DMA mode, it need to transfer all 32bits (command+8bit data) to this register at the same time.
Thank you for the attention.
Have a great day,
Mike
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------