i.MX7: SPI transactions at 1 MHz?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX7: SPI transactions at 1 MHz?

Jump to solution
2,624 Views
skrap
Contributor IV

In our application, we’re using the i.MX7's SDMA controller to drive ECSPI peripherals #2 and #3, which are in turn connected to external ADCs.  This is using the linux rel_imx_4.1.15_2.0.0_ga release. We need to sample these ADCs regularly at 1 MHz x 14 bits, for a total SCLK rate of 16 MHz. I am having trouble keeping the SPI transactions (SS going low) at a regular interval. There will be occasional gaps of around 10 µs where no activity is happening on the bus. I’m assuming this is happening because the ECSPI’s TXFIFO is empty, and that the SDMA is unable to keep up.

If I set the sampling rate to 250 kHz, I don't see these gaps.  Any idea what bottleneck I could be hitting against?   DMA maxburst is set as per the linux SDMA driver (TX maxburst is 16, RX maxburst is 32).  Priority on both SDMA channels is set at maximum, and nothing else on the system is using SDMA.

Here's what I see: (magenta = SS, green = SCK, yellow = SDO). 

scope_0.png

Labels (1)
Tags (2)
1 Solution
1,550 Views
skrap
Contributor IV

This is caused by two different bugs in the 4.1.15 2.0.0 GA BSP release.

If you're a NXP person reading this, please feel free to pass along my contact info to the responsible engineers.  I would be glad to help feed back my fixes into the NXP mainline.

The issue is twofold.

1) The TX DMA watermark is being forced to zero, so the SDMA only refills the TX FIFO when it has already been emptied.  This means that there will always be a gap in the SPI transactions, as you see above.

if (spi_imx->dma_is_inited) {
 if (spi_imx->devtype_data->devtype != IMX6UL_ECSPI)
 spi_imx->tx_wml = 1;             // **** THIS IS BAD ****
 dma = (spi_imx->rx_wml - 1) << MX51_ECSPI_DMA_RX_WML_OFFSET
 | (spi_imx->tx_wml - 1) << MX51_ECSPI_DMA_TX_WML_OFFSET
 | (1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
 | (1 << MX51_ECSPI_DMA_RXDEN_OFFSET);
 writel(dma, spi_imx->base + MX51_ECSPI_DMA);
 }

(from linux-fslc/spi-imx.c at 4.1-2.0.x-imx · Freescale/linux-fslc · GitHub )

2) The SDMA driver recently (ok, in 2015) introduced a flag on sdmacs called "context_loaded", which (if true) causes sdma_load_context() to exit early.  This breaks the IMX SPI driver, which calls sdma_load_context() first in probe(), and then later (with different parameters) in its setup_transfer function.  I just deleted the early return in sdma_load_context().  Perhaps it is there for some reason, but to my eyes, the code is broken.

I wanted to leave these breadcrumbs here for future engineers' benefit.  I spent nearly two weeks tracking down these bugs.

View solution in original post

6 Replies
1,550 Views
jimkapcio
Contributor I

I am trying to get ECSPI DMA working on my i.MX7 board.

Can you provide the snippet of the DTS file for setting up dmas and dma-names?

What chip and driver are you using?

0 Kudos
1,551 Views
skrap
Contributor IV

This is caused by two different bugs in the 4.1.15 2.0.0 GA BSP release.

If you're a NXP person reading this, please feel free to pass along my contact info to the responsible engineers.  I would be glad to help feed back my fixes into the NXP mainline.

The issue is twofold.

1) The TX DMA watermark is being forced to zero, so the SDMA only refills the TX FIFO when it has already been emptied.  This means that there will always be a gap in the SPI transactions, as you see above.

if (spi_imx->dma_is_inited) {
 if (spi_imx->devtype_data->devtype != IMX6UL_ECSPI)
 spi_imx->tx_wml = 1;             // **** THIS IS BAD ****
 dma = (spi_imx->rx_wml - 1) << MX51_ECSPI_DMA_RX_WML_OFFSET
 | (spi_imx->tx_wml - 1) << MX51_ECSPI_DMA_TX_WML_OFFSET
 | (1 << MX51_ECSPI_DMA_TEDEN_OFFSET)
 | (1 << MX51_ECSPI_DMA_RXDEN_OFFSET);
 writel(dma, spi_imx->base + MX51_ECSPI_DMA);
 }

(from linux-fslc/spi-imx.c at 4.1-2.0.x-imx · Freescale/linux-fslc · GitHub )

2) The SDMA driver recently (ok, in 2015) introduced a flag on sdmacs called "context_loaded", which (if true) causes sdma_load_context() to exit early.  This breaks the IMX SPI driver, which calls sdma_load_context() first in probe(), and then later (with different parameters) in its setup_transfer function.  I just deleted the early return in sdma_load_context().  Perhaps it is there for some reason, but to my eyes, the code is broken.

I wanted to leave these breadcrumbs here for future engineers' benefit.  I spent nearly two weeks tracking down these bugs.

1,550 Views
weidong_sun
NXP TechSupport
NXP TechSupport

Hello Jonah Petri,

  The speed of eCSPI moudle on I.MX7D or I.MX7S is up to 80MHz frequency. We can see it In i.mx7s reference manual!

pastedImage_1.png

So speed can meet your requirments of your applicaiton.

Best Regards,

Weidong

0 Kudos
1,550 Views
skrap
Contributor IV

Hello Weidong,

I understand the ECSPI peripheral can be clocked at that rate, but (see above scope capture) the SDMA does not seem to be able to keep it transmitting consistently at even 16 MHz.

Do you have a comment on that?

Also, see:

https://community.nxp.com/message/869666 

0 Kudos
1,550 Views
erickrieg
Contributor I

I agree that you don't appear to be running too fast for the processor or the sdma engine.  I noticed the rate of your bursts was a little slower than the 1MHZ speed you mentioned.  Also, I noticed there were at least 21 good burst that went out before your strange dead time of 12uS - this leads me to question the theory of it being from a full transition since the fifo in the spi engine is 16 32 bit samples wide.  My suspicion is there could be some periodic task kicking off in linux that interfere for some reason.   In a direct message to you, I expressed some skepticism about being able to easily get the very complex sdma engine working - I gave up on figuring that thing out myself and am working on a 30Khz spi continuous stream transaction based on processor interrupts just refilling it in time.  I have a bare metal application - so less worst case interrupt latency than you would have with linux.   You could always try to get this working from another processor core - there are 3 in it.    It could be interesting to try having a very tight loop of code that continuously does it all while logging spi status back to a RAM buffer - this might be able to let you know if those 12uS dead times are a quirk in the spi engine.  Conversely it would be interesting to go back to your 250khz rate that works and see if it still works if you simultaneously had another sdma channel running copying a large unused memory area onto its self.   - that could help prove if there is a problem with sdma contention for some reason.    Please do post back here if/when you find a solution.  Eric

0 Kudos
1,550 Views
skrap
Contributor IV

Hi Eric,

The issue was caused by some bugs in the NXP linux drivers.  You can see lower down in this thread for the solution.

Jonah

0 Kudos