Just a note, returning from spiStart() after failing to allocate DMAs is not the usualy behavior, the function is assumed to never fail, you should use assertions there.
Giovanni
SPI driver for KINETIS K20.
Moderator: utzig
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: SPI driver for KINETIS K20.
Thanks. So it would be something that looks like this.
Code: Select all
// can't allocate DMA channels!?
chDbgAssert((SPID1.DMA_Rx==DMA_NONE_AVAIL)||
(SPID1.DMA_Tx==DMA_NONE_AVAIL),"No DMA Ch.");
- Giovanni
- Site Admin
- Posts: 14457
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: SPI driver for KINETIS K20.
Exactly, just like the STM32 equivalent does.
I have been thinking about giving xxxStart() functions a failure mode but probably that would only mean moving the problem to the application level.
Giovanni
I have been thinking about giving xxxStart() functions a failure mode but probably that would only mean moving the problem to the application level.
Giovanni
Re: SPI driver for KINETIS K20.
I got the old STM32F103 fatfs demo code compiled and I am testing on my FPGA eval board. mmcConnect() failed as the MicroSD card didn't power up.
Here is what I see in mmcConnect(). It uses spi_lld_ignore() to send 128 clock pulses.
While spi_lld_ignore() technically can send whatever it wants, mmcConnect() relies on that particular 0xff value.
Also note that sout value changed after the 5th value. This is because both the Tx/Rx DMA shares a common dummy variable in spi_lld_ignore(). The Tx value get overwritten by the Rx DMA after the Rx FIFO was filled. I think we should split them up as the Rx is toggling. It only cost an extra byte in RAM.
I changed my code to the following:
Note: the dmaTxDummy, dmaRxDummy do not and cannot be in the stack as DMA would try to access them after the routine returns.
That change get the SD card to toggle it output (Sin pin on the K22) and make mmcConnect() happy. Fat FS get mounted after that.
We are making good progress here!
Here is what I see in mmcConnect(). It uses spi_lld_ignore() to send 128 clock pulses.
Code: Select all
/* Use dmaDummy as the source/destination when a buffer is not provided */
dmaDummy = 0;
While spi_lld_ignore() technically can send whatever it wants, mmcConnect() relies on that particular 0xff value.
Also note that sout value changed after the 5th value. This is because both the Tx/Rx DMA shares a common dummy variable in spi_lld_ignore(). The Tx value get overwritten by the Rx DMA after the Rx FIFO was filled. I think we should split them up as the Rx is toggling. It only cost an extra byte in RAM.
I changed my code to the following:
Code: Select all
volatile uint8_t dmaTxDummy, dmaRxDummy;
:
dmaTxDummy = dmaRxDummy = 0xff;
:
DMA->TCD[spip->DMA_Rx].DADDR = (uint32_t)&dmaRxDummy;
:
DMA->TCD[spip->DMA_Tx].SADDR = (uint32_t)&dmaTxDummy;
Note: the dmaTxDummy, dmaRxDummy do not and cannot be in the stack as DMA would try to access them after the routine returns.
That change get the SD card to toggle it output (Sin pin on the K22) and make mmcConnect() happy. Fat FS get mounted after that.
We are making good progress here!
-
- Posts: 49
- Joined: Mon Aug 11, 2014 6:40 am
Re: SPI driver for KINETIS K20.
The MMC/SPI driver communicates with the card at the discovery stage for its capability at a slower rate (< 400kbps) and then it get switched to a faster speed (25Mbps) for the actual data transfer.
I notice that the SPI tar0 init code is inside the "if (spip->state == SPI_STOP)" branch. I moved that code after the if statement because the mmc/spi changes its speeds on the fly without stopping/restarting the SPI driver. So a subsequent call to spi_lld_start(), tar0 is not initialized for the higher speed because (state==SPI_STOP) is false.
Edit: the code that sets the SPI byte/word size from the tar0 in the config needs to be moved too.
By boosting the priority of the thread that calls the SPI (in the demo code), it gets right back into transferring more data instead of every 20ms (as in my previous trace) ! Before these changes, the demo was like floppy drive speed. It took a couple of seconds (1.88s) to mount the sd. Now I can barely see the LED blink! 1.44ms to mount the SD. The SPI is now kept busy as you can see a block of red in the Sck activities vs the tick marks previously! Very nice!
I notice that the SPI tar0 init code is inside the "if (spip->state == SPI_STOP)" branch. I moved that code after the if statement because the mmc/spi changes its speeds on the fly without stopping/restarting the SPI driver. So a subsequent call to spi_lld_start(), tar0 is not initialized for the higher speed because (state==SPI_STOP) is false.
Edit: the code that sets the SPI byte/word size from the tar0 in the config needs to be moved too.
Code: Select all
void spi_lld_start(SPIDriver *spip) {
/* If in stopped state then enables the SPI and DMA clocks.*/
if (spip->state == SPI_STOP) {
:
if (spip->config->tar0) {
spip->spi->CTAR[0] = spip->config->tar0;
} else {
spip->spi->CTAR[0] = KINETIS_SPI_TAR0_DEFAULT;
}
:
}
// <--- move the tar0 block here
}
By boosting the priority of the thread that calls the SPI (in the demo code), it gets right back into transferring more data instead of every 20ms (as in my previous trace) ! Before these changes, the demo was like floppy drive speed. It took a couple of seconds (1.88s) to mount the sd. Now I can barely see the LED blink! 1.44ms to mount the SD. The SPI is now kept busy as you can see a block of red in the Sck activities vs the tick marks previously! Very nice!
Who is online
Users browsing this forum: No registered users and 35 guests