SPI

SPI (Serial Peripheral Interface) is a synchronous 4-wire serial interface commonly used to connect components in embedded systems.

For a detailed description of SPI, see Wikipedia.

Description

The Mynewt HAL interface supports the SPI master functionality with both blocking and non-blocking interface. SPI slave functionality is supported in non-blocking mode.

Theory Of Operation

SPI is called a 4-wire interface because of the 4 signals, MISO, MOSI, CLK, and SS. The SS signal (slave select) is an active low signal that activates a SPI slave device. This is how a master “addresses” a particular slave device. Often this signal is also referred to as “chip select” as it selects particular slave device for communications.

The Mynewt SPI HAL has blocking and non-blocking transfers. Blocking means that the API call to transfer a byte will wait until the byte completes transmissions before the function returns. Blocking interface can be used for only the master slave SPI type. Non-blocking means he function returns control to the execution environment immediately after the API call and a callback function is executed at the completion of the transmission. Non-blocking interface can be used for both master and slave SPI types.

The hal_spi_config method in the API above allows the SPI to be configured with appropriate settings for master or slave. It Must be called after the spi is initialized (i.e. after hal_spi_init is called) and when the spi is disabled (i.e. user must call hal_spi_disable if the spi has been enabled through hal_spi_enable prior to calling this function). It can also be used to reconfigure an initialized SPI (assuming it is disabled as described previously).

int hal_spi_config(int spi_num, struct hal_spi_settings *psettings);

The SPI settings consist of the following:

struct hal_spi_settings {
    uint8_t         data_mode;
    uint8_t         data_order;
    uint8_t         word_size;
    uint32_t        baudrate;           /* baudrate in kHz */
};

The Mynewt SPI HAL does not include built-in SS (Slave Select) signaling. It’s up to the hal_spi user to control their own SS pins. Typically applications will do this with GPIO.

API

typedef void (*hal_spi_txrx_cb)(void *arg, int len)
int hal_spi_init(int spi_num, void *cfg, uint8_t spi_type)

Initialize the SPI, given by spi_num.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: The number of the SPI to initialize

  • cfg: HW/MCU specific configuration, passed to the underlying implementation, providing extra configuration.

  • spi_type: SPI type (master or slave)

int hal_spi_init_hw(uint8_t spi_num, uint8_t spi_type, const struct hal_spi_hw_settings *cfg)

Initialize SPI controller.

This initializes SPI controller hardware before 1st use. Shall be called only once.

Return

0 on success, non-zero error code on failure

Parameters
  • spi_num: Number of SPI controller

  • cfg: Configuration

int hal_spi_config(int spi_num, struct hal_spi_settings *psettings)

Configure the spi.

Must be called after the spi is initialized (after hal_spi_init is called) and when the spi is disabled (user must call hal_spi_disable if the spi has been enabled through hal_spi_enable prior to calling this function). Can also be used to reconfigure an initialized SPI (assuming it is disabled as described previously).

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: The number of the SPI to configure.

  • psettings: The settings to configure this SPI with

int hal_spi_set_txrx_cb(int spi_num, hal_spi_txrx_cb txrx_cb, void *arg)

Sets the txrx callback (executed at interrupt context) when the buffer is transferred by the master or the slave using the non-blocking API.

Cannot be called when the spi is enabled. This callback will also be called when chip select is de-asserted on the slave.

NOTE: This callback is only used for the non-blocking interface and must be called prior to using the non-blocking API.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: SPI interface on which to set callback

  • txrx: Callback function

  • arg: Argument to be passed to callback function

int hal_spi_enable(int spi_num)

Enables the SPI.

This does not start a transmit or receive operation; it is used for power mgmt. Cannot be called when a SPI transfer is in progress.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num:

int hal_spi_disable(int spi_num)

Disables the SPI.

Used for power mgmt. It will halt any current SPI transfers in progress.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num:

uint16_t hal_spi_tx_val(int spi_num, uint16_t val)

Blocking call to send a value on the SPI.

Returns the value received from the SPI slave.

MASTER: Sends the value and returns the received value from the slave. SLAVE: Invalid API. Returns 0xFFFF

Return

uint16_t Value received on SPI interface from slave. Returns 0xFFFF if called when the SPI is configured to be a slave

Parameters
  • spi_num: Spi interface to use

  • val: Value to send

int hal_spi_txrx(int spi_num, void *txbuf, void *rxbuf, int cnt)

Blocking interface to send a buffer and store the received values from the slave.

The transmit and receive buffers are either arrays of 8-bit (uint8_t) values or 16-bit values depending on whether the spi is configured for 8 bit data or more than 8 bits per value. The ‘cnt’ parameter is the number of 8-bit or 16-bit values. Thus, if ‘cnt’ is 10, txbuf/rxbuf would point to an array of size 10 (in bytes) if the SPI is using 8-bit data; otherwise txbuf/rxbuf would point to an array of size 20 bytes (ten, uint16_t values).

NOTE: these buffers are in the native endian-ness of the platform.

MASTER: master sends all the values in the buffer and stores the
        stores the values in the receive buffer if rxbuf is not NULL.
        The txbuf parameter cannot be NULL.
SLAVE: cannot be called for a slave; returns -1

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: SPI interface to use

  • txbuf: Pointer to buffer where values to transmit are stored.

  • rxbuf: Pointer to buffer to store values received from peer.

  • cnt: Number of 8-bit or 16-bit values to be transferred.

int hal_spi_txrx_noblock(int spi_num, void *txbuf, void *rxbuf, int cnt)

Non-blocking interface to send a buffer and store received values.

Can be used for both master and slave SPI types. The user must configure the callback (using hal_spi_set_txrx_cb); the txrx callback is executed at interrupt context when the buffer is sent.

The transmit and receive buffers are either arrays of 8-bit (uint8_t) values or 16-bit values depending on whether the spi is configured for 8 bit data or more than 8 bits per value. The ‘cnt’ parameter is the number of 8-bit or 16-bit values. Thus, if ‘cnt’ is 10, txbuf/rxbuf would point to an array of size 10 (in bytes) if the SPI is using 8-bit data; otherwise txbuf/rxbuf would point to an array of size 20 bytes (ten, uint16_t values).

NOTE: these buffers are in the native endian-ness of the platform.

MASTER: master sends all the values in the buffer and stores the
        stores the values in the receive buffer if rxbuf is not NULL.
        The txbuf parameter cannot be NULL
SLAVE: Slave "preloads" the data to be sent to the master (values
       stored in txbuf) and places received data from master in rxbuf
       (if not NULL). The txrx callback occurs when len values are
       transferred or master de-asserts chip select. If txbuf is NULL,
       the slave transfers its default byte. Both rxbuf and txbuf cannot
       be NULL.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: SPI interface to use

  • txbuf: Pointer to buffer where values to transmit are stored.

  • rxbuf: Pointer to buffer to store values received from peer.

  • cnt: Number of 8-bit or 16-bit values to be transferred.

int hal_spi_slave_set_def_tx_val(int spi_num, uint16_t val)

Sets the default value transferred by the slave.

Not valid for master

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: SPI interface to use

int hal_spi_abort(int spi_num)

This aborts the current transfer but keeps the spi enabled.

NOTE: does not return an error if no transfer was in progress.

Return

int 0 on success, non-zero error code on failure.

Parameters
  • spi_num: SPI interface on which transfer should be aborted.

int hal_spi_data_mode_breakout(uint8_t data_mode, int *out_cpol, int *out_cpha)

Extracts CPOL and CPHA values from a data-mode constant.

Utility function, defined once for every MCU.

Return

0 on success; nonzero on invalid input.

Parameters
  • data_mode: The HAL_SPI_MODE value to convert.

  • out_cpol: The CPOL gets written here on success.

  • out_cpha: The CPHA gets written here on success.

HAL_SPI_TYPE_MASTER
HAL_SPI_TYPE_SLAVE
HAL_SPI_MODE0

SPI mode 0.

HAL_SPI_MODE1

SPI mode 1.

HAL_SPI_MODE2

SPI mode 2.

HAL_SPI_MODE3

SPI mode 3.

HAL_SPI_MSB_FIRST

SPI data order, most significant bit first.

HAL_SPI_LSB_FIRST

SPI data order, least significant bit first.

HAL_SPI_WORD_SIZE_8BIT

SPI word size 8 bit.

HAL_SPI_WORD_SIZE_9BIT

SPI word size 9 bit.

struct hal_spi_hw_settings
#include <hal_spi.h>

SPI controller hardware settings.

struct hal_spi_settings
#include <hal_spi.h>

since one spi device can control multiple devices, some configuration can be changed on the fly from the hal

Public Members

uint8_t data_mode

Data mode of SPI driver, defined by HAL_SPI_MODEn.

uint8_t data_order

Data order, either HAL_SPI_MSB_FIRST or HAL_SPI_LSB_FIRST.

uint8_t word_size

The word size of the SPI transaction, either 8-bit or 9-bit.

uint32_t baudrate

Baudrate in kHz.