qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

spi.md (6627B)


      1 # SPI Master Driver {#spi-master-driver}
      2 
      3 The SPI Master drivers used in QMK have a set of common functions to allow portability between MCUs.
      4 
      5 ## Usage {#usage}
      6 
      7 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](../features/oled_driver).
      8 
      9 However, if you need to use the driver standalone, add the following to your `rules.mk`:
     10 
     11 ```make
     12 SPI_DRIVER_REQUIRED = yes
     13 ```
     14 
     15 You can then call the SPI API by including `spi_master.h` in your code.
     16 
     17 ## AVR Configuration {#avr-configuration}
     18 
     19 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:
     20 
     21 |MCU              |`SS`|`SCK`|`MOSI`|`MISO`|
     22 |-----------------|----|-----|------|------|
     23 |ATmega16/32U2/4  |`B0`|`B1` |`B2`  |`B3`  |
     24 |AT90USB64/128/162|`B0`|`B1` |`B2`  |`B3`  |
     25 |ATmega32A        |`B4`|`B7` |`B5`  |`B6`  |
     26 |ATmega328/P      |`B2`|`B5` |`B3`  |`B4`  |
     27 
     28 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.
     29 `SPI_SS_PIN` can be passed to `spi_start()` to refer to `SS`.
     30 
     31 ## ChibiOS/ARM Configuration {#arm-configuration}
     32 
     33 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.
     34 
     35 To enable SPI, modify your board's `halconf.h` to enable SPI, then modify your board's `mcuconf.h` to enable the peripheral you've chosen:
     36 
     37 ::: code-group
     38 ```c [halconf.h]
     39 #pragma once
     40 
     41 #define HAL_USE_SPI TRUE // [!code focus]
     42 
     43 #include_next <halconf.h>
     44 ```
     45 ```c [mcuconf.h]
     46 #pragma once
     47 
     48 #include_next <mcuconf.h>
     49 
     50 #undef STM32_SPI_USE_SPI2 // [!code focus]
     51 #define STM32_SPI_USE_SPI2 TRUE // [!code focus]
     52 ```
     53 :::
     54 
     55 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.
     56 
     57 |`config.h` Override|Description                                                  |Default|
     58 |-------------------|-------------------------------------------------------------|-------|
     59 |`SPI_DRIVER`       |SPI peripheral to use - SPI1 -> `SPID1`, SPI2 -> `SPID2` etc.|`SPID2`|
     60 |`SPI_SCK_PIN`      |The pin to use for SCK                                       |`B13`  |
     61 |`SPI_SCK_PAL_MODE` |The alternate function mode for SCK                          |`5`    |
     62 |`SPI_MOSI_PIN`     |The pin to use for MOSI                                      |`B15`  |
     63 |`SPI_MOSI_PAL_MODE`|The alternate function mode for MOSI                         |`5`    |
     64 |`SPI_MISO_PIN`     |The pin to use for MISO                                      |`B14`  |
     65 |`SPI_MISO_PAL_MODE`|The alternate function mode for MISO                         |`5`    |
     66 
     67 As per the AVR configuration, you may choose any other standard GPIO as a slave select pin, which should be supplied to `spi_start()`.
     68 
     69 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:
     70  - in `config.h`: `#define SPI_MISO_PIN NO_PIN`
     71  - in `config.h`: `#define SPI_MOSI_PIN NO_PIN`
     72  - in `mcuconf.h`: `#define SPI_SELECT_MODE SPI_SELECT_MODE_NONE`, in this case the `slavePin` argument passed to `spi_start()` may be `NO_PIN` if the slave select pin is not used.
     73 
     74 ## API {#api}
     75 
     76 ### `void spi_init(void)` {#api-spi-init}
     77 
     78 Initialize the SPI driver. This function must be called only once, before any of the below functions can be called.
     79 
     80 ---
     81 
     82 ### `bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor)` {#api-spi-start}
     83 
     84 Start an SPI transaction.
     85 
     86 #### Arguments {#api-spi-start-arguments}
     87 
     88  - `pin_t slavePin`  
     89    The GPIO pin connected to the desired device's `SS` line.
     90  - `bool lsbFirst`  
     91    Determines the endianness of the transmission. If `true`, the least significant bit of each byte is sent first.
     92  - `uint8_t mode`  
     93    The SPI mode to use:
     94 
     95    |Mode|Clock Polarity      |Clock Phase            |
     96    |----|--------------------|-----------------------|
     97    |`0` |Leading edge rising |Sample on leading edge |
     98    |`1` |Leading edge rising |Sample on trailing edge|
     99    |`2` |Leading edge falling|Sample on leading edge |
    100    |`3` |Leading edge falling|Sample on trailing edge|
    101 
    102  - `uint16_t divisor`  
    103    The SPI clock divisor, will be rounded up to the nearest power of two. This number can be calculated by dividing the MCU's clock speed by the desired SPI clock speed. For example, an MCU running at 8 MHz wanting to talk to an SPI device at 4 MHz would set the divisor to `2`.
    104 
    105 #### Return Value {#api-spi-start-return}
    106 
    107 `true` if the operation was successful, otherwise `false` if the supplied parameters are invalid or the SPI peripheral is already in use.
    108 
    109 ---
    110 
    111 ### `spi_status_t spi_write(uint8_t data)` {#api-spi-write}
    112 
    113 Write a byte to the selected SPI device.
    114 
    115 #### Arguments {#api-spi-write-arguments}
    116 
    117  - `uint8_t data`  
    118    The byte to write.
    119 
    120 #### Return Value {#api-spi-write-return}
    121 
    122 `SPI_STATUS_TIMEOUT` if the timeout period elapses, or `SPI_STATUS_SUCCESS`.
    123 
    124 ---
    125 
    126 ### `spi_status_t spi_read(void)` {#api-spi-read}
    127 
    128 Read a byte from the selected SPI device.
    129 
    130 #### Return Value {#api-spi-read-return}
    131 
    132 `SPI_STATUS_TIMEOUT` if the timeout period elapses, otherwise the byte read from the device.
    133 
    134 ---
    135 
    136 ### `spi_status_t spi_transmit(const uint8_t *data, uint16_t length)` {#api-spi-transmit}
    137 
    138 Send multiple bytes to the selected SPI device.
    139 
    140 #### Arguments {#api-spi-transmit-arguments}
    141 
    142  - `const uint8_t *data`  
    143    A pointer to the data to write from.
    144  - `uint16_t length`  
    145    The number of bytes to write. Take care not to overrun the length of `data`.
    146 
    147 #### Return Value {#api-spi-transmit-return}
    148 
    149 `SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
    150 
    151 ---
    152 
    153 ### `spi_status_t spi_receive(uint8_t *data, uint16_t length)` {#api-spi-receive}
    154 
    155 Receive multiple bytes from the selected SPI device.
    156 
    157 #### Arguments {#api-spi-receive-arguments}
    158 
    159  - `uint8_t *data`  
    160    A pointer to a buffer to read into.
    161  - `uint16_t length`  
    162    The number of bytes to read. Take care not to overrun the length of `data`.
    163 
    164 #### Return Value {#api-spi-receive-return}
    165 
    166 `SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
    167 
    168 ---
    169 
    170 ### `void spi_stop(void)` {#api-spi-stop}
    171 
    172 End the current SPI transaction. This will deassert the slave select pin and reset the endianness, mode and divisor configured by `spi_start()`.