logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

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