Hello,
does anybody know where to find an example for configuring SPI as a master and performing write/read synchronously (no interrupts, no dma) on KL16 devices? I've only found a thread showing some tips for DSPI on K10 and similar MCUs, but the peripheral on KL devices seems totally different.
please refer the processor expert sample code under CW10.5 install\MCU\CodeWarrior_Examples\Processor_Expert\Kinetis\TWR-KL25Z48M\SPI
hope this helps!
Hello, I'm using IAR Embedded Workbench for developing on Kinetis, is there another way to access the example you're referring to?
Just as ZhangJennie mentioned, you can download the FRDM-KL25Z and TWRKL25Z48M Sample Code Package and use the IAR example code as base for your development, you will find it in this path:
C:\(your download path)\KL25 Sample Code\kl25_sc_rev10\klxx-sc-pex\projects\spi_demo\iar
Have a nice day :P,
Perla
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi Perla,
Is there any SPI example for the KL26Z MCu? I am configuring the KL25Z SPI example to Kl26Z board not succeeded.
Thanks in advance for you are help,
Regards,
Ram.
Ram
See https://community.freescale.com/message/427243?et=watches.email.thread
The SPI peripheral in the KL26 is not fully compatible with the one in the KL25. You need KL46 example code, which is compatible in relation to the SPI, or you can take complete working code from the uTasker project which works on all KL and K parts (automatically adapts itself accordingly).
Regards
Mark
hi Palestro,
You can use PE to create a SPI example for KL16. PE is best for helping you study how to use Kinetis MCU. You can download PE at Processor Expert Software and Embedded Components.
Hello, I tried PE but found it way too difficult to use, so I'm looking for a simple example that just explain how to do things!
Thank you anyway for the help!
Hi
The SPI in the KL devices is different from the DSPI in the K devices; it doesn't have FIFOs and doesn't automatically control the chip select line in the same way.
Below is configuration code for master use of SPI1 on a certain set of pins (you can interpret it for the names since the code is from the uTaker project which uses some special configuration macros).
POWER_UP(4, SIM_SCGC4_SPI1); // enable the SPI
_CONFIG_PERIPHERAL(E, 2, PE_2_SPI1_SCK); // configure interface lines
_CONFIG_PERIPHERAL(E, 1, (PE_1_SPI1_MOSI | PORT_SRE_FAST | PORT_DSE_HIGH));
_CONFIG_PERIPHERAL(E, 3, (PE_3_SPI1_MISO | PORT_PS_UP_ENABLE));
_CONFIG_DRIVE_PORT_OUTPUT_VALUE(E, CS0_LINE, CS0_LINE, (PORT_SRE_FAST | PORT_DSE_HIGH));
SPI1_C1 = (SPI_C1_CPHA | SPI_C1_CPOL | SPI_C1_MSTR | SPI_C1_SPE); // configure master mode
SPI1_BR = (SPI_BR_SPPR_PRE_1 | SPI_BR_SPR_DIV_2); // set speed
(volatile unsigned char)SPI1_S; // read status register and data register to prepare for operation
(volatile unsigned char)SPI1_D;
To write and read a byte:
SPI1_D = byte; // write a byte that is sent
while (!(SPI1_S & (SPI_S_SPRF))) {} // wait for the byte to be completely transmitted
byte = SPI1_D; // read the byte that was read
Repeate for additional data.
The only tricky bit is the fact that the status and data register should be read "once" before starting. If this is not performed the first loop will hang since the status will not be set accordingly.
Also, never let the debugger view the SPI registers when stepping such code since it will also read the data register and reset status flags in the process (causing the loop to hang).
Regards
Mark
Hello Mark,
thank you for the help, I'm trying to implement this; one thing I don't understand is how is driven the Chip Select pin: It seems to me from reading the datasheet that I should use MODFEN = 1 and SSOE = 1 to use SS as "slave select output", but I don't see any flag regarding SS on your example. Maybe it must be driven by software?
Also, I'm writing the DSPI driver for K series, and I found the usual problems with hardware SPI devices: I cannot use various queue/buffer flags to successfully enqueue next byte without waiting the end of transmission; the result is that, even with high speed, resulting throughput is very low, because the bytes get transmitted fast but there is a long pause between two bytes.
Here is an example of a communication made of 1 byte tx (value CMD_READ_ID) and 3 bytes rx, with chip select asserted during the whole communication:
SPI0_PUSHR = (CMD_READ_ID | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1));
while ((SPI0_SR & SPI_SR_RXCTR_MASK) == 0);
manufacturer_id = SPI0_POPR; // dummy
SPI0_PUSHR = (0xFF | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1));
while ((SPI0_SR & SPI_SR_RXCTR_MASK) == 0);
manufacturer_id = SPI0_POPR;
SPI0_PUSHR = (0xFF | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1));
while ((SPI0_SR & SPI_SR_RXCTR_MASK) == 0);
device_id1 = SPI0_POPR;
SPI0_PUSHR = (0xFF | SPI_PUSHR_PCS(1));
while ((SPI0_SR & SPI_SR_RXCTR_MASK) == 0);
device_id2 = SPI0_POPR;
Do you know how to speed up the process? I'm expecting the same problem with SPI driver in KL series. In fact I wrote:
SIM_SCGC4 |= SIM_SCGC4_SPI1_MASK; |
PORTD_PCR4 = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK; | // alt2: spi1 cs |
PORTD_PCR5 = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK; | // alt2: spi1 clk |
PORTD_PCR6 = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK; | // alt2: spi1 mosi |
PORTD_PCR7 = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK; | // alt2: spi1 miso |
SPI1_C1 = SPI_C1_MSTR_MASK | SPI_C1_CPHA_MASK | SPI_C1_CPOL_MASK | SPI_C1_SPE_MASK;
SPI1_BR = SPI_BR_SPR(1);
SPI1_DL = CMD_READ_ID;
while (SPI1_S & SPI_S_SPRF_MASK);
manufacturer_id = SPI1_DL; | // dummy |
SPI1_DL = 0xFF;
while (SPI1_S & SPI_S_SPRF_MASK);
manufacturer_id = SPI1_DL;
SPI1_DL = 0xFF;
while (SPI1_S & SPI_S_SPRF_MASK);
device_id1 = SPI1_DL;
SPI1_DL = 0xFF;
while (SPI1_S & SPI_S_SPRF_MASK);
device_id2 = SPI1_DL;
But the execution freezes in the last while.
Thank you again
Best regards
Marco
Hi Marco
I simply control the CS line using an output with the KL's SPI:
_CLEARBITS(E, PORTE_BIT4); // assert the CS line
write/read a number of bytes
_SETBITS(E, PORTE_BIT4); // negate the chip select line
I see no reason why your KL driver should freeze in the last while - as pointed out previously, make sure that this is not due to the debugger reading its status register and clearing the flag that the code is waiting for.
In the case of the DSPI you can slightly improve performance by making use of the 4 deep FIFO. This allows 4 bytes to be sent at maximum speed (no space between them) but you will still need to wait on the final byte to be completely read in before extracting the final rx data byte. In your case, when reading the manufacturer's ID of an SPI Flash device, you can do.
SPI0_PUSHR = (CMD_READ_ID | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1)); // queue 4 writes, controlling the CS line to be asserted at the start and negated after transmission
SPI0_PUSHR = (0xFF | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1));
SPI0_PUSHR = (0xFF | SPI_PUSHR_CONT_MASK | SPI_PUSHR_PCS(1));
SPI0_PUSHR = (0xFF | SPI_PUSHR_PCS(1));
while ((SPI0_SR & SPI_SR_RXCTR_MASK) < (3 << 4)); // wait until 3 bytes have been received
device_id2 = SPI0_POPR; // 3 dummy reads
device_id2 = SPI0_POPR;
device_id2 = SPI0_POPR;
while ((SPI0_SR & SPI_SR_RXCTR_MASK) == 0); // wait until the final byte has been received
device_id2 = SPI0_POPR; // the result
It is also possible to wait for all 4 bytes, read 3 dummy ones and then keep the fourth. The above will just be two or three instructions faster (a few ns...) since the 3 byte flush is performed during the fourth byte transmission/reception.
Since the SPI in the KL doesn't have FIFOs the techniques to improve performance are:
1. Send the first byte.
2. Wait for the TX status to indicate that a further byte can be written. This is before the Rx byte has been received (maybe after about 2 bits transmission - I didn't measure this though).
3. Send the next byte (if there is further data to be sent)
4. Wait for the Rx and read when it is ready.
5. Go to 2.
Or
Configure DMA for Tx and Rx. Let the DMA controller send and receive and wait until the DMA controller informs that the requested number of bytes have been transmitted and received. Then read the 4th byte from the DMA Rx buffer in the example case.
Regards
Mark
P.S. I use the DSPI and SPI for SD card and AT45DBxxx, ST25P(E)xxx, SSTxxx SPI Flash.
Thank you Mark, I'm slowly getting this thing to work. In the last test, I confused the test condition:
while ((SPI1_S & SPI_S_SPRF_MASK) == 0); // read buffer empty
Anyway, it still works weird:
If I put a breakpoint just after turning on the peripheral:
SIM_SCGC4 |= SIM_SCGC4_SPI1_MASK;
then the test works fine; if I don't put the breakpoint or execute it without the debugger it stops looping on the first while:
SIM_SCGC4 |= SIM_SCGC4_SPI1_MASK; |
PORTD_PCR4 = PORT_PCR_MUX(1);
//PORTD_PCR4 = PORT_PCR_MUX(2) | PORT_PCR_DSE_MASK; | // alt2: spi1 cs |
PORTD_PCR5 = PORT_PCR_MUX(2); | // alt2: spi1 clk |
PORTD_PCR6 = PORT_PCR_MUX(2); | // alt2: spi1 mosi |
PORTD_PCR7 = PORT_PCR_MUX(2); | // alt2: spi1 miso |
SPI1_C1 = SPI_C1_MSTR_MASK | SPI_C1_CPHA_MASK | SPI_C1_CPOL_MASK | SPI_C1_SPE_MASK;
SPI1_BR = SPI_BR_SPR(1);
// test
F_CS_H;
F_CS_L;
SPI1_DL = CMD_READ_ID;
while ((SPI1_S & SPI_S_SPRF_MASK) == 0);
manufacturer_id = SPI1_DL; | // dummy |
SPI1_DL = 0xFF;
while ((SPI1_S & SPI_S_SPRF_MASK) == 0);
manufacturer_id = SPI1_DL;
Really can't get how it's supposed to be...