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 }