spi_master.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  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 "timer.h"
  18. static pin_t currentSlavePin = NO_PIN;
  19. #if defined(K20x) || defined(KL2x) || defined(RP2040)
  20. static SPIConfig spiConfig = {NULL, 0, 0, 0};
  21. #else
  22. static SPIConfig spiConfig = {false, NULL, 0, 0, 0, 0};
  23. #endif
  24. __attribute__((weak)) void spi_init(void) {
  25. static bool is_initialised = false;
  26. if (!is_initialised) {
  27. is_initialised = true;
  28. // Try releasing special pins for a short time
  29. setPinInput(SPI_SCK_PIN);
  30. setPinInput(SPI_MOSI_PIN);
  31. setPinInput(SPI_MISO_PIN);
  32. chThdSleepMilliseconds(10);
  33. #if defined(USE_GPIOV1)
  34. palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_PAL_MODE);
  35. palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_PAL_MODE);
  36. palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_PAL_MODE);
  37. #else
  38. palSetPadMode(PAL_PORT(SPI_SCK_PIN), PAL_PAD(SPI_SCK_PIN), SPI_SCK_FLAGS);
  39. palSetPadMode(PAL_PORT(SPI_MOSI_PIN), PAL_PAD(SPI_MOSI_PIN), SPI_MOSI_FLAGS);
  40. palSetPadMode(PAL_PORT(SPI_MISO_PIN), PAL_PAD(SPI_MISO_PIN), SPI_MISO_FLAGS);
  41. #endif
  42. spiStop(&SPI_DRIVER);
  43. currentSlavePin = NO_PIN;
  44. }
  45. }
  46. bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
  47. if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
  48. return false;
  49. }
  50. #if !(defined(WB32F3G71xx) || defined(WB32FQ95xx))
  51. uint16_t roundedDivisor = 2;
  52. while (roundedDivisor < divisor) {
  53. roundedDivisor <<= 1;
  54. }
  55. if (roundedDivisor < 2 || roundedDivisor > 256) {
  56. return false;
  57. }
  58. #endif
  59. #if defined(K20x) || defined(KL2x)
  60. spiConfig.tar0 = SPIx_CTARn_FMSZ(7) | SPIx_CTARn_ASC(1);
  61. if (lsbFirst) {
  62. spiConfig.tar0 |= SPIx_CTARn_LSBFE;
  63. }
  64. switch (mode) {
  65. case 0:
  66. break;
  67. case 1:
  68. spiConfig.tar0 |= SPIx_CTARn_CPHA;
  69. break;
  70. case 2:
  71. spiConfig.tar0 |= SPIx_CTARn_CPOL;
  72. break;
  73. case 3:
  74. spiConfig.tar0 |= SPIx_CTARn_CPHA | SPIx_CTARn_CPOL;
  75. break;
  76. }
  77. switch (roundedDivisor) {
  78. case 2:
  79. spiConfig.tar0 |= SPIx_CTARn_BR(0);
  80. break;
  81. case 4:
  82. spiConfig.tar0 |= SPIx_CTARn_BR(1);
  83. break;
  84. case 8:
  85. spiConfig.tar0 |= SPIx_CTARn_BR(3);
  86. break;
  87. case 16:
  88. spiConfig.tar0 |= SPIx_CTARn_BR(4);
  89. break;
  90. case 32:
  91. spiConfig.tar0 |= SPIx_CTARn_BR(5);
  92. break;
  93. case 64:
  94. spiConfig.tar0 |= SPIx_CTARn_BR(6);
  95. break;
  96. case 128:
  97. spiConfig.tar0 |= SPIx_CTARn_BR(7);
  98. break;
  99. case 256:
  100. spiConfig.tar0 |= SPIx_CTARn_BR(8);
  101. break;
  102. }
  103. #elif defined(HT32)
  104. spiConfig.cr0 = SPI_CR0_SELOEN;
  105. spiConfig.cr1 = SPI_CR1_MODE | 8; // 8 bits and in master mode
  106. if (lsbFirst) {
  107. spiConfig.cr1 |= SPI_CR1_FIRSTBIT;
  108. }
  109. switch (mode) {
  110. case 0:
  111. spiConfig.cr1 |= SPI_CR1_FORMAT_MODE0;
  112. break;
  113. case 1:
  114. spiConfig.cr1 |= SPI_CR1_FORMAT_MODE1;
  115. break;
  116. case 2:
  117. spiConfig.cr1 |= SPI_CR1_FORMAT_MODE2;
  118. break;
  119. case 3:
  120. spiConfig.cr1 |= SPI_CR1_FORMAT_MODE3;
  121. break;
  122. }
  123. spiConfig.cpr = (roundedDivisor - 1) >> 1;
  124. #elif defined(WB32F3G71xx) || defined(WB32FQ95xx)
  125. if (!lsbFirst) {
  126. osalDbgAssert(lsbFirst != FALSE, "unsupported lsbFirst");
  127. }
  128. if (divisor < 1) {
  129. return false;
  130. }
  131. spiConfig.SPI_BaudRatePrescaler = (divisor << 2);
  132. switch (mode) {
  133. case 0:
  134. spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
  135. spiConfig.SPI_CPOL = SPI_CPOL_Low;
  136. break;
  137. case 1:
  138. spiConfig.SPI_CPHA = SPI_CPHA_2Edge;
  139. spiConfig.SPI_CPOL = SPI_CPOL_Low;
  140. break;
  141. case 2:
  142. spiConfig.SPI_CPHA = SPI_CPHA_1Edge;
  143. spiConfig.SPI_CPOL = SPI_CPOL_High;
  144. break;
  145. case 3:
  146. spiConfig.SPI_CPHA = SPI_CPHA_2Edge;
  147. spiConfig.SPI_CPOL = SPI_CPOL_High;
  148. break;
  149. }
  150. #elif defined(MCU_RP)
  151. if (lsbFirst) {
  152. osalDbgAssert(lsbFirst == false, "RP2040s PrimeCell SPI implementation does not support sending LSB first.");
  153. }
  154. // Motorola frame format and 8bit transfer data size.
  155. spiConfig.SSPCR0 = SPI_SSPCR0_FRF_MOTOROLA | SPI_SSPCR0_DSS_8BIT;
  156. // Serial output clock = (ck_sys or ck_peri) / (SSPCPSR->CPSDVSR * (1 +
  157. // SSPCR0->SCR)). SCR is always set to zero, as QMK SPI API expects the
  158. // passed divisor to be the only value to divide the input clock by.
  159. spiConfig.SSPCPSR = roundedDivisor; // Even number from 2 to 254
  160. switch (mode) {
  161. case 0:
  162. spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
  163. spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
  164. break;
  165. case 1:
  166. spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPO; // Clock polarity: low
  167. spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
  168. break;
  169. case 2:
  170. spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
  171. spiConfig.SSPCR0 &= ~SPI_SSPCR0_SPH; // Clock phase: sample on first edge
  172. break;
  173. case 3:
  174. spiConfig.SSPCR0 |= SPI_SSPCR0_SPO; // Clock polarity: high
  175. spiConfig.SSPCR0 |= SPI_SSPCR0_SPH; // Clock phase: sample on second edge transition
  176. break;
  177. }
  178. #else
  179. spiConfig.cr1 = 0;
  180. if (lsbFirst) {
  181. spiConfig.cr1 |= SPI_CR1_LSBFIRST;
  182. }
  183. switch (mode) {
  184. case 0:
  185. break;
  186. case 1:
  187. spiConfig.cr1 |= SPI_CR1_CPHA;
  188. break;
  189. case 2:
  190. spiConfig.cr1 |= SPI_CR1_CPOL;
  191. break;
  192. case 3:
  193. spiConfig.cr1 |= SPI_CR1_CPHA | SPI_CR1_CPOL;
  194. break;
  195. }
  196. switch (roundedDivisor) {
  197. case 2:
  198. break;
  199. case 4:
  200. spiConfig.cr1 |= SPI_CR1_BR_0;
  201. break;
  202. case 8:
  203. spiConfig.cr1 |= SPI_CR1_BR_1;
  204. break;
  205. case 16:
  206. spiConfig.cr1 |= SPI_CR1_BR_1 | SPI_CR1_BR_0;
  207. break;
  208. case 32:
  209. spiConfig.cr1 |= SPI_CR1_BR_2;
  210. break;
  211. case 64:
  212. spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_0;
  213. break;
  214. case 128:
  215. spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1;
  216. break;
  217. case 256:
  218. spiConfig.cr1 |= SPI_CR1_BR_2 | SPI_CR1_BR_1 | SPI_CR1_BR_0;
  219. break;
  220. }
  221. #endif
  222. currentSlavePin = slavePin;
  223. spiConfig.ssport = PAL_PORT(slavePin);
  224. spiConfig.sspad = PAL_PAD(slavePin);
  225. setPinOutput(slavePin);
  226. spiStart(&SPI_DRIVER, &spiConfig);
  227. spiSelect(&SPI_DRIVER);
  228. return true;
  229. }
  230. spi_status_t spi_write(uint8_t data) {
  231. uint8_t rxData;
  232. spiExchange(&SPI_DRIVER, 1, &data, &rxData);
  233. return rxData;
  234. }
  235. spi_status_t spi_read(void) {
  236. uint8_t data = 0;
  237. spiReceive(&SPI_DRIVER, 1, &data);
  238. return data;
  239. }
  240. spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
  241. spiSend(&SPI_DRIVER, length, data);
  242. return SPI_STATUS_SUCCESS;
  243. }
  244. spi_status_t spi_receive(uint8_t *data, uint16_t length) {
  245. spiReceive(&SPI_DRIVER, length, data);
  246. return SPI_STATUS_SUCCESS;
  247. }
  248. void spi_stop(void) {
  249. if (currentSlavePin != NO_PIN) {
  250. spiUnselect(&SPI_DRIVER);
  251. spiStop(&SPI_DRIVER);
  252. currentSlavePin = NO_PIN;
  253. }
  254. }