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.

SPIFIFO.h 5.9KB

11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
11 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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