import { _ as _export_sfc, c as createElementBlock, o as openBlock, a8 as createStaticVNode } from "./chunks/framework.B9AX-CPi.js"; const __pageData = JSON.parse('{"title":"SPI Master Driver","description":"","frontmatter":{},"headers":[],"relativePath":"drivers/spi.md","filePath":"drivers/spi.md"}'); const _sfc_main = { name: "drivers/spi.md" }; const _hoisted_1 = /* @__PURE__ */ createStaticVNode('

SPI Master Driver

The SPI Master drivers used in QMK have a set of common functions to allow portability between MCUs.

Usage

In most cases, the SPI Master driver code is automatically included if you are using a feature or driver which requires it, such as OLED.

However, if you need to use the driver standalone, add the following to your rules.mk:

make
SPI_DRIVER_REQUIRED = yes

You can then call the SPI API by including spi_master.h in your code.

AVR Configuration

No special setup is required - just connect the SS, SCK, MOSI and MISO pins of your SPI devices to the matching pins on the MCU:

MCUSSSCKMOSIMISO
ATmega16/32U2/4B0B1B2B3
AT90USB64/128/162B0B1B2B3
ATmega32AB4B7B5B6
ATmega328/PB2B5B3B4

You may use more than one slave select pin, not just the SS pin. This is useful when you have multiple devices connected and need to communicate with them individually. SPI_SS_PIN can be passed to spi_start() to refer to SS.

ChibiOS/ARM Configuration

You'll need to determine which pins can be used for SPI -- as an example, STM32 parts generally have multiple SPI peripherals, labeled SPI1, SPI2, SPI3 etc.

To enable SPI, modify your board's halconf.h to enable SPI:

c
#define HAL_USE_SPI TRUE\n#define SPI_USE_WAIT TRUE\n#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD

Then, modify your board's mcuconf.h to enable the peripheral you've chosen, for example:

c
#undef STM32_SPI_USE_SPI2\n#define STM32_SPI_USE_SPI2 TRUE

Configuration-wise, you'll need to set up the peripheral as per your MCU's datasheet -- the defaults match the pins for a Proton-C, i.e. STM32F303.

config.h OverrideDescriptionDefault
SPI_DRIVERSPI peripheral to use - SPI1 -> SPID1, SPI2 -> SPID2 etc.SPID2
SPI_SCK_PINThe pin to use for SCKB13
SPI_SCK_PAL_MODEThe alternate function mode for SCK5
SPI_MOSI_PINThe pin to use for MOSIB15
SPI_MOSI_PAL_MODEThe alternate function mode for MOSI5
SPI_MISO_PINThe pin to use for MISOB14
SPI_MISO_PAL_MODEThe alternate function mode for MISO5

As per the AVR configuration, you may choose any other standard GPIO as a slave select pin, which should be supplied to spi_start().

If a complete SPI interface is not required, then the following can be done to disable certain SPI pins, so they don't occupy a GPIO unnecessarily:

API

void spi_init(void)

Initialize the SPI driver. This function must be called only once, before any of the below functions can be called.


bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor)

Start an SPI transaction.

Arguments

Return Value

false if the supplied parameters are invalid or the SPI peripheral is already in use, or true.


spi_status_t spi_write(uint8_t data)

Write a byte to the selected SPI device.

Arguments

Return Value

SPI_STATUS_TIMEOUT if the timeout period elapses, or SPI_STATUS_SUCCESS.


spi_status_t spi_read(void)

Read a byte from the selected SPI device.

Return Value

SPI_STATUS_TIMEOUT if the timeout period elapses, or the byte read from the device.


spi_status_t spi_transmit(const uint8_t *data, uint16_t length)

Send multiple bytes to the selected SPI device.

Arguments

Return Value

SPI_STATUS_TIMEOUT if the timeout period elapses, SPI_STATUS_ERROR if some other error occurs, otherwise SPI_STATUS_SUCCESS.


spi_status_t spi_receive(uint8_t *data, uint16_t length)

Receive multiple bytes from the selected SPI device.

Arguments

Return Value

SPI_STATUS_TIMEOUT if the timeout period elapses, SPI_STATUS_ERROR if some other error occurs, otherwise SPI_STATUS_SUCCESS.


void spi_stop(void)

End the current SPI transaction. This will deassert the slave select pin and reset the endianness, mode and divisor configured by spi_start().

', 61); const _hoisted_62 = [ _hoisted_1 ]; function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { return openBlock(), createElementBlock("div", null, _hoisted_62); } const spi = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]); export { __pageData, spi as default };