-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdisplay_st7735.h
More file actions
468 lines (405 loc) · 15.1 KB
/
display_st7735.h
File metadata and controls
468 lines (405 loc) · 15.1 KB
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
/***************************************************************************
* Copyright (C) 2013 by Salaorni Davide, Velati Matteo *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* As a special exception, if other files instantiate templates or use *
* macros or inline functions from this file, or you compile this file *
* and link it with other works to produce a work based on this file, *
* this file does not by itself cause the resulting work to be covered *
* by the GNU General Public License. However the source code for this *
* file must still be made available in accordance with the GNU General *
* Public License. This exception does not invalidate any other reasons *
* why a work based on this file might be covered by the GNU General *
* Public License. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, see <http://www.gnu.org/licenses/> *
***************************************************************************/
#ifndef MXGUI_LIBRARY
#error "This is header is private, it can be used only within mxgui."
#error "If your code depends on a private header, it IS broken."
#endif //MXGUI_LIBRARY
#ifndef DISPLAY_ST7735H
#define DISPLAY_ST7735H
#ifdef _BOARD_STM32F4DISCOVERY
#include <config/mxgui_settings.h>
#include "display.h"
#include "point.h"
#include "color.h"
#include "font.h"
#include "image.h"
#include "iterator_direction.h"
#include "misc_inst.h"
#include "line.h"
#include "miosix.h"
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
using namespace miosix;
namespace mxgui {
#ifndef MXGUI_COLOR_DEPTH_16_BIT
#error The ST7735 driver requires a color depth 16 per pixel
#endif
//Hardware mapping
typedef Gpio<GPIOB_BASE, 13> scl; //PB13, SPI1_SCK (af5)
typedef Gpio<GPIOB_BASE, 15> sda; //PB15, SPI1_MOSI (af5)
typedef Gpio<GPIOB_BASE, 4> csx; //PB4, free I/O pin
typedef Gpio<GPIOC_BASE, 6> resx; //PC6, free I/O pin
typedef Gpio<GPIOA_BASE, 8> dcx; //PA8, free I/O pin, used only in 4-line SPI
//A falling edge of CSX enables the SPI transaction
class SPITransaction
{
public:
SPITransaction() { csx::low(); }
~SPITransaction() { csx::high(); }
};
//A falling edge on DCX means that the transmitted byte is a command
class CommandTransaction
{
public:
CommandTransaction() { dcx::low(); }
~CommandTransaction() { dcx::high(); }
};
class DisplayImpl : public Display
{
public:
/**
* \return an instance to this class(singleton)
*/
static DisplayImpl& instance();
/**
* Turn the display On after it has been turned Off.
* Display initial state On.
*/
void doTurnOn() override;
/**
* Turn the display Off. It can be later turned back On.
*/
void doTurnOff() override;
/**
* Set display brightness. Depending on the underlying driver,
* may do nothing.
* \param brt from 0 to 100
*/
void doSetBrightness(int brt) override;
/**
* \return a pair with the display height and width
*/
std::pair<short int, short int> doGetSize() const override;
/**
* Write text to the display. If text is too long it will be truncated
* \param p point where the upper left corner of the text will be printed
* \param text, text to print.
*/
void write(Point p, const char *text) override;
/**
* Write part of text to the display
* \param p point of the upper left corner where the text will be drawn.
* Negative coordinates are allowed, as long as the clipped view has
* positive or zero coordinates
* \param a Upper left corner of clipping rectangle
* \param b Lower right corner of clipping rectangle
* \param text text to write
*/
void clippedWrite(Point p, Point a, Point b, const char *text) override;
/**
* Clear the Display. The screen will be filled with the desired color
* \param color fill color
*/
void clear(Color color) override;
/**
* Clear an area of the screen
* \param p1 upper left corner of area to clear
* \param p2 lower right corner of area to clear
* \param color fill color
*/
void clear(Point p1, Point p2, Color color) override;
/**
* This member function is used on some target displays to reset the
* drawing window to its default value. You have to call beginPixel() once
* before calling setPixel(). You can then make any number of calls to
* setPixel() without calling beginPixel() again, as long as you don't
* call any other member function in this class. If you call another
* member function, for example line(), you have to call beginPixel() again
* before calling setPixel().
*/
void beginPixel() override;
/**
* Draw a pixel with desired color.
* \param p point where to draw pixel
* \param color pixel color
*/
void setPixel(Point p, Color color) override;
/**
* Draw a line between point a and point b, with color c
* \param a first point
* \param b second point
* \param c line color
*/
void line(Point a, Point b, Color color) override;
/**
* Draw an horizontal line on screen.
* Instead of line(), this member function takes an array of colors to be
* able to individually set pixel colors of a line.
* \param p starting point of the line
* \param colors an array of pixel colors whoase size must be b.x()-a.x()+1
* \param length length of colors array.
* p.x()+length must be <= display.width()
*/
void scanLine(Point p, const Color *colors, unsigned short length) override;
/**
* \return a buffer of length equal to this->getWidth() that can be used to
* render a scanline.
*/
Color *getScanLineBuffer() override;
/**
* Draw the content of the last getScanLineBuffer() on an horizontal line
* on the screen.
* \param p starting point of the line
* \param length length of colors array.
* p.x()+length must be <= display.width()
*/
void scanLineBuffer(Point p, unsigned short length) override;
/**
* Draw an image on the screen
* \param p point of the upper left corner where the image will be drawn
* \param i image to draw
*/
void drawImage(Point p, const ImageBase& img) override;
/**
* Draw part of an image on the screen
* \param p point of the upper left corner where the image will be drawn.
* Negative coordinates are allowed, as long as the clipped view has
* positive or zero coordinates
* \param a Upper left corner of clipping rectangle
* \param b Lower right corner of clipping rectangle
* \param img Image to draw
*/
void clippedDrawImage(Point p, Point a, Point b, const ImageBase& img) override;
/**
* Draw a rectangle (not filled) with the desired color
* \param a upper left corner of the rectangle
* \param b lower right corner of the rectangle
* \param c color of the line
*/
void drawRectangle(Point a, Point b, Color c) override;
/**
* Make all changes done to the display since the last call to update()
* visible.
*/
void update() override;
/**
* Pixel iterator. A pixel iterator is an output iterator that allows to
* define a window on the display and write to its pixels.
*/
class pixel_iterator
{
public:
/**
* Default constructor, results in an invalid iterator.
*/
pixel_iterator(): pixelLeft(0) {}
/**
* Set a pixel and move the pointer to the next one
* \param color color to set the current pixel
* \return a reference to this
*/
pixel_iterator& operator= (Color color)
{
pixelLeft--;
unsigned char lsb = color & 0xFF;
unsigned char msb = (color >> 8) & 0xFF;
SPITransaction t;
writeRam(msb);
writeRam(lsb);
return *this;
}
/**
* Compare two pixel_iterators for equality.
* They are equal if they point to the same location.
*/
bool operator== (const pixel_iterator& itr)
{
return this->pixelLeft==itr.pixelLeft;
}
/**
* Compare two pixel_iterators for inequality.
* They different if they point to different locations.
*/
bool operator!= (const pixel_iterator& itr)
{
return this->pixelLeft!=itr.pixelLeft;
}
/**
* \return a reference to this.
*/
pixel_iterator& operator* () { return *this; }
/**
* \return a reference to this. Does not increment pixel pointer.
*/
pixel_iterator& operator++ () { return *this; }
/**
* \return a reference to this. Does not increment pixel pointer.
*/
pixel_iterator& operator++ (int) { return *this; }
/**
* Must be called if not all pixels of the required window are going
* to be written.
*/
void invalidate() {}
private:
/**
* Constructor
* \param pixelLeft number of remaining pixels
*/
pixel_iterator(unsigned int pixelLeft): pixelLeft(pixelLeft) {}
unsigned int pixelLeft; ///< How many pixels are left to draw
friend class DisplayImpl; //Needs access to ctor
};
/**
* Specify a window on screen and return an object that allows to write
* its pixels.
* Note: a call to begin() will invalidate any previous iterator.
* \param p1 upper left corner of window
* \param p2 lower right corner (included)
* \param d increment direction
* \return a pixel iterator
*/
pixel_iterator begin(Point p1, Point p2, IteratorDirection d);
/**
* \return an iterator which is one past the last pixel in the pixel
* specified by begin. Behaviour is undefined if called before calling
* begin()
*/
pixel_iterator end() const
{
// Default ctor: pixelLeft is zero
return pixel_iterator();
}
/**
* Destructor
*/
~DisplayImpl() override;
private:
#if defined MXGUI_ORIENTATION_VERTICAL
static const short int width = 128;
static const short int height = 160;
#elif defined MXGUI_ORIENTATION_HORIZONTAL
static const short int width = 160;
static const short int height = 128;
#else
#error Orientation not defined
#endif
/**
* Constructor.
* Do not instantiate objects of this type directly from application code.
*/
DisplayImpl();
/**
* Set cursor to desired location
* \param point where to set cursor (0<=x<=127, 0<=y<=159)
*/
static inline void setCursor(Point p)
{
window(p, p, false);
}
/**
* Register 0x36: MADCTL
* bit 7------0
* 4: |||||+-- MH horizontal referesh (0 L-to-R, 1 R-to-L)
* 8: ||||+--- RGB BRG order (0 for RGB)
* 16: |||+---- ML vertical refesh (0 T-to-B, 1 B-to-T)
* 32: ||+----- MV row column exchange (1 for X-Y exchange)
* 64: |+------ MX column address order (1 for mirror X axis)
* 128: +------- MY row address order (1 for mirror Y axis)
*/
/**
* Set a hardware window on the screen, optimized for writing text.
* The GRAM increment will be set to up-to-down first, then left-to-right
* which is the correct increment to draw fonts
* \param p1 upper left corner of the window
* \param p2 lower right corner of the window
*/
static inline void textWindow(Point p1, Point p2)
{
#ifdef MXGUI_ORIENTATION_VERTICAL
writeReg (0x36, 0xE0); // MADCTL: MX + MY + MV
window(p1, p2, true);
#else //MXGUI_ORIENTATION_HORIZONTAL
writeReg (0x36, 0x80); // MADCTL: MY
window(p1, p2, true);
#endif
}
/**
* Set a hardware window on the screen, optimized for drawing images.
* The GRAM increment will be set to left-to-right first, then up-to-down
* which is the correct increment to draw images
* \param p1 upper left corner of the window
* \param p2 lower right corner of the window
*/
static inline void imageWindow(Point p1, Point p2)
{
#ifdef MXGUI_ORIENTATION_VERTICAL
writeReg (0x36, 0xC0); // MADCTL: MX + MY
window(p1, p2, false);
#else //MXGUI_ORIENTATION_HORIZONTAL
writeReg (0x36, 0xA0); // MADCTL: MY + MV
window(p1, p2, false);
#endif
}
/**
* Common part of all window commands
*/
static void window(Point p1, Point p2, bool swap);
/**
* Sends command 0x2C to signal the start of data sending
*/
static void writeRamBegin()
{
CommandTransaction c;
writeRam(0x2C); //ST7735_RAMWR, to write the GRAM
}
/**
* Used to send pixel data to the display's RAM, and also to send commands.
* The SPI chip select must be low before calling this member function
* \param data data to write
*/
static unsigned char writeRam(unsigned char data)
{
SPI2->DR = data;
while((SPI2->SR & SPI_SR_RXNE) == 0) ;
return SPI2->DR; //Note: reading back SPI2->DR is necessary.
}
/**
* Write data to a display register
* \param reg which register?
* \param data data to write
*/
static void writeReg(unsigned char reg, unsigned char data);
/**
* Write data to a display register
* \param reg which register?
* \param data data to write, if null only reg will be written (zero arg cmd)
* \param len length of data, number of argument bytes
*/
static void writeReg(unsigned char reg, const unsigned char *data=0, int len=1);
/**
* Send multiple commands to the display MCU (we use to send init sequence)
* \param cmds static array containing the commands
*/
static void sendCmds(const unsigned char *cmds);
Color *buffer; //< For scanLineBuffer
};
} //namespace mxgui
#endif //_BOARD_STM32F4DISCOVERY
#endif //DISPLAY_ST7735H