SPI

Macros

SPI_OFFSET
0x204000

This macro defines the offset at which the SPI registers are located from the peripheral base.

SPI_SIZE
0x14

This macro holds the size of the I2C registers which needs to be mapped.

Configuration Macros

SPI_CS_CE0 Use chip enable 0
SPI_CS_CE1 Use chip enable 1
SPI_CS_CE2 Use chip enable 2
SPI_CPHA_CLK_BEGINNING Data on clock leading edge
SPI_CPHA_CLK_MIDDLE Data on clock trailing edge
SPI_CPOL_RESET_LOW Clock polarity: active low
SPI_CPOL_RESET_HIGH Clock polarity: active high
SPI_CSPOL_ACTIVE_LOW Chip enable: active low
SPI_CSPOL_ACTIVE_HIGH Chip enable: active high

Registers

volatile uint32_t *spi_base_ptr

This pointer points, when mapped, to the base of the SPI registers.

struct spi_register_map

This struct maps the registers of the SPI. The names of the struct members correspond to the registers from the Datasheet:

struct spi_register_map {
    uint32_t CS;
    uint32_t FIFO;
    uint32_t CLK;
    uint32_t DLEN;
    uint32_t LTOH;
    uint32_t DC;
};
SPI
#define SPI ((volatile struct spi_register_map *)spi_base_ptr)

By using this macro, the registers of the SPI can be accessed like this SPI->CS.

Structs

spi_channel_config_t

This struct is used to configure SPI:

typedef struct {
    union {
        struct {
            uint32_t: 2;
            uint32_t cpha: 1;
            uint32_t cpol: 1;
            uint32_t: 2;
            uint32_t cspol: 1;
            uint32_t: 14;
            uint32_t cspol0: 1;
            uint32_t cspol1: 1;
            uint32_t cspol2: 1;
        };
        uint32_t cs_register;
    };

    uint16_t divisor;
} spi_channel_config_t;
uint32_t cs_register

This member can be directly edited by the anonymous struct inside this union. This register maps directly to the CS register. The settings of this register are described in the Macros.

uint16_t divisor

The master clock divisor.

Note

The clock source is the core clock with a frequency, according to the Datasheet, of 150 MHz and according to this file and other sources of 250 MHz. When I tested the clock speed of I2C and SPI with a logic analyzer, it seems that 250 MHz is correct (at least for the Raspberry Pi Zero I use).

Functions

uint32_t * spi_map(void)

This function maps the SPI registers. It calls peripheral_map() with the values SPI_OFFSET and SPI_SIZE.

void spi_unmap(void)

This function unmaps the SPI registers.

void spi_configure(spi_channel_config_t *config)

This function configures SPI with a spi_channel_config_t pointed to by config.

void spi_set_ce(uint8_t ce)

This function sets which chip enable line the SPI controller should use. This can be a 3 bit value.

void spi_transfer_start(void)

This function starts a SPI transfer.

void spi_transfer_stop(void)

This function stops the current SPI transfer.

uint8_t spi_transfer_byte(uint8_t data)

While there is a SPI transfer active you can call this function as often as needed by the slave, to send and receive. This function needs to be called between spi_transfer_start() and spi_transfer_stop(), it sends data over SPI and asynchronously receives data and returns it.

uint8_t spi_send2_recv1(uint8_t data0, uint8_t data1)

This function writes to bytes of data and than keeps the clock running to receive and return the third byte. spi_transfer_start() and spi_transfer_stop() may not be called when using this function.