Teensy 4.1 core updated for C++20
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.

175 lines
5.9KB

  1. #ifndef _SPIFIFO_h_
  2. #define _SPIFIFO_h_
  3. #include "avr_emulation.h"
  4. #if F_BUS == 48000000
  5. // SCK baud rate = (fSYS/PBR) x [(1+DBR)/BR]
  6. #define HAS_SPIFIFO
  7. #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(48 / 2) * ((1+1)/2)
  8. #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(48 / 3) * ((1+1)/2) 33% duty cycle
  9. #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(48 / 2) * ((1+0)/2)
  10. #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(48 / 3) * ((1+0)/2)
  11. #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1)) //(48 / 2) * ((1+0)/4)
  12. #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(1)) //(48 / 3) * ((1+0)/4)
  13. #elif F_BUS == 42000000
  14. #define HAS_SPIFIFO
  15. #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(42 / 2) * ((1+1)/2) 21 MHz
  16. #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(42 / 3) * ((1+1)/2) 33% duty cycle 14 MHz
  17. #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(42 / 2) * ((1+0)/2) 10.5 MHz
  18. #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(42 / 3) * ((1+0)/2) 7.5 MHz
  19. #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(42 / 7) * ((1+1)/2) 33% duty cycle
  20. #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(1)) //(42 / 3) * ((1+0)/4) 3.5 MHz
  21. #elif F_BUS == 40000000
  22. #define HAS_SPIFIFO
  23. #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 2) * ((1+1)/2) 20 MHz
  24. #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 3) * ((1+1)/2) 33% duty cycle 13.3 MHz
  25. #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(40 / 2) * ((1+0)/2) 10 MHz
  26. #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 5) * ((1+1)/2) 40% duty cycle
  27. #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 7) * ((1+0)/2) 57% duty cycle 5.7 MHz
  28. #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0)) //(40 / 5) * ((1+0)/2)
  29. #elif F_BUS == 24000000
  30. #define HAS_SPIFIFO
  31. #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2) 12 MHz
  32. #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2) 12 MHz
  33. #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2)
  34. #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 3) * ((1+1)/2) 33% duty cycle
  35. #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(24 / 2) * ((1+0)/2)
  36. #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0)) //(24 / 3) * ((1+0)/2)
  37. #else
  38. #error
  39. #endif
  40. // sck = F_BUS / PBR * ((1+DBR)/BR)
  41. // PBR = 2, 3, 5, 7
  42. // DBR = 0, 1 -- zero preferred
  43. // BR = 2, 4, 6, 8, 16, 32, 64, 128, 256, 512
  44. #ifdef HAS_SPIFIFO
  45. #ifndef SPI_MODE0
  46. #define SPI_MODE0 0x00 // CPOL = 0, CPHA = 0
  47. #define SPI_MODE1 0x04 // CPOL = 0, CPHA = 1
  48. #define SPI_MODE2 0x08 // CPOL = 1, CPHA = 0
  49. #define SPI_MODE3 0x0C // CPOL = 1, CPHA = 1
  50. #endif
  51. #define SPI_CONTINUE 1
  52. class SPIFIFOclass
  53. {
  54. public:
  55. inline void begin(uint8_t pin, uint32_t speed, uint32_t mode=SPI_MODE0) __attribute__((always_inline)) {
  56. uint32_t p, ctar = speed;
  57. SIM_SCGC6 |= SIM_SCGC6_SPI0;
  58. SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
  59. if (mode & 0x08) ctar |= SPI_CTAR_CPOL;
  60. if (mode & 0x04) {
  61. ctar |= SPI_CTAR_CPHA;
  62. ctar |= (ctar & 0x0F) << 8;
  63. } else {
  64. ctar |= (ctar & 0x0F) << 12;
  65. }
  66. SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7);
  67. SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15);
  68. if (pin == 10) { // PTC4
  69. CORE_PIN10_CONFIG = PORT_PCR_MUX(2);
  70. p = 0x01;
  71. } else if (pin == 2) { // PTD0
  72. CORE_PIN2_CONFIG = PORT_PCR_MUX(2);
  73. p = 0x01;
  74. } else if (pin == 9) { // PTC3
  75. CORE_PIN9_CONFIG = PORT_PCR_MUX(2);
  76. p = 0x02;
  77. } else if (pin == 6) { // PTD4
  78. CORE_PIN6_CONFIG = PORT_PCR_MUX(2);
  79. p = 0x02;
  80. } else if (pin == 20) { // PTD5
  81. CORE_PIN20_CONFIG = PORT_PCR_MUX(2);
  82. p = 0x04;
  83. } else if (pin == 23) { // PTC2
  84. CORE_PIN23_CONFIG = PORT_PCR_MUX(2);
  85. p = 0x04;
  86. } else if (pin == 21) { // PTD6
  87. CORE_PIN21_CONFIG = PORT_PCR_MUX(2);
  88. p = 0x08;
  89. } else if (pin == 22) { // PTC1
  90. CORE_PIN22_CONFIG = PORT_PCR_MUX(2);
  91. p = 0x08;
  92. } else if (pin == 15) { // PTC0
  93. CORE_PIN15_CONFIG = PORT_PCR_MUX(2);
  94. p = 0x10;
  95. } else {
  96. reg = portOutputRegister(pin);
  97. *reg = 1;
  98. pinMode(pin, OUTPUT);
  99. p = 0;
  100. }
  101. pcs = p;
  102. clear();
  103. SPCR.enable_pins();
  104. }
  105. inline void write(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) {
  106. uint32_t pcsbits = pcs << 16;
  107. if (pcsbits) {
  108. SPI0.PUSHR = (b & 0xFF) | pcsbits | (cont ? SPI_PUSHR_CONT : 0);
  109. while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full
  110. } else {
  111. *reg = 0;
  112. SPI0.SR = SPI_SR_EOQF;
  113. SPI0.PUSHR = (b & 0xFF) | (cont ? 0 : SPI_PUSHR_EOQ);
  114. if (cont) {
  115. while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ;
  116. } else {
  117. while (!(SPI0.SR & SPI_SR_EOQF)) ;
  118. *reg = 1;
  119. }
  120. }
  121. }
  122. inline void write16(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) {
  123. uint32_t pcsbits = pcs << 16;
  124. if (pcsbits) {
  125. SPI0.PUSHR = (b & 0xFFFF) | (pcs << 16) |
  126. (cont ? SPI_PUSHR_CONT : 0) | SPI_PUSHR_CTAS(1);
  127. while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ;
  128. } else {
  129. *reg = 0;
  130. SPI0.SR = SPI_SR_EOQF;
  131. SPI0.PUSHR = (b & 0xFFFF) | (cont ? 0 : SPI_PUSHR_EOQ) | SPI_PUSHR_CTAS(1);
  132. if (cont) {
  133. while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ;
  134. } else {
  135. while (!(SPI0.SR & SPI_SR_EOQF)) ;
  136. *reg = 1;
  137. }
  138. }
  139. }
  140. inline uint32_t read(void) __attribute__((always_inline)) {
  141. while ((SPI0.SR & (15 << 4)) == 0) ; // TODO, could wait forever
  142. return SPI0.POPR;
  143. }
  144. inline void clear(void) __attribute__((always_inline)) {
  145. SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
  146. }
  147. private:
  148. static uint8_t pcs;
  149. static volatile uint8_t *reg;
  150. };
  151. extern SPIFIFOclass SPIFIFO;
  152. #endif
  153. #endif