KL17 SPI - I'm missing something

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

KL17 SPI - I'm missing something

1,874 Views
JHinkle
Senior Contributor I

The KL17 SPI should be very simple to set up and use, ... but I'm dead in the water.

My setup ... 

SIM_SCGC4 |= SIM_SCGC4_SPI1_MASK; // turn clock on
SIM_SCGC5 |- SIM_SCGC5_PORTB_MASK;
SIM_SCGC5 |- SIM_SCGC5_PORTD_MASK;

PORTB->PCR[16] = PORT_PCR_MUX(2); // SPI_MOSI
PORTD->PCR[5] = PORT_PCR_MUX(2); // SPI_CLK

SPI1_C1 =  SPI_C1_SPE_MASK |  SPI_C1_MSTR_MASK |  SPI_C1_CPOL_MASK;

SPI1_C2 = SPI_C2_SPIMODE_MASK; // set 16 bit data

SPI1_BR = 4;

That should be it ... but I have to be missing something because it won't xmit!!!

the SPI1_S register always has the  SPTEF  flag set  which says the xmitter is empty so you can load data to send.

No movement of the MOSI or clock pins.

After 6 hours burning brain matter try to see what I've missed ... I'm asking ... I have to be missing something ... please tell me what.

Thanks.

Joe

15 Replies

1,345 Views
JHinkle
Senior Contributor I

SPI_DMA.png

I have found the documentation not very detailed.

Seems like the semi companies like NXP are putting a lot into the SDK's and not a lot of detail into the documentation.

I don't use the SDKs -- never will.  I want to understand and use the hardware directly.

Now that I'm off my soapbox -- I got DMA working and I thank Mark for suggesting it since I had not considered using it since all the channels are being used elsewhere.  The two processes do NOT overlap so I can flip-flip DMA channel between SPI and my other hardware.

To save anyone from trail and error as I just had to go thru ...

Incoming SPI packets are 16 bits.

Here's the DMA setup 

DMA_SAR0 = (dword)&SPI1_DL;
DMA_DAR0 = (dword)Location_To_Place_SPI_Word;
DMA_DSR_BCR0 = (Expected_Number_SPI_Words << 1); // make bytes
DMA_DCR0 = DMA_DCR_EINT_MASK | // enable interrupt at end of xfer
DMA_DCR_ERQ_MASK | // Enable Peripheral Request
DMA_DCR_CS_MASK | // Cycle Steal
//DMA_DCR_SINC_MASK | // source INC ... no source increment
DMA_DCR_SSIZE(2) | // 16 bit inc
DMA_DCR_DINC_MASK |   // .... destination inc by 2
DMA_DCR_DSIZE(2) | // 16 bit
DMA_DCR_D_REQ_MASK; // DMA hardware automatically clears the corresponding DCRn[ERQ] bit when the byte count register reaches 0.

A DMA to DL (with size set for 16 bits) will actually acquire the 16 bit data 

Thanks again Mark --- this direction just cut my total transfer time in half.

The ONLY way the KL will do SPI at 12 MHZ is using DMA!!!  

You will actually be tight doing interrupt based SPI at a clock speed of 6 MHZ.

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Mark:

My whole problem I had starting to use the SPI on the KL was that the data register is NOT a 16 bit reg -- it's two 8 bit registers that must be read separately.

I'm attempting to do a dma - spi test -- but my concerns come back about the register size.

The KL documentation states that DMA can be used but does not state that it can be used for 16 - 8 bit is given.

Example -- what register do you assign to the DMA source .. DL or DH.  Little endian suggest DL but I don't think DH will get accessed by the DMA controller since it thinks the source is 16 bit capable (KL DMA is not like DMA on a K series micro where you can have inner and outer loops).  That's were my original issue occurred -- I was attempting a 16 bit read and it does NOTHING unless bot 8 bit regs (DH:DL) are read.

I'm asking because it takes about 4 hours to revamp the code in both projects to do the test and my gut says it won't work for 16 bits.

Any insight?

Thanks.

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Mark:

I my case, there are only 3 interrupts.  ARM TIC, UART, and SPI.

I have the SPI  a higher priority (lower number) than the UART and the design is such that there should be no uart activity while the spi is active.

The KL is a slave daughter board to the main K64 board.  The KL is used for dedicated hardware processing with very controlled timing between process phases so it can work nearly 90% of the time.

The spi is used to pump 6k of data down to the KL board every 25 msec.  I need to get the data transferred as quickly as possible because the time in between these transfers is used to process it.  I looked into backing down the spi clock to 6 MHZ but the overall time to transfer the data goes up about 5% so, for me, its better to extend the delay between each packet and keep the speed up.  

Running the spi at 6MHZ, give a packet timing of 2.7usec (16 bits at 6mhz), then you add a gap delay between packets... even the smallest allowed, and the transfer speed is slower.

I did not consider using DMA because I am using the 4 DMA channels to actually crunch the data in between transfers but I need to re look at that and see what  play out.  

Thanks fot the suggestion.

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Forgot the PIC.

SPI_TEST.png

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Well - I apologize for this thread.

Issue was entirely mine.

Got so use to working with faster micros, I forgot to think about the actual time required to process the IRQ on a M0+ micro.

I added a toggle pin the the SPI interrupt routine (it adds additional time).

The bottom trace is the pin toggle.  You can clearly see the latency with entering the interrupt and then the amount of time to process it.

My added delay was required to make sure the IRQ process had completed prior to another packet arriving.

Must be getting old to easily miss that.

Thanks for all the comments above.

Joe

0 Kudos
Reply

1,345 Views
mjbcswitzerland
Specialist V

Joe

I think that you missed showing the IRQ timing diagram (?)

If the IRQ is the limiting factor and overruns may take place you may also need to consider what happens when other interrupts are being processed at the same time (eg. do you use re-entrant interrupts that allow a lower priority one to be interrupted? Or do you intend to increase the gap to respect the worst case at the SPI receiver, which may be several times that of the present case in a complete system?).

Once the worst case is known, it may be better to reduce the SPI clock rate rather than add delays since it will accurately dictate the interrupt speed without the delays, which may change based on compiler optimisation or compiler version in case realised as a delay loop at the Tx.

In such cases where it looks like interrupt latency may be a potential problem it is probably also best to implement a DMA driver Rx buffer to reduce or remove such impact (or potential unreliability in case of exceptional latency that may only happen rarely). DMA + buffer should allow 12Mb/s again.

Don't forget that you look to be showing that the m0+ is spending close to 100% of its time handling the SPI IRQ when you set the present SPI equivalent speed of around 6Mb/s so there is close to no power remaining for other activities; depending on the overall requirements you may like to specify a maximum loading for this particular task so that all other tasks can achieve there work (task meaning "work" and not necessarily an OS instance).

Regards

Mark

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Kerry:

The SPI clock is running at 12 mhz (it's the upper limit for the KL17).

Using two K micros I was able to keep the timing between the packets very small.

On the KL I had to increase the time delay between the packets by 4 times or the KL would miss packets.

For the test I was polling.  Process was simply read 16 bits, write to buffer, inc buffer count, compare buffer count to max allowed, start again.

I was sending a group of 6 - 16 bit packets.  The issue was the reception of the sixth packet -- it was being missed.  I had to extend the gap size to finally acquire the last packet.

Timing for the reception of 16 bits at 12 mhz is 1.3 usec.

The KL runs really slow at 48 mhz.  The SPI on the KL does not have any kind of an overflow flag.

I had not thought of it at the time but maybe the KL is just not fast enough.  Had I considered it, I would have toggled a pin before and after the capture process and compared it to the timing of the spi packets.  Maybe my 6 packet test was the boundary condition where it takes more time to process the packet compared to packet timing and over 5 packets .. it skipped one.

I'll have to go back and re-look at this.  The issue may be my expectations of a KL working with a 12MHZ SPI ... might not be possible. 

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

I'm normally working with the K or V series micros.

This is my first application where I use a MO+ micro.

There is a reason the silicon is cheaper - the behavior changes of at least the SPI compared to a K series.

I started with the transmission parameters I've used when using SPI between two K micros.  Here is the timing for 6 - 16bit words being sent.

KL17_1.png

Notice the size of the gap between words compared to the size of the word.  I say that because the next pic is not to the same scale.

My problem is  ---- the KL17 does NOT properly acquire That set of 6 words with the inter gap shown.  I had to extend the gap to 4 times that size!!!!!!!! to get the KL17 to properly acquire.

KL17_2.png

You can see the timing of the first transmission took about 10 usec while the second timing takes over 15 usec.

I tried byte size packets instead of words and it gets worse since the inner gap has to be between bytes --- so it over 20 usec in length.

Just thought I's share to maybe save someone else some time 

Not all SPI's are created equal!!!

Joe

0 Kudos
Reply

1,345 Views
kerryzhou
NXP TechSupport
NXP TechSupport

Hi Joe,

     Thank you for your experience sharing.

    Did you use the same code from K or KV?

   K and KV have higher core frequency than KL.

   Actually, the gap between the SPI Byte is mainly controlled by your code, if you want to have smaller gap, just use short delay in your KL project.

Wish it helps you!

Have a great day,
Kerry

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Got it working.

Thanks Mark for your comments.

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

I already do that when I enable the interrupt .. make sure the first one is not garbage.

I switched over to my actual need -- and that's to read.

I have two boards (a K64 sending SPI to the KL17 receiving it).

I have a logic probe that captures the data stream to make sure all is well.

I now have the KL17 generating an interrupt when data arrives .. my problem is ... the data at DL is always zero. (note:  I switched to 8 bit mode until I get thing working).

Any ideas as to why the captured data is zero?

I wanted to make sure that the MOSI pin was actually reaching the board connector -- that's why I did the transmit test.  The KL17 send data on the MOSI pin so it should receive data on the same pin when in slave mode.

Joe

0 Kudos
Reply

1,345 Views
JHinkle
Senior Contributor I

Thanks Mark.

Before I saw your post, I did it get to xmit.

My mistake ... I assumed since the K17 was a 32 bit device that writing to DL would also write to DH.

Wrong!.  When I changed to 8 bit transmission and wrote to DL -- it worked. 

Not sure of your post ... (void)SPI1_D;   .. there no definition for SPI1_D unless it's attempt to write to both registers with with a single write.

Now ... I have to get it to read -- since THAT is what the application requires.  I switched to transmit to make sure I had an understanding of it's operation.

Joe

0 Kudos
Reply

1,345 Views
mjbcswitzerland
Specialist V

Joe

SPI1_D is in fact a byte read of SPI1_DL.

The two reads are to ensure that flags are in their correct initial state so may be needed for reading too (without them it is possible that code waiting on flags will fail the first time).

Regards

Mark

0 Kudos
Reply

1,345 Views
mjbcswitzerland
Specialist V

Joe

Try adding this after config and before use:

(void)SPI1_S;
(void)SPI1_D;

Then you may find that it works.

Regards

Mark
Kinetis for professionals: http://www.utasker.com/kinetis.html

1,345 Views
andrewpikul
Contributor I

Hey Joe,

    If you have FIFO mode on that model, use it- it's a lot easier. You have to read SPI1_S and read the DATA register before you can transmit without it, apparently.

Are you scoping for the transmit or clock?

Are you sure you're not throwing an exception before getting through your whole SPI sequence?

PORTD and PORTB clocks don't need to be turned on unless you're using them as GPIO, as far as I know (we don't turn them on). We use D4,5,6, and 7. 

We also use MODFEN = 1 and SSOE for automatic CS... but we've done manual CS with GPIOs.

edit: fyi, we use the kl03 and kl43

0 Kudos
Reply