Pixels
Pixels_SPIhw.h
1 /*
2  * Pixels. Graphics library for TFT displays.
3  *
4  * Copyright (C) 2012-2013 Igor Repinetski
5  *
6  * The code is written in C/C++ for Arduino and can be easily ported to any microcontroller by rewritting the low level pin access functions.
7  *
8  * Text output methods of the library rely on Pixelmeister's font data format. See: http://pd4ml.com/pixelmeister
9  *
10  * This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/
11  *
12  * This library includes some code portions and algoritmic ideas derived from works of
13  * - Andreas Schiffler -- aschiffler at ferzkopp dot net (SDL_gfx Project)
14  * - K. Townsend http://microBuilder.eu (lpc1343codebase Project)
15  */
16 
17 /*
18  * Hardware SPI layer (SCL=13, SDA=11 on Arduino)
19  */
20 
21 #include "Pixels.h"
22 
23 #ifdef PIXELS_MAIN
24 #error Pixels_SPIhw.h must be included before Pixels_<CONTROLLER>.h
25 #endif
26 
27 #ifndef PIXELS_SPIHW_H
28 #define PIXELS_SPIHW_H
29 
30 #define SPI_CLOCK_DIV4 0x00
31 #define SPI_CLOCK_DIV16 0x01
32 #define SPI_CLOCK_DIV64 0x02
33 #define SPI_CLOCK_DIV128 0x03
34 #define SPI_CLOCK_DIV2 0x04
35 #define SPI_CLOCK_DIV8 0x05
36 #define SPI_CLOCK_DIV32 0x06
37 #define SPI_CLOCK_DIV64 0x07
38 
39 #define SPI_MODE0 0x00
40 #define SPI_MODE1 0x04
41 #define SPI_MODE2 0x08
42 #define SPI_MODE3 0x0C
43 
44 #define SPI_MODE_MASK 0x0C // CPOL = bit 3, CPHA = bit 2 on SPCR
45 #define SPI_CLOCK_MASK 0x03 // SPR1 = bit 1, SPR0 = bit 0 on SPCR
46 #define SPI_2XCLOCK_MASK 0x01 // SPI2X = bit 0 on SPSR
47 
48 #define SPI(X) SPDR=X;while(!(SPSR&_BV(SPIF)))
49 
50 class SPIhw {
51 private:
52  uint8_t pinSCL;
53  uint8_t pinSDA;
54  uint8_t pinWR;
55  uint8_t pinCS;
56  uint8_t pinRST;
57 
58  regtype *registerSCL;
59  regtype *registerSDA;
60  regtype *registerWR;
61  regsize bitmaskSCL;
62  regsize bitmaskSDA;
63  regsize bitmaskWR;
64 
65  void beginSPI();
66  void endSPI();
67 
68  bool eightBit;
69 
70 protected:
71  void reset() {
72  digitalWrite(pinRST,LOW);
73  delay(100);
74  digitalWrite(pinRST,HIGH);
75  delay(100);
76  }
77 
78  void writeCmd(uint8_t b);
79  __attribute__((noinline)) void writeData(uint8_t data); // noinline saves 4-5kb sketch code in the case. An impact to performance is to be learned.
80 
81  void writeData(uint8_t hi, uint8_t lo) {
82  writeData(hi);
83  writeData(lo);
84  }
85 
86  void writeDataTwice(uint8_t b) {
87  writeData(b);
88  writeData(b);
89  }
90 
91  void writeCmdData(uint8_t cmd, uint16_t data) {
92  writeCmd(cmd);
93  writeData(highByte(data));
94  writeData(lowByte(data));
95  }
96 
97 public:
98  void setSPIBitOrder(uint8_t bitOrder);
99  void setSPIDataMode(uint8_t mode);
100  void setSPIClockDivider(uint8_t rate);
101 // void setSPIEightBit(bool bits) {
102 // eightBit = bits;
103 // }
104 
113  inline void setSpiPins(uint8_t scl, uint8_t sda, uint8_t cs, uint8_t rst, uint8_t wr = 255) {
114  pinSCL = scl;
115  pinSDA = sda;
116  pinCS = cs;
117  pinRST = rst;
118  pinWR = wr;
119  eightBit = wr != 255;
120  }
121 
126  inline void setPpiPins(uint8_t rs, uint8_t wr, uint8_t cs, uint8_t rst, uint8_t rd) {
127  }
128 
129  inline void registerSelect() {
130  }
131 
132  void initInterface();
133 };
134 
135 void SPIhw::initInterface() {
136  registerSCL = portOutputRegister(digitalPinToPort(pinSCL));
137  bitmaskSCL = digitalPinToBitMask(pinSCL);
138  registerSDA = portOutputRegister(digitalPinToPort(pinSDA));
139  bitmaskSDA = digitalPinToBitMask(pinSDA);
140  registerWR = portOutputRegister(digitalPinToPort(pinWR));
141  bitmaskWR = digitalPinToBitMask(pinWR);
142  registerCS = portOutputRegister(digitalPinToPort(pinCS));
143  bitmaskCS = digitalPinToBitMask(pinCS);
144 
145  pinMode(pinSCL,OUTPUT);
146  pinMode(pinSDA,OUTPUT);
147  pinMode(pinWR,OUTPUT);
148  pinMode(pinRST,OUTPUT);
149  pinMode(pinCS,OUTPUT);
150 
151  reset();
152 
153  setSPIBitOrder(MSBFIRST);
154  setSPIDataMode(SPI_MODE3);
155  // setSPIClockDivider(SPI_CLOCK_DIV64);
156  beginSPI();
157 }
158 
159 void SPIhw::writeCmd(uint8_t cmd) {
160  if ( eightBit ) {
161  *registerWR &= ~bitmaskWR;
162  } else {
163  SPCR &= ~_BV(SPE); // Disable SPI to get control of the SCK pin.
164  cbi(registerSDA, bitmaskSDA);
165  cbi(registerSCL, bitmaskSCL); // Pull SPI SCK high
166  // delay(1); // Insert extra time to the hight pulse, typically needed
167  sbi(registerSCL, bitmaskSCL); // Pull SPI SCK low
168  SPCR |= _BV(SPE); // Enable SPI again
169  }
170 
171 #if defined(TEENSYDUINO)
172  SPI0_SR = SPI_SR_TCF;
173  SPI0_PUSHR = cmd;
174  while (!(SPI0_SR & SPI_SR_TCF)) ; // wait
175 #else
176  SPDR = cmd;
177  while (!(SPSR & _BV(SPIF)));
178 #endif
179 }
180 
181 void SPIhw::writeData(uint8_t data) {
182  if ( eightBit ) {
183  *registerWR |= bitmaskWR;
184  } else {
185  SPCR &= ~_BV(SPE); // Disable SPI to get control of the SCK pin.
186  sbi(registerSDA, bitmaskSDA);
187  cbi(registerSCL, bitmaskSCL); // Pull SPI SCK high
188  // delay(1); // Insert extra time to the hight pulse, typically needed
189  sbi(registerSCL, bitmaskSCL); // Pull SPI SCK low
190  SPCR |= _BV(SPE); // Enable SPI again
191  }
192 
193 #if defined(TEENSYDUINO)
194  SPI0_SR = SPI_SR_TCF;
195  SPI0_PUSHR = data;
196  while (!(SPI0_SR & SPI_SR_TCF)) ; // wait
197 #else
198  SPDR = data;
199  while (!(SPSR & _BV(SPIF)));
200 #endif
201 }
202 
203 void SPIhw::beginSPI() {
204  cbi(registerSCL, bitmaskSCL);
205  cbi(registerSDA, bitmaskSDA);
206  digitalWrite(pinCS, HIGH);
207 
208  // Warning: if the SS pin ever becomes a LOW INPUT then SPI
209  // automatically switches to Slave, so the data direction of
210  // the SS pin MUST be kept as OUTPUT.
211 
212  SPCR |= _BV(MSTR);
213  SPCR |= _BV(SPE);
214 
215 #if defined(TEENSYDUINO)
216  uint32_t ctar = SPI_CTAR_FMSZ(7) |
217  SPI_CTAR_PBR(0) | SPI_CTAR_BR(0) | SPI_CTAR_CSSCK(0) | SPI_CTAR_DBR;
218 
219  SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
220  SPI0_CTAR0 = ctar;
221  SPI0_CTAR1 = ctar | SPI_CTAR_FMSZ(8);
222  SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
223 #else
224  DDRB = DDRB | B00000001; // PB0 as OUTPUT
225  PORTB = PORTB | B00000001; // PB0 as HIGH
226 #endif
227 }
228 
229 void SPIhw::endSPI() {
230  SPCR &= ~_BV(SPE);
231 }
232 
233 void SPIhw::setSPIBitOrder(uint8_t bitOrder) {
234  if(bitOrder == LSBFIRST) {
235  SPCR |= _BV(DORD);
236  } else {
237  SPCR &= ~(_BV(DORD));
238  }
239 }
240 
241 void SPIhw::setSPIDataMode(uint8_t mode) {
242  SPCR = (SPCR & ~SPI_MODE_MASK) | mode;
243 }
244 
245 void SPIhw::setSPIClockDivider(uint8_t rate) {
246  SPCR = (SPCR & ~SPI_CLOCK_MASK) | (rate & SPI_CLOCK_MASK);
247  SPSR = (SPSR & ~SPI_2XCLOCK_MASK) | ((rate >> 2) & SPI_2XCLOCK_MASK);
248 }
249 #endif
void setSpiPins(uint8_t scl, uint8_t sda, uint8_t cs, uint8_t rst, uint8_t wr=255)
Definition: Pixels_SPIhw.h:113
void setPpiPins(uint8_t rs, uint8_t wr, uint8_t cs, uint8_t rst, uint8_t rd)
Definition: Pixels_SPIhw.h:126