qmk_firmware

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

spi_master.h (3543B)


      1 // Copyright 2025 QMK
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 
      4 #pragma once
      5 
      6 #include <stdint.h>
      7 #include <stdbool.h>
      8 #include "gpio.h"
      9 
     10 /**
     11  * \file
     12  *
     13  * \defgroup spi_master SPI Master API
     14  *
     15  * \brief API to communicate with SPI devices.
     16  * \{
     17  */
     18 
     19 // Hardware SS pin is defined in the header so that user code can refer to it
     20 #ifdef __AVR__
     21 #    if defined(__AVR_AT90USB162__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB647__) || defined(__AVR_AT90USB1286__) || defined(__AVR_AT90USB1287__)
     22 #        define SPI_SS_PIN B0
     23 #    elif defined(__AVR_ATmega32A__)
     24 #        define SPI_SS_PIN B4
     25 #    elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
     26 #        define SPI_SS_PIN B2
     27 #    endif
     28 #endif
     29 
     30 typedef int16_t spi_status_t;
     31 
     32 #define SPI_STATUS_SUCCESS (0)
     33 #define SPI_STATUS_ERROR (-1)
     34 #define SPI_STATUS_TIMEOUT (-2)
     35 
     36 #define SPI_TIMEOUT_IMMEDIATE (0)
     37 #define SPI_TIMEOUT_INFINITE (0xFFFF)
     38 
     39 #ifdef __cplusplus
     40 extern "C" {
     41 #endif
     42 
     43 typedef struct spi_start_config_t {
     44     pin_t    slave_pin;
     45     bool     lsb_first;
     46     uint8_t  mode;
     47     uint16_t divisor;
     48     bool     cs_active_low;
     49 } spi_start_config_t;
     50 
     51 /**
     52  * \brief Initialize the SPI driver. This function must be called only once, before any of the below functions can be called.
     53  */
     54 void spi_init(void);
     55 
     56 /**
     57  * \brief Start an SPI transaction.
     58  *
     59  * \param slavePin The GPIO pin connected to the desired device's `SS` line.
     60  * \param lsbFirst Determines the endianness of the transmission. If `true`, the least significant bit of each byte is sent first.
     61  * \param mode The SPI mode to use.
     62  * \param divisor The SPI clock divisor.
     63  *
     64  * \return `true` if the operation was successful, otherwise `false` if the supplied parameters are invalid or the SPI peripheral is already in use.
     65  */
     66 bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor);
     67 
     68 bool spi_start_extended(spi_start_config_t *start_config);
     69 
     70 /**
     71  * \brief Write a byte to the selected SPI device.
     72  *
     73  * \param data The byte to write.
     74  *
     75  * \return `SPI_STATUS_TIMEOUT` if the timeout period elapses, or `SPI_STATUS_SUCCESS`.
     76  */
     77 spi_status_t spi_write(uint8_t data);
     78 
     79 /**
     80  * \brief Read a byte from the selected SPI device.
     81  *
     82  * \return `SPI_STATUS_TIMEOUT` if the timeout period elapses, otherwise the byte read from the device.
     83  */
     84 spi_status_t spi_read(void);
     85 
     86 /**
     87  * \brief Send multiple bytes to the selected SPI device.
     88  *
     89  * \param data A pointer to the data to write from.
     90  * \param length The number of bytes to write. Take care not to overrun the length of `data`.
     91  *
     92  * \return `SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
     93  */
     94 spi_status_t spi_transmit(const uint8_t *data, uint16_t length);
     95 
     96 /**
     97  * \brief Receive multiple bytes from the selected SPI device.
     98  *
     99  * \param data A pointer to a buffer to read into.
    100  * \param length The number of bytes to read. Take care not to overrun the length of `data`.
    101  *
    102  * \return `SPI_STATUS_TIMEOUT` if the timeout period elapses, `SPI_STATUS_ERROR` if some other error occurs, otherwise `SPI_STATUS_SUCCESS`.
    103  */
    104 spi_status_t spi_receive(uint8_t *data, uint16_t length);
    105 
    106 /**
    107  * \brief End the current SPI transaction. This will deassert the slave select pin and reset the endianness, mode and divisor configured by `spi_start()`.
    108  *
    109  */
    110 void spi_stop(void);
    111 
    112 #ifdef __cplusplus
    113 }
    114 #endif
    115 
    116 /** \} */