logo

qmk_firmware

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

spi_master.c (5496B)


  1. /* Copyright 2020
  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. #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__)
  19. # define SPI_SCK_PIN B1
  20. # define SPI_MOSI_PIN B2
  21. # define SPI_MISO_PIN B3
  22. #elif defined(__AVR_ATmega32A__)
  23. # define SPI_SCK_PIN B7
  24. # define SPI_MOSI_PIN B5
  25. # define SPI_MISO_PIN B6
  26. #elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328__)
  27. # define SPI_SCK_PIN B5
  28. # define SPI_MOSI_PIN B3
  29. # define SPI_MISO_PIN B4
  30. #endif
  31. #ifndef SPI_TIMEOUT
  32. # define SPI_TIMEOUT 100
  33. #endif
  34. static pin_t current_slave_pin = NO_PIN;
  35. static bool current_cs_active_low = true;
  36. static uint8_t current_slave_config = 0;
  37. static bool current_slave_2x = false;
  38. static inline void spi_select(void) {
  39. gpio_write_pin(current_slave_pin, current_cs_active_low ? 0 : 1);
  40. }
  41. static inline void spi_unselect(void) {
  42. gpio_write_pin(current_slave_pin, current_cs_active_low ? 1 : 0);
  43. }
  44. void spi_init(void) {
  45. gpio_write_pin_high(SPI_SS_PIN);
  46. gpio_set_pin_output(SPI_SCK_PIN);
  47. gpio_set_pin_output(SPI_MOSI_PIN);
  48. gpio_set_pin_input(SPI_MISO_PIN);
  49. SPCR = (_BV(SPE) | _BV(MSTR));
  50. }
  51. bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
  52. spi_start_config_t start_config = {0};
  53. start_config.slave_pin = slavePin;
  54. start_config.lsb_first = lsbFirst;
  55. start_config.mode = mode;
  56. start_config.divisor = divisor;
  57. start_config.cs_active_low = true;
  58. return spi_start_extended(&start_config);
  59. }
  60. bool spi_start_extended(spi_start_config_t *start_config) {
  61. if (current_slave_pin != NO_PIN || start_config->slave_pin == NO_PIN) {
  62. return false;
  63. }
  64. current_slave_config = 0;
  65. if (start_config->lsb_first) {
  66. current_slave_config |= _BV(DORD);
  67. }
  68. switch (start_config->mode) {
  69. case 1:
  70. current_slave_config |= _BV(CPHA);
  71. break;
  72. case 2:
  73. current_slave_config |= _BV(CPOL);
  74. break;
  75. case 3:
  76. current_slave_config |= (_BV(CPOL) | _BV(CPHA));
  77. break;
  78. }
  79. uint16_t roundedDivisor = 1;
  80. while (roundedDivisor < start_config->divisor) {
  81. roundedDivisor <<= 1;
  82. }
  83. switch (roundedDivisor) {
  84. case 16:
  85. current_slave_config |= _BV(SPR0);
  86. break;
  87. case 64:
  88. current_slave_config |= _BV(SPR1);
  89. break;
  90. case 128:
  91. current_slave_config |= (_BV(SPR1) | _BV(SPR0));
  92. break;
  93. case 2:
  94. current_slave_2x = true;
  95. break;
  96. case 8:
  97. current_slave_2x = true;
  98. current_slave_config |= _BV(SPR0);
  99. break;
  100. case 32:
  101. current_slave_2x = true;
  102. current_slave_config |= _BV(SPR1);
  103. break;
  104. }
  105. SPCR |= current_slave_config;
  106. if (current_slave_2x) {
  107. SPSR |= _BV(SPI2X);
  108. }
  109. current_slave_pin = start_config->slave_pin;
  110. current_cs_active_low = start_config->cs_active_low;
  111. gpio_set_pin_output(current_slave_pin);
  112. spi_select();
  113. return true;
  114. }
  115. spi_status_t spi_write(uint8_t data) {
  116. SPDR = data;
  117. uint16_t timeout_timer = timer_read();
  118. while (!(SPSR & _BV(SPIF))) {
  119. if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
  120. return SPI_STATUS_TIMEOUT;
  121. }
  122. }
  123. return SPDR;
  124. }
  125. spi_status_t spi_read() {
  126. SPDR = 0x00; // Dummy
  127. uint16_t timeout_timer = timer_read();
  128. while (!(SPSR & _BV(SPIF))) {
  129. if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
  130. return SPI_STATUS_TIMEOUT;
  131. }
  132. }
  133. return SPDR;
  134. }
  135. spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
  136. spi_status_t status;
  137. for (uint16_t i = 0; i < length; i++) {
  138. status = spi_write(data[i]);
  139. if (status < 0) {
  140. return status;
  141. }
  142. }
  143. return SPI_STATUS_SUCCESS;
  144. }
  145. spi_status_t spi_receive(uint8_t *data, uint16_t length) {
  146. spi_status_t status;
  147. for (uint16_t i = 0; i < length; i++) {
  148. status = spi_read();
  149. if (status >= 0) {
  150. data[i] = status;
  151. } else {
  152. return status;
  153. }
  154. }
  155. return SPI_STATUS_SUCCESS;
  156. }
  157. void spi_stop(void) {
  158. if (current_slave_pin != NO_PIN) {
  159. gpio_set_pin_output(current_slave_pin);
  160. spi_unselect();
  161. current_slave_pin = NO_PIN;
  162. SPSR &= ~(_BV(SPI2X));
  163. SPCR &= ~(current_slave_config);
  164. current_slave_config = 0;
  165. current_slave_2x = false;
  166. }
  167. }