-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathILI9341.c
320 lines (293 loc) · 11.4 KB
/
ILI9341.c
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
///////////////////////////////////////////////////////////////////////////
//// ////
//// ILI9341.c ////
//// ////
//// ILI9341 display driver for CCS C compiler ////
//// ////
///////////////////////////////////////////////////////////////////////////
//// ////
//// This is a free software with NO WARRANTY. ////
//// https://simple-circuit.com/ ////
//// ////
///////////////////////////////////////////////////////////////////////////
#include "ILI9341.h"
/**************************************************************************/
/*!
@brief Call before issuing command(s) or data to display. Performs
chip-select (if required). Required
for all display types; not an SPI-specific function.
*/
/**************************************************************************/
void startWrite(void) {
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_RESET);
}
/**************************************************************************/
/*!
@brief Call after issuing command(s) or data to display. Performs
chip-deselect (if required). Required
for all display types; not an SPI-specific function.
*/
/**************************************************************************/
void endWrite(void) {
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
}
void ILI9341_SPI_XFER(uint8_t data){
LL_SPI_TransmitData8(SPI1, data);
}
/**************************************************************************/
/*!
@brief Write a single command byte to the display. Chip-select and
transaction must have been previously set -- this ONLY sets
the device to COMMAND mode, issues the byte and then restores
DATA mode. There is no corresponding explicit writeData()
function -- just use ILI9341_SPI_XFER().
@param cmd 8-bit command to write.
*/
/**************************************************************************/
void writeCommand(uint8_t cmd) {
HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_RESET);
ILI9341_SPI_XFER(cmd);
HAL_GPIO_WritePin(LCD_DC_GPIO_Port, LCD_DC_Pin, GPIO_PIN_SET);
}
/**************************************************************************/
/*!
@brief Initialize ILI9341 chip
Connects to the ILI9341 over SPI and sends initialization procedure commands
@param freq Desired SPI clock frequency
*/
/**************************************************************************/
void tft_begin(void) {
#ifdef TFT_RST
HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
HAL_Delay(100);
HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(LCD_RST_GPIO_Port, LCD_RST_Pin, GPIO_PIN_SET);
HAL_Delay(200);
#else // If no hardware reset pin...
writeCommand(ILI9341_SWRESET); // Engage software reset
HAL_Delay(150);
#endif
HAL_GPIO_WritePin(LCD_CS_GPIO_Port, LCD_CS_Pin, GPIO_PIN_SET);
startWrite();
uint8_t cmd, x, numArgs;
static const uint8_t *addr = initcmd;
cmd = *addr++;
while( cmd > 0 ) {
writeCommand(cmd);
x = *addr++;
numArgs = x & 0x7F;
while(numArgs--) ILI9341_SPI_XFER(*addr++);
if(x & 0x80) HAL_Delay(150);
cmd = *addr++;
}
endWrite();
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
rotation = 0;
}
/**************************************************************************/
/*!
@brief Set the "address window" - the rectangle we will write to RAM with the next chunk of SPI data writes. The ILI9341 will automatically wrap the data as each row is filled
@param x1 TFT memory 'x' origin
@param y1 TFT memory 'y' origin
@param w Width of rectangle
@param h Height of rectangle
*/
/**************************************************************************/
void setAddrWindow(uint16_t x1, uint16_t y1, uint16_t w, uint16_t h) {
uint16_t x2 = (x1 + w - 1),
y2 = (y1 + h - 1);
writeCommand(ILI9341_CASET); // Column address set
ILI9341_SPI_XFER(x1 >> 8);
ILI9341_SPI_XFER(x1);
ILI9341_SPI_XFER(x2 >> 8);
ILI9341_SPI_XFER(x2);
writeCommand(ILI9341_PASET); // Row address set
ILI9341_SPI_XFER(y1 >> 8);
ILI9341_SPI_XFER(y1);
ILI9341_SPI_XFER(y2 >> 8);
ILI9341_SPI_XFER(y2);
writeCommand(ILI9341_RAMWR); // Write to RAM
}
/**************************************************************************/
/*!
@brief Set origin of (0,0) and orientation of TFT display
@param m The index for rotation, from 0-3 inclusive
*/
/**************************************************************************/
void setRotation(uint8_t m) {
rotation = m % 4; // can't be higher than 3
switch (rotation) {
case 0:
m = (MADCTL_MX | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 1:
m = (MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
case 2:
m = (MADCTL_MY | MADCTL_BGR);
_width = ILI9341_TFTWIDTH;
_height = ILI9341_TFTHEIGHT;
break;
case 3:
m = (MADCTL_MX | MADCTL_MY | MADCTL_MV | MADCTL_BGR);
_width = ILI9341_TFTHEIGHT;
_height = ILI9341_TFTWIDTH;
break;
}
startWrite();
writeCommand(ILI9341_MADCTL);
ILI9341_SPI_XFER(m);
endWrite();
}
void drawPixel(uint16_t x, uint16_t y, uint16_t color) {
if((x < _width) && (y < _height)) {
startWrite();
setAddrWindow(x, y, 1, 1);
LL_SPI_TransmitData16(SPI1,color);
endWrite();
}
}
/**************************************************************************/
/*!
@brief Draw a perfectly horizontal line (this is often optimized in a subclass!)
@param x Left-most x coordinate
@param y Left-most y coordinate
@param w Width in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void drawHLine(uint16_t x, uint16_t y, uint16_t w, uint16_t color) {
if( (x < _width) && (y < _height) && w) {
//uint8_t hi = color >> 8, lo = color;
if((x + w - 1) >= _width)
w = _width - x;
startWrite();
setAddrWindow(x, y, w, 1);
while (w--) {
LL_SPI_TransmitData16(SPI1,color);
}
endWrite();
}
}
/**************************************************************************/
/*!
@brief Draw a perfectly vertical line (this is often optimized in a subclass!)
@param x Top-most x coordinate
@param y Top-most y coordinate
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void drawVLine(uint16_t x, uint16_t y, uint16_t h, uint16_t color) {
if( (x < _width) && (y < _height) && h) {
//uint8_t hi = color >> 8, lo = color;
if((y + h - 1) >= _height)
h = _height - y;
startWrite();
setAddrWindow(x, y, 1, h);
while (h--) {
LL_SPI_TransmitData16(SPI1,color);
}
endWrite();
}
}
/**************************************************************************/
/*!
@brief Fill a rectangle completely with one color. Update in subclasses if desired!
@param x Top left corner x coordinate
@param y Top left corner y coordinate
@param w Width in pixels
@param h Height in pixels
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {
if(w && h) { // Nonzero width and height?
//uint8_t hi = color >> 8, lo = color;
if((x >= _width) || (y >= _height))
return;
if((x + w - 1) >= _width)
w = _width - x;
if((y + h - 1) >= _height)
h = _height - y;
startWrite();
setAddrWindow(x, y, w, h);
uint32_t px = (uint32_t)w * h;
while (px--) {
LL_SPI_TransmitData16(SPI1,color);
}
endWrite();
}
}
/**************************************************************************/
/*!
@brief Fill the screen completely with one color. Update in subclasses if desired!
@param color 16-bit 5-6-5 Color to fill with
*/
/**************************************************************************/
void fillScreen(uint16_t color) {
fillRect(0, 0, _width, _height, color);
}
/**************************************************************************/
/*!
@brief Invert the colors of the display (if supported by hardware).
Self-contained, no transaction setup required.
@param i true = inverted display, false = normal display.
*/
/**************************************************************************/
void invertDisplay(bool i) {
startWrite();
writeCommand(i ? ILI9341_INVON : ILI9341_INVOFF);
endWrite();
}
/**************************************************************************/
/*!
@brief Scroll display memory
@param y How many pixels to scroll display by
*/
/**************************************************************************/
void tft_scrollTo(uint16_t y) {
startWrite();
writeCommand(ILI9341_VSCRSADD);
LL_SPI_TransmitData16(SPI1,y);
endWrite();
}
/**************************************************************************/
/*!
@brief Read 8 bits of data from ILI9341 configuration memory. NOT from RAM!
This is highly undocumented/supported, it's really a hack but kinda works?
@param command The command register to read data from
@param index The byte index into the command to read from
@return Unsigned 8-bit data read from ILI9341 register
*/
/**************************************************************************/
uint8_t tft_readcommand8(uint8_t command, uint8_t index) {
startWrite();
writeCommand(0xD9); // woo sekret command?
ILI9341_SPI_XFER(0x10 + index);
writeCommand(command);
ILI9341_SPI_XFER(0xFF);
uint8_t r = LL_SPI_ReceiveData8(SPI1);
endWrite();
return r;
}
/*!
@brief Essentially writePixel() with a transaction around it. I don't
think this is in use by any of our code anymore (believe it was
for some older BMP-reading examples), but is kept here in case
any user code relies on it. Consider it DEPRECATED.
@param color 16-bit pixel color in '565' RGB format.
*/
void pushColor(uint16_t color) {
//uint8_t hi = color >> 8, lo = color;
startWrite();
LL_SPI_TransmitData16(SPI1,color);
endWrite();
}
// end of code.