I'm running MQX 4.1 on a Kinetis K60 and using CW 10.6 and I'm seeing a long delay on the SPI bus from when the chip select is pulled low to when the clock actually starts running. And then again when the clock stops till the chip select goes high. As you can see in the scope capture (SPI CS is 1 and CLK is 2) the clock (and data too) are pretty quick (around 1.5 us) but the whole time for the transaction is long due to CS being held low for so much longer (around 40 us). I'm using a protocol that does lots of short 1 byte transfers and this 40us starts to add up even though the data is actually sent pretty fast.
I can't figure out how to control this time in MQX. Does anyone know how to adjust these delays under MQX?
Thanks,
Sean
I suppose that you use SPI driver and not SPI_legacy driver. Correct?
SPI driver allow use two ways how to generate CS signal(s):
Please check your settings of BSP_SPI_MEMORY_GPIO_CS macro.
Cannot be this delay caused by any printf function?
Could you please place here some example project (or at least part of code) which highlights this issue?
Have a great day,
RadekS
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Yes, I'm using the SPI driver not SPI_Legacy.
I'm letting the SPI module generate the signal, or at least I'm not registering any CS callback. Though I suppose MQX could be registering it's own callback without my knowledge.
Here is some sample code. It's pretty easy to get the 40us issue to occur. Basically after init any fwrite or fread will produce it.
uint8_t buffer = 0xFF; uint32_t param; MQX_FILE_PTR spi_flash = NULL;
spi_flash = fopen ("spi1:1", NULL); param = 12000000; SPI_OK != ioctl (spi_flash, IO_IOCTL_SPI_SET_BAUD, ¶m) param = SPI_CLK_POL_PHA_MODE0; SPI_OK != ioctl (spi_flash, IO_IOCTL_SPI_SET_MODE, ¶m)
param = SPI_DEVICE_MASTER_MODE; SPI_OK != ioctl (spi_flash, IO_IOCTL_SPI_SET_TRANSFER_MODE, ¶m)
fwrite (buffer, 1, 1, spi_flash);
I can't find BSP_SPI_MEMORY_GPIO_CS anywhere in my code base (application or MQX) so I'm not doing anything with that.
Hope that helps explain my situation
Thanks,
Sean
Try with::
spi_flash = fopen ("spi1:", NULL);
Do you have some basis for that suggestion?
The documentation (MQXIOUG) appears quite clear that to use hardware generation of CS signals you provide a number after the colon that specifies the CS signals to use in the form of a bit-mask (so providing "1" will therefore get you CS0). It may be that omitting the specifier would also get you CS0, but I see no reason to believe this would be faster, and it will be no use if you need one of the other CS signals.
I have also seen the delays that Sean has reported. I am using CS0 and CS1 alternately on the same bus (using file handles opened with "spi1:1" and "spi1:2") and I see the same delay on each, before and after the data burst. I am transferring more data per packet so it is not such a problem for me, but I too would be interested to know if there is a way to shorten this. The whole point of hardware-generated CS is that they should be fast.
Please refer to this (CSSCK, this link will take you directly to the page I am referring to): http://cache.freescale.com/files/32bit/doc/ref_manual/K60P144M100SF2V2RM.pdf#Page=1416
And what is your BUS Clock running at, from the Math it seems like it is at 10MHz.
I tested your example code (I just add fflush (spi_flash); behing fwrite command for generating CS0 rising edge) on my FRDM-K64F (120MHz) and I saw approximately 2us delay between CS0 falling edge and SPI clock rising edge. Time delay between last SPI clock falling edge and CS0 rising edge was approximately 12us (it was almost independent on SPI baud rate).
I also measure the same behavior in case when I used external callback for generating CS signal.
In fact, CS signal in DSPI driver is not generated directly by DSPI module and standard delay registers. Real change of CS signal(s) is caused by driver’s write into PCSIS bit in SPIx_MCR register. So, these delays are caused mainly by software overhead.
Unfortunately DSPI module cannot directly drive CS signal at end of transfer. Both CS edges are triggered by write into register. For that reason, DSPI module contains delay registers. Unfortunately correct settings of these delays will cause that it will effectively slow down real data transfer (it adds also delays between data words). Therefore DSPI driver handle CS signals by software and there isn’t any additional delay between data words.
We can expect two typical cases:
So, if you need send lot of data in time, please check whether you can keep CS signal low during transfer of whole block and use fwrite for some big buffer of data – it will be fast. Unfortunately CS handling takes additional time, therefore don’t do it if you don’t need it.
I hope it helps you.
I actually have an fflush() after the fwrite() too. Made a copy/paste error there and left that out.
I'm running a MK60FN1M0VLQ15 at 150MHz but as you know I'm getting that long delay. Looks like things are working a little better on that freedom board though.
The device I'm trying to communicate with is a WiFi module and I can do multiple bytes per CS activation when running in SPI mode 1 (mode 0 only allows 1 byte per CS activation). Using mode 1 helps a good bit but there are still a lot of transactions on the SPI bus. I'm just trying to eliminate all possible places for slowness and this looked like a good culprit since I tend to have a lot of transactions on the SPI bus regardless of the mode. I see this delay regardless of what kind of SPI device I'm trying to communicate with. I think the delay just adds up with WiFi since networking traffic involves a lot of transactions of various amounts of bytes per activation of the CS.
Nitin, I'm setting the bus to 12MHz. Or at least that's what I'm trying to do when setting IOCTL_SPI_SET_BAUD.
I found a spot in spi_dspi_common.c that appears to set the CSSCK value. But changing the values (best_scaler & best_pres) doesn't seem to decrease the time at all. However I have been able to increase the time by adjusting them.
/* add delay scalers and prescaler settings to ctar */
ctar |= DSPI_CTAR_CSSCK(best_scaler) | DSPI_CTAR_PCSSCK(best_pres);
ctar |= DSPI_CTAR_ASC(best_scaler) | DSPI_CTAR_PASC(best_pres);
Unfortunately I'm getting the feeling there is not a whole lot I can do to decrease the time. It's just part of the DSPI driver. Is this correct?
Thanks,
Sean
Sean
I see your SPI baud rate is set to 12 MHz but how about your Bus CLOCK i.e. source for the SPI module.
e.g. in init_spi.c:
static const DSPI_DMA_INIT_STRUCT _bsp_dspi0_init = {
0, /* SPI channel */
CM_CLOCK_SOURCE_BUS, /* Relevant module clock source */
BSP_DSPI0_DMA_RX_CHANNEL, /* DMA channel for RX */
BSP_DSPI0_DMA_TX_CHANNEL, /* DMA channel for TX */
BSP_DSPI0_DMA_RX_SOURCE, /* Source to be used with RX channel */
BSP_DSPI0_DMA_TX_SOURCE /* Source to be used with TX channel */
};
const SPI_INIT_STRUCT _bsp_spi0_init = {
&_spi_dspi_dma_devif, /* Low level driver interface */
&_bsp_dspi0_init, /* Low level driver init data */
{ /* Default parameters: */
BSP_DSPI_BAUDRATE_SPI0, /* Baudrate 1 MHz (SPI Bus Freq between K60 and CML */
SPI_CLK_POL_PHA_MODE0, /* Mode */
8, /* Frame size */
1, /* Chip select */
0, /* Attributes */
0xFFFFFFFF /* Dummy pattern */
}
};
And In my case(the code above) CM_CLOCK_SOURCE_BUS is set to 60MHz although BSP_DSPI_BAUDRATE_SPI0 is set to 1MHz (SPI speed).
As per my previous reply these 2 clcoks scale the delay between CS and CLK signal. And from your settings it appears your SPI is running at 12MHz but your bus clock is set to 10MHz
Please verify !
Nitin
Checked and CM_CLOCK_SOURCE_BUS is actually at 75MHz and BSP_DSPI_BAUDRATE_SPI1 is 10MHz. But then I change that to 12MHz as seen in the sample code I posted.
Thanks,
Sean
Yes, there are just several dedicated options how to set baud rate divider.
Therefore I would like to recommend always call IO_IOCTL_SPI_GET_BAUD just after IO_IOCTL_SPI_SET_BAUD.
IO_IOCTL_SPI_SET_BAUD will tell your “wish” to driver however IO_IOCTL_SPI_GET_BAUD will tell you real baud rate which you really set.
I see. I added IO_IOCTL_SPI_GET_BAUD after setting the baud rate and I'm actually getting 12.5MHz when setting it to 12MHz.
Just to follow up. I tried adjusting the CSSCK and PSSCK registers described in the doc Nitin posted. However that did not make a difference. I think I'm just seeing the software delays Radek mentioned. Anyway I was able to increase the size of my transfers so that the CS delay is a pretty small part of the overall time the transfers are taking.
Thanks for all your help.
-Sean