SPIFIFO.h
1 #ifndef _SPIFIFO_h_ 2 #define _SPIFIFO_h_ 3 4 #include "avr_emulation.h" 5 6 #if F_BUS == 60000000 7 #define HAS_SPIFIFO 8 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(60 / 3) * ((1+1)/2) = 20 MHz 9 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(60 / 2) * ((1+0)/2) = 15 MHz 10 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(60 / 5) * ((1+1)/2) 11 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1)) //(60 / 2) * ((1+0)/4) = 7.5 MHz 12 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0)) //(60 / 5) * ((1+0)/2) 13 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(2) | SPI_CTAR_DBR) //(60 / 5) * ((1+1)/6) 14 15 #elif F_BUS == 56000000 16 #define HAS_SPIFIFO 17 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(56 / 3) * ((1+1)/2) = 18.67 18 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(56 / 2) * ((1+0)/2) = 14 19 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(56 / 5) * ((1+1)/2) = 11.2 20 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(56 / 7) * ((1+1)/2) 21 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0)) //(56 / 5) * ((1+0)/2) 22 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(0)) //(56 / 7) * ((1+0)/2) 23 24 #elif F_BUS == 48000000 25 #define HAS_SPIFIFO 26 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(48 / 2) * ((1+1)/2) 27 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(48 / 3) * ((1+1)/2) 28 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(48 / 2) * ((1+0)/2) 29 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2) | SPI_CTAR_DBR) //(48 / 2) * ((1+1)/6) 30 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1)) //(48 / 2) * ((1+0)/4) 31 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2)) //(48 / 2) * ((1+0)/6) 32 33 #elif F_BUS == 40000000 34 #define HAS_SPIFIFO 35 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 2) * ((1+1)/2) = 20 36 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 3) * ((1+1)/2) = 13.33 37 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(40 / 2) * ((1+0)/2) = 10 38 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(40 / 5) * ((1+1)/2) 39 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(3) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(40 / 7) * ((1+1)/2) = 5.71 40 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(1)) //(40 / 5) * ((1+0)/2) 41 42 #elif F_BUS == 36000000 43 #define HAS_SPIFIFO 44 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(36 / 2) * ((1+1)/2) = 18 45 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(36 / 3) * ((1+1)/2) = 12 46 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(36 / 3) * ((1+1)/2) = 12 47 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(2) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(36 / 5) * ((1+1)/2) = 7.2 48 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2) | SPI_CTAR_DBR) //(36 / 2) * ((1+1)/6) 49 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(2) | SPI_CTAR_DBR) //(36 / 3) * ((1+1)/6) 50 51 #elif F_BUS == 24000000 52 #define HAS_SPIFIFO 53 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2) 12 MHz 54 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2) 12 MHz 55 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/2) 56 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(1) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(24 / 3) * ((1+1)/2) 57 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0)) //(24 / 2) * ((1+0)/2) 58 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(2) | SPI_CTAR_DBR) //(24 / 2) * ((1+1)/6) 59 60 #elif F_BUS == 16000000 61 #define HAS_SPIFIFO 62 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 63 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 64 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 65 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 66 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 67 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(3) | SPI_CTAR_DBR) //(16 / 2) * ((1+1)/8) = 2 MHz 68 69 #elif F_BUS == 8000000 70 #define HAS_SPIFIFO 71 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 72 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 73 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 74 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 75 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 76 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(1) | SPI_CTAR_DBR) //(8 / 2) * ((1+1)/4) = 2 MHz 77 78 #elif F_BUS == 4000000 79 #define HAS_SPIFIFO 80 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 81 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 82 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 83 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 84 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 85 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 2 MHz 86 87 #elif F_BUS == 2000000 88 #define HAS_SPIFIFO 89 #define SPI_CLOCK_24MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 90 #define SPI_CLOCK_16MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 91 #define SPI_CLOCK_12MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 92 #define SPI_CLOCK_8MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 93 #define SPI_CLOCK_6MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 94 #define SPI_CLOCK_4MHz (SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_DBR) //(4 / 2) * ((1+1)/2) = 1 MHz 95 96 #endif 97 98 /* 99 #! /usr/bin/perl 100 $clock = 60; 101 for $i (2, 3, 5, 7) { 102 for $j (0, 1) { 103 for $k (2, 4, 6, 8, 16, 32) { 104 $out = $clock / $i * (1 + $j) / $k; 105 printf "%0.2f : ", $out; 106 print "$clock / $i * (1 + $j) / $k = $out\n"; 107 } 108 } 109 } 110 */ 111 112 // sck = F_BUS / PBR * ((1+DBR)/BR) 113 // PBR = 2, 3, 5, 7 114 // DBR = 0, 1 -- zero preferred 115 // BR = 2, 4, 6, 8, 16, 32, 64, 128, 256, 512 116 117 118 #ifdef HAS_SPIFIFO 119 120 #ifndef SPI_MODE0 121 #define SPI_MODE0 0x00 // CPOL = 0, CPHA = 0 122 #define SPI_MODE1 0x04 // CPOL = 0, CPHA = 1 123 #define SPI_MODE2 0x08 // CPOL = 1, CPHA = 0 124 #define SPI_MODE3 0x0C // CPOL = 1, CPHA = 1 125 #endif 126 127 #define SPI_CONTINUE 1 128 129 class SPIFIFOclass 130 { 131 public: 132 inline void begin(uint8_t pin, uint32_t speed, uint32_t mode=SPI_MODE0) __attribute__((always_inline)) { 133 uint32_t p, ctar = speed; 134 SIM_SCGC6 |= SIM_SCGC6_SPI0; 135 136 SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F); 137 if (mode & 0x08) ctar |= SPI_CTAR_CPOL; 138 if (mode & 0x04) { 139 ctar |= SPI_CTAR_CPHA; 140 ctar |= (ctar & 0x0F) << 8; 141 } else { 142 ctar |= (ctar & 0x0F) << 12; 143 } 144 SPI0.CTAR0 = ctar | SPI_CTAR_FMSZ(7); 145 SPI0.CTAR1 = ctar | SPI_CTAR_FMSZ(15); 146 if (pin == 10) { // PTC4 147 CORE_PIN10_CONFIG = PORT_PCR_MUX(2); 148 p = 0x01; 149 } else if (pin == 2) { // PTD0 150 CORE_PIN2_CONFIG = PORT_PCR_MUX(2); 151 p = 0x01; 152 } else if (pin == 9) { // PTC3 153 CORE_PIN9_CONFIG = PORT_PCR_MUX(2); 154 p = 0x02; 155 } else if (pin == 6) { // PTD4 156 CORE_PIN6_CONFIG = PORT_PCR_MUX(2); 157 p = 0x02; 158 } else if (pin == 20) { // PTD5 159 CORE_PIN20_CONFIG = PORT_PCR_MUX(2); 160 p = 0x04; 161 } else if (pin == 23) { // PTC2 162 CORE_PIN23_CONFIG = PORT_PCR_MUX(2); 163 p = 0x04; 164 } else if (pin == 21) { // PTD6 165 CORE_PIN21_CONFIG = PORT_PCR_MUX(2); 166 p = 0x08; 167 } else if (pin == 22) { // PTC1 168 CORE_PIN22_CONFIG = PORT_PCR_MUX(2); 169 p = 0x08; 170 } else if (pin == 15) { // PTC0 171 CORE_PIN15_CONFIG = PORT_PCR_MUX(2); 172 p = 0x10; 173 } else { 174 reg = portOutputRegister(pin); 175 *reg = 1; 176 pinMode(pin, OUTPUT); 177 p = 0; 178 } 179 pcs = p; 180 clear(); 181 SPCR.enable_pins(); 182 } 183 inline void write(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { 184 uint32_t pcsbits = pcs << 16; 185 if (pcsbits) { 186 SPI0.PUSHR = (b & 0xFF) | pcsbits | (cont ? SPI_PUSHR_CONT : 0); 187 while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; // wait if FIFO full 188 } else { 189 *reg = 0; 190 SPI0.SR = SPI_SR_EOQF; 191 SPI0.PUSHR = (b & 0xFF) | (cont ? 0 : SPI_PUSHR_EOQ); 192 if (cont) { 193 while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; 194 } else { 195 while (!(SPI0.SR & SPI_SR_EOQF)) ; 196 *reg = 1; 197 } 198 } 199 } 200 inline void write16(uint32_t b, uint32_t cont=0) __attribute__((always_inline)) { 201 uint32_t pcsbits = pcs << 16; 202 if (pcsbits) { 203 SPI0.PUSHR = (b & 0xFFFF) | (pcs << 16) | 204 (cont ? SPI_PUSHR_CONT : 0) | SPI_PUSHR_CTAS(1); 205 while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; 206 } else { 207 *reg = 0; 208 SPI0.SR = SPI_SR_EOQF; 209 SPI0.PUSHR = (b & 0xFFFF) | (cont ? 0 : SPI_PUSHR_EOQ) | SPI_PUSHR_CTAS(1); 210 if (cont) { 211 while (((SPI0.SR) & (15 << 12)) > (3 << 12)) ; 212 } else { 213 while (!(SPI0.SR & SPI_SR_EOQF)) ; 214 *reg = 1; 215 } 216 } 217 } 218 inline uint32_t read(void) __attribute__((always_inline)) { 219 while ((SPI0.SR & (15 << 4)) == 0) ; // TODO, could wait forever 220 return SPI0.POPR; 221 } 222 inline void clear(void) __attribute__((always_inline)) { 223 SPI0.MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F) | SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF; 224 } 225 private: 226 static uint8_t pcs; 227 static volatile uint8_t *reg; 228 }; 229 extern SPIFIFOclass SPIFIFO; 230 231 #endif 232 #endif