egoShield
screen.cpp
Go to the documentation of this file.
1 /********************************************************************************************
2 * File: screen.h *
3 * Version: 1.1.1 *
4 * Date: April 1st, 2020 *
5 * Author: Mogens Groth Nicolaisen *
6 * *
7 *********************************************************************************************
8 * (C) 2020 *
9 * *
10 * uStepper ApS *
11 * www.ustepper.com *
12 * administration@ustepper.com *
13 * *
14 * The code contained in this file is released under the following open source license: *
15 * *
16 * Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International *
17 * *
18 * The code in this file is provided without warranty of any kind - use at own risk! *
19 * neither uStepper ApS nor the author, can be held responsible for any damage *
20 * caused by the use of the code contained in this file ! *
21 * *
22 ********************************************************************************************/
29 #include "screen.h"
30 #include "egoShieldS.h"
31 
32 Screen::Screen(bool i2cChannel)
33 {
34  if(i2cChannel)
35  {
36  // activate internal pullups for twi.
37  digitalWrite(SDA0, HIGH);
38  digitalWrite(SCL0, HIGH);
39  }
40  else
41  {
42  // activate internal pullups for twi.
43  digitalWrite(SDA1, HIGH);
44  digitalWrite(SCL1, HIGH);
45  }
46 
47  if(i2cChannel)
48  {
49  this->twsr = 0xD9;
50  this->twbr = 0xD8;
51  this->twdr = 0xDB;
52  this->twcr = 0xDC;
53  }
54  else
55  {
56  this->twsr = 0xB9;
57  this->twbr = 0xB8;
58  this->twdr = 0xBB;
59  this->twcr = 0xBC;
60  }
61 
62 }
63 void Screen::init()
64 {
65 
66  if(this->busFailure)
67  {
68  _SFR_MEM8(this->twcr) = (1 << TWEN0)| (1 << TWINT0) | (1 << TWSTO0); // Send STOP
69 
70  }
71  this->busFailure = 0;
72 
73  //reset bus
74  _SFR_MEM8(this->twsr) = 0;
75  _SFR_MEM8(this->twcr) = 0;
76 
77  // set bit rate register to 72 to obtain 100kHz scl frequency (in combination with no prescaling!)
78  _SFR_MEM8(this->twbr) = 72;
79  // no prescaler
80  _SFR_MEM8(this->twsr) &= 0xFC;
81  // enable twi module, acks, and twi interrupt
82  _SFR_MEM8(this->twcr) = _BV(TWEN0);
83 
84  SSD1306_SEND_CMD(SSD1306_DISPLAY_OFF);
85  SSD1306_SEND_CMD(SSD1306_SET_DISPLAY_CLOCK_DIV_RATIO);
86  SSD1306_SEND_CMD(0x80);
87  SSD1306_SEND_CMD(SSD1306_SET_MULTIPLEX_RATIO);
88  SSD1306_SEND_CMD(H64_MULTIPLEX_RATIO); // 0x3F for 128x64, 0x1F for 128x32
89  SSD1306_SEND_CMD(SSD1306_SET_DISPLAY_OFFSET);
90  SSD1306_SEND_CMD(0x0);
91  SSD1306_SEND_CMD(SSD1306_SET_START_LINE | 0x0);
92  SSD1306_SEND_CMD(SSD1306_CHARGE_PUMP);
93  SSD1306_SEND_CMD(0x14);
94  SSD1306_SEND_CMD(SSD1306_MEMORY_ADDR_MODE);
95  SSD1306_SEND_CMD(0x00);
96  SSD1306_SEND_CMD(SSD1306_SET_SEGMENT_REMAP | 0x1);
97  SSD1306_SEND_CMD(SSD1306_COM_SCAN_DIR_DEC);
98  SSD1306_SEND_CMD(SSD1306_SET_COM_PINS);
99  SSD1306_SEND_CMD(H64_COM_PINS); // 0x12 for 128x64, 0x02 for 128x32
100  SSD1306_SEND_CMD(SSD1306_SET_CONTRAST_CONTROL);
101  SSD1306_SEND_CMD(0xCF);
102  SSD1306_SEND_CMD(SSD1306_SET_PRECHARGE_PERIOD);
103  SSD1306_SEND_CMD(0xF1);
104  SSD1306_SEND_CMD(SSD1306_SET_VCOM_DESELECT);
105  SSD1306_SEND_CMD(0x40);
106  SSD1306_SEND_CMD(SSD1306_DISPLAY_ALL_ON_RESUME);
107  SSD1306_SEND_CMD(SSD1306_NORMAL_DISPLAY);
108  SSD1306_SEND_CMD(SSD1306_DISPLAY_ON);
109 
110  clrScreen();
111 }
112 
113 void* Screen::operator new(size_t size)
114 {
115  void *object = malloc(size);
116  return object;
117 }
118 
119 bool Screen::waitForAck()
120 {
121  int32_t time = millis();
122 
123  while ((_SFR_MEM8(this->twcr) & (1 << TWINT0)) == 0)
124  {
125  if(millis() - time > 10)
126  {
127  return 1;
128  }
129  };
130  return 0;
131 }
132 
133 void Screen::clrScreen()
134 {
135 
136  if(this->busFailure)
137  {
138  return;
139  }
140 
141  SSD1306_SEND_CMD(SSD1306_SET_COLUMN_ADDR);
142  SSD1306_SEND_CMD(0);
143  SSD1306_SEND_CMD(127);
144 
145  SSD1306_SEND_CMD(SSD1306_SET_PAGE_ADDR);
146  SSD1306_SEND_CMD(0);
147  SSD1306_SEND_CMD(7);
148 
149  // Send start address
150  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWEA0) | (1 << TWINT0) | (1 << TWSTA0);
151  if(this->waitForAck()){this->busFailure = 1; return;}
152  _SFR_MEM8(this->twdr) = SSD1306_ADDR<<1;
153  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
154  if(this->waitForAck()){this->busFailure = 1; return;}
155  _SFR_MEM8(this->twdr) = SSD1306_DATA_CONTINUE;
156  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
157  if(this->waitForAck()){this->busFailure = 1; return;}
158 
159  for (uint16_t b=0; b < 128*8; b++) // Send data
160  {
161  _SFR_MEM8(this->twdr) = 0x00;
162  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
163  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
164  }
165 
166  _SFR_MEM8(this->twcr) = (1 << TWEN0)| (1 << TWINT0) | (1 << TWSTO0); // Send STOP
167 
168 }
169 
170 void Screen::drawImage(const uint8_t *image, uint8_t x, uint8_t y, uint8_t width, uint8_t height, bool invert)
171 {
172  int16_t i;
173  uint8_t pattern;
174 
175  if(this->busFailure)
176  {
177  return;
178  }
179 
180  SSD1306_SEND_CMD(SSD1306_SET_COLUMN_ADDR);
181  SSD1306_SEND_CMD(x);
182  SSD1306_SEND_CMD(x+width-1);
183 
184  SSD1306_SEND_CMD(SSD1306_SET_PAGE_ADDR);
185  SSD1306_SEND_CMD(y/8);
186  SSD1306_SEND_CMD(y/8 + height/8 - 1);
187 
188  // Send start address
189  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWEA0) | (1 << TWINT0) | (1 << TWSTA0);
190  if(this->waitForAck()){this->busFailure = 1; return;}
191  _SFR_MEM8(this->twdr) = SSD1306_ADDR<<1;
192  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
193  if(this->waitForAck()){this->busFailure = 1; return;}
194  _SFR_MEM8(this->twdr) = SSD1306_DATA_CONTINUE;
195  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
196  if(this->waitForAck()){this->busFailure = 1; return;}
197  for(i = (width*(height/8))-1; i > 0; i--)
198  {
199  pattern = pgm_read_byte(&(image[i]));
200 
201  if(invert)
202  {
203  pattern ^= 0xFF;
204  }
205 
206  _SFR_MEM8(this->twdr) = pattern;
207 
208  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
209  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
210  }
211 
212  _SFR_MEM8(this->twcr) = (1 << TWEN0)| (1 << TWINT0) | (1 << TWSTO0); // Send STOP
213 
214 }
215 
216 void Screen::printString(const uint8_t *string, uint8_t x, uint8_t y, bool invert)
217 {
218  if(this->busFailure)
219  {
220  return;
221  }
222 
223  const uint8_t *usedFont = font;
224  uint16_t i, j, len, k;
225  uint8_t pattern, width, height, rows = pgm_read_byte(&(usedFont[0])), offset = pgm_read_byte(&(usedFont[2]));
226  uint8_t patternOffset, runs;
227 
228  len = strlen(string);
229 
230  width = len*rows;
231  height = width/128;
232  if(width > 128)
233  {
234  width = 128;
235  }
236 
237 
238 
239  SSD1306_SEND_CMD(SSD1306_SET_COLUMN_ADDR);
240  SSD1306_SEND_CMD(x);
241  SSD1306_SEND_CMD(x+width-1);
242 
243  SSD1306_SEND_CMD(SSD1306_SET_PAGE_ADDR);
244  SSD1306_SEND_CMD(y/8);
245  SSD1306_SEND_CMD(y/8+height+runs-1);
246 
247  // Send start address
248  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWEA0) | (1 << TWINT0) | (1 << TWSTA0);
249  if(this->waitForAck()){this->busFailure = 1; return;}
250  _SFR_MEM8(this->twdr) = SSD1306_ADDR<<1;
251  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
252  if(this->waitForAck()){this->busFailure = 1; return;}
253  _SFR_MEM8(this->twdr) = SSD1306_DATA_CONTINUE;
254  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
255  if(this->waitForAck()){this->busFailure = 1; return;}
256 
257  for(i = 0; i < len; i++)
258  {
259  for(j = 0; j < rows; j++)
260  {
261  pattern = pgm_read_byte(&(usedFont[((string[i]-offset)*rows) + 4 + j]));
262 
263  if(invert)
264  {
265  pattern ^= 0xFF;
266  }
267 
268  _SFR_MEM8(this->twdr) = pattern;
269 
270  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
271  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
272  }
273  }
274 
275 
276  _SFR_MEM8(this->twcr) = (1 << TWEN0)| (1 << TWINT0) | (1 << TWSTO0); // Send STOP
277 
278 }
279 
280 void Screen::drawRect(int x1, int y1, int x2, int y2, bool color)
281 {
282  uint16_t b = 0;
283  uint8_t pattern;
284  uint8_t mask;
285 
286  if(this->busFailure)
287  {
288  return;
289  }
290 
291  if(y2 < y1 || x2 < x1)
292  {
293  return;
294  }
295  if(x1 < 0 || x2 > 127 || y1 < 0 || y2 > 63)
296  {
297  return;
298  }
299 
300 
301  SSD1306_SEND_CMD(SSD1306_SET_COLUMN_ADDR);
302  SSD1306_SEND_CMD(x1);
303  SSD1306_SEND_CMD(x2);
304 
305  SSD1306_SEND_CMD(SSD1306_SET_PAGE_ADDR);
306  SSD1306_SEND_CMD(y1/8);
307  SSD1306_SEND_CMD(y2/8);
308 
309  // Send start address
310  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWEA0) | (1 << TWINT0) | (1 << TWSTA0);
311  if(this->waitForAck()){this->busFailure = 1; return;}
312  _SFR_MEM8(this->twdr) = SSD1306_ADDR<<1;
313  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
314  if(this->waitForAck()){this->busFailure = 1; return;}
315  _SFR_MEM8(this->twdr) = SSD1306_DATA_CONTINUE;
316  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0);
317  if(this->waitForAck()){this->busFailure = 1; return;}
318 
319  if(color)
320  {
321  pattern = 0xFF;
322  }
323  else
324  {
325  pattern = 0x00;
326  }
327  mask = 0x01;
328  for(b = y1%8; b > 0; b--)
329  {
330  pattern ^= mask;
331  mask <<= 1;
332  }
333 
334  if(y2/8 == y1/8)
335  {
336  mask = 0x80;
337  for(b = 7 - y2%8; b > 0; b--)
338  {
339  pattern ^= mask;
340  mask >>= 1;
341  }
342  }
343 
344  for (b=0; b < (x2 - x1)+1; b++) // Send data
345  {
346  _SFR_MEM8(this->twdr) = pattern;
347 
348  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
349  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
350  }
351 
352  if(y2/8 != y1/8)
353  {
354  if((y2/8 - y1/8) > 1)
355  {
356  if(color)
357  {
358  pattern = 0xFF;
359  }
360  else
361  {
362  pattern = 0x00;
363  }
364  for (b=0; b < (((y2/8) - (y1/8)) - 1) * ((x2 - x1) + 1); b++) // Send data
365  {
366  _SFR_MEM8(this->twdr) = pattern;
367 
368  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
369  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
370  }
371  }
372 
373  if(color)
374  {
375  pattern = 0x00;
376  }
377  else
378  {
379  pattern = 0xFF;
380  }
381  mask = 0x01;
382  for(b = y2%8 + 1; b > 0; b--)
383  {
384  pattern ^= mask;
385  mask <<= 1;
386  }
387  for (b=0; b < (x2 - x1)+1; b++) // Send data
388  {
389  _SFR_MEM8(this->twdr) = pattern;
390 
391  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
392  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
393  }
394  }
395 
396 
397  _SFR_MEM8(this->twcr) = (1 << TWEN0)| (1 << TWINT0) | (1 << TWSTO0); // Send STOP
398 
399 
400 }
401 
402 void Screen::cmd(uint8_t cmd)
403 {
404  if(this->busFailure)
405  {
406  return;
407  }
408 
409  // Send start address
410  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWEA0) | (1 << TWINT0) | (1 << TWSTA0); // Send START
411  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
412  _SFR_MEM8(this->twdr) = SSD1306_ADDR<<1;
413  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
414  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
415 
416  _SFR_MEM8(this->twdr) = SSD1306_COMMAND;
417  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
418  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
419  _SFR_MEM8(this->twdr) = cmd;
420  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWEA0); // Clear TWINT to proceed
421  if(this->waitForAck()){this->busFailure = 1; return;} // Wait for TWI to be ready
422 
423  _SFR_MEM8(this->twcr) = (1 << TWEN0) | (1 << TWINT0) | (1 << TWSTO0); // Send STOP
424 
425 }
screen.h
class definitions for the screen handling
egoShieldS.h
Class definition for the egoShieldS library.