qmk_firmware

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

spi_master.c (13579B)


      1 /* Copyright 2020 Nick Brassel (tzarc)
      2  *
      3  *  This program is free software: you can redistribute it and/or modify
      4  *  it under the terms of the GNU General Public License as published by
      5  *  the Free Software Foundation, either version 3 of the License, or
      6  *  (at your option) any later version.
      7  *
      8  *  This program is distributed in the hope that it will be useful,
      9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  *  GNU General Public License for more details.
     12  *
     13  *  You should have received a copy of the GNU General Public License
     14  *  along with this program.  If not, see <https://www.gnu.org/licenses/>.
     15  */
     16 
     17 #include "spi_master.h"
     18 #include "chibios_config.h"
     19 #include <ch.h>
     20 #include <hal.h>
     21 
     22 #ifndef SPI_DRIVER
     23 #    define SPI_DRIVER SPID2
     24 #endif
     25 
     26 #ifndef SPI_SCK_PIN
     27 #    define SPI_SCK_PIN B13
     28 #endif
     29 
     30 #ifndef SPI_SCK_PAL_MODE
     31 #    ifdef USE_GPIOV1
     32 #        define SPI_SCK_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
     33 #    else
     34 #        define SPI_SCK_PAL_MODE 5
     35 #    endif
     36 #endif
     37 
     38 #ifndef SPI_MOSI_PIN
     39 #    define SPI_MOSI_PIN B15
     40 #endif
     41 
     42 #ifndef SPI_MOSI_PAL_MODE
     43 #    ifdef USE_GPIOV1
     44 #        define SPI_MOSI_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
     45 #    else
     46 #        define SPI_MOSI_PAL_MODE 5
     47 #    endif
     48 #endif
     49 
     50 #ifndef SPI_MISO_PIN
     51 #    define SPI_MISO_PIN B14
     52 #endif
     53 
     54 #ifndef SPI_MISO_PAL_MODE
     55 #    ifdef USE_GPIOV1
     56 #        define SPI_MISO_PAL_MODE PAL_MODE_ALTERNATE_PUSHPULL
     57 #    else
     58 #        define SPI_MISO_PAL_MODE 5
     59 #    endif
     60 #endif
     61 
     62 static bool spiStarted = false;
     63 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
     64 static pin_t current_slave_pin     = NO_PIN;
     65 static bool  current_cs_active_low = true;
     66 #endif
     67 
     68 static SPIConfig spiConfig;
     69 
     70 static inline void spi_select(void) {
     71     spiSelect(&SPI_DRIVER);
     72 
     73 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
     74     if (current_slave_pin != NO_PIN) {
     75         gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
     76     }
     77 #endif
     78 }
     79 
     80 static inline void spi_unselect(void) {
     81 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
     82     if (current_slave_pin != NO_PIN) {
     83         gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
     84     }
     85 #endif
     86 
     87     spiUnselect(&SPI_DRIVER);
     88 }
     89 
     90 __attribute__((weak)) void spi_init(void) {
     91     static bool is_initialised = false;
     92     if (!is_initialised) {
     93         is_initialised = true;
     94 
     95         // Try releasing special pins for a short time
     96         gpio_set_pin_input(SPI_SCK_PIN);
     97         if (SPI_MOSI_PIN != NO_PIN) {
     98             gpio_set_pin_input(SPI_MOSI_PIN);
     99         }
    100         if (SPI_MISO_PIN != NO_PIN) {
    101             gpio_set_pin_input(SPI_MISO_PIN);
    102         }
    103 
    104         chThdSleepMilliseconds(10);
    105 #if defined(USE_GPIOV1)
    106         palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_PAL_MODE);
    107         if (SPI_MOSI_PIN != NO_PIN) {
    108             palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
    109         }
    110         if (SPI_MISO_PIN != NO_PIN) {
    111             palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
    112         }
    113 #else
    114         palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_FLAGS);
    115         if (SPI_MOSI_PIN != NO_PIN) {
    116             palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_FLAGS);
    117         }
    118         if (SPI_MISO_PIN != NO_PIN) {
    119             palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_FLAGS);
    120         }
    121 #endif
    122         spiStop(&SPI_DRIVER);
    123         spiStarted = false;
    124     }
    125 }
    126 
    127 bool spi_start_extended(spi_start_config_t *start_config) {
    128 #if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    129     spiAcquireBus(&SPI_DRIVER);
    130 #endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    131 
    132     if (spiStarted) {
    133 #if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    134         spiReleaseBus(&SPI_DRIVER);
    135 #endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    136         return false;
    137     }
    138 #if SPI_SELECT_MODE != SPI_SELECT_MODE_NONE
    139     if (start_config->slave_pin == NO_PIN) {
    140 #    if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    141         spiReleaseBus(&SPI_DRIVER);
    142 #    endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    143         return false;
    144     }
    145 #endif
    146 
    147 #if !(defined(WB32F3G71xx) || defined(WB32FQ95xx))
    148     uint16_t roundedDivisor = 2;
    149     while (roundedDivisor < start_config->divisor) {
    150         roundedDivisor <<= 1;
    151     }
    152 
    153 #    if defined(AT32F415)
    154     if (roundedDivisor < 2 || roundedDivisor > 1024) {
    155 #        if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    156         spiReleaseBus(&SPI_DRIVER);
    157 #        endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    158         return false;
    159     }
    160 #    else
    161     if (roundedDivisor < 2 || roundedDivisor > 256) {
    162 #        if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    163         spiReleaseBus(&SPI_DRIVER);
    164 #        endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    165         return false;
    166     }
    167 #    endif
    168 #endif
    169 
    170 #if defined(K20x) || defined(KL2x)
    171     spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
    172 
    173     if (start_config->lsb_first) {
    174         spiConfig.tar0 |= SPIx_CTARn_LSBFE;
    175     }
    176 
    177     switch (start_config->mode) {
    178         case 0:
    179             break;
    180         case 1:
    181             spiConfig.tar0 |= SPIx_CTARn_CPHA;
    182             break;
    183         case 2:
    184             spiConfig.tar0 |= SPIx_CTARn_CPOL;
    185             break;
    186         case 3:
    187             spiConfig.tar0 |= SPIx_CTARn_CPHA | SPIx_CTARn_CPOL;
    188             break;
    189     }
    190 
    191     switch (roundedDivisor) {
    192         case 2:
    193             spiConfig.tar0 |= SPIx_CTARn_BR(0);
    194             break;
    195         case 4:
    196             spiConfig.tar0 |= SPIx_CTARn_BR(1);
    197             break;
    198         case 8:
    199             spiConfig.tar0 |= SPIx_CTARn_BR(3);
    200             break;
    201         case 16:
    202             spiConfig.tar0 |= SPIx_CTARn_BR(4);
    203             break;
    204         case 32:
    205             spiConfig.tar0 |= SPIx_CTARn_BR(5);
    206             break;
    207         case 64:
    208             spiConfig.tar0 |= SPIx_CTARn_BR(6);
    209             break;
    210         case 128:
    211             spiConfig.tar0 |= SPIx_CTARn_BR(7);
    212             break;
    213         case 256:
    214             spiConfig.tar0 |= SPIx_CTARn_BR(8);
    215             break;
    216     }
    217 
    218 #elif defined(HT32)
    219     spiConfig.cr0 = SPI_CR0_SELOEN;
    220     spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
    221 
    222     if (start_config->lsb_first) {
    223         spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
    224     }
    225 
    226     switch (start_config->mode) {
    227         case 0:
    228             spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
    229             break;
    230         case 1:
    231             spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1;
    232             break;
    233         case 2:
    234             spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2;
    235             break;
    236         case 3:
    237             spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3;
    238             break;
    239     }
    240 
    241     spiConfig.cpr = (roundedDivisor - 1) >> 1;
    242 
    243 #elif defined(WB32F3G71xx) || defined(WB32FQ95xx)
    244     if (!start_config->lsb_first) {
    245         osalDbgAssert(start_config->lsb_first != FALSE, "unsupported lsb_first");
    246     }
    247 
    248     if (start_config->divisor < 1) {
    249 #    if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    250         spiReleaseBus(&SPI_DRIVER);
    251 #    endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    252         return false;
    253     }
    254 
    255     spiConfig.SPI_BaudRatePrescaler = (start_config->divisor << 2);
    256 
    257     switch (start_config->mode) {
    258         case 0:
    259             spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
    260             spiConfig.SPI_CPOL = SPI_CPOL_Low;
    261             break;
    262         case 1:
    263             spiConfig.SPI_CPHA = SPI_CPHA_2Edge;
    264             spiConfig.SPI_CPOL = SPI_CPOL_Low;
    265             break;
    266         case 2:
    267             spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
    268             spiConfig.SPI_CPOL = SPI_CPOL_High;
    269             break;
    270         case 3:
    271             spiConfig.SPI_CPHA = SPI_CPHA_2Edge;
    272             spiConfig.SPI_CPOL = SPI_CPOL_High;
    273             break;
    274     }
    275 #elif defined(MCU_RP)
    276     if (start_config->lsb_first) {
    277         osalDbgAssert(start_config->lsb_first == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
    278     }
    279 
    280     // Motorola frame format and 8bit transfer data size.
    281     spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT;
    282     // Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 +
    283     // SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the
    284     // passed divisor to be the only value to divide the input clock by.
    285     spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
    286 
    287     switch (start_config->mode) {
    288         case 0:
    289             spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
    290             spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
    291             break;
    292         case 1:
    293             spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
    294             spiConfig.SSPCR0 |= SPI_SSPCR0_SPH;  // Clock phase: sample on second edge transition
    295             break;
    296         case 2:
    297             spiConfig.SSPCR0 |= SPI_SSPCR0_SPO;  // Clock polarity: high
    298             spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
    299             break;
    300         case 3:
    301             spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
    302             spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
    303             break;
    304     }
    305 #elif defined(AT32F415)
    306     spiConfig.ctrl1 = 0;
    307 
    308     if (start_config->lsb_first) {
    309         spiConfig.ctrl1 |= SPI_CTRL1_LTF;
    310     }
    311 
    312     switch (start_config->mode) {
    313         case 0:
    314             break;
    315         case 1:
    316             spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA;
    317             break;
    318         case 2:
    319             spiConfig.ctrl1 |= SPI_CTRL1_CLKPOL;
    320             break;
    321         case 3:
    322             spiConfig.ctrl1 |= SPI_CTRL1_CLKPHA | SPI_CTRL1_CLKPOL;
    323             break;
    324     }
    325 
    326     switch (roundedDivisor) {
    327         case 2:
    328             break;
    329         case 4:
    330             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
    331             break;
    332         case 8:
    333             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1;
    334             break;
    335         case 16:
    336             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
    337             break;
    338         case 32:
    339             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2;
    340             break;
    341         case 64:
    342             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_0;
    343             break;
    344         case 128:
    345             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1;
    346             break;
    347         case 256:
    348             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_2 | SPI_CTRL1_MDIV_1 | SPI_CTRL1_MDIV_0;
    349             break;
    350         case 512:
    351             spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
    352             break;
    353         case 1024:
    354             spiConfig.ctrl2 |= SPI_CTRL1_MDIV_3;
    355             spiConfig.ctrl1 |= SPI_CTRL1_MDIV_0;
    356             break;
    357     }
    358 #else
    359     spiConfig.cr1 = 0;
    360 
    361     if (start_config->lsb_first) {
    362         spiConfig.cr1 |= SPI_CR1_LSBFIRST;
    363     }
    364 
    365     switch (start_config->mode) {
    366         case 0:
    367             break;
    368         case 1:
    369             spiConfig.cr1 |= SPI_CR1_CPHA;
    370             break;
    371         case 2:
    372             spiConfig.cr1 |= SPI_CR1_CPOL;
    373             break;
    374         case 3:
    375             spiConfig.cr1 |= SPI_CR1_CPHA | SPI_CR1_CPOL;
    376             break;
    377     }
    378 
    379     switch (roundedDivisor) {
    380         case 2:
    381             break;
    382         case 4:
    383             spiConfig.cr1 |= SPI_CR1_BR_0;
    384             break;
    385         case 8:
    386             spiConfig.cr1 |= SPI_CR1_BR_1;
    387             break;
    388         case 16:
    389             spiConfig.cr1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
    390             break;
    391         case 32:
    392             spiConfig.cr1 |= SPI_CR1_BR_2;
    393             break;
    394         case 64:
    395             spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
    396             break;
    397         case 128:
    398             spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
    399             break;
    400         case 256:
    401             spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
    402             break;
    403     }
    404 #endif
    405 
    406     spiStarted = true;
    407 #if SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
    408     current_slave_pin     = start_config->slave_pin;
    409     current_cs_active_low = start_config->cs_active_low;
    410 #endif
    411 #if SPI_SELECT_MODE == SPI_SELECT_MODE_PAD
    412     spiConfig.ssport = PAL_PORT(start_config->slave_pin);
    413     spiConfig.sspad  = PAL_PAD(start_config->slave_pin);
    414     gpio_set_pin_output(start_config->slave_pin);
    415 #elif SPI_SELECT_MODE == SPI_SELECT_MODE_NONE
    416     if (start_config->slave_pin != NO_PIN) {
    417         gpio_set_pin_output(start_config->slave_pin);
    418     }
    419 #else
    420 #    error "Unsupported SPI_SELECT_MODE"
    421 #endif
    422 
    423     spiStart(&SPI_DRIVER, &spiConfig);
    424     spi_select();
    425 
    426     return true;
    427 }
    428 
    429 bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
    430     spi_start_config_t start_config = {0};
    431     start_config.slave_pin          = slavePin;
    432     start_config.lsb_first          = lsbFirst;
    433     start_config.mode               = mode;
    434     start_config.divisor            = divisor;
    435     start_config.cs_active_low      = true;
    436     return spi_start_extended(&start_config);
    437 }
    438 
    439 spi_status_t spi_write(uint8_t data) {
    440     uint8_t rxData;
    441     spiExchange(&SPI_DRIVER, 1, &data, &rxData);
    442 
    443     return rxData;
    444 }
    445 
    446 spi_status_t spi_read(void) {
    447     uint8_t data = 0;
    448     spiReceive(&SPI_DRIVER, 1, &data);
    449 
    450     return data;
    451 }
    452 
    453 spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
    454     spiSend(&SPI_DRIVER, length, data);
    455     return SPI_STATUS_SUCCESS;
    456 }
    457 
    458 spi_status_t spi_receive(uint8_t *data, uint16_t length) {
    459     spiReceive(&SPI_DRIVER, length, data);
    460     return SPI_STATUS_SUCCESS;
    461 }
    462 
    463 void spi_stop(void) {
    464     if (spiStarted) {
    465         spi_unselect();
    466         spiStop(&SPI_DRIVER);
    467         spiStarted = false;
    468     }
    469 
    470 #if (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    471     spiReleaseBus(&SPI_DRIVER);
    472 #endif // (SPI_USE_MUTUAL_EXCLUSION == TRUE)
    473 }