Baremetal SPI example for K64

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

Baremetal SPI example for K64

6,283 Views
drew_k
Contributor III

Does anyone have a baremetal example for the SPI peripherals on the K64, ideally working in Master mode? Alternatively, a decent functional walkthrough would work too. The SPI documentation in the K64 Reference Manual leaves a lot to be desired. (Edit: To clarify, I'm using the TWR-K64F12M so the specific chip is the PK64FN1M0VMD12 - 144pin BGA)

Currently I'm running into trouble getting  transmission to occur. I've configured my SPI1 in the following manner:

MCR:

  • Master Mode
  • Continuous SCK disabled
  • SPI configuration
  • Freeze disabled
  • Modified format disabled.
  • PCS Strobe Disabled
  • RX Fifo Overwrite enabled
  • PCS inactive high for all PCS pins.
  • Doze disabled
  • Module ENabled (MDIS cleared)
  • TX FIFO enabled (DIS_TXF cleared)
  • RX FIFIO enabled (DIS_RXF cleared)
  • Sample point, 0 cycles,
  • Halt disabled.

CTAR 0:

  • Double baud rate disabled
  • Frame size - 8 bits
  • SCK Inactive high
  • MSB first
  • Various timing prescalers to 1
  • Baud Prescaler  = 2
  • Timing scalers = 2
  • Baud Rate Scaler = 32 (Running a 60Mhz bus clock so this gives me a 975kHz SCK frequency)

(CTAR1 is unused)

After configuring the SPI and setting proper pin mux values, I'm trying to push 2 bytes out over the bus to a daq chip I've got just to read the device ID registers. I create a 2-byte buffer, and pass it to my SPI_Push_Bytes function that loops through the buffer for a specified number of bytes, builds the command value from specified pcs and ctar selection settings (both 0 in this case), and appends the current byte before writing the PUSHR register with the new value. When I put a breakpoint after that write I can clearly see the PUSHR and TXFR0 values update for the first byte. When the function loops back around to the second byte, it again formats the PUSHR value correctly, but seems to be overwriting the TXFR0 value and nothing is transmitting.

I'm configuring the command for that last byte to include the "End of Queue" trigger and then am waiting for the SR[EOQF] flag to get set but it never does, so clearly nothing is happening at all.  Is there a step I'm missing somewhere? Some flag that needs to be set or cleared before the transmitter becomes active? I've enabled the clock gate from the SIM and have gone through the SPI register documentation multiple times but can't seem to find what I'm missing. As far as I'm aware, everything is configured properly to start the transfers according to pg 1470 in the reference manual:

  • SR[EOQF] is clear,
  • MCR[FRZ] is clear so debugging doesn't stop serial transfers, and
  • MCR[HALT] is clear so the device should be in the running state.

Any help would be appreciated.

-Drew

12 Replies

3,265 Views
mjbcswitzerland
Specialist V

Hi Drew

You didn't mention which SPI interface you are using.

The K64 has three SPIs - SPI0 has a FIFO of depth 4 but the others (SPI1 and SPI2) have only a single byte depth so is not compatible).

If you use SPI0 it is compatible with the DSPI in all other regular Kinetis parts.

Regards

Mark

Kinetis: µTasker Kinetis support

K64: µTasker Kinetis FRDM-K64F support / µTasker Kinetis TWR-K64F120M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

3,266 Views
drew_k
Contributor III

Well that is almost certainly part of the problem - I'm using SPI1. Can you point me to what doc says that? I'm just curious because I didn't come across that anywhere. I'll rework to send a byte at a time and see if things change tomorrow.

0 Kudos
Reply

3,266 Views
mjbcswitzerland
Specialist V

Drew

pastedImage_0.png

Regards

Mark

Kinetis: µTasker Kinetis support

K64: µTasker Kinetis FRDM-K64F support / µTasker Kinetis TWR-K64F120M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

3,266 Views
drew_k
Contributor III

?? Was there supposed to be something in that reply? If so I can't see it.

0 Kudos
Reply

3,266 Views
mjbcswitzerland
Specialist V

Drew

Yes, the image went missing (this tends to happen sometimes) so I just edited it back in.

Regards

Mark

Kinetis: µTasker Kinetis support

K64: µTasker Kinetis FRDM-K64F support / µTasker Kinetis TWR-K64F120M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

3,266 Views
drew_k
Contributor III

Well... upon further inspection I realized I'm an idiot. Somehow I forgot to specify the frame size in my CTAR0 configuration and when I wrote the other settings I was setting FMSZ to 0, which is obviously invalid. Fixed that and now transmission is occurring.

Thanks for the assistance!

-Drew Kelley

0 Kudos
Reply

3,266 Views
drew_k
Contributor III

Hey Mark,

so I'm still having trouble getting the transmission to actually occur. It's populating the TXFR0 register just fine but my scope isn't showing any output on the SPI bus, the FIFO isn't clearing and the TCR register isn't updating. Seems like I've forgotten to enable something somewhere but I'm not sure what.

Is there anything I'm forgetting in those configuration settings I posted in the initial post?

Thanks,

Drew

Edit: Sorry for not getting back to you sooner, I got sidetracked with a separate project at work.

0 Kudos
Reply

3,266 Views
mjbcswitzerland
Specialist V

Hi Drew

I can't see from your description since it is not showing the actual values but I assume that the pin MUX is OK, whereby this woudln't stop the output being send, but just not show it on the pin(s) if it were not set correctly.

Below is code from the uTasker project for K64 SPI1 as comparison.

Configuration (ports and SPI1):

_CONFIG_PERIPHERAL(D, 4, (PD_4_SPI1_PCS0 | PORT_DSE_HIGH | PORT_PS_UP_ENABLE | PORT_SRE_FAST));

_CONFIG_PERIPHERAL(D, 6, (PD_6_SPI1_SOUT | PORT_DSE_HIGH | PORT_PS_UP_ENABLE | PORT_SRE_FAST));

_CONFIG_PERIPHERAL(D, 7, (PD_7_SPI1_SIN | PORT_PS_UP_ENABLE));

_CONFIG_PERIPHERAL(D, 5, (PD_5_SPI1_SCK  | PORT_DSE_HIGH | PORT_PS_UP_ENABLE | PORT_SRE_FAST))

POWER_UP(6, SIM_SCGC6_SPI1);

SPI1_MCR = (SPI_MCR_MSTR | SPI_MCR_DCONF_SPI | SPI_MCR_CLR_RXF | SPI_MCR_CLR_TXF | SPI_MCR_PCSIS_CS0 | SPI_MCR_PCSIS_CS1 | SPI_MCR_PCSIS_CS2 | SPI_MCR_PCSIS_CS3 | SPI_MCR_PCSIS_CS4 | SPI_MCR_PCSIS_CS5);\

SPI1_CTAR0 = (SPI_CTAR_ASC_10 | SPI_CTAR_PBR_3 | SPI_CTAR_DBR | SPI_CTAR_FMSZ_8 | SPI_CTAR_PDT_7 | SPI_CTAR_BR_4 | SPI_CTAR_CPHA | SPI_CTAR_CPOL); // for 120MHz system, 10MHz speed

To send a byte to the SPI it uses the macro:

#define WRITE_SPI(byte)                  SPI1_PUSHR = (byte | SPI_PUSHR_CONT | SPI_PUSHR_PCS0 | SPI_PUSHR_CTAS_CTAR0) // write a single byte to the output FIFO - assert CS0 line

(when sending a final byte where the CS0 line shoudl be deasserted automatically after transmission, SPI_PUSHR_CONT can be replaced by SPI_PUSHR_EOQ)

However, before sending data it is important to ensure that the FIFO has been flushed and the status flags reset; this can be done with the macro:

#define FLUSH_SPI_FIFO_AND_FLAGS()              SPI1_MCR |= SPI_MCR_CLR_RXF; SPI1_SR = (SPI_SR_EOQF | SPI_SR_TFUF | SPI_SR_TFFF | SPI_SR_RFOF | SPI_SR_RFDF)

If that doesn't help there is a binary that runs on the FRDM-K64F which controls a Nordic Semiconductor 2.4GHz wireless transceiver nRF24L01+ on SPI1 (connected to the RF socket) at

http://www.utasker.com/kinetis/FRDM-K64F.html

that will regularly try to connunicate with the device.

You could connect the debugger and check the SPI1 register settings.

Regards

Mark

Kinetis: µTasker Kinetis support

K64: µTasker Kinetis FRDM-K64F support / µTasker Kinetis TWR-K64F120M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

0 Kudos
Reply

3,266 Views
rafaeltoledo
Contributor III

Hi Mark,

I'm trying to find a simple SPI Baremetal example code for K64F to learn about the registers configuration and communication, but this has been a hard task.

You have any simple example to provide?

0 Kudos
Reply

3,266 Views
mjbcswitzerland
Specialist V

Raphael

I have attached a low level interface to an ATMEL SPI Flash as reference.

Below are the macros used by the K64:

#define CS0_LINE                    SPI_PUSHR_PCS0           // CS0 line used when SPI FLASH is enabled

#define POWER_UP_SPI_FLASH_INTERFACE()  POWER_UP(6, SIM_SCGC6_SPI0)

define CONFIGURE_SPI_FLASH_INTERFACE() _CONFIG_PERIPHERAL(D, 0, (PD_0_SPI0_PCS0 | PORT_SRE_FAST | PORT_DSE_HIGH));\
                                       _CONFIG_PERIPHERAL(D, 1, (PD_1_SPI0_SCK | PORT_SRE_FAST | PORT_DSE_HIGH));\
                                       _CONFIG_PERIPHERAL(D, 2, (PD_2_SPI0_SOUT | PORT_SRE_FAST | PORT_DSE_HIGH));\
                                       _CONFIG_PERIPHERAL(D, 3, (PD_3_SPI0_SIN));\
                                       SPI0_MCR = (SPI_MCR_MSTR | SPI_MCR_DCONF_SPI | SPI_MCR_CLR_RXF | SPI_MCR_CLR_TXF | SPI_MCR_PCSIS_CS0 | SPI_MCR_PCSIS_CS1 | SPI_MCR_PCSIS_CS2 | SPI_MCR_PCSIS_CS3 | SPI_MCR_PCSIS_CS4 | SPI_MCR_PCSIS_CS5);\
                                       SPI0_CTAR0 = (SPI_CTAR_DBR | SPI_CTAR_FMSZ_8 | SPI_CTAR_PDT_7 | SPI_CTAR_BR_2 | SPI_CTAR_CPHA | SPI_CTAR_CPOL); // for 50MHz bus, 25MHz speed and 140ns min de-select time

#define POWER_DOWN_SPI_FLASH_INTERFACE() POWER_DOWN(6, SIM_SCGC6_SPI0) // power down SPI interface if no SPI Flash detected

#define FLUSH_SPI_FIFO_AND_FLAGS() SPI0_MCR |= SPI_MCR_CLR_RXF; SPI0_SR = (SPI_SR_EOQF | SPI_SR_TFUF | SPI_SR_TFFF | SPI_SR_RFOF | SPI_SR_RFDF);

#define WRITE_SPI_CMD0(byte)       SPI0_PUSHR = (byte | SPI_PUSHR_CONT | ulChipSelectLine | SPI_PUSHR_CTAS_CTAR0) // write a single byte to the output FIFO - assert CS line
#define WRITE_SPI_CMD0_LAST(byte)  SPI0_PUSHR = (byte | SPI_PUSHR_EOQ  | ulChipSelectLine | SPI_PUSHR_CTAS_CTAR0) // write final byte to output FIFO - this will negate the CS line when complete
#define READ_SPI_FLASH_DATA()      (unsigned char)SPI0_POPR
#define WAIT_SPI_RECEPTION_END()   while ((SPI0_SR & SPI_SR_RFDF) == 0) {}
#define CLEAR_RECEPTION_FLAG()     SPI0_SR |= SPI_SR_RFDF
#define SET_SPI_FLASH_MODE()                                     // this can be used to change SPI settings on-the-fly when the SPI is shared with SPI Flash and other devices
#define REMOVE_SPI_FLASH_MODE()                                  // this can be used to change SPI settings on-the-fly when the SPI is shared with SPI Flash and other devices

Beware however that the K64 has 3 SPIs that are not identical - only the first one (SPI0) has a 4-deep FIFO and the others have only one depth, which means that the code making use of the buffering is only operational on SPI0.

The complete code is available at KINETIS Project Code and it can be simulated using VisualStudio in case you need to learn about the details invoved.

Regards

Mark

Kinetis: µTasker Kinetis support

K64: µTasker Kinetis FRDM-K64F support  / µTasker Kinetis TWR-K64F120M support  / µTasker Kinetis TWR-K65F180M support

For the complete "out-of-the-box" Kinetis experience and faster time to market

3,266 Views
drew_k
Contributor III

I appreciate the example Mark! I work for a company that is bound by ITAR regulations so to avoid any potential problems I just never post code. I doubt I'd be violating anything by posting an SPI configuration but better safe than sorry. Otherwise I'd have posted my code first thing. Turns out I'm just an idiot and did indeed have something misconfigured with my CTAR0 reg (see my other reply - hopefully we're not posting over each other... haha).

Thanks again for the help!

Drew

0 Kudos
Reply

3,266 Views
drew_k
Contributor III

Oh wow, I stared right at that page and missed it :smileyplain:. Embarrassing...The SPI section of the "Chip Configuration" chapter seems to be only one that provides any useful information about the peripheral it's supposedly describing! Lol. Thanks for that... Still haven't gotten around to reworking for single-byte fifo but I'll check in once I do with an update this afternoon/evening.

0 Kudos
Reply