Bonjour,
Plus j'avance dans mon projet et plus je découvre que je dois maîtriser vraiment à fond le C++ qui se cache derrière l'environnement Arduino
Avez-vous un bon cours ou un bon livre à me recommander ?
En particulier, ce que je souhaite approfondir :
- les templates
- les classes
- variables, fonctions statiques, attribus
- l'usage de l'assembleur
- l'accès au hardware
Pour illustrer mon besoin, j'ai trois fichiers venant d'une bibliothèque que j'ai commencé à optimiser mais elles utilisent massivement tout ce que je viens d'énumérer ci-dessus et que je ne maîtrise pas :
PDQ_FastPin.h
PDQ_ILI9341.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489 // // This excellent template library is from FastLED http://fastled.io // // I was considering writing something similar, but FastPin seemed perfect. // // Thanks FastLED people! Here is the license from FastLED followed by the // header // /* The MIT License (MIT) Copyright (c) 2013 FastLED Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __INC_FASTPIN_H #define __INC_FASTPIN_H #include<avr/io.h> // Arduino.h needed for convinience functions digitalPinToPort/BitMask/portOutputRegister and the pinMode methods. #include<Arduino.h> #define NO_PIN 255 // Class to ensure that a minimum amount of time has kicked since the last time run - and delay if not enough time has passed yet // this should make sure that chipsets that have template<int WAIT> class CMinWait { long mLastMicros; public: CMinWait() { mLastMicros = 0; } void wait() { long diff = micros() - mLastMicros; while(diff < WAIT) { diff = micros() - mLastMicros; } } void mark() { mLastMicros = micros(); } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Pin access class - needs to tune for various platforms (naive fallback solution?) // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) #define _CYCLES(_PIN) (((_PIN >= 62 ) || (_PIN>=42 && _PIN<=49) || (_PIN>=14 && _PIN <=17) || (_PIN>=6 && _PIN <=9)) ? 2 : 1) #else #define _CYCLES(_PIN) ((_PIN >= 24) ? 2 : 1) #endif class Selectable { public: virtual void select() = 0; virtual void release() = 0; virtual bool isSelected() = 0; }; class Pin : public Selectable { uint8_t mPinMask; uint8_t mPin; volatile uint8_t *mPort; void _init() { mPinMask = digitalPinToBitMask(mPin); mPort = portOutputRegister(digitalPinToPort(mPin)); } public: Pin(int pin) : mPin(pin) { _init(); } typedef volatile uint8_t * port_ptr_t; typedef uint8_t port_t; inline void setOutput() { pinMode(mPin, OUTPUT); } inline void setInput() { pinMode(mPin, INPUT); } inline void hi() __attribute__ ((always_inline)) { *mPort |= mPinMask; } inline void lo() __attribute__ ((always_inline)) { *mPort &= ~mPinMask; } inline void strobe() __attribute__ ((always_inline)) { hi(); lo(); } inline void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= mPinMask; } inline void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~mPinMask; } inline void set(register port_t val) __attribute__ ((always_inline)) { *mPort = val; } inline void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } port_t hival() __attribute__ ((always_inline)) { return *mPort | mPinMask; } port_t loval() __attribute__ ((always_inline)) { return *mPort & ~mPinMask; } port_ptr_t port() __attribute__ ((always_inline)) { return mPort; } port_t mask() __attribute__ ((always_inline)) { return mPinMask; } virtual void select() { hi(); } virtual void release() { lo(); } virtual bool isSelected() { return (*mPort & mPinMask) == mPinMask; } }; class OutputPin : public Pin { public: OutputPin(int pin) : Pin(pin) { setOutput(); } }; class InputPin : public Pin { public: InputPin(int pin) : Pin(pin) { setInput(); } }; /// The simplest level of Pin class. This relies on runtime functions durinig initialization to get the port/pin mask for the pin. Most /// of the accesses involve references to these static globals that get set up. This won't be the fastest set of pin operations, but it /// will provide pin level access on pretty much all arduino environments. In addition, it includes some methods to help optimize access in /// various ways. Namely, the versions of hi, lo, and fastset that take the port register as a passed in register variable (saving a global /// dereference), since these functions are aggressively inlined, that can help collapse out a lot of extraneous memory loads/dereferences. /// /// In addition, if, while writing a bunch of data to a pin, you know no other pins will be getting written to, you can get/cache a value of /// the pin's port register and use that to do a full set to the register. This results in one being able to simply do a store to the register, /// vs. the load, and/or, and store that would be done normally. /// /// There are platform specific instantiations of this class that provide direct i/o register access to pins for much higher speed pin twiddling. /// /// Note that these classes are all static functions. So the proper usage is Pin<13>::hi(); or such. Instantiating objects is not recommended, /// as passing Pin objects around will likely -not- have the effect you're expecting. template<uint8_t PIN> class FastPin { static uint8_t sPinMask; static volatile uint8_t *sPort; static void _init() { sPinMask = digitalPinToBitMask(PIN); sPort = portOutputRegister(digitalPinToPort(PIN)); } public: typedef volatile uint8_t * port_ptr_t; typedef uint8_t port_t; inline static void setOutput() { _init(); pinMode(PIN, OUTPUT); } inline static void setInput() { _init(); pinMode(PIN, INPUT); } inline static void hi() __attribute__ ((always_inline)) { *sPort |= sPinMask; } inline static void lo() __attribute__ ((always_inline)) { *sPort &= ~sPinMask; } inline static void strobe() __attribute__ ((always_inline)) { hi(); lo(); } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port |= sPinMask; } inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port &= ~sPinMask; } inline static void set(register port_t val) __attribute__ ((always_inline)) { *sPort = val; } inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } static port_t hival() __attribute__ ((always_inline)) { return *sPort | sPinMask; } static port_t loval() __attribute__ ((always_inline)) { return *sPort & ~sPinMask; } static port_ptr_t port() __attribute__ ((always_inline)) { return sPort; } static port_t mask() __attribute__ ((always_inline)) { return sPinMask; } }; template<uint8_t PIN> uint8_t FastPin<PIN>::sPinMask; template<uint8_t PIN> volatile uint8_t *FastPin<PIN>::sPort; /// Class definition for a Pin where we know the port registers at compile time for said pin. This allows us to make /// a lot of optimizations, as the inlined hi/lo methods will devolve to a single io register write/bitset. template<uint8_t PIN, uint8_t _MASK, typename _PORT, typename _DDR, typename _PIN> class _AVRPIN { public: typedef volatile uint8_t * port_ptr_t; typedef uint8_t port_t; inline static void setOutput() { _DDR::r() |= _MASK; } inline static void setInput() { _DDR::r() &= ~_MASK; } inline static void hi() __attribute__ ((always_inline)) { _PORT::r() |= _MASK; } inline static void lo() __attribute__ ((always_inline)) { _PORT::r() &= ~_MASK; } inline static void set(register uint8_t val) __attribute__ ((always_inline)) { _PORT::r() = val; } inline static void strobe() __attribute__ ((always_inline)) { hi(); lo(); } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } inline static void fastset(register port_ptr_t port, register uint8_t val) __attribute__ ((always_inline)) { set(val); } inline static port_t hival() __attribute__ ((always_inline)) { return _PORT::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PORT::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PORT::r(); } inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; /// Template definition for teensy 3.0 style ARM pins, providing direct access to the various GPIO registers. Note that this /// uses the full port GPIO registers. In theory, in some way, bit-band register access -should- be faster, however I have found /// that something about the way gcc does register allocation results in the bit-band code being slower. It will need more fine tuning. template<uint8_t PIN, uint32_t _MASK, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> class _ARMPIN { public: typedef volatile uint32_t * port_ptr_t; typedef uint32_t port_t; inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } inline static void hi() __attribute__ ((always_inline)) { _PSOR::r() = _MASK; } inline static void lo() __attribute__ ((always_inline)) { _PCOR::r() = _MASK; } inline static void set(register port_t val) __attribute__ ((always_inline)) { _PDOR::r() = val; } inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } inline static void toggle() __attribute__ ((always_inline)) { _PTOR::r() = _MASK; } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { hi(); } inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { lo(); } inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } inline static port_t hival() __attribute__ ((always_inline)) { return _PDOR::r() | _MASK; } inline static port_t loval() __attribute__ ((always_inline)) { return _PDOR::r() & ~_MASK; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return &_PDOR::r(); } inline static port_t mask() __attribute__ ((always_inline)) { return _MASK; } }; /// Template definition for teensy 3.0 style ARM pins using bit banding, providing direct access to the various GPIO registers. GCC /// does a poor job of optimizing around these accesses so they are not being used just yet. template<uint8_t PIN, int _BIT, typename _PDOR, typename _PSOR, typename _PCOR, typename _PTOR, typename _PDIR, typename _PDDR> class _ARMPIN_BITBAND { public: typedef volatile uint32_t * port_ptr_t; typedef uint32_t port_t; inline static void setOutput() { pinMode(PIN, OUTPUT); } // TODO: perform MUX config { _PDDR::r() |= _MASK; } inline static void setInput() { pinMode(PIN, INPUT); } // TODO: preform MUX config { _PDDR::r() &= ~_MASK; } inline static void hi() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 1; } inline static void lo() __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = 0; } inline static void set(register port_t val) __attribute__ ((always_inline)) { *_PDOR::template rx<_BIT>() = val; } inline static void strobe() __attribute__ ((always_inline)) { toggle(); toggle(); } inline static void toggle() __attribute__ ((always_inline)) { *_PTOR::template rx<_BIT>() = 1; } inline static void hi(register port_ptr_t port) __attribute__ ((always_inline)) { *port = 1; } inline static void lo(register port_ptr_t port) __attribute__ ((always_inline)) { *port = 0; } inline static void fastset(register port_ptr_t port, register port_t val) __attribute__ ((always_inline)) { *port = val; } inline static port_t hival() __attribute__ ((always_inline)) { return 1; } inline static port_t loval() __attribute__ ((always_inline)) { return 0; } inline static port_ptr_t port() __attribute__ ((always_inline)) { return _PDOR::template rx<_BIT>(); } inline static port_t mask() __attribute__ ((always_inline)) { return 1; } }; /// AVR definitions for pins. Getting around the fact that I can't pass GPIO register addresses in as template arguments by instead creating /// a custom type for each GPIO register with a single, static, aggressively inlined function that returns that specific GPIO register. A similar /// trick is used a bit further below for the ARM GPIO registers (of which there are far more than on AVR!) typedef volatile uint8_t & reg8_t; #define _R(T) struct __gen_struct_ ## T #define _RD8(T) struct __gen_struct_ ## T { static inline reg8_t r() { return T; }}; #define _IO(L) _RD8(DDR ## L); _RD8(PORT ## L); _RD8(PIN ## L); #define _DEFPIN_AVR(PIN, MASK, L) template<> class FastPin<PIN> : public _AVRPIN<PIN, MASK, _R(PORT ## L), _R(DDR ## L), _R(PIN ## L)> {}; // ARM definitions #define GPIO_BITBAND_ADDR(reg, bit) (((uint32_t)&(reg) - 0x40000000) * 32 + (bit) * 4 + 0x42000000) #define GPIO_BITBAND_PTR(reg, bit) ((uint32_t *)GPIO_BITBAND_ADDR((reg), (bit))) typedef volatile uint32_t & reg32_t; typedef volatile uint32_t * ptr_reg32_t; #define _RD32(T) struct __gen_struct_ ## T { static __attribute__((always_inline)) inline reg32_t r() { return T; } \ template<int BIT> static __attribute__((always_inline)) inline ptr_reg32_t rx() { return GPIO_BITBAND_PTR(T, BIT); } }; #define _IO32(L) _RD32(GPIO ## L ## _PDOR); _RD32(GPIO ## L ## _PSOR); _RD32(GPIO ## L ## _PCOR); _RD32(GPIO ## L ## _PTOR); _RD32(GPIO ## L ## _PDIR); _RD32(GPIO ## L ## _PDDR); #define _DEFPIN_ARM(PIN, BIT, L) template<> class FastPin<PIN> : public _ARMPIN<PIN, 1 << BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), \ _R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; // Don't use bit band'd pins for now, the compiler generates far less efficient code around them // #define _DEFPIN_ARM(PIN, BIT, L) template<> class Pin<PIN> : public _ARMPIN_BITBAND<PIN, BIT, _R(GPIO ## L ## _PDOR), _R(GPIO ## L ## _PSOR), _R(GPIO ## L ## _PCOR), // _R(GPIO ## L ## _PTOR), _R(GPIO ## L ## _PDIR), _R(GPIO ## L ## _PDDR)> {}; /////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Pin definitions for AVR and ARM. If there are pin definitions supplied below for the platform being // built on, then much higher speed access will be possible, namely with direct GPIO register accesses. // /////////////////////////////////////////////////////////////////////////////////////////////////////////// #if defined(FORCE_SOFTWARE_PINS) #warning "Softwrae pin support forced pin access will be slightly slower. See fastpin.h for info." #define NO_HARDWARE_PIN_SUPPORT #elif defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) _IO(B); _DEFPIN_AVR(0, 0x01, B); _DEFPIN_AVR(1, 0x02, B); _DEFPIN_AVR(2, 0x04, B); _DEFPIN_AVR(3, 0x08, B); _DEFPIN_AVR(4, 0x10, B); _DEFPIN_AVR(5, 0x20, B); #elif(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) _IO(A); _IO(B); _DEFPIN_AVR(0, 0x01, A); _DEFPIN_AVR(1, 0x02, A); _DEFPIN_AVR(2, 0x04, A); _DEFPIN_AVR(3, 0x08, A); _DEFPIN_AVR(4, 0x10, A); _DEFPIN_AVR(5, 0x20, A); _DEFPIN_AVR(6, 0x40, A); _DEFPIN_AVR(7, 0x80, A); _DEFPIN_AVR(8, 0x04, B); _DEFPIN_AVR(9, 0x02, B); _DEFPIN_AVR(10, 0x01, B); #elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) // Accelerated port definitions for arduino avrs _IO(D); _IO(B); _IO(C); _DEFPIN_AVR( 0, 0x01, D); _DEFPIN_AVR( 1, 0x02, D); _DEFPIN_AVR( 2, 0x04, D); _DEFPIN_AVR( 3, 0x08, D); _DEFPIN_AVR( 4, 0x10, D); _DEFPIN_AVR( 5, 0x20, D); _DEFPIN_AVR( 6, 0x40, D); _DEFPIN_AVR( 7, 0x80, D); _DEFPIN_AVR( 8, 0x01, B); _DEFPIN_AVR( 9, 0x02, B); _DEFPIN_AVR(10, 0x04, B); _DEFPIN_AVR(11, 0x08, B); _DEFPIN_AVR(12, 0x10, B); _DEFPIN_AVR(13, 0x20, B); _DEFPIN_AVR(14, 0x01, C); _DEFPIN_AVR(15, 0x02, C); _DEFPIN_AVR(16, 0x04, C); _DEFPIN_AVR(17, 0x08, C); _DEFPIN_AVR(18, 0x10, C); _DEFPIN_AVR(19, 0x20, C); #define SPI_DATA 11 #define SPI_CLOCK 13 #define SPI_SELECT 10 #define AVR_HARDWARE_SPI #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) // megas _IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _IO(G); _IO(H); _IO(J); _IO(K); _IO(L); _DEFPIN_AVR(0, 1, E); _DEFPIN_AVR(1, 2, E); _DEFPIN_AVR(2, 16, E); _DEFPIN_AVR(3, 32, E); _DEFPIN_AVR(4, 32, G); _DEFPIN_AVR(5, 8, E); _DEFPIN_AVR(6, 8, H); _DEFPIN_AVR(7, 16, H); _DEFPIN_AVR(8, 32, H); _DEFPIN_AVR(9, 64, H); _DEFPIN_AVR(10, 16, B); _DEFPIN_AVR(11, 32, B); _DEFPIN_AVR(12, 64, B); _DEFPIN_AVR(13, 128, B); _DEFPIN_AVR(14, 2, J); _DEFPIN_AVR(15, 1, J); _DEFPIN_AVR(16, 2, H); _DEFPIN_AVR(17, 1, H); _DEFPIN_AVR(18, 8, D); _DEFPIN_AVR(19, 4, D); _DEFPIN_AVR(20, 2, D); _DEFPIN_AVR(21, 1, D); _DEFPIN_AVR(22, 1, A); _DEFPIN_AVR(23, 2, A); _DEFPIN_AVR(24, 4, A); _DEFPIN_AVR(25, 8, A); _DEFPIN_AVR(26, 16, A); _DEFPIN_AVR(27, 32, A); _DEFPIN_AVR(28, 64, A); _DEFPIN_AVR(29, 128, A); _DEFPIN_AVR(30, 128, C); _DEFPIN_AVR(31, 64, C); _DEFPIN_AVR(32, 32, C); _DEFPIN_AVR(33, 16, C); _DEFPIN_AVR(34, 8, C); _DEFPIN_AVR(35, 4, C); _DEFPIN_AVR(36, 2, C); _DEFPIN_AVR(37, 1, C); _DEFPIN_AVR(38, 128, D); _DEFPIN_AVR(39, 4, G); _DEFPIN_AVR(40, 2, G); _DEFPIN_AVR(41, 1, G); _DEFPIN_AVR(42, 128, L); _DEFPIN_AVR(43, 64, L); _DEFPIN_AVR(44, 32, L); _DEFPIN_AVR(45, 16, L); _DEFPIN_AVR(46, 8, L); _DEFPIN_AVR(47, 4, L); _DEFPIN_AVR(48, 2, L); _DEFPIN_AVR(49, 1, L); _DEFPIN_AVR(50, 8, B); _DEFPIN_AVR(51, 4, B); _DEFPIN_AVR(52, 2, B); _DEFPIN_AVR(53, 1, B); _DEFPIN_AVR(54, 1, F); _DEFPIN_AVR(55, 2, F); _DEFPIN_AVR(56, 4, F); _DEFPIN_AVR(57, 8, F); _DEFPIN_AVR(58, 16, F); _DEFPIN_AVR(59, 32, F); _DEFPIN_AVR(60, 64, F); _DEFPIN_AVR(61, 128, F); _DEFPIN_AVR(62, 1, K); _DEFPIN_AVR(63, 2, K); _DEFPIN_AVR(64, 4, K); _DEFPIN_AVR(65, 8, K); _DEFPIN_AVR(66, 16, K); _DEFPIN_AVR(67, 32, K); _DEFPIN_AVR(68, 64, K); _DEFPIN_AVR(69, 128, K); #define SPI_DATA 51 #define SPI_CLOCK 52 #define SPI_SELECT 53 #define AVR_HARDWARE_SPI #elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) // Xark: Add ATMega644,644P,1284 and 1284P (using pinout from http://maniacbug.wordpress.com/2011/11/27/arduino-on-atmega1284p-4/) _IO(A); _IO(B); _IO(C); _IO(D); _DEFPIN_AVR( 0, (1<<0), B); _DEFPIN_AVR( 1, (1<<1), B); _DEFPIN_AVR( 2, (1<<2), B); _DEFPIN_AVR( 3, (1<<3), B); _DEFPIN_AVR( 4, (1<<4), B); _DEFPIN_AVR( 5, (1<<5), B); _DEFPIN_AVR( 6, (1<<6), B); _DEFPIN_AVR( 7, (1<<7), B); _DEFPIN_AVR( 8, (1<<0), D); _DEFPIN_AVR( 9, (1<<1), D); _DEFPIN_AVR(10, (1<<2), D); _DEFPIN_AVR(11, (1<<3), D); _DEFPIN_AVR(12, (1<<4), D); _DEFPIN_AVR(13, (1<<5), D); _DEFPIN_AVR(14, (1<<6), D); _DEFPIN_AVR(15, (1<<7), D); _DEFPIN_AVR(16, (1<<0), C); _DEFPIN_AVR(17, (1<<1), C); _DEFPIN_AVR(18, (1<<2), C); _DEFPIN_AVR(19, (1<<3), C); _DEFPIN_AVR(20, (1<<4), C); _DEFPIN_AVR(21, (1<<5), C); _DEFPIN_AVR(22, (1<<6), C); _DEFPIN_AVR(23, (1<<7), C); _DEFPIN_AVR(24, (1<<0), A); _DEFPIN_AVR(25, (1<<1), A); _DEFPIN_AVR(26, (1<<2), A); _DEFPIN_AVR(27, (1<<3), A); _DEFPIN_AVR(28, (1<<4), A); _DEFPIN_AVR(29, (1<<5), A); _DEFPIN_AVR(30, (1<<6), A); _DEFPIN_AVR(31, (1<<7), A); #define SPI_DATA 5 #define SPI_CLOCK 7 #define SPI_SELECT 4 #define AVR_HARDWARE_SPI // Leonardo, teensy, blinkm #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) // Leonardo, teensy, blinkm #elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) // teensy defs _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _DEFPIN_AVR(0, 1, B); _DEFPIN_AVR(1, 2, B); _DEFPIN_AVR(2, 4, B); _DEFPIN_AVR(3, 8, B); _DEFPIN_AVR(4, 128, B); _DEFPIN_AVR(5, 1, D); _DEFPIN_AVR(6, 2, D); _DEFPIN_AVR(7, 4, D); _DEFPIN_AVR(8, 8, D); _DEFPIN_AVR(9, 64, C); _DEFPIN_AVR(10, 128, C); _DEFPIN_AVR(11, 64, D); _DEFPIN_AVR(12, 128, D); _DEFPIN_AVR(13, 16, B); _DEFPIN_AVR(14, 32, B); _DEFPIN_AVR(15, 64, B); _DEFPIN_AVR(16, 128, F); _DEFPIN_AVR(17, 64, F); _DEFPIN_AVR(18, 32, F); _DEFPIN_AVR(19, 16, F); _DEFPIN_AVR(20, 2, F); _DEFPIN_AVR(21, 1, F); _DEFPIN_AVR(22, 16, D); _DEFPIN_AVR(23, 32, D); #define SPI_DATA 2 #define SPI_CLOCK 1 #define SPI_SELECT 3 #define AVR_HARDWARE_SPI #elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__) // teensy++ 2 defs _IO(A); _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _DEFPIN_AVR(0, 1, D); _DEFPIN_AVR(1, 2, D); _DEFPIN_AVR(2, 4, D); _DEFPIN_AVR(3, 8, D); _DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 32, D); _DEFPIN_AVR(6, 64, D); _DEFPIN_AVR(7, 128, D); _DEFPIN_AVR(8, 1, E); _DEFPIN_AVR(9, 2, E); _DEFPIN_AVR(10, 1, C); _DEFPIN_AVR(11, 2, C); _DEFPIN_AVR(12, 4, C); _DEFPIN_AVR(13, 8, C); _DEFPIN_AVR(14, 16, C); _DEFPIN_AVR(15, 32, C); _DEFPIN_AVR(16, 64, C); _DEFPIN_AVR(17, 128, C); _DEFPIN_AVR(18, 64, E); _DEFPIN_AVR(19, 128, E); _DEFPIN_AVR(20, 1, B); _DEFPIN_AVR(21, 2, B); _DEFPIN_AVR(22, 4, B); _DEFPIN_AVR(23, 8, B); _DEFPIN_AVR(24, 16, B); _DEFPIN_AVR(25, 32, B); _DEFPIN_AVR(26, 64, B); _DEFPIN_AVR(27, 128, B); _DEFPIN_AVR(28, 1, A); _DEFPIN_AVR(29, 2, A); _DEFPIN_AVR(30, 4, A); _DEFPIN_AVR(31, 8, A); _DEFPIN_AVR(32, 16, A); _DEFPIN_AVR(33, 32, A); _DEFPIN_AVR(34, 64, A); _DEFPIN_AVR(35, 128, A); _DEFPIN_AVR(36, 16, E); _DEFPIN_AVR(37, 32, E); _DEFPIN_AVR(38, 1, F); _DEFPIN_AVR(39, 2, F); _DEFPIN_AVR(40, 4, F); _DEFPIN_AVR(41, 8, F); _DEFPIN_AVR(42, 16, F); _DEFPIN_AVR(43, 32, F); _DEFPIN_AVR(44, 64, F); _DEFPIN_AVR(45, 128, F); #define SPI_DATA 22 #define SPI_CLOCK 21 #define SPI_SELECT 20 #define AVR_HARDWARE_SPI #elif defined(__AVR_ATmega32U4__) // leonard defs _IO(B); _IO(C); _IO(D); _IO(E); _IO(F); _DEFPIN_AVR(0, 4, D); _DEFPIN_AVR(1, 8, D); _DEFPIN_AVR(2, 2, D); _DEFPIN_AVR(3, 1, D); _DEFPIN_AVR(4, 16, D); _DEFPIN_AVR(5, 64, C); _DEFPIN_AVR(6, 128, D); _DEFPIN_AVR(7, 64, E); _DEFPIN_AVR(8, 16, B); _DEFPIN_AVR(9, 32, B); _DEFPIN_AVR(10, 64, B); _DEFPIN_AVR(11, 128, B); _DEFPIN_AVR(12, 64, D); _DEFPIN_AVR(13, 128, C); _DEFPIN_AVR(14, 8, B); _DEFPIN_AVR(15, 2, B); _DEFPIN_AVR(16, 4, B); _DEFPIN_AVR(17, 1, B); _DEFPIN_AVR(18, 128, F); _DEFPIN_AVR(19, 64, F); _DEFPIN_AVR(20, 32, F); _DEFPIN_AVR(21, 16, F); _DEFPIN_AVR(22, 2, F); _DEFPIN_AVR(23, 0, F); #define SPI_DATA 16 #define SPI_CLOCK 15 #define AVR_HARDWARE_SPI #elif defined(__MK20DX128__) && defined(CORE_TEENSY) _IO32(A); _IO32(B); _IO32(C); _IO32(D); _IO32(E); _DEFPIN_ARM(0, 16, B); _DEFPIN_ARM(1, 17, B); _DEFPIN_ARM(2, 0, D); _DEFPIN_ARM(3, 12, A); _DEFPIN_ARM(4, 13, A); _DEFPIN_ARM(5, 7, D); _DEFPIN_ARM(6, 4, D); _DEFPIN_ARM(7, 2, D); _DEFPIN_ARM(8, 3, D); _DEFPIN_ARM(9, 3, C); _DEFPIN_ARM(10, 4, C); _DEFPIN_ARM(11, 6, C); _DEFPIN_ARM(12, 7, C); _DEFPIN_ARM(13, 5, C); _DEFPIN_ARM(14, 1, D); _DEFPIN_ARM(15, 0, C); _DEFPIN_ARM(16, 0, B); _DEFPIN_ARM(17, 1, B); _DEFPIN_ARM(18, 3, B); _DEFPIN_ARM(19, 2, B); _DEFPIN_ARM(20, 5, D); _DEFPIN_ARM(21, 6, D); _DEFPIN_ARM(22, 1, C); _DEFPIN_ARM(23, 2, C); _DEFPIN_ARM(24, 5, A); _DEFPIN_ARM(25, 19, B); _DEFPIN_ARM(26, 1, E); _DEFPIN_ARM(27, 9, C); _DEFPIN_ARM(28, 8, C); _DEFPIN_ARM(29, 10, C); _DEFPIN_ARM(30, 11, C); _DEFPIN_ARM(31, 0, E); _DEFPIN_ARM(32, 18, B); _DEFPIN_ARM(33, 4, A); #define SPI_DATA 11 #define SPI_CLOCK 13 #define ARM_HARDWARE_SPI #elif defined(__SAM3X8E__) DUE_IO32(A); DUE_IO32(B); DUE_IO32(C); DUE_IO32(D); _DEFPIN_DUE(0, 8, A); _DEFPIN_DUE(1, 9, A); _DEFPIN_DUE(2, 25, B); _DEFPIN_DUE(3, 28, C); _DEFPIN_DUE(4, 26, C); _DEFPIN_DUE(5, 25, C); _DEFPIN_DUE(6, 24, C); _DEFPIN_DUE(7, 23, C); _DEFPIN_DUE(8, 22, C); _DEFPIN_DUE(9, 21, C); _DEFPIN_DUE(10, 29, C); _DEFPIN_DUE(11, 7, D); _DEFPIN_DUE(12, 8, D); _DEFPIN_DUE(13, 27, B); _DEFPIN_DUE(14, 4, D); _DEFPIN_DUE(15, 5, D); _DEFPIN_DUE(16, 13, A); _DEFPIN_DUE(17, 12, A); _DEFPIN_DUE(18, 11, A); _DEFPIN_DUE(19, 10, A); _DEFPIN_DUE(20, 12, B); _DEFPIN_DUE(21, 13, B); _DEFPIN_DUE(22, 26, B); _DEFPIN_DUE(23, 14, A); _DEFPIN_DUE(24, 15, A); _DEFPIN_DUE(25, 0, D); _DEFPIN_DUE(26, 1, D); _DEFPIN_DUE(27, 2, D); _DEFPIN_DUE(28, 3, D); _DEFPIN_DUE(29, 6, D); _DEFPIN_DUE(30, 9, D); _DEFPIN_DUE(31, 7, A); _DEFPIN_DUE(32, 10, D); _DEFPIN_DUE(33, 1, C); _DEFPIN_DUE(34, 2, C); _DEFPIN_DUE(35, 3, C); _DEFPIN_DUE(36, 4, C); _DEFPIN_DUE(37, 5, C); _DEFPIN_DUE(38, 6, C); _DEFPIN_DUE(39, 7, C); _DEFPIN_DUE(40, 8, C); _DEFPIN_DUE(41, 9, C); _DEFPIN_DUE(42, 19, A); _DEFPIN_DUE(43, 20, A); _DEFPIN_DUE(44, 19, C); _DEFPIN_DUE(45, 18, C); _DEFPIN_DUE(46, 17, C); _DEFPIN_DUE(47, 16, C); _DEFPIN_DUE(48, 15, C); _DEFPIN_DUE(49, 14, C); _DEFPIN_DUE(50, 13, C); _DEFPIN_DUE(51, 12, C); _DEFPIN_DUE(52, 21, B); _DEFPIN_DUE(53, 14, B); _DEFPIN_DUE(54, 16, A); _DEFPIN_DUE(55, 24, A); _DEFPIN_DUE(56, 23, A); _DEFPIN_DUE(57, 22, A); _DEFPIN_DUE(58, 6, A); _DEFPIN_DUE(59, 4, A); _DEFPIN_DUE(60, 3, A); _DEFPIN_DUE(61, 2, A); _DEFPIN_DUE(62, 17, B); _DEFPIN_DUE(63, 18, B); _DEFPIN_DUE(64, 19, B); _DEFPIN_DUE(65, 20, B); _DEFPIN_DUE(66, 15, B); _DEFPIN_DUE(67, 16, B); _DEFPIN_DUE(68, 1, A); _DEFPIN_DUE(69, 0, A); _DEFPIN_DUE(70, 17, A); _DEFPIN_DUE(71, 18, A); _DEFPIN_DUE(72, 30, C); _DEFPIN_DUE(73, 21, A); _DEFPIN_DUE(74, 25, A); _DEFPIN_DUE(75, 26, A); _DEFPIN_DUE(76, 27, A); _DEFPIN_DUE(77, 28, A); _DEFPIN_DUE(78, 23, B); #else #warning "No pin/port mappings found, pin access will be slightly slower. See fastpin.h for info." #define NO_HARDWARE_PIN_SUPPORT #endif #endif
PDQ_GFX.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264 // This is the PDQ re-mixed version of Adafruit's library // here is the original copyright notice: /*************************************************** This is an Arduino Library for the Adafruit 2.2" SPI display. This library works with the Adafruit 2.2" TFT Breakout w/SD card ----> http://www.adafruit.com/products/1480 Check out the links above for our tutorials and wiring diagrams These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution ****************************************************/ //=============================================================== // This PDQ optimized version is by Xark // // Inspiration from Paul Stoffregen and the Teensy 3.1 community. // // GOALS: // 1) Maintain "sketch" compatibility with original Adafruit libraries. // 2) Be as much faster as is reasonably possible honoring goal 1. :-) // 3) Be at least as small as Adafruit libraries. // // I believe all three of these have largely been achieved: // 1) Near full compatibility. Only minor initialization changes in original sketch. // 2) Between ~2.5 and ~12 times faster (fillRect ~2.5x, drawLine ~12x). // An average of ~4x faster over entire "graphictest.ino" benchmark. // // Even if this library is faster, it was based on the Adafruit original. // Adafruit deserves your support for making their library open-source (and // for having some nice LCD modules and all kinds of other great parts too). // Consider giving them your support if possible! #if !defined(_PDQ_ILI9341H_) #define _PDQ_ILI9341H_ #include "Arduino.h" #include "Print.h" #include <RLucas_TFT_GFX.h> #include <avr/pgmspace.h> #if !defined(ILI9341_CS_PIN) || !defined(ILI9341_DC_PIN) #error Oops! You need to #include "PDQ_ILI9341_config.h" (modified with your pin configuration and options) from your sketch before #include "PDQ_ILI9341.h". #endif #include <RLucas_TFT_FastPin.h> #if !defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny45__) #define INLINE inline #define INLINE_OPT __attribute__((always_inline)) #else #define INLINE #define INLINE_OPT #endif // Color definitions enum { ILI9341_BLACK = 0x0000, ILI9341_BLUE = 0x001F, ILI9341_RED = 0xF800, ILI9341_GREEN = 0x07E0, ILI9341_CYAN = 0x07FF, ILI9341_MAGENTA = 0xF81F, ILI9341_YELLOW = 0xFFE0, ILI9341_WHITE = 0xFFFF, }; class PDQ_ILI9341 : public PDQ_GFX<PDQ_ILI9341> { public: // ILI9341 commands // For datasheet see https://www.adafruit.com/products/1480 enum { ILI9341_NOP = 0x00, ILI9341_SWRESET = 0x01, ILI9341_RDDID = 0x04, ILI9341_RDDST = 0x09, ILI9341_SLPIN = 0x10, ILI9341_SLPOUT = 0x11, ILI9341_PTLON = 0x12, ILI9341_NORON = 0x13, ILI9341_RDMODE = 0x0A, ILI9341_RDMADCTL = 0x0B, ILI9341_RDPIXFMT = 0x0C, ILI9341_RDIMGFMT = 0x0A, ILI9341_RDSELFDIAG = 0x0F, ILI9341_INVOFF = 0x20, ILI9341_INVON = 0x21, ILI9341_GAMMASET = 0x26, ILI9341_DISPOFF = 0x28, ILI9341_DISPON = 0x29, ILI9341_CASET = 0x2A, ILI9341_PASET = 0x2B, ILI9341_RAMWR = 0x2C, ILI9341_RAMRD = 0x2E, ILI9341_PTLAR = 0x30, ILI9341_MADCTL = 0x36, ILI9341_PIXFMT = 0x3A, ILI9341_FRMCTR1 = 0xB1, ILI9341_FRMCTR2 = 0xB2, ILI9341_FRMCTR3 = 0xB3, ILI9341_INVCTR = 0xB4, ILI9341_DFUNCTR = 0xB6, ILI9341_PWCTR1 = 0xC0, ILI9341_PWCTR2 = 0xC1, ILI9341_PWCTR3 = 0xC2, ILI9341_PWCTR4 = 0xC3, ILI9341_PWCTR5 = 0xC4, ILI9341_VMCTR1 = 0xC5, ILI9341_VMCTR2 = 0xC7, ILI9341_RDID1 = 0xDA, ILI9341_RDID2 = 0xDB, ILI9341_RDID3 = 0xDC, ILI9341_RDID4 = 0xDD, ILI9341_GMCTRP1 = 0xE0, ILI9341_GMCTRN1 = 0xE1, // ILI9341_PWCTR6 = 0xFC, }; // some other misc. constants enum { // screen dimensions ILI9341_TFTWIDTH = 240, ILI9341_TFTHEIGHT = 320, // MADCTL bits ILI9341_MADCTL_MH = 0x04, // bit 2 = 0 for refresh left -> right, 1 for refresh right -> left ILI9341_MADCTL_RGB = 0x00, // bit 3 = 0 for RGB color order ILI9341_MADCTL_BGR = 0x08, // bit 3 = 1 for BGR color order ILI9341_MADCTL_ML = 0x10, // bit 4 = 0 for refresh top -> bottom, 1 for bottom -> top ILI9341_MADCTL_MV = 0x20, // bit 5 = 0 for column, row order (portrait), 1 for row, column order (landscape) ILI9341_MADCTL_MX = 0x40, // bit 6 = 0 for left -> right, 1 for right -> left order ILI9341_MADCTL_MY = 0x80, // bit 7 = 0 for top -> bottom, 1 for bottom -> top // delay indicator bit for commandList() DELAY = 0x80 }; // higher-level routines PDQ_ILI9341(); static void inline begin(void); static void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1); static void pushColor(uint16_t color); static void pushColor(uint16_t color, int cnt); // Pass 8-bit (each) R,G,B, get back 16-bit packed color static INLINE uint16_t color565(uint8_t r, uint8_t g, uint8_t b) { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } static INLINE uint16_t Color565(uint8_t r, uint8_t g, uint8_t b) // older inconsistent name for compatibility { return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3); } // required driver primitive methods (all except drawPixel can call generic version in PDQ_GFX with "_" postfix). static void drawPixel(int x, int y, uint16_t color); static void drawFastVLine(int x, int y, int h, uint16_t color); static void drawFastHLine(int x, int y, int w, uint16_t color); static void setRotation(uint8_t r); static void invertDisplay(boolean i); static void drawFastBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, uint8_t angleFM); static void drawFastChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); static inline void fillScreen(uint16_t color) __attribute__((always_inline)) { fillScreen_(color); // call generic version } static void drawLine(int x0, int y0, int x1, int y1, uint16_t color); static void fillRect(int x, int y, int w, int h, uint16_t color); // === lower-level internal routines ========= static void commandList(const uint8_t *addr); // NOTE: Make sure each spi_begin() is matched with a single spi_end() (and don't call either twice) // set CS back to low (LCD selected) static inline void spi_begin() __attribute__((always_inline)) { #if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) swapValue(save_SPCR, SPCR); // swap initial/current SPCR settings #endif FastPin<ILI9341_CS_PIN>::lo(); // CS <= LOW (selected) } // NOTE: Make sure each spi_begin() is matched with a single spi_end() (and don't call either twice) // reset CS back to high (LCD unselected) static inline void spi_end() __attribute__((always_inline)) { FastPin<ILI9341_CS_PIN>::hi(); // CS <= HIGH (deselected) #if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) swapValue(SPCR, save_SPCR); // swap current/initial SPCR settings #endif } #if defined(AVR_HARDWARE_SPI) // 10 cycle delay (including "call") static void delay10() __attribute__((noinline)) __attribute__((naked)) { __asm__ __volatile__ ( // +4 (call to get here) #if !defined(__AVR_HAVE_RAMPD__) " adiw r24,0\n" // +2 (2-cycle NOP) #else " nop\n" // +1 (1-cycle NOP) #endif " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) // = 10 cycles : : : ); } // 13 cycle delay (including "call") static void delay13() __attribute__((noinline)) __attribute__((naked)) { __asm__ __volatile__ ( // +4 (call to get here) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) #if !defined(__AVR_HAVE_RAMPD__) " nop\n" // +1 (1-cycle NOP) #endif " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) // = 13 cycles : : : ); } // 15 cycle delay (including "call") static void delay15() __attribute__((noinline)) __attribute__((naked)) { __asm__ __volatile__ ( // +4 (call to get here) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) #if !defined(__AVR_HAVE_RAMPD__) " nop\n" // +1 (1-cycle NOP) #endif " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) // = 15 cycles : : : ); } // 17 cycle delay (including "call") static void delay17() __attribute__((noinline)) __attribute__((naked)) { __asm__ __volatile__ ( // +4 (call to get here) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) " adiw r24,0\n" // +2 (2-cycle NOP) #if !defined(__AVR_HAVE_RAMPD__) " nop\n" // +1 (2-cycle NOP) #endif " ret\n" // +4 (or +5 on >64KB AVR with RAMPD reg) // = 17 cycles : : : ); } // normal SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) static INLINE void spiWrite(uint8_t data) INLINE_OPT { SPDR = data; __asm__ __volatile__ ( " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) : : : ); } // special SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) - minus 2 cycles for RS (etc.) change static INLINE void spiWrite_preCmd(uint8_t data) INLINE_OPT { SPDR = data; __asm__ __volatile__ ( " call _ZN11PDQ_ILI93417delay15Ev\n" // call mangled delay15 (compiler would needlessly save/restore regs) : : : ); } // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) static INLINE void spiWrite16(uint16_t data) INLINE_OPT { uint8_t temp; __asm__ __volatile__ ( " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) : [temp] "=d" (temp) : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) : ); } // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) minus 2 cycles static INLINE void spiWrite16_preCmd(uint16_t data) INLINE_OPT { uint8_t temp; __asm__ __volatile__ ( " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay15Ev\n" // call mangled delay15 (compiler would needlessly save/restore regs) : [temp] "=d" (temp) : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) : ); } // SPI 16-bit write with minimal hand-tuned delay (assuming max DIV2 SPI rate) minus 4 cycles static INLINE void spiWrite16_lineDraw(uint16_t data) INLINE_OPT { uint8_t temp; __asm__ __volatile__ ( " out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) : [temp] "=d" (temp) : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) : ); } // normal SPI write with minimal hand-tuned delay (assuming max DIV2 SPI rate) static INLINE void spiWrite16(uint16_t data, int count) INLINE_OPT { uint8_t temp; __asm__ __volatile__ ( " sbiw %[count],0\n" // test count " brmi 4f\n" // if < 0 then done " breq 4f\n" // if == 0 then done "1: out %[spi],%[hi]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay17Ev\n" // call mangled delay17 (compiler would needlessly save/restore regs) " out %[spi],%[lo]\n" // write SPI data (18 cycles until next write) " call _ZN11PDQ_ILI93417delay13Ev\n" // call mangled delay13 (compiler would needlessly save/restore regs) " sbiw %[count],1\n" // +2 decrement count " brne 1b\n" // +2/1 if != 0 then loop // = 13 + 2 + 2 (17 cycles) "4:\n" : [temp] "=d" (temp), [count] "+w" (count) : [spi] "i" (_SFR_IO_ADDR(SPDR)), [lo] "r" ((uint8_t)data), [hi] "r" ((uint8_t)(data>>8)) : ); } #else // bit-bang #if defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) // USI hardware assisted static void spiWrite(uint8_t data) __attribute__((noinline)) { USIDR = data; __asm__ __volatile__ ( " out %[spi],%[clkp0]\n" // MSB " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" // LSB " out %[spi],%[clkp1]\n" : : [spi] "i" (_SFR_IO_ADDR(USICR)), [clkp0] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC))), [clkp1] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK))) : ); } static void spiWrite16(uint16_t data) __attribute__((noinline)) { USIDR = data>>8; __asm__ __volatile__ ( " out %[spi],%[clkp0]\n" // MSB " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" // LSB " out %[spi],%[clkp1]\n" : : [spi] "i" (_SFR_IO_ADDR(USICR)), [clkp0] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC))), [clkp1] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK))) : ); USIDR = data&0xff; __asm__ __volatile__ ( " out %[spi],%[clkp0]\n" // MSB " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" " out %[spi],%[clkp1]\n" " out %[spi],%[clkp0]\n" // LSB " out %[spi],%[clkp1]\n" : : [spi] "i" (_SFR_IO_ADDR(USICR)), [clkp0] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC))), [clkp1] "a" ((uint8_t)((1<<USIWM0)|(0<<USICS0)|(1<<USITC)|(1<<USICLK))) : ); } #else static void spiWrite(uint8_t data) __attribute__((noinline)) { // Fast SPI bitbang swiped from LPD8806 library for(uint8_t bit = 0x80; bit; bit >>= 1) { if (data & bit) FastPin<ILI9341_MOSI_PIN>::hi(); else FastPin<ILI9341_MOSI_PIN>::lo(); FastPin<ILI9341_SCLK_PIN>::hi(); FastPin<ILI9341_SCLK_PIN>::lo(); } } static void spiWrite16(uint16_t data) __attribute__((noinline)) { spiWrite(data >> 8); spiWrite(data & 0xff); } #endif static INLINE void spiWrite_preCmd(uint8_t data) INLINE_OPT { spiWrite(data); } static INLINE void spiWrite16_preCmd(uint16_t data) INLINE_OPT { spiWrite16(data); } static INLINE void spiWrite16_lineDraw(uint16_t data) INLINE_OPT { spiWrite16(data); } static INLINE void spiWrite16(uint16_t data, int count) INLINE_OPT { while (count-- > 0) spiWrite16(data); } static inline void delay10() { } static inline void delay13() { } static inline void delay15() { } static inline void delay17() { } #endif // write SPI byte with RS (aka D/C) pin set low to indicate a command byte (and then reset back to high when done) static INLINE void writeCommand(uint8_t data) INLINE_OPT { FastPin<ILI9341_DC_PIN>::lo(); // RS <= LOW indicate command byte spiWrite_preCmd(data); FastPin<ILI9341_DC_PIN>::hi(); // RS <= HIGH indicate data byte (always assumed left in data mode) } // write SPI byte with RS assumed low indicating a data byte static inline void writeData(uint8_t data) __attribute__((always_inline)) { spiWrite(data); } // internal version that does not spi_begin()/spi_end() static INLINE void setAddrWindow_(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) INLINE_OPT { writeCommand(ILI9341_CASET); // column address set spiWrite16(x0); // XSTART spiWrite16_preCmd(x1); // XEND writeCommand(ILI9341_PASET); // row address set spiWrite16(y0); // YSTART spiWrite16_preCmd(y1); // YEND writeCommand(ILI9341_RAMWR); // write to RAM } #if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) static volatile uint8_t save_SPCR; // initial SPCR value/saved SPCR value (swapped in spi_begin/spi_end) #endif }; typedef PDQ_GFX_Button_<PDQ_ILI9341> PDQ_GFX_Button; /*************************************************** This is an Arduino Library for the Adafruit 2.2" SPI display. This library works with the Adafruit 2.2" TFT Breakout w/SD card ----> http://www.adafruit.com/products/1480 Check out the links above for our tutorials and wiring diagrams These displays use SPI to communicate, 4 or 5 pins are required to interface (RST is optional) Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Limor Fried/Ladyada for Adafruit Industries. MIT license, all text above must be included in any redistribution ****************************************************/ #if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) // static data needed by base class volatile uint8_t PDQ_ILI9341::save_SPCR; #endif // Constructor when using hardware SPI. PDQ_ILI9341::PDQ_ILI9341() : PDQ_GFX<PDQ_ILI9341>(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) { #if defined(AVR_HARDWARE_SPI) // must reference these functions from C++ or they will be stripped by linker (called from inline asm) delay10(); delay13(); delay15(); delay17(); #endif } // Companion code to the above tables. Reads and issues // a series of LCD commands stored in PROGMEM byte array. void PDQ_ILI9341::commandList(const uint8_t *addr) { uint8_t numCommands, numArgs; uint16_t ms; numCommands = pgm_read_byte(addr++); // Number of commands to follow while (numCommands--) // For each command... { writeCommand(pgm_read_byte(addr++)); // Read, issue command numArgs = pgm_read_byte(addr++); // Number of args to follow ms = numArgs & DELAY; // If hibit set, delay follows args numArgs &= ~DELAY; // Mask out delay bit while (numArgs--) // For each argument... { writeData(pgm_read_byte(addr++)); // Read, issue argument } if (ms) { ms = pgm_read_byte(addr++); // Read post-command delay time (ms) if(ms == 255) ms = 500; // If 255, delay for 500 ms delay(ms); } } } void PDQ_ILI9341::begin(void) { // set CS and RS pin directions to output FastPin<ILI9341_CS_PIN>::setOutput(); FastPin<ILI9341_DC_PIN>::setOutput(); #if !defined(AVR_HARDWARE_SPI) #if defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) USICR = (0<<USISIE)|(0<<USIOIE)|(0<<USIWM1)|(1<<USIWM0)|(0<<USICS1)|(1<<USICS0)|(1<<USICLK)|(0<<USITC); #endif #if defined (ILI9341_MISO_PIN) FastPin<ILI9341_MISO_PIN>::setInput(); #endif FastPin<ILI9341_MOSI_PIN>::setOutput(); FastPin<ILI9341_SCLK_PIN>::setOutput(); FastPin<ILI9341_MOSI_PIN>::lo(); FastPin<ILI9341_SCLK_PIN>::lo(); #endif FastPin<ILI9341_CS_PIN>::hi(); // CS <= HIGH (deselected, so no spurious data) FastPin<ILI9341_DC_PIN>::hi(); // RS <= HIGH (default data byte) #if defined(AVR_HARDWARE_SPI) #if ILI9341_SAVE_SPCR uint8_t oldSPCR = SPCR; // save initial SPCR settings #endif SPI.begin(); SPI.setBitOrder(MSBFIRST); SPI.setDataMode(SPI_MODE0); SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz (full! speed!) [1 byte every 18 cycles] #endif #if ILI9341_SAVE_SPCR && defined(AVR_HARDWARE_SPI) save_SPCR = SPCR; // save SPCR settings SPCR = oldSPCR; // restore previous SPCR settings (spi_begin/spi_end will switch between the two) #endif spi_begin(); // Initialization commands for ILI9341 screens static const uint8_t ILI9341_cmds[] PROGMEM = { 22, ILI9341_SWRESET, DELAY, // 1 5, 0xEF, 3, // 2 0x03, 0x80, 0x02, 0xCF, 3, // 3 0x00, 0xC1, 0x30, 0xED, 4, // 4 0x64, 0x03, 0x12, 0x81, 0xE8, 3, // 5 0x85, 0x00, 0x78, 0xCB, 5, // 6 0x39, 0x2C, 0x00, 0x34, 0x02, 0xF7, 1, // 7 0x20, 0xEA, 2, // 8 0x00, 0x00, ILI9341_PWCTR1, 1, // 9 power control 0x23, // VRH[5:0] ILI9341_PWCTR2, 1, // 10 power control 0x10, // SAP[2:0];BT[3:0] ILI9341_VMCTR1, 2, // 11 VCM control 0x3e, 0x28, ILI9341_VMCTR2, 1, // 12 VCM control2 0x86, // -- ILI9341_MADCTL, 1, // 13 (ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR), ILI9341_PIXFMT, 1, // 14 0x55, ILI9341_FRMCTR1, 2, // 15 0x00, 0x18, ILI9341_DFUNCTR, 3, // 16 0x08, 0x82, 0x27, 0xF2, 1, // 17 3Gamma Function Disable 0x00, ILI9341_GAMMASET, 1, // 18 Gamma curve selected 0x01, ILI9341_GMCTRP1, 15, // 19 Set Gamma 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00, ILI9341_GMCTRN1, 15, // 20 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F, ILI9341_SLPOUT, DELAY, // 21 120, ILI9341_DISPON, 0, // 22 }; commandList(ILI9341_cmds); spi_end(); } void PDQ_ILI9341::setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) { spi_begin(); setAddrWindow_(x0, y0, x1, y1); spi_end(); } void PDQ_ILI9341::pushColor(uint16_t color) { spi_begin(); spiWrite16_preCmd(color); spi_end(); } void PDQ_ILI9341::pushColor(uint16_t color, int count) { spi_begin(); spiWrite16(color, count); spi_end(); } void PDQ_ILI9341::drawPixel(int x, int y, uint16_t color) { if ((x < 0) ||(x >= _width) || (y < 0) || (y >= _height)) return; spi_begin(); setAddrWindow_(x, y, x, y); // Il est très stupide d'appeller cette fonction de nombreuses fois dans un rectangle spiWrite16_preCmd(color); spi_end(); } void PDQ_ILI9341::drawFastVLine(int x, int y, int h, uint16_t color) { // clipping if ((x < 0) || (x >= _width) || (y >= _height)) return; if (y < 0) { h += y; y = 0; } int y1 = y+h; if (y1 < 0) return; if (y1 > _height) h = _height-y; spi_begin(); setAddrWindow_(x, y, x, _height); spiWrite16(color, h); spi_end(); } void PDQ_ILI9341::drawFastHLine(int x, int y, int w, uint16_t color) { // clipping if ((x >= _width) || (y < 0) || (y >= _height)) return; if (x < 0) { w += x; x = 0; } int x1 = x+w; if (x1 < 0) return; if (x1 > _width) w = _width-w; spi_begin(); setAddrWindow_(x, y, _width, y); spiWrite16(color, w); spi_end(); } void PDQ_ILI9341::fillRect(int x, int y, int w, int h, uint16_t color) { // rudimentary clipping (drawChar w/big text requires this) if ((x >= _width) || (y >= _height)) return; if (x < 0) { w += x; x = 0; } if (y < 0) { h += y; y = 0; } if ((x + w) > _width) w = _width - x; if ((y + h) > _height) h = _height - y; spi_begin(); setAddrWindow_(x, y, x+w-1, _height); for (; h > 0; h--) { spiWrite16(color, w); } spi_end(); } //Fonction à la fois plus rapide (vitesse X 1,5) et qui optimise le stockage du bitmap (plus de bits "gaspillés" si la largeur n'est pas multiple de 8) //Mais ne fonctionne pas pour bitmap "transparent" void PDQ_ILI9341::drawFastBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, uint8_t angleFM) { coord_t i, j, tmp; unsigned int numPix; bool mirror; mirror = angleFM > 3; if (mirror) { angleFM-=4; } mirror ^= (angleFM > 1); if (angleFM == 1 || angleFM == 3) { tmp = h; h = w; w = tmp; } spi_begin(); setAddrWindow_(x, y, x + w - 1, _height); for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (mirror) { tmp = w - i - 1; }else{ tmp = i; } switch (angleFM) { case 0: numPix = tmp + j * w; break; case 1: numPix = h - j - 1 + tmp * h; break; case 2: numPix = tmp + (h - j - 1) * w; break; default: numPix = j + tmp * h; break; } if (bitmap[numPix >> 3] & (0b10000000 >> (numPix & 0b111))) spiWrite16(color); else spiWrite16(bg); // Dommage on ne peut pas "sauter" un pixel donc impossible de faire un bitmap transparent } } spi_end(); } /* void PDQ_ILI9341::drawFastBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, bool drawBG, uint8_t angleFM) { coord_t i, j; //, byteWidth = (w + 7) / 8; coord_t xx, yy; unsigned int numPix; uint8_t nBit; uint8_t masque; uint8_t octet; //coord_t xx, yy; bool mirror; mirror = angleFM>3; if (mirror) { angleFM-=4; } spi_begin(); if (angleFM==1 || angleFM==3) { xx = h; h = w; w = xx; } setAddrWindow_(x, y, x+w-1, _height); for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { switch (angleFM) { case 0: if (mirror) { xx = w - i - 1; }else{ xx = i; } yy = j; numPix = xx+yy*w; break; case 1: xx = h - j - 1; if (mirror) { yy = w - i - 1; }else{ yy = i; } numPix = xx+yy*h; break; case 2: if (mirror) { xx = i; }else{ xx = w - i - 1; } yy = h - j - 1; numPix = xx+yy*w; break; default: xx = j; if (mirror) { yy = i; }else{ yy = w - i - 1; } numPix = xx+yy*h; break; } octet = bitmap[numPix >> 3]; //octet = bitmap[numPix / 8]; nBit = numPix % 8; masque = 0b10000000 >> nBit; if (octet & masque) spiWrite16(color); else spiWrite16(bg); } } spi_end(); } */ // Draw a character with built-in font // Il faut trouver moyen de sauter un pixel si texte sur fond transparent void PDQ_ILI9341::drawFastChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size) { if ((x >= _width) || (y >= _height) || ((x + (6 * size) - 1) < 0) || ((y + (8 * size) - 1) < 0)) return; int8_t i; int8_t j; int8_t k; //uint8_t is_opaque = (bg != color); if(!_cp437 && (c >= 176)) // Handle 'classic' charset behavior c++; spi_begin(); int8_t size2 = size * size; for (i=0; i<6; i++) { uint8_t line; if (i == 5) line = 0x0; else line = pgm_read_byte(RLucas_glcdfont+(c*5)+i); // Dommage les caractères s'impriment colonne par colonne, du coup on doit appeller setAddrWindow_ pour chaque colonne // On pourrait optimiser encore plus en modifiant la façon de stocker les caractères (et gagner un peu de ROM aussi) setAddrWindow_(x+(i*size), y, x+(i*size)+size-1, _height); if (size == 1) { for (j = 0; j < 8; j++) { if (line & 0x1) { spiWrite16(color); //drawPixel(x+i, y+j, color); //else if (is_opaque) } else { spiWrite16(bg); //drawPixel(x+i, y+j, bg); } line >>= 1; } } else { for (j = 0; j < 8; j++) { for (k = 0; k<size2 ; k++) { if (line & 0x1) { spiWrite16(color); //fillRect(x+(i*size), y+(j*size), size, size, color); //else if (is_opaque) } else { spiWrite16(bg); //fillRect(x+(i*size), y+(j*size), size, size, bg); } } line >>= 1; } } } spi_end(); } // Bresenham's algorithm - thx Wikipedia void PDQ_ILI9341::drawLine(int x0, int y0, int x1, int y1, uint16_t color) { #if 0 && defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny45__) drawLine_(x0, y0, x1, y1, color); #else int8_t steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swapValue(x0, y0); swapValue(x1, y1); } if (x0 > x1) { swapValue(x0, x1); swapValue(y0, y1); } if (x1 < 0) return; int dx, dy; dx = x1 - x0; dy = abs(y1 - y0); int err = dx / 2; int8_t ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1; } uint8_t setaddr = 1; #if 0 && defined(__AVR_ATtiny85__) && !defined(__AVR_ATtiny45__) int end = steep ? _height-1 : _width-1; if (x1 > end) x1 = end; for (; x0 <= x1; x0++) { if ((x0 >= 0) && (y0 >= 0) && (y0 <= end)) break; err -= dy; if (err < 0) { err += dx; y0 += ystep; } } if (x0 > x1) return; spi_begin(); for (; x0 <= x1; x0++) { if (setaddr) { if (steep) setAddrWindow_(y0, x0, y0, end+1); else setAddrWindow_(x0, y0, end+1, y0); setaddr = 0; } spiWrite16_lineDraw(color); err -= dy; if (err < 0) { y0 += ystep; if ((y0 < 0) || (y0 > end)) break; err += dx; setaddr = 1; } } #else if (steep) // y increments every iteration (y0 is x-axis, and x0 is y-axis) { if (x1 >= _height) x1 = _height - 1; for (; x0 <= x1; x0++) { if ((x0 >= 0) && (y0 >= 0) && (y0 < _width)) break; err -= dy; if (err < 0) { err += dx; y0 += ystep; } } if (x0 > x1) return; spi_begin(); for (; x0 <= x1; x0++) { if (setaddr) { setAddrWindow_(y0, x0, y0, _height); setaddr = 0; } spiWrite16_lineDraw(color); err -= dy; if (err < 0) { y0 += ystep; if ((y0 < 0) || (y0 >= _width)) break; err += dx; setaddr = 1; } #if defined(AVR_HARDWARE_SPI) else { __asm__ __volatile__ ( " call _ZN11PDQ_ILI93417delay10Ev\n" : : : ); } #endif } } else // x increments every iteration (x0 is x-axis, and y0 is y-axis) { if (x1 >= _width) x1 = _width - 1; for (; x0 <= x1; x0++) { if ((x0 >= 0) && (y0 >= 0) && (y0 < _height)) break; err -= dy; if (err < 0) { err += dx; y0 += ystep; } } if (x0 > x1) return; spi_begin(); for (; x0 <= x1; x0++) { if (setaddr) { setAddrWindow_(x0, y0, _width, y0); setaddr = 0; } spiWrite16_lineDraw(color); err -= dy; if (err < 0) { y0 += ystep; if ((y0 < 0) || (y0 >= _height)) break; err += dx; setaddr = 1; } #if defined(AVR_HARDWARE_SPI) else { __asm__ __volatile__ ( " call _ZN11PDQ_ILI93417delay10Ev\n" : : : ); } #endif } } #endif spi_end(); #endif } void PDQ_ILI9341::setRotation(uint8_t m) { rotation = (m & 3); // can't be higher than 3 spi_begin(); writeCommand(ILI9341_MADCTL); switch (rotation) { default: case 0: writeData(ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR); _width = ILI9341_TFTWIDTH; _height = ILI9341_TFTHEIGHT; break; case 1: writeData(ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR); _width = ILI9341_TFTHEIGHT; _height = ILI9341_TFTWIDTH; break; case 2: writeData(ILI9341_MADCTL_MY | ILI9341_MADCTL_BGR); _width = ILI9341_TFTWIDTH; _height = ILI9341_TFTHEIGHT; break; case 3: writeData(ILI9341_MADCTL_MV | ILI9341_MADCTL_MY | ILI9341_MADCTL_MX | ILI9341_MADCTL_BGR); _width = ILI9341_TFTHEIGHT; _height = ILI9341_TFTWIDTH; break; } spi_end(); } void PDQ_ILI9341::invertDisplay(boolean i) { spi_begin(); writeCommand(i ? ILI9341_INVON : ILI9341_INVOFF); spi_end(); } #endif // !defined(_PDQ_ILI9341H_)
C'est déjà à la base une bonne bibliothèque, programmé par des passionnés qui maîtrisent le langage, même si j'ai réussi à améliorer encore certaines fonctions.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452 // This is the PDQ re-mixed version of Adafruit's library from Xark // here is the original copyright notice and license: /* This is the core graphics library for all our displays, providing a common set of graphics primitives (points, lines, circles, etc.). It needs to be paired with a hardware-specific library for each display device we carry (to handle the lower-level functions). Adafruit invests time and resources providing this open source code, please support Adafruit & open-source hardware by purchasing products from Adafruit! Copyright (c) 2013 Adafruit Industries. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // This PDQ optimized version is by Xark // // Inspiration from Paul Stoffregen and the Teensy 3.1 community. // // GOALS: // 1) Maintain "sketch" compatibility with original Adafruit libraries. // 2) Be as much faster as is reasonably possible honoring goal 1. :-) // 3) Be at least as small as Adafruit libraries. // // I believe all three of these have largely been achieved: // 1) Near full compatibility. Only minor initialization changes in original sketch. // 2) Between ~2.5 and ~12 times faster (fillRect ~2.5x, drawLine ~12x). // An average of ~4x faster over entire "graphictest.ino" benchmark. // // Even if this library is faster, it was based on the Adafruit original. // Adafruit deserves your support for making their library open-source (and // for having some nice LCD modules and all kinds of other great parts too). // Consider giving them your support if possible! #ifndef _PDQ_GFX_H #define _PDQ_GFX_H #include "Arduino.h" #include "Print.h" #ifndef pgm_read_byte #define pgm_read_byte(addr) (*(const unsigned char *)(addr)) #endif #ifndef pgm_read_word #define pgm_read_word(addr) (*(const unsigned short *)(addr)) #endif #ifndef pgm_read_dword #define pgm_read_dword(addr) (*(const unsigned long *)(addr)) #endif #if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFFL) #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) #else #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) #endif #include "RLucas_gfxfont.h" #define GFX_FONT_PACKED typedef int coord_t; // type used for coordinates (signed) for parameters (int16_t used for storage) typedef uint16_t color_t; // type used for colors (unsigned) // swap any type template<typename T> static inline void swapValue(T& x, T& y) { T tmp = x; x = y; y = tmp; } // minimum value for any type template<typename T> static inline T minValue(T& x, T& y) { return x < y ? x : y; } // maximum value for any type template<typename T> static inline T maxValue(T& x, T& y) { return x >= y ? x : y; } template <class HW> class PDQ_GFX : public Print { public: PDQ_GFX(coord_t w, coord_t h); // Constructor (called by HW driver) // Graphic primitives // drawPixel MUST be defined by the driver subclass (and has no generic fall-back): // These are generic versions of routines for drivers that don't provide device-optimized code. // Drivers are required to have these functions (without "_" postfix), but can fall back to using // these if needed (they should not be called directly with "_" postfix or it will bypass any // device-optimized implementations). static void drawLine_(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color); static void drawFastVLine_(coord_t x, coord_t y, coord_t h, color_t color); static void drawFastHLine_(coord_t x, coord_t y, coord_t w, color_t color); static void fillRect_(coord_t x, coord_t y, coord_t w, coord_t h, color_t color); static void fillScreen_(color_t color); // These are usually overridden in the driver subclass to be useful (but not internally referenced) static void setRotation(uint8_t r); // only swaps width/height if not supported by driver static void invertDisplay(boolean i); // only if supported by driver // These exist in PDQ_GFX (and generally have no subclass override) static void drawRect(coord_t x, coord_t y, coord_t w, coord_t h, color_t color); static void drawCircle(coord_t x0, coord_t y0, coord_t r, color_t color); static void drawCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, color_t color); static void fillCircle(coord_t x0, coord_t y0, coord_t r, color_t color); static void fillCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, coord_t delta, color_t color); static void drawTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color); static void fillTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color); static void drawRoundRect(coord_t x0, coord_t y0, coord_t w, coord_t h, coord_t radius, color_t color); static void fillRoundRect(coord_t x0, coord_t y0, coord_t w, coord_t h, coord_t radius, color_t color); // static void drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color); // static void drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg); // static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color); // static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg); //static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, bool drawBG, uint8_t angleFM); static void drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, uint8_t angleFM); // static void drawXBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color); static void drawChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); static void drawCharGFX(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size); static inline void setCursor(coord_t x, coord_t y); static inline void setTextColor(color_t c); static inline void setTextColor(color_t c, color_t bg); static inline void setTextSize(uint8_t s); static inline void setTextWrap(boolean w); static inline void cp437(boolean x=true); static inline void setFont(const GFXfont *f = NULL); static inline coord_t width() __attribute__ ((always_inline)) { return _width; } static inline coord_t height() __attribute__ ((always_inline)) { return _height; } static inline uint8_t getRotation() __attribute__ ((always_inline)) { return rotation; } static inline coord_t getCursorX() __attribute__ ((always_inline)) { return cursor_x; } static inline coord_t getCursorY() __attribute__ ((always_inline)) { return cursor_y; } static inline void getTextBounds(char *string, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); static inline void getTextBounds(const __FlashStringHelper *s, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); virtual size_t write(uint8_t); // used by Arduino "Print.h" (and the one required virtual function) protected: static GFXfont* gfxFont; static coord_t WIDTH, HEIGHT; // This is the 'raw' display w/h - never changes static coord_t _width, _height; // Display w/h as modified by current rotation static coord_t cursor_x, cursor_y; static color_t textcolor, textbgcolor; static uint8_t textsize; static uint8_t rotation; static boolean wrap; // If set, 'wrap' text at right edge of display static boolean _cp437; // If set, use correct CP437 charset (default is off) }; template <class HW> class PDQ_GFX_Button_ { public: PDQ_GFX_Button_(); void initButton(PDQ_GFX<HW> *gfx, coord_t x, coord_t y, coord_t w, coord_t h, color_t outline, color_t fill, color_t textcolor, const char *label, uint8_t textsize); void drawButton(boolean inverted = false); boolean contains(coord_t x, coord_t y); void press(boolean p); boolean isPressed(); boolean justPressed(); boolean justReleased(); private: PDQ_GFX<HW> *_gfx; int16_t _x, _y; int16_t _w, _h; uint8_t _textsize; color_t _outlinecolor, _fillcolor, _textcolor; char _label[10]; boolean currstate, laststate; }; // ----------------------------------------------- extern const unsigned char RLucas_glcdfont[] PROGMEM; template<class HW> int16_t PDQ_GFX<HW>::WIDTH; // This is the 'raw' display w/h - never changes template<class HW> int16_t PDQ_GFX<HW>::HEIGHT; template<class HW> int16_t PDQ_GFX<HW>::_width; // Display w/h as modified by current rotation template<class HW> int16_t PDQ_GFX<HW>::_height; template<class HW> int16_t PDQ_GFX<HW>::cursor_x; template<class HW> int16_t PDQ_GFX<HW>::cursor_y; template<class HW> color_t PDQ_GFX<HW>::textcolor; template<class HW> color_t PDQ_GFX<HW>::textbgcolor; template<class HW> uint8_t PDQ_GFX<HW>::textsize; template<class HW> uint8_t PDQ_GFX<HW>::rotation; template<class HW> boolean PDQ_GFX<HW>::wrap; // If set, 'wrap' text at right edge of display template<class HW> boolean PDQ_GFX<HW>::_cp437; // If set, use correct CP437 charset (default is off) template<class HW> GFXfont *PDQ_GFX<HW>::gfxFont; template<class HW> PDQ_GFX<HW>::PDQ_GFX(coord_t w, coord_t h) { WIDTH = (int16_t)w; HEIGHT = (int16_t)h; _width = (int16_t)w; _height = (int16_t)h; cursor_x = 0; cursor_y = 0; rotation = 0; textsize = 1; textcolor = 0xffff; textbgcolor = 0xffff; wrap = true; _cp437 = false; gfxFont = NULL; } // Draw a circle outline template<class HW> void PDQ_GFX<HW>::drawCircle(coord_t x0, coord_t y0, coord_t r, color_t color) { coord_t f = 1 - r; coord_t ddF_x = 1; coord_t ddF_y = -2 * r; coord_t x = 0; coord_t y = r; HW::drawPixel(x0 , y0+r, color); HW::drawPixel(x0 , y0-r, color); HW::drawPixel(x0+r, y0 , color); HW::drawPixel(x0-r, y0 , color); while (x < y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; HW::drawPixel(x0 + x, y0 + y, color); HW::drawPixel(x0 - x, y0 + y, color); HW::drawPixel(x0 + x, y0 - y, color); HW::drawPixel(x0 - x, y0 - y, color); HW::drawPixel(x0 + y, y0 + x, color); HW::drawPixel(x0 - y, y0 + x, color); HW::drawPixel(x0 + y, y0 - x, color); HW::drawPixel(x0 - y, y0 - x, color); } } template<class HW> void PDQ_GFX<HW>::drawCircleHelper( coord_t x0, coord_t y0, coord_t r, uint8_t cornername, color_t color) { coord_t f = 1 - r; coord_t ddF_x = 1; coord_t ddF_y = -2 * r; coord_t x = 0; coord_t y = r; while (x < y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x4) { HW::drawPixel(x0 + x, y0 + y, color); HW::drawPixel(x0 + y, y0 + x, color); } if (cornername & 0x2) { HW::drawPixel(x0 + x, y0 - y, color); HW::drawPixel(x0 + y, y0 - x, color); } if (cornername & 0x8) { HW::drawPixel(x0 - y, y0 + x, color); HW::drawPixel(x0 - x, y0 + y, color); } if (cornername & 0x1) { HW::drawPixel(x0 - y, y0 - x, color); HW::drawPixel(x0 - x, y0 - y, color); } } } template<class HW> void PDQ_GFX<HW>::fillCircle(coord_t x0, coord_t y0, coord_t r, color_t color) { HW::drawFastVLine(x0, y0-r, 2*r+1, color); fillCircleHelper(x0, y0, r, 3, 0, color); } // Used to do circles and roundrects template<class HW> void PDQ_GFX<HW>::fillCircleHelper(coord_t x0, coord_t y0, coord_t r, uint8_t cornername, coord_t delta, color_t color) { coord_t f = 1 - r; coord_t ddF_x = 1; coord_t ddF_y = -2 * r; coord_t x = 0; coord_t y = r; while (x < y) { if (f >= 0) { y--; ddF_y += 2; f += ddF_y; } x++; ddF_x += 2; f += ddF_x; if (cornername & 0x1) { HW::drawFastVLine(x0+x, y0-y, 2*y+1+delta, color); HW::drawFastVLine(x0+y, y0-x, 2*x+1+delta, color); } if (cornername & 0x2) { HW::drawFastVLine(x0-x, y0-y, 2*y+1+delta, color); HW::drawFastVLine(x0-y, y0-x, 2*x+1+delta, color); } } } // Bresenham's algorithm - thx Wikipedia template<class HW> void PDQ_GFX<HW>::drawLine_(coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color) { int8_t steep = abs(y1 - y0) > abs(x1 - x0); if (steep) { swapValue(x0, y0); swapValue(x1, y1); } if (x0 > x1) { swapValue(x0, x1); swapValue(y0, y1); } coord_t dx, dy; dx = x1 - x0; dy = abs(y1 - y0); coord_t err = dx / 2; coord_t ystep; if (y0 < y1) { ystep = 1; } else { ystep = -1; } for (; x0<=x1; x0++) { if (steep) { HW::drawPixel(y0, x0, color); } else { HW::drawPixel(x0, y0, color); } err -= dy; if (err < 0) { y0 += ystep; err += dx; } } } // Draw a rectangle template<class HW> void PDQ_GFX<HW>::drawRect(coord_t x, coord_t y, coord_t w, coord_t h, color_t color) { HW::drawFastHLine(x , y , w, color); HW::drawFastHLine(x , y+h-1, w, color); HW::drawFastVLine(x , y , h, color); HW::drawFastVLine(x+w-1, y , h, color); } template<class HW> void PDQ_GFX<HW>::drawFastVLine_(coord_t x, coord_t y, coord_t h, color_t color) { // Used by driver when it has no special support HW::drawLine(x, y, x, y+h-1, color); } template<class HW> void PDQ_GFX<HW>::drawFastHLine_(coord_t x, coord_t y, coord_t w, color_t color) { // Used by driver when it has no special support HW::drawLine(x, y, x+w-1, y, color); } template<class HW> void PDQ_GFX<HW>::fillRect_(coord_t x, coord_t y, coord_t w, coord_t h, color_t color) { // Used by driver when it has no special support for (coord_t i=x; i<x+w; i++) { HW::drawFastVLine(i, y, h, color); } } template<class HW> void PDQ_GFX<HW>::fillScreen_(color_t color) { // Used by driver when it has no special support HW::fillRect(0, 0, _width, _height, color); } // Draw a rounded rectangle template<class HW> void PDQ_GFX<HW>::drawRoundRect(coord_t x, coord_t y, coord_t w, coord_t h, coord_t r, color_t color) { // smarter version HW::drawFastHLine(x+r , y , w-2*r, color); // Top HW::drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom HW::drawFastVLine(x , y+r , h-2*r, color); // Left HW::drawFastVLine(x+w-1, y+r , h-2*r, color); // Right // draw four corners drawCircleHelper(x+r , y+r , r, 1, color); drawCircleHelper(x+w-r-1, y+r , r, 2, color); drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color); drawCircleHelper(x+r , y+h-r-1, r, 8, color); } // Fill a rounded rectangle template<class HW> void PDQ_GFX<HW>::fillRoundRect(coord_t x, coord_t y, coord_t w, coord_t h, coord_t r, color_t color) { // smarter version HW::fillRect(x+r, y, w-2*r, h, color); // draw four corners fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color); fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color); } // Draw a triangle template<class HW> void PDQ_GFX<HW>::drawTriangle(coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color) { HW::drawLine(x0, y0, x1, y1, color); HW::drawLine(x1, y1, x2, y2, color); HW::drawLine(x2, y2, x0, y0, color); } // Fill a triangle template<class HW> void PDQ_GFX<HW>::fillTriangle( coord_t x0, coord_t y0, coord_t x1, coord_t y1, coord_t x2, coord_t y2, color_t color) { coord_t a, b, y, last; // Sort coordinates by Y order (y2 >= y1 >= y0) if (y0 > y1) { swapValue(y0, y1); swapValue(x0, x1); } if (y1 > y2) { swapValue(y2, y1); swapValue(x2, x1); } if (y0 > y1) { swapValue(y0, y1); swapValue(x0, x1); } if (y0 == y2) // Handle awkward all-on-same-line case as its own thing { a = b = x0; if (x1 < a) a = x1; else if (x1 > b) b = x1; if (x2 < a) a = x2; else if (x2 > b) b = x2; HW::drawFastHLine(a, y0, b-a+1, color); return; } coord_t dx01 = x1 - x0; coord_t dy01 = y1 - y0; coord_t dx02 = x2 - x0; coord_t dy02 = y2 - y0; coord_t dx12 = x2 - x1; coord_t dy12 = y2 - y1; int32_t sa = 0; int32_t sb = 0; // For upper part of triangle, find scanline crossings for segments // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 // is included here (and second loop will be skipped, avoiding a /0 // error there), otherwise scanline y1 is skipped here and handled // in the second loop...which also avoids a /0 error here if y0=y1 // (flat-topped triangle). if (y1 == y2) last = y1; // Include y1 scanline else last = y1-1; // Skip it for (y = y0; y <= last; y++) { a = x0 + sa / dy01; b = x0 + sb / dy02; sa += dx01; sb += dx02; /* longhand: a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); */ if (a > b) swapValue(a, b); HW::drawFastHLine(a, y, b-a+1, color); } // For lower part of triangle, find scanline crossings for segments // 0-2 and 1-2. This loop is skipped if y1=y2. sa = dx12 * (y - y1); sb = dx02 * (y - y0); for (; y <= y2; y++) { a = x1 + sa / dy12; b = x0 + sb / dy02; sa += dx12; sb += dx02; /* longhand: a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); */ if (a > b) swapValue(a, b); HW::drawFastHLine(a, y, b-a+1, color); } } /* // Draw a 1-bit image (bitmap) at the specified (x, y) position from the // provided bitmap buffer (must be PROGMEM memory) using the specified // foreground color (unset bits are transparent). template<class HW> void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color) { coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); else byte <<= 1; if (byte & 0x80) HW::drawPixel(x+i, y+j, color); } } } // Draw a 1-bit image (bitmap) at the specified (x, y) position from the // provided bitmap buffer (must be PROGMEM memory) using the specified // foreground (for set bits) and background (for clear bits) colors. template<class HW> void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg) { coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); else byte <<= 1; if (byte & 0x80) HW::drawPixel(x+i, y+j, color); else HW::drawPixel(x+i, y+j, bg); } } } // drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps. template<class HW> void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color) { coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = bitmap[j * byteWidth + i / 8]; else byte <<= 1; if (byte & 0x80) HW::drawPixel(x+i, y+j, color); } } } // drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps. template<class HW> void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg) { coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = bitmap[j * byteWidth + i / 8]; else byte <<= 1; if (byte & 0x80) HW::drawPixel(x+i, y+j, color); else HW::drawPixel(x+i, y+j, bg); } } } */ // Pour dessiner des bitmaps avec en plus un angle, et un mirror : template<class HW> void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg, uint8_t angleFM) { //drawFastBitmap : 26754 octets de ROM - 272 ms => 1,5 x plus rapide HW::drawFastBitmap(x, y, bitmap, w, h, color, bg, angleFM); //Version classique : 26674 octets de ROM - 404 ms /* coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; coord_t xx, yy; bool mirror; mirror = angleFM>3; if (mirror) { angleFM-=4; } for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = bitmap[j * byteWidth + i / 8]; else byte <<= 1; switch (angleFM) { case 0: if (mirror) { xx = w - i - 1; }else{ xx = i; } yy = j; break; case 1: xx = h - j - 1; if (mirror) { yy = w - i - 1; }else{ yy = i; } break; case 2: if (mirror) { xx = i; }else{ xx = w - i - 1; } yy = h - j - 1; break; default: xx = j; if (mirror) { yy = i; }else{ yy = w - i - 1; } break; } if (byte & 0x80) HW::drawPixel(xx + x, yy + y, color); else if (drawBG) HW::drawPixel(xx + x, yy + y, bg); } } */ } /* // Draw XBitMap Files (*.xbm), exported from GIMP, // Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. // C Array can be directly used with this function template<class HW> void PDQ_GFX<HW>::drawXBitmap(coord_t x, coord_t y, const uint8_t *bitmap, coord_t w, coord_t h, color_t color) { coord_t i, j, byteWidth = (w + 7) / 8; uint8_t byte; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (i % 8 == 0) byte = pgm_read_byte(bitmap + j * byteWidth + i / 8); else byte >>= 1; if (byte & 0x01) HW::drawPixel(x+i, y+j, color); } } } */ template<class HW> size_t PDQ_GFX<HW>::write(uint8_t c) { // 'Classic' built-in font if (!gfxFont) { if (c == '\n') { cursor_x = 0; cursor_y += (coord_t)textsize*8; } else if (c != '\r') { HW::drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); cursor_x += textsize*6; if (wrap && (cursor_x > (_width - textsize*6))) { cursor_x = 0; cursor_y += textsize*8; } } } else { if(c == '\n') { cursor_x = 0; cursor_y += (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); } else if (c != '\r') { uint8_t first = pgm_read_byte(&gfxFont->first); if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { uint8_t c2 = c - pgm_read_byte(&gfxFont->first); GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]); uint8_t w = pgm_read_byte(&glyph->width); uint8_t h = pgm_read_byte(&glyph->height); // Is there an associated bitmap? if ((w > 0) && (h > 0)) { coord_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) { // Drawing character would go off right edge; wrap to new line cursor_x = 0; cursor_y += (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); } HW::drawCharGFX(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize); } cursor_x += pgm_read_byte(&glyph->xAdvance) * (coord_t)textsize; } } } return 1; } // Draw a character with built-in font template<class HW> void PDQ_GFX<HW>::drawChar(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size) { // HW::drawFastChar : 26754 octets de ROM - 320 ms pour l'affichage taille 2 - 237 ms pour l'affichage taille 2 => 1,5 x plus rapide HW::drawFastChar(x, y, c, color, bg, size); // Code classique : 26674 octets de ROM - 475 ms pour l'affichage taille 2 - 367 ms pour l'affichage taille 2 /* if ((x >= _width) || (y >= _height) || ((x + (6 * size) - 1) < 0) || ((y + (8 * size) - 1) < 0)) return; uint8_t is_opaque = (bg != color); if(!_cp437 && (c >= 176)) // Handle 'classic' charset behavior c++; for (int8_t i=0; i<6; i++) { uint8_t line; if (i == 5) line = 0x0; else line = pgm_read_byte(RLucas_glcdfont+(c*5)+i); if (size == 1) { for (int8_t j = 0; j < 8; j++) { if (line & 0x1) { HW::drawPixel(x+i, y+j, color); } else if (is_opaque) { HW::drawPixel(x+i, y+j, bg); } line >>= 1; } } else { for (int8_t j = 0; j < 8; j++) { if (line & 0x1) { HW::fillRect(x+(i*size), y+(j*size), size, size, color); } else if (is_opaque) { HW::fillRect(x+(i*size), y+(j*size), size, size, bg); } line >>= 1; } } } */ } // Draw a character with GFX font template<class HW> void PDQ_GFX<HW>::drawCharGFX(coord_t x, coord_t y, unsigned char c, color_t color, color_t bg, uint8_t size) { // Character is assumed previously filtered by write() to eliminate // newlines, returns, non-printable characters, etc. Calling drawChar() // directly with 'bad' characters of font may cause mayhem! c -= pgm_read_byte(&gfxFont->first); GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); uint16_t bo = pgm_read_word(&glyph->bitmapOffset); uint8_t w = pgm_read_byte(&glyph->width); uint8_t h = pgm_read_byte(&glyph->height); // uint8_t xa = pgm_read_byte(&glyph->xAdvance); int8_t xo = pgm_read_byte(&glyph->xOffset); int8_t yo = pgm_read_byte(&glyph->yOffset); // Todo: Add character clipping here // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. // THIS IS ON PURPOSE AND BY DESIGN. The background color feature // has typically been used with the 'classic' font to overwrite old // screen contents with new data. This ONLY works because the // characters are a uniform size; it's not a sensible thing to do with // proportionally-spaced fonts with glyphs of varying sizes (and that // may overlap). To replace previously-drawn text when using a custom // font, use the getTextBounds() function to determine the smallest // rectangle encompassing a string, erase the area with fillRect(), // then draw new text. This WILL infortunately 'blink' the text, but // is unavoidable. Drawing 'background' pixels will NOT fix this, // only creates a new set of problems. Have an idea to work around // this (a canvas object type for MCUs that can afford the RAM and // displays supporting setAddrWindow() and pushColors()), but haven't // implemented this yet. if (bo & 0x8000) { // packed font uint8_t bits_cnt = 0; uint8_t bits; uint8_t cnt,cnt2; bo &= 0x7FFF; coord_t _y = y+yo; for (coord_t yy=0; yy<h; yy++, _y++) { coord_t _x = x+xo; for (coord_t xx=0; xx<w; xx+=cnt2) { if (bits_cnt == 0) { bits = pgm_read_byte(&bitmap[bo++]); bits_cnt = 2; cnt = (bits & 0x7)+1; } if (xx+cnt >= w) { cnt2 = w-xx; } else { cnt2 = cnt; } if (bits & 0x8) { if (size == 1) { HW::drawFastHLine(_x, _y, cnt2, color); _x += cnt2; } else { HW::fillRect(x+xo+xx*size, y+yo+yy*size, cnt2*size, size, color); // _x not used if size > 1, so not need to increment it } } else { _x += cnt2; } cnt -= cnt2; if (cnt == 0) { bits >>= 4; cnt = (bits & 0x7)+1; bits_cnt--; } } } } else { uint8_t bit = 0; uint8_t bits = 0; if (size == 1) { coord_t _y = y+yo; for (coord_t yy=0; yy<h; yy++, _y++) { coord_t _x = x+xo; for (coord_t xx=0; xx<w; xx++, _x++) { if (bit == 0) { bits = pgm_read_byte(&bitmap[bo++]); } bit = (bit+1) & 0x7; if (bits & 0x80) { HW::drawPixel(_x, _y, color); } bits <<= 1; } } } else { for (coord_t yy=0; yy<h; yy++) { for (coord_t xx=0; xx<w; xx++) { if (bit == 0) { bits = pgm_read_byte(&bitmap[bo++]); } bit = (bit+1) & 0x7; if (bits & 0x80) { HW::fillRect(x+xo+xx*size, y+yo+yy*size, size, size, color); } bits <<= 1; } } } } } template<class HW> void PDQ_GFX<HW>::setCursor(coord_t x, coord_t y) { cursor_x = (int16_t)x; cursor_y = (int16_t)y; } template<class HW> void PDQ_GFX<HW>::setTextSize(uint8_t s) { textsize = (s > 0) ? s : 1; } template<class HW> void PDQ_GFX<HW>::setTextColor(color_t c) { // For 'transparent' background, we'll set the bg // to the same as fg instead of using a flag textcolor = c; textbgcolor = c; } template<class HW> void PDQ_GFX<HW>::setTextColor(color_t c, color_t b) { textcolor = c; textbgcolor = b; } template<class HW> void PDQ_GFX<HW>::setTextWrap(boolean w) { wrap = w; } template<class HW> void PDQ_GFX<HW>::setRotation(uint8_t x) { // Used by driver when it has no special support rotation = x & 3; switch(rotation) { case 0: case 2: _width = WIDTH; _height = HEIGHT; break; case 1: case 3: _width = HEIGHT; _height = WIDTH; break; } } template<class HW> void PDQ_GFX<HW>::cp437(boolean x) { _cp437 = x; } template<class HW> void PDQ_GFX<HW>::setFont(const GFXfont *f) { if (f) // Font struct pointer passed in? { if (!gfxFont) // And no current font struct? { // Switching from classic to new font behavior. // Move cursor pos down 6 pixels so it's on baseline. cursor_y += 6; } } else if (gfxFont) // NULL passed. Current font struct defined? { // Switching from new to classic font behavior. // Move cursor pos up 6 pixels so it's at top-left of char. cursor_y -= 6; } gfxFont = (GFXfont *)f; } // Pass string and a cursor position, returns UL corner and W,H. template<class HW> void PDQ_GFX<HW>::getTextBounds(char *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { uint8_t c; // Current character *x1 = x; *y1 = y; *w = *h = 0; if (gfxFont) { GFXglyph *glyph; uint8_t first = pgm_read_byte(&gfxFont->first); uint8_t last = pgm_read_byte(&gfxFont->last); uint8_t gw, gh, xa; int8_t xo, yo; int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; coord_t gx1, gy1, gx2, gy2; coord_t ts = (coord_t)textsize, ya = (coord_t)textsize * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); while((c = *str++)) { if (c != '\n') // Not a newline { if (c != '\r') // Not a carriage return, is normal char { if ((c >= first) && (c <= last)) // Char present in current font { c -= first; glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); gw = pgm_read_byte(&glyph->width); gh = pgm_read_byte(&glyph->height); xa = pgm_read_byte(&glyph->xAdvance); xo = pgm_read_byte(&glyph->xOffset); yo = pgm_read_byte(&glyph->yOffset); if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap { x = 0; // Reset x to 0 y += ya; // Advance y by 1 line } gx1 = x + xo * ts; gy1 = y + yo * ts; gx2 = gx1 + gw * ts - 1; gy2 = gy1 + gh * ts - 1; if (gx1 < minx) minx = gx1; if (gy1 < miny) miny = gy1; if (gx2 > maxx) maxx = gx2; if (gy2 > maxy) maxy = gy2; x += xa * ts; } } // Carriage return = do nothing } else // Newline { x = 0; // Reset x y += ya; // Advance y by 1 line } } // End of string *x1 = minx; *y1 = miny; if (maxx >= minx) *w = maxx - minx + 1; if (maxy >= miny) *h = maxy - miny + 1; } else // Default font { uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines while((c = *str++)) { if (c != '\n') // Not a newline { if (c != '\r') // Not a carriage return, is normal char { lineWidth += textsize * 6; // Includes interchar x gap if (wrap && (cursor_x > (_width - textsize*6))) { x = 0; y += textsize*8; if (lineWidth > maxWidth) // Save widest line maxWidth = lineWidth; lineWidth = textsize * 6; // First char on new line } } // Carriage return = do nothing } else // Newline { x = 0; // Reset x to 0 y += textsize * 8; // Advance y by 1 line if (lineWidth > maxWidth) // Save widest line maxWidth = lineWidth; lineWidth = 0; // Reset lineWidth for new line } } // End of string if (lineWidth) // Add height of last (or only) line y += textsize * 8; *w = maxWidth - 1; // Don't include last interchar x gap *h = y - *y1; } // End classic vs custom font } // Same as above, but for PROGMEM strings template<class HW> void PDQ_GFX<HW>::getTextBounds(const __FlashStringHelper *str, coord_t x, coord_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) { uint8_t *s = (uint8_t *)str; uint8_t c; *x1 = x; *y1 = y; *w = *h = 0; if (gfxFont) { GFXglyph *glyph; uint8_t first = pgm_read_byte(&gfxFont->first); uint8_t last = pgm_read_byte(&gfxFont->last); uint8_t gw, gh, xa; int8_t xo, yo; int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; coord_t gx1, gy1, gx2, gy2; coord_t ts = (coord_t)textsize; coord_t ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); while((c = pgm_read_byte(s++))) { if (c != '\n') // Not a newline { if (c != '\r') // Not a carriage return, is normal char { if ((c >= first) && (c <= last)) // Char present in current font { c -= first; glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); gw = pgm_read_byte(&glyph->width); gh = pgm_read_byte(&glyph->height); xa = pgm_read_byte(&glyph->xAdvance); xo = pgm_read_byte(&glyph->xOffset); yo = pgm_read_byte(&glyph->yOffset); if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) // Line wrap { x = 0; // Reset x to 0 y += ya; // Advance y by 1 line } gx1 = x + xo * ts; gy1 = y + yo * ts; gx2 = gx1 + gw * ts - 1; gy2 = gy1 + gh * ts - 1; if (gx1 < minx) minx = gx1; if (gy1 < miny) miny = gy1; if (gx2 > maxx) maxx = gx2; if (gy2 > maxy) maxy = gy2; x += xa * ts; } } // Carriage return = do nothing } else // Newline { x = 0; // Reset x y += ya; // Advance y by 1 line } } // End of string *x1 = minx; *y1 = miny; if (maxx >= minx) *w = maxx - minx + 1; if (maxy >= miny) *h = maxy - miny + 1; } else // Default font { uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines while((c = pgm_read_byte(s++))) { if (c != '\n') // Not a newline { if (c != '\r') // Not a carriage return, is normal char { if (wrap && ((x + textsize * 6) >= _width)) { x = 0; // Reset x to 0 y += textsize * 8; // Advance y by 1 line if (lineWidth > maxWidth) // Save widest line maxWidth = lineWidth; lineWidth = textsize * 6; // First char on new line } else // No line wrap, just keep incrementing X { lineWidth += textsize * 6; // Includes interchar x gap } } // Carriage return = do nothing } else // Newline { x = 0; // Reset x to 0 y += textsize * 8; // Advance y by 1 line if (lineWidth > maxWidth) // Save widest line maxWidth = lineWidth; lineWidth = 0; // Reset lineWidth for new line } } // End of string if (lineWidth) // Add height of last (or only) line y += textsize * 8; *w = maxWidth - 1; // Don't include last interchar x gap *h = y - *y1; } // End classic vs custom font } template<class HW> void PDQ_GFX<HW>::invertDisplay(boolean i) { // Used by driver when it has no special support // Do nothing, must be supported by driver } /***************************************************************************/ // code for the GFX button UI element template <class HW> PDQ_GFX_Button_<HW>::PDQ_GFX_Button_() { _gfx = 0; } template <class HW> void PDQ_GFX_Button_<HW>::initButton(PDQ_GFX<HW> *gfx, coord_t x, coord_t y, coord_t w, coord_t h, color_t outline, color_t fill, color_t textcolor, const char *label, uint8_t textsize) { _gfx = gfx; _x = x; _y = y; _w = w; _h = h; _outlinecolor = outline; _fillcolor = fill; _textcolor = textcolor; _textsize = textsize; strncpy(_label, label, 9); _label[9] = 0; } template <class HW> void PDQ_GFX_Button_<HW>::drawButton(boolean inverted) { uint16_t fill, outline, text; if (!inverted) { fill = _fillcolor; outline = _outlinecolor; text = _textcolor; } else { fill = _textcolor; outline = _outlinecolor; text = _fillcolor; } _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill); _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline); _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize); _gfx->setTextColor(text); _gfx->setTextSize(_textsize); _gfx->print(_label); } template <class HW> boolean PDQ_GFX_Button_<HW>::contains(coord_t x, coord_t y) { if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false; if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false; return true; } template <class HW> void PDQ_GFX_Button_<HW>::press(boolean p) { laststate = currstate; currstate = p; } template <class HW> boolean PDQ_GFX_Button_<HW>::isPressed() { return currstate; } template <class HW> boolean PDQ_GFX_Button_<HW>::justPressed() { return (currstate && !laststate); } template <class HW> boolean PDQ_GFX_Button_<HW>::justReleased() { return (!currstate && laststate); } #endif // _PDQ_GFX_H
Je dois mieux maîtriser le langage pour aller plus loin dans mon optimisation d'une part, et surtout d'autre part pour améliorer le code de mon projet.
Je sais qu'on trouve beaucoup de choses sur Internet mais même aujourd'hui rien ne vaut un bon livre.
J'ai dépassé le stade du tutoriel pour faire clignoter une led , il me faut un ouvrage de référence qui va au bout des choses mais sans oublier une étape.
Etant donné le niveau que je recherche j'aimerais si possible un livre en français, pour limiter le niveau de migraine et que ce passe temps reste un plaisir
A bientôt
Partager