You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.5 KiB

  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 currentSlavePin = NO_PIN;
  35. static uint8_t currentSlaveConfig = 0;
  36. static bool currentSlave2X = false;
  37. void spi_init(void) {
  38. writePinHigh(SPI_SS_PIN);
  39. setPinOutput(SPI_SCK_PIN);
  40. setPinOutput(SPI_MOSI_PIN);
  41. setPinInput(SPI_MISO_PIN);
  42. SPCR = (_BV(SPE) | _BV(MSTR));
  43. }
  44. bool spi_start(pin_t slavePin, bool lsbFirst, uint8_t mode, uint16_t divisor) {
  45. if (currentSlavePin != NO_PIN || slavePin == NO_PIN) {
  46. return false;
  47. }
  48. currentSlaveConfig = 0;
  49. if (lsbFirst) {
  50. currentSlaveConfig |= _BV(DORD);
  51. }
  52. switch (mode) {
  53. case 1:
  54. currentSlaveConfig |= _BV(CPHA);
  55. break;
  56. case 2:
  57. currentSlaveConfig |= _BV(CPOL);
  58. break;
  59. case 3:
  60. currentSlaveConfig |= (_BV(CPOL) | _BV(CPHA));
  61. break;
  62. }
  63. uint16_t roundedDivisor = 1;
  64. while (roundedDivisor < divisor) {
  65. roundedDivisor <<= 1;
  66. }
  67. switch (roundedDivisor) {
  68. case 16:
  69. currentSlaveConfig |= _BV(SPR0);
  70. break;
  71. case 64:
  72. currentSlaveConfig |= _BV(SPR1);
  73. break;
  74. case 128:
  75. currentSlaveConfig |= (_BV(SPR1) | _BV(SPR0));
  76. break;
  77. case 2:
  78. currentSlave2X = true;
  79. break;
  80. case 8:
  81. currentSlave2X = true;
  82. currentSlaveConfig |= _BV(SPR0);
  83. break;
  84. case 32:
  85. currentSlave2X = true;
  86. currentSlaveConfig |= _BV(SPR1);
  87. break;
  88. }
  89. SPCR |= currentSlaveConfig;
  90. if (currentSlave2X) {
  91. SPSR |= _BV(SPI2X);
  92. }
  93. currentSlavePin = slavePin;
  94. setPinOutput(currentSlavePin);
  95. writePinLow(currentSlavePin);
  96. return true;
  97. }
  98. spi_status_t spi_write(uint8_t data) {
  99. SPDR = data;
  100. uint16_t timeout_timer = timer_read();
  101. while (!(SPSR & _BV(SPIF))) {
  102. if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
  103. return SPI_STATUS_TIMEOUT;
  104. }
  105. }
  106. return SPDR;
  107. }
  108. spi_status_t spi_read() {
  109. SPDR = 0x00; // Dummy
  110. uint16_t timeout_timer = timer_read();
  111. while (!(SPSR & _BV(SPIF))) {
  112. if ((timer_read() - timeout_timer) >= SPI_TIMEOUT) {
  113. return SPI_STATUS_TIMEOUT;
  114. }
  115. }
  116. return SPDR;
  117. }
  118. spi_status_t spi_transmit(const uint8_t *data, uint16_t length) {
  119. spi_status_t status;
  120. for (uint16_t i = 0; i < length; i++) {
  121. status = spi_write(data[i]);
  122. if (status < 0) {
  123. return status;
  124. }
  125. }
  126. return SPI_STATUS_SUCCESS;
  127. }
  128. spi_status_t spi_receive(uint8_t *data, uint16_t length) {
  129. spi_status_t status;
  130. for (uint16_t i = 0; i < length; i++) {
  131. status = spi_read();
  132. if (status >= 0) {
  133. data[i] = status;
  134. } else {
  135. return status;
  136. }
  137. }
  138. return SPI_STATUS_SUCCESS;
  139. }
  140. void spi_stop(void) {
  141. if (currentSlavePin != NO_PIN) {
  142. setPinOutput(currentSlavePin);
  143. writePinHigh(currentSlavePin);
  144. currentSlavePin = NO_PIN;
  145. SPSR &= ~(_BV(SPI2X));
  146. SPCR &= ~(currentSlaveConfig);
  147. currentSlaveConfig = 0;
  148. currentSlave2X = false;
  149. }
  150. }