/ teensy3 / SPIFIFO.h
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