Author Topic: Using SPI master in the uTasker project  (Read 10521 times)

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3240
    • View Profile
    • uTasker
Using SPI master in the uTasker project
« on: October 18, 2015, 03:49:58 PM »
Hi All

Since SPI usage is very particular to different slave devices it is realised based on macros which can be found in app_hw_xxxx.h for each board.
[app_hw_xxxx.h is processor family dependent, whereby xxxx specifies the type, such as app_hw-kinetis.h]

Generally it is advised to use the SPI SD card or an SPI Flash [eg. spi_flash_xxxx_atmel.h] interface as reference, whereby the following example is valid for Kinetis KL parts (other processors and sub-families may vary in the detail but the priciple remains true - see the specific references for the full details)

For example, SPI configuration for the pins that are used is something like:

        // Configure to suit special connection SPI mode at between 100k and 400k (SPI0)
        //
        #define SPI_CS1_0              PORTC_BIT4
        #define INITIALISE_SPI_SD_INTERFACE() POWER_UP(4, SIM_SCGC4_SPI0); \
        _CONFIG_PERIPHERAL(C, 5, PC_5_SPI0_SCK); \
        _CONFIG_PERIPHERAL(C, 6, (PC_6_SPI0_MOSI | PORT_SRE_FAST | PORT_DSE_HIGH)); \
        _CONFIG_PERIPHERAL(C, 7, (PC_7_SPI0_MISO | PORT_PS_UP_ENABLE)); \
        _CONFIG_DRIVE_PORT_OUTPUT_VALUE(C, SPI_CS1_0, SPI_CS1_0, (PORT_SRE_FAST | PORT_DSE_HIGH)); \
        SPI0_C1 = (SPI_C1_CPHA | SPI_C1_CPOL | SPI_C1_MSTR | SPI_C1_SPE); \
        SPI0_BR = (SPI_BR_SPPR_PRE_8 | SPI_BR_SPR_DIV_16); \
        (void)SPI0_S; (void)SPI0_D


which is used by the FRDM-KL27Z for its SD card interface (the last two instructions are required to prepare the SPI for use).


The SPI master speed is set by the SPI0_BR values - depending on the clock rate the prescaler and divide settings are chosen to give the required frequency. The values above are for 48MHz clock operation to give 375kHz SPI (48MHz/8/16)

The clock polarity and phase are configured in SPI0_C1
SPI_C1_CPHA | SPI_C1_CPOL
is 3 and with them removed it gives mode 0.

Master mode is controlled by SPI_C1_MSTR (without it it would be a slave)

To write to the SPI the macro

#define WRITE_SPI_CMD(byte)    SPI0_D = (byte)
is used.
To read
#define READ_SPI_DATA()        (unsigned char)SPI0_D

Note that it is usually necessary to wait until a byte transmission/reception has terminated:

#define WAIT_TRANSMISSON_END() while ((SPI0_S & (SPI_S_SPRF)) == 0) {}

Finally note that the SPI in the KL27 has no automatic chip select line control so a port output is also configured during initialisation.
To control the chip select line macros are also used:
        #define SET_SD_CS_LOW()      _CLEARBITS(C, SPI_CS1_0)            // assert the CS line of the SD card to be read
        #define SET_SD_CS_HIGH()     _SETBITS(C, SPI_CS1_0)              // negate the CS line of the SD card to be read



Generally the initialisation must be called once:

INITIALISE_SPI_SD_INTERFACE();


Then data can be sent and returned data from the slave read using the sequence:

SET_SD_CS_LOW();
WRITE_SPI_CMD(0x55);
WAIT_TRANSMISSON_END();
ucReceivedByte = READ_SPI_DATA();
SET_SD_CS_LOW();


This assumes that the CS line has to be asserted (low) around the Tx/Rx.

If the returned data is not required by teh code, it should normally still be read
(void)READ_SPI_DATA();
in order to clear the buffer and reset flags for the next use.

Loops can be inserted round the tx/rx code in order to transmit or read multiple bytes of data.


Based on these macros it is possible to write custom SPI code to control slve devices that have a high degree of portability and moving between interfaces, eg. SPI0 to SPI1 would require just editing the registers used in the macros.
Some SPI designs (in the processor) may vary slightly - for example some may have FIFOs to allow multiple writes to be prepared without waiting for the first to complete, or allow the SPI master to automatically control the chip select line - but the above is usually a good starting point and the additional capabilities can then be enabled in order to possibly optimise in a certain case.

Regards

Mark