libpynq (release 5EWC0-2023 version 0.2.2 of 2023-09-24 22:22)
Loading...
Searching...
No Matches
display.c
Go to the documentation of this file.
1/*
2Copyright (c) 2023 Eindhoven University of Technology
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in all
12copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20SOFTWARE.
21*/
23#include <display.h>
24#include <gpio.h>
25#include <lcdconfig.h>
26#include <log.h>
27#include <math.h>
28#include <platform.h>
29#include <string.h>
30#include <switchbox.h>
31#include <unistd.h>
32#include <util.h>
33
34#undef LOG_DOMAIN
35#define LOG_DOMAIN "display"
36
37#define TAG "ST7789"
38#define _DEBUG_ 0
39
40#define M_PI 3.14159265358979323846
41
42static arm_shared spi0_handle;
43static volatile uint32_t *spi0 = NULL;
44
45// states that are set for usage of the DC pin in SPI
46typedef enum { SPI_Data_Mode = 1, SPI_Command_Mode = 0 } spi_mode_t;
47
48#define GPIO_MODE_OUTPUT 1
49
51 switch (mode) {
52 case SPI_Data_Mode:
53 return GPIO_LEVEL_HIGH;
55 return GPIO_LEVEL_LOW;
56 default:
57 return GPIO_LEVEL_LOW;
58 }
59}
60
61bool spi_master_write_command(display_t *display, uint8_t cmd) {
63 spi0[0x68 / 4] = cmd;
64 while (((spi0[0x64 / 4]) & 4) == 0) {
65 }
66 usleep(1);
67 return true;
68}
69
70bool spi_master_write_data_byte(display_t *display, uint8_t data) {
72
73 spi0[0x68 / 4] = data;
74 while (((spi0[0x64 / 4]) & 4) == 0) {
75 }
76 return true;
77}
78
79bool spi_master_write_data_word(display_t *display, uint16_t data) {
80 static uint8_t Byte[2];
81 Byte[0] = (data >> 8) & 0xFF;
82 Byte[1] = data & 0xFF;
84 spi0[0x68 / 4] = Byte[0];
85 spi0[0x68 / 4] = Byte[1];
86
87 while (((spi0[0x64 / 4]) & 4) == 0) {
88 }
89 return true;
90}
91
92bool spi_master_write_addr(display_t *display, uint16_t addr1, uint16_t addr2) {
93 static uint8_t Byte[4];
94 Byte[0] = (addr1 >> 8) & 0xFF;
95 Byte[1] = addr1 & 0xFF;
96 Byte[2] = (addr2 >> 8) & 0xFF;
97 Byte[3] = addr2 & 0xFF;
99
100 // check ordering
101 spi0[0x68 / 4] = Byte[0];
102 spi0[0x68 / 4] = Byte[1];
103 spi0[0x68 / 4] = Byte[2];
104 spi0[0x68 / 4] = Byte[3];
105
106 while (((spi0[0x64 / 4]) & 4) == 0) {
107 }
108 return true;
109}
110
111bool spi_master_write_color(display_t *display, uint16_t color, uint16_t size) {
113 for (int i = 0; i < size; i++) {
114 while (((spi0[0x64 / 4]) & 8) == 8) {
115 }
116 spi0[0x68 / 4] = (color >> 8) & 0xFF;
117 while (((spi0[0x64 / 4]) & 8) == 8) {
118 }
119 spi0[0x68 / 4] = (color)&0xFF;
120 }
121 while (((spi0[0x64 / 4]) & 4) == 0) {
122 }
123 return -1;
124}
125
126bool spi_master_write_colors(display_t *display, uint16_t *colors,
127 uint16_t size) {
129 for (int i = 0; i < size; i++) {
130 while (((spi0[0x64 / 4]) & 8) == 8) {
131 }
132 spi0[0x68 / 4] = (colors[i] >> 8) & 0xFF;
133 while (((spi0[0x64 / 4]) & 8) == 8) {
134 }
135 spi0[0x68 / 4] = (colors[i]) & 0xFF;
136 }
137 // wait till empty, then add a small extra buffer
138 // because last byte we don't exactly know when send.
139 while (((spi0[0x64 / 4]) & 4) == 0) {
140 }
141 return true;
142}
143
145 // linking given pins in the switchbox
150 switchbox_set_pin(LCD_RESET, SWB_GPIO);
152
153 // setting the appropriate direction of each protocol pin
158 gpio_set_level(LCD_RESET, GPIO_LEVEL_LOW);
160
161 // creating a shared memory instance for communicating the hardware addresses
162 // of the linked pins
163 spi0 = arm_shared_init(&spi0_handle, axi_quad_spi_1, 4096);
164 if (_DEBUG_)
165 printf("spi reset: %08X\n", spi0[0x40 / 4]);
166 spi0[0x40 / 4] = 0x0000000a;
167 if (_DEBUG_)
168 printf("spi control: %08X\n", spi0[0x60 / 4]);
169 spi0[0x60 / 4] = (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1);
170 if (_DEBUG_)
171 printf("spi control: %08X\n", spi0[0x60 / 4]);
172 if (_DEBUG_)
173 printf("spi status: %08X\n", spi0[0x64 / 4]);
174
175 // select slave 1
176 spi0[0x70 / 4] = 0;
177 if (_DEBUG_)
178 printf("spi control: %08X\n", spi0[0x60 / 4]);
179 if (_DEBUG_)
180 printf("testing DISPLAY\n");
181 if (_DEBUG_)
182 printf("LCD_CS=%d\n", LCD_CS);
183 if (LCD_CS >= 0) {
184 gpio_reset_pin(LCD_CS);
186 gpio_set_level(LCD_CS, 0);
187 }
188
189 if (_DEBUG_)
190 printf("LCD_DC=%d", LCD_DC);
191 gpio_reset_pin(LCD_DC);
193 gpio_set_level(LCD_DC, 0);
194 if (_DEBUG_)
195 printf("LCD_RESET=%d", LCD_RESET);
196
197 if (LCD_RESET >= 0) {
198 gpio_reset_pin(LCD_RESET);
200 gpio_set_level(LCD_RESET, 1);
201 sleep_msec(100);
202 gpio_set_level(LCD_RESET, 0);
203 sleep_msec(500);
204 gpio_set_level(LCD_RESET, 1);
205 sleep_msec(300);
206 }
207
208 if (_DEBUG_)
209 printf("LCD_BL=%d", LCD_BL);
210 if (LCD_BL >= 0) {
211 gpio_reset_pin(LCD_BL);
213 gpio_set_level(LCD_BL, 0);
214 }
215
216 if (_DEBUG_)
217 printf("LCD_MOSI=%d", LCD_MOSI);
218 if (_DEBUG_)
219 printf("LCD_SCLK=%d\n", LCD_SCLK);
220
221 display->_dc = LCD_DC;
222 display->_bl = LCD_BL;
223}
224
225void displayInit(display_t *display, int width, int height, int offsetx,
226 int offsety) {
227 spi_master_init(display);
228 display->_width = width;
229 display->_height = height;
230 display->_offsetx = offsetx;
231 display->_offsety = offsety;
233 display->_font_fill = false;
234 display->_font_underline = false;
235
236 spi_master_write_command(display, 0x01); // software Reset
237 sleep_msec(150);
238
239 spi_master_write_command(display, 0x11); // sleep Out
240 sleep_msec(255);
241
242 spi_master_write_command(display, 0x3A); // Interface Pixel Format
243 spi_master_write_data_byte(display, 0x55);
244 sleep_msec(10);
245
246 spi_master_write_command(display, 0x36); // Memory Data Access Control
247 spi_master_write_data_byte(display, 0x00);
248
249 spi_master_write_command(display, 0x2A); // Column Address Set
250 spi_master_write_data_byte(display, 0x00);
251 spi_master_write_data_byte(display, 0x00);
252 spi_master_write_data_byte(display, 0x00);
253 spi_master_write_data_byte(display, 0xF0);
254
255 spi_master_write_command(display, 0x2B); // Row Address Set
256 spi_master_write_data_byte(display, 0x00);
257 spi_master_write_data_byte(display, 0x00);
258 spi_master_write_data_byte(display, 0x00);
259 spi_master_write_data_byte(display, 0xF0);
260
261 spi_master_write_command(display, 0x21); // Display Inversion On
262 sleep_msec(10);
263
264 spi_master_write_command(display, 0x13); // Normal Display Mode On
265 sleep_msec(10);
266
267 spi_master_write_command(display, 0x29); // Display ON
268 sleep_msec(255);
269
270 if (display->_bl >= 0) {
271 gpio_set_level(display->_bl, 1);
272 }
273}
274
275void display_set_flip(display_t *display, bool xflip, bool yflip) {
276 if (display == NULL) {
277 pynq_error("display_destroy: display has not been initialized\n");
278 }
279 if (display->_width != DISPLAY_WIDTH || display->_height != DISPLAY_HEIGHT) {
280 pynq_error("display_destroy: internal error (wrong display hardware)\n");
281 }
282 spi_master_write_command(display, 0x36); // Memory Data Access Control
283 uint8_t set = (yflip << 7) | (xflip << 6);
284 spi_master_write_data_byte(display, set);
285 if (yflip) {
286 display->_offsety = 320 - display->_height;
287 } else {
288 display->_offsety = 0;
289 }
290 if (xflip) {
291 display->_offsetx = 240 - display->_width;
292 } else {
293 display->_offsetx = 0;
294 }
295}
296
297void display_init(display_t *display) {
299 display_set_flip(display, true, true);
300}
301
302void display_destroy(display_t *display __attribute__((unused))) {
303 if (display == NULL || display->_width != DISPLAY_WIDTH) {
304 pynq_error("display_destroy: display has not been initialized\n");
305 }
306 // if channel is open
307 if (spi0 != NULL) {
308 (void)arm_shared_close(&spi0_handle);
309 spi0 = NULL;
310 }
311}
312
313void displayDrawPixel(display_t *display, uint16_t x, uint16_t y,
314 uint16_t color) {
315 if (display == NULL || display->_width != DISPLAY_WIDTH) {
316 pynq_error("displayDrawPixel: display has not been initialized\n");
317 }
318 if (x >= display->_width || y >= display->_height) {
319 pynq_error("displayDrawPixel: x=%d y=%d outside screen boundaries\n", x, y);
320 }
321 uint16_t _x = x + display->_offsetx;
322 uint16_t _y = y + display->_offsety;
323
324 spi_master_write_command(display, 0x2A); // set column(x) address
325 spi_master_write_addr(display, _x, _x);
326 spi_master_write_command(display, 0x2B); // set Page(y) address
327 spi_master_write_addr(display, _y, _y);
328 spi_master_write_command(display, 0x2C); // memory write
329 spi_master_write_data_word(display, color);
330}
331
332void displayDrawMultiPixels(display_t *display, uint16_t x, uint16_t y,
333 uint16_t size, uint16_t *colors) {
334 if (display == NULL || display->_width != DISPLAY_WIDTH) {
335 pynq_error("displayDrawMultiPixels: display has not been initialized\n");
336 }
337 if (x > display->_width || x + size > display->_width ||
338 y >= display->_height) {
340 "displayDrawMultiPixels: x=%d y=%d size=%d outside screen boundaries\n",
341 x, y, size);
342 }
343
344 uint16_t _x1 = x + display->_offsetx;
345 uint16_t _x2 = _x1 + size;
346 uint16_t _y1 = y + display->_offsety;
347 uint16_t _y2 = _y1;
348
349 spi_master_write_command(display, 0x2A); // set column(x) address
350 spi_master_write_addr(display, _x1, _x2);
351 spi_master_write_command(display, 0x2B); // set Page(y) address
352 spi_master_write_addr(display, _y1, _y2);
353 spi_master_write_command(display, 0x2C); // memory write
354 spi_master_write_colors(display, colors, size);
355}
356
357void displayDrawFillRect(display_t *display, uint16_t x1, uint16_t y1,
358 uint16_t x2, uint16_t y2, uint16_t color) {
359 if (display == NULL || display->_width != DISPLAY_WIDTH) {
360 pynq_error("displayDrawPixel: display has not been initialized\n");
361 }
362 if (x1 >= display->_width || x2 >= display->_width ||
363 y1 >= display->_height || y2 >= display->_height) {
364 pynq_error("displayDrawFillRect: x1=%d y1=%d x2=%d y2=%d outside screen "
365 "boundaries\n",
366 x1, y1, x2, y2);
367 }
368 // swapping points so that it is always plotted from x1 y1 bottom left, x2 y2
369 // top right
370 uint16_t x1_temp = x1, x2_temp = x2;
371 uint16_t y1_temp = y1, y2_temp = y2;
372 if (x1 > x2) {
373 x1 = x2_temp;
374 x2 = x1_temp;
375 }
376
377 if (y1 > y2) {
378 y1 = y2_temp;
379 y2 = y1_temp;
380 }
381
382 // printf("offset(x)=%d offset(y)=%d",display->_offsetx,display->_offsety);
383 uint16_t _x1 = x1 + display->_offsetx;
384 uint16_t _x2 = x2 + display->_offsetx;
385 uint16_t _y1 = y1 + display->_offsety;
386 uint16_t _y2 = y2 + display->_offsety;
387
388 spi_master_write_command(display, 0x2A); // set column(x) address
389 spi_master_write_addr(display, _x1, _x2);
390 spi_master_write_command(display, 0x2B); // set Page(y) address
391 spi_master_write_addr(display, _y1, _y2);
392 spi_master_write_command(display, 0x2C); // memory write
393 for (int i = _x1; i <= _x2; i++) {
394 uint16_t size = _y2 - _y1 + 1;
395 spi_master_write_color(display, color, size);
396 }
397}
398
400 if (display == NULL || display->_width != DISPLAY_WIDTH) {
401 pynq_error("displayDisplayOff: display has not been initialized\n");
402 }
403 spi_master_write_command(display, 0x28); // display off
404}
405
407 if (display == NULL || display->_width != DISPLAY_WIDTH) {
408 pynq_error("displayDisplayOn: display has not been initialized\n");
409 }
410 spi_master_write_command(display, 0x29); // display on
411}
412
413void displayFillScreen(display_t *display, uint16_t color) {
414 if (display == NULL || display->_width != DISPLAY_WIDTH) {
415 pynq_error("displayFillScreen: display has not been initialized\n");
416 }
417 displayDrawFillRect(display, 0, 0, display->_width - 1, display->_height - 1,
418 color);
419}
420
421void displayDrawLine(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2,
422 uint16_t y2, uint16_t color) {
423 if (display == NULL || display->_width != DISPLAY_WIDTH) {
424 pynq_error("displayDrawLine: display has not been initialized\n");
425 }
426 if (x1 >= display->_width || y1 >= display->_height) {
427 pynq_error("displayDrawLine: x1=%d y1=%d outside screen boundaries\n", x1,
428 y1);
429 } else if (x2 >= display->_width || y2 >= display->_height) {
430 pynq_error("displayDrawLine: x2=%d y2=%d outside screen boundaries\n", x2,
431 y2);
432 }
433 int i;
434 int dx, dy;
435 int sx, sy;
436 int E;
437
438 /* distance between two points */
439 dx = (x2 > x1) ? x2 - x1 : x1 - x2;
440 dy = (y2 > y1) ? y2 - y1 : y1 - y2;
441
442 /* direction of two point */
443 sx = (x2 > x1) ? 1 : -1;
444 sy = (y2 > y1) ? 1 : -1;
445
446 /* inclination < 1 */
447 if (dx > dy) {
448 E = -dx;
449 for (i = 0; i <= dx; i++) {
450 displayDrawPixel(display, x1, y1, color);
451 x1 += sx;
452 E += 2 * dy;
453 if (E >= 0) {
454 y1 += sy;
455 E -= 2 * dx;
456 }
457 }
458
459 /* inclination >= 1 */
460 } else {
461 E = -dy;
462 for (i = 0; i <= dy; i++) {
463 displayDrawPixel(display, x1, y1, color);
464 y1 += sy;
465 E += 2 * dx;
466 if (E >= 0) {
467 x1 += sx;
468 E -= 2 * dy;
469 }
470 }
471 }
472}
473
474void displayDrawRect(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2,
475 uint16_t y2, uint16_t color) {
476 if (display == NULL || display->_width != DISPLAY_WIDTH) {
477 pynq_error("displayDrawRect: display has not been initialized\n");
478 }
479 if (x1 >= display->_width || y1 >= display->_height) {
480 pynq_error("displayDrawRect: x1=%d y1=%d outside screen boundaries\n", x1,
481 y1);
482 } else if (x2 >= display->_width || y2 >= display->_height) {
483 pynq_error("displayDrawRect: x2=%d y2=%d outside screen boundaries\n", x2,
484 y2);
485 }
486 displayDrawLine(display, x1, y1, x2, y1, color);
487 displayDrawLine(display, x2, y1, x2, y2, color);
488 displayDrawLine(display, x2, y2, x1, y2, color);
489 displayDrawLine(display, x1, y2, x1, y1, color);
490}
491
492void displayDrawRectAngle(display_t *display, uint16_t xc, uint16_t yc,
493 uint16_t w, uint16_t h, uint16_t angle,
494 uint16_t color) {
495 double xd, yd, rd;
496 int x1, y1;
497 int x2, y2;
498 int x3, y3;
499 int x4, y4;
500 rd = -angle * M_PI / 180.0;
501 xd = 0.0 - w / 2;
502 yd = h / 2;
503 x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
504 y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
505
506 yd = 0.0 - yd;
507 x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
508 y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
509
510 xd = w / 2;
511 yd = h / 2;
512 x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
513 y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
514
515 yd = 0.0 - yd;
516 x4 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
517 y4 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
518
519 if (display == NULL || display->_width != DISPLAY_WIDTH) {
520 pynq_error("displayDrawRectAngle: display has not been initialized\n");
521 }
522 if (x1 >= display->_width || y1 >= display->_height) {
523 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
524 x1, y1);
525 } else if (x2 >= display->_width || y2 >= display->_height) {
526 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
527 x2, y2);
528 } else if (x3 >= display->_width || y3 >= display->_height) {
529 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
530 x3, y3);
531 } else if (x4 >= display->_width || y4 >= display->_height) {
532 pynq_error("displayDrawRectAngle: x4=%d y4=%d outside screen boundaries\n",
533 x4, y4);
534 }
535
536 displayDrawLine(display, x1, y1, x2, y2, color);
537 displayDrawLine(display, x1, y1, x3, y3, color);
538 displayDrawLine(display, x2, y2, x4, y4, color);
539 displayDrawLine(display, x3, y3, x4, y4, color);
540}
541
542// x1: First X coordinate of triangle point
543// y1: First Y coordinate of triangle point
544// x2: Second X coordinate of triangle point
545// y2: Second Y coordinate of triangle point
546// x3: Third X coordinate of triangle point
547// y3: Third Y coordinate of triangle point
548// color:color
549void displayDrawTriangle(display_t *display, uint16_t x1, uint16_t y1,
550 uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3,
551 uint16_t color) {
552 if (display == NULL || display->_width != DISPLAY_WIDTH) {
553 pynq_error("displayDrawTriangle: display has not been initialized\n");
554 }
555 if (x1 >= display->_width || y1 >= display->_height) {
556 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
557 x1, y1);
558 } else if (x2 >= display->_width || y2 >= display->_height) {
559 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
560 x2, y2);
561 } else if (x3 >= display->_width || y3 >= display->_height) {
562 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
563 x3, y3);
564 }
565
566 // draw the lines for the basic triangle
567 displayDrawLine(display, x1, y1, x2, y2, color);
568 displayDrawLine(display, x2, y2, x3, y3, color);
569 displayDrawLine(display, x3, y3, x1, y1, color);
570}
571
572// when the origin is (0, 0), the point (x1, y1) after rotating the point (x, y)
573// by the angle is obtained by the following calculation.
574// x1 = x * cos(angle) - y * sin(angle)
575// y1 = x * sin(angle) + y * cos(angle)
576void displayDrawTriangleCenter(display_t *display, uint16_t xc, uint16_t yc,
577 uint16_t w, uint16_t h, uint16_t angle,
578 uint16_t color) {
579 double xd, yd, rd;
580 int x1, y1;
581 int x2, y2;
582 int x3, y3;
583 rd = -angle * M_PI / 180.0;
584 xd = 0.0;
585 yd = h / 2;
586 x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
587 y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
588
589 xd = w / 2;
590 yd = 0.0 - yd;
591 x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
592 y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
593
594 xd = 0.0 - w / 2;
595 x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
596 y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
597
598 if (display == NULL || display->_width != DISPLAY_WIDTH) {
599 pynq_error("displayDrawTriangleCenter: display has not been initialized\n");
600 }
601 if (x1 >= display->_width || y1 >= display->_height) {
602 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
603 x1, y1);
604 } else if (x2 >= display->_width || y2 >= display->_height) {
605 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
606 x2, y2);
607 } else if (x3 >= display->_width || y3 >= display->_height) {
608 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
609 x3, y3);
610 }
611
612 displayDrawLine(display, x1, y1, x2, y2, color);
613 displayDrawLine(display, x1, y1, x3, y3, color);
614 displayDrawLine(display, x2, y2, x3, y3, color);
615}
616
617void displayDrawCircle(display_t *display, uint16_t x_center, uint16_t y_center,
618 uint16_t r, uint16_t color) {
619 if (display == NULL || display->_width != DISPLAY_WIDTH) {
620 pynq_error("displayDrawCircle: display has not been initialized\n");
621 }
622 if (r == 0) {
624 "displayDrawCircle: x_center=%d y_center=%d r=%d r cannot be 0\n",
625 x_center, y_center, r);
626 }
627
628 int x_max = x_center + r, x_min = x_center - r, y_max = y_center + r,
629 y_min = y_center - r;
630
631 if (x_max >= display->_width || x_min < 0 || y_max >= display->_height ||
632 y_min < 0) {
633 pynq_error("displayDrawCircle: x_center=%d y_center=%d r=%d outside screen "
634 "boundaries\n",
635 x_center, y_center, r);
636 }
637
638 int x;
639 int y;
640 int err;
641 int old_err;
642
643 x = 0;
644 y = -r;
645 err = 2 - 2 * r;
646 do {
647 displayDrawPixel(display, x_center - x, y_center + y, color);
648 displayDrawPixel(display, x_center - y, y_center - x, color);
649 displayDrawPixel(display, x_center + x, y_center - y, color);
650 displayDrawPixel(display, x_center + y, y_center + x, color);
651 if ((old_err = err) <= x)
652 err += ++x * 2 + 1;
653 if (old_err > y || err > x)
654 err += ++y * 2 + 1;
655 } while (y < 0);
656}
657
658void displayDrawFillCircle(display_t *display, uint16_t x_center,
659 uint16_t y_center, uint16_t r, uint16_t color) {
660 if (display == NULL || display->_width != DISPLAY_WIDTH) {
661 pynq_error("displayDrawFillCircle: display has not been initialized\n");
662 }
663 if (r == 0) {
665 "displayDrawFillCircle: x_center=%d y_center=%d r=%d r cannot be 0\n",
666 x_center, y_center, r);
667 }
668
669 int x_max = x_center + r, x_min = x_center - r, y_max = y_center + r,
670 y_min = y_center - r;
671
672 if (x_max >= display->_width || x_min < 0 || y_max >= display->_height ||
673 y_min < 0) {
674 pynq_error("displayDrawFillCircle: x_center=%d y_center=%d r=%d outside "
675 "screen boundaries\n",
676 x_center, y_center, r);
677 }
678
679 int x;
680 int y;
681 int err;
682 int old_err;
683 int ChangeX;
684
685 x = 0;
686 y = -r;
687 err = 2 - 2 * r;
688 ChangeX = 1;
689 do {
690 if (ChangeX) {
691 displayDrawLine(display, x_center - x, y_center - y, x_center - x,
692 y_center + y, color);
693 displayDrawLine(display, x_center + x, y_center - y, x_center + x,
694 y_center + y, color);
695 } // endif
696 ChangeX = (old_err = err) <= x;
697 if (ChangeX)
698 err += ++x * 2 + 1;
699 if (old_err > y || err > x)
700 err += ++y * 2 + 1;
701 } while (y <= 0);
702}
703
704void displayDrawRoundRect(display_t *display, uint16_t x1, uint16_t y1,
705 uint16_t x2, uint16_t y2, uint16_t r,
706 uint16_t color) {
707 if (display == NULL || display->_width != DISPLAY_WIDTH) {
708 pynq_error("displayDrawRoundRect: display has not been initialized\n");
709 }
710 if (r == 0) {
711 pynq_error("displayDrawRoundRect: x_center=%d x1=%d y1=%d r cannot be 0\n",
712 x1, y1, r);
713 } else if (x1 >= display->_width || y1 >= display->_height) {
714 pynq_error("displayDrawRoundRect: x1=%d y1=%d outside screen boundaries\n",
715 x1, y1);
716 } else if (x2 >= display->_width || y2 >= display->_height) {
717 pynq_error("displayDrawRoundRect: x2=%d y2=%d outside screen boundaries\n",
718 x2, y2);
719 }
720 int x;
721 int y;
722 int err;
723 int old_err;
724 unsigned char temp;
725
726 if (x1 > x2) {
727 temp = x1;
728 x1 = x2;
729 x2 = temp;
730 }
731
732 if (y1 > y2) {
733 temp = y1;
734 y1 = y2;
735 y2 = temp;
736 }
737
738 if (_DEBUG_)
739 printf("x1=%d x2=%d delta=%d r=%d", x1, x2, x2 - x1, r);
740 if (_DEBUG_)
741 printf("y1=%d y2=%d delta=%d r=%d", y1, y2, y2 - y1, r);
742 if (x2 - x1 < r)
743 return; // TODO add 20190517?
744 if (y2 - y1 < r)
745 return; // TODO add 20190517?
746
747 x = 0;
748 y = -r;
749 err = 2 - 2 * r;
750
751 do {
752 if (x) {
753 displayDrawPixel(display, x1 + r - x, y1 + r + y, color);
754 displayDrawPixel(display, x2 - r + x, y1 + r + y, color);
755 displayDrawPixel(display, x1 + r - x, y2 - r - y, color);
756 displayDrawPixel(display, x2 - r + x, y2 - r - y, color);
757 }
758 if ((old_err = err) <= x)
759 err += ++x * 2 + 1;
760 if (old_err > y || err > x)
761 err += ++y * 2 + 1;
762 } while (y < 0);
763
764 if (_DEBUG_)
765 printf("x1+r=%d x2-r=%d", x1 + r, x2 - r);
766 displayDrawLine(display, x1 + r, y1, x2 - r, y1, color);
767 displayDrawLine(display, x1 + r, y2, x2 - r, y2, color);
768 if (_DEBUG_)
769 printf("y1+r=%d y2-r=%d", y1 + r, y2 - r);
770 displayDrawLine(display, x1, y1 + r, x1, y2 - r, color);
771 displayDrawLine(display, x2, y1 + r, x2, y2 - r, color);
772}
773
774uint16_t rgb_conv(uint16_t r, uint16_t g, uint16_t b) {
775 return (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
776}
777
778int displayDrawChar(display_t *display, FontxFile *fxs, uint16_t x, uint16_t y,
779 uint8_t ascii, uint16_t color) {
780 uint16_t xx, yy, bit, ofs;
781 unsigned char fonts[128]; // font pattern
782 unsigned char pw, ph;
783 int h, w;
784 uint16_t mask;
785 bool rc = GetFontx(fxs, ascii, fonts, &pw, &ph);
786
787 if (display == NULL || display->_width != DISPLAY_WIDTH) {
788 pynq_error("displayDrawChar: display has not been initialized\n");
789 }
790 if (_DEBUG_) {
791 printf("_font_direction=%d\n", display->_font_direction);
792 printf("GetFontx rc=%d pw=%d ph=%d\n", rc, pw, ph);
793 }
794
795 if (!rc) {
796 pynq_error("displayDrawChar: cannot get font from font file\n");
797 }
798
799 switch (display->_font_direction) {
800 case TEXT_DIRECTION0:
801 if (x + pw >= display->_width || y + ph >= display->_height) {
802 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
803 "direction=%d outside screen boundaries\n",
804 x, y, ph, pw, display->_font_direction);
805 }
806 break;
807 case TEXT_DIRECTION90:
808 if (x + ph >= display->_height || y + pw >= display->_width) {
809 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
810 "direction=%d outside screen boundaries\n",
811 x, y, ph, pw, display->_font_direction);
812 }
813 break;
815 if (x - pw <= 0 || y - ph <= 0) {
816 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
817 "direction=%d outside screen boundaries\n",
818 x, y, ph, pw, display->_font_direction);
819 }
820 break;
822 if (x - ph <= 0 || y - pw <= 0) {
823 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
824 "direction=%d outside screen boundaries\n",
825 x, y, ph, pw, display->_font_direction);
826 }
827 break;
828 }
829
830 int16_t xd1 = 0, yd1 = 0, xd2 = 0, yd2 = 0;
831 uint16_t xss = 0, yss = 0;
832 int16_t xsd = 0, ysd = 0, next = 0;
833 uint16_t x0 = 0, x1 = 0, y0 = 0, y1 = 0;
834 if (display->_font_direction == 0) {
835 xd1 = +1;
836 yd1 = +1; //-1;
837 xd2 = 0;
838 yd2 = 0;
839 xss = x;
840 yss = y - (ph - 1);
841 xsd = 1;
842 ysd = 0;
843 next = x + pw;
844
845 x0 = x;
846 y0 = y - (ph - 1);
847 x1 = x + (pw - 1);
848 y1 = y;
849 } else if (display->_font_direction == 2) {
850 xd1 = -1;
851 yd1 = -1; //+1;
852 xd2 = 0;
853 yd2 = 0;
854 xss = x;
855 yss = y + ph + 1;
856 xsd = 1;
857 ysd = 0;
858 next = x - pw;
859
860 x0 = x - (pw - 1);
861 y0 = y;
862 x1 = x;
863 y1 = y + (ph - 1);
864 } else if (display->_font_direction == 1) {
865 xd1 = 0;
866 yd1 = 0;
867 xd2 = -1;
868 yd2 = +1; //-1;
869 xss = x + ph;
870 yss = y;
871 xsd = 0;
872 ysd = 1;
873 next = y + pw; // y - pw;
874
875 x0 = x;
876 y0 = y;
877 x1 = x + (ph - 1);
878 y1 = y + (pw - 1);
879 } else if (display->_font_direction == 3) {
880 xd1 = 0;
881 yd1 = 0;
882 xd2 = +1;
883 yd2 = -1; //+1;
884 xss = x - (ph - 1);
885 yss = y;
886 xsd = 0;
887 ysd = 1;
888 next = y - pw; // y + pw;
889
890 x0 = x - (ph - 1);
891 y0 = y - (pw - 1);
892 x1 = x;
893 y1 = y;
894 }
895
896 // TODO: fix the problem of underflow properly some time
897 if (display->_font_fill && x0 < DISPLAY_WIDTH && y0 < DISPLAY_HEIGHT &&
898 x1 < DISPLAY_WIDTH && y1 < DISPLAY_HEIGHT) {
899 displayDrawFillRect(display, x0, y0, x1, y1, display->_font_fill_color);
900 }
901
902 int bits;
903 if (_DEBUG_)
904 printf("xss=%d yss=%d\n", xss, yss);
905 ofs = 0;
906 yy = yss;
907 xx = xss;
908 for (h = 0; h < ph; h++) {
909 if (xsd)
910 xx = xss;
911 if (ysd)
912 yy = yss;
913 bits = pw;
914 for (w = 0; w < ((pw + 4) / 8); w++) {
915 mask = 0x80;
916 for (bit = 0; bit < 8; bit++) {
917 bits--;
918 if (bits < 0)
919 continue;
920 // TODO: fix the problem of underflow properly some time
921 if (fonts[ofs] & mask && xx < DISPLAY_WIDTH && yy < DISPLAY_HEIGHT) {
922 displayDrawPixel(display, xx, yy, color);
923 }
924 // TODO: fix the problem of underflow properly some time
925 if (h == (ph - 2) && display->_font_underline && xx < DISPLAY_WIDTH &&
926 yy < DISPLAY_HEIGHT)
927 displayDrawPixel(display, xx, yy, display->_font_underline_color);
928 // TODO: fix the problem of underflow properly some time
929 if (h == (ph - 1) && display->_font_underline && xx < DISPLAY_WIDTH &&
930 yy < DISPLAY_HEIGHT)
931 displayDrawPixel(display, xx, yy, display->_font_underline_color);
932 xx = xx + xd1;
933 yy = yy + yd2;
934 mask = mask >> 1;
935 }
936 ofs++;
937 }
938 yy = yy + yd1;
939 xx = xx + xd2;
940 }
941
942 if (next < 0)
943 next = 0;
944 return next;
945}
946
947int displayDrawString(display_t *display, FontxFile *fx, uint16_t x, uint16_t y,
948 uint8_t *ascii, uint16_t color) {
949 int length = strlen((char *)ascii);
950 if (display == NULL || display->_width != DISPLAY_WIDTH) {
951 pynq_error("displayDrawString: display has not been initialized\n");
952 }
953 if (_DEBUG_)
954 printf("displayDrawString length=%d\n", length);
955 for (int i = 0; i < length; i++) {
956 if (_DEBUG_)
957 printf("ascii[%d]=%x x=%d y=%d\n", i, ascii[i], x, y);
958 if (display->_font_direction == 0)
959 x = displayDrawChar(display, fx, x, y, ascii[i], color);
960 if (display->_font_direction == 1)
961 y = displayDrawChar(display, fx, x, y, ascii[i], color);
962 if (display->_font_direction == 2)
963 x = displayDrawChar(display, fx, x, y, ascii[i], color);
964 if (display->_font_direction == 3)
965 y = displayDrawChar(display, fx, x, y, ascii[i], color);
966 }
967 if (display->_font_direction == 0)
968 return x;
969 if (display->_font_direction == 2)
970 return x;
971 if (display->_font_direction == 1)
972 return y;
973 if (display->_font_direction == 3)
974 return y;
975 return 0;
976}
977
978void displaySetFontDirection(display_t *display, uint16_t dir) {
979 if (display == NULL || display->_width != DISPLAY_WIDTH) {
980 pynq_error("displaySetFontDirection: display has not been initialized\n");
981 }
982 display->_font_direction = dir;
983}
984
985void displaySetFontFill(display_t *display, uint16_t color) {
986 if (display == NULL || display->_width != DISPLAY_WIDTH) {
987 pynq_error("displaySetFontFill: display has not been initialized\n");
988 }
989 display->_font_fill = true;
990 display->_font_fill_color = color;
991}
992
993void displayUnsetFontFill(display_t *display) { display->_font_fill = false; }
994
995void displaySetFontUnderLine(display_t *display, uint16_t color) {
996 if (display == NULL || display->_width != DISPLAY_WIDTH) {
997 pynq_error("displaySetFontUnderLine: display has not been initialized\n");
998 }
999 display->_font_underline = true;
1000 display->_font_underline_color = color;
1001}
1002
1004 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1005 pynq_error("displayUnsetFontUnderLine: display has not been initialized\n");
1006 }
1007 display->_font_underline = false;
1008}
1009
1011 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1012 pynq_error("displayBacklightOff: display has not been initialized\n");
1013 }
1014 if (display->_bl >= 0) {
1015 gpio_set_level(display->_bl, 0);
1016 }
1017}
1018
1020 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1021 pynq_error("displayBacklightOn: display has not been initialized\n");
1022 }
1023 if (display->_bl >= 0) {
1024 gpio_set_level(display->_bl, 1);
1025 }
1026}
1027
1029 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1030 pynq_error("displayInversionOff: display has not been initialized\n");
1031 }
1032 spi_master_write_command(display, 0x21); // display Inversion Off
1033}
1034
1036 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1037 pynq_error("displayInversionOn: display has not been initialized\n");
1038 }
1039 spi_master_write_command(display, 0x20); // display Inversion On
1040}
void displayInit(display_t *display, int width, int height, int offsetx, int offsety)
Definition display.c:225
void spi_master_init(display_t *display)
Definition display.c:144
#define _DEBUG_
Definition display.c:38
void display_destroy(display_t *display __attribute__((unused)))
Definition display.c:302
gpio_level_t spi_to_gpio(spi_mode_t mode)
Definition display.c:50
bool spi_master_write_command(display_t *display, uint8_t cmd)
Definition display.c:61
bool spi_master_write_addr(display_t *display, uint16_t addr1, uint16_t addr2)
Definition display.c:92
bool spi_master_write_color(display_t *display, uint16_t color, uint16_t size)
Definition display.c:111
bool spi_master_write_data_word(display_t *display, uint16_t data)
Definition display.c:79
spi_mode_t
Definition display.c:46
@ SPI_Command_Mode
Definition display.c:46
@ SPI_Data_Mode
Definition display.c:46
#define GPIO_MODE_OUTPUT
Definition display.c:48
bool spi_master_write_data_byte(display_t *display, uint8_t data)
Definition display.c:70
bool spi_master_write_colors(display_t *display, uint16_t *colors, uint16_t size)
Definition display.c:126
void displayDrawMultiPixels(display_t *display, uint16_t x, uint16_t y, uint16_t size, uint16_t *colors)
Definition display.c:332
#define M_PI
Definition display.c:40
void arm_shared_close(arm_shared *handle)
void * arm_shared_init(arm_shared *handle, const uint32_t address, const uint32_t length)
int displayDrawString(display_t *display, FontxFile *fx, uint16_t x, uint16_t y, uint8_t *ascii, uint16_t color)
Function to draw a string on the display.
Definition display.c:947
void display_set_flip(display_t *display, bool xflip, bool yflip)
Flip the drawing off the screen.
Definition display.c:275
void displayDrawFillRect(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
Draw a filled rectangle to the display.
Definition display.c:357
void displaySetFontUnderLine(display_t *display, uint16_t color)
Turns on _font_underline in the display handle and sets the _font_underline_color to the specified co...
Definition display.c:995
void displaySetFontDirection(display_t *display, uint16_t dir)
Changes the direction the characters will be printed.
Definition display.c:978
#define DISPLAY_HEIGHT
Definition display.h:79
#define DISPLAY_WIDTH
Definition display.h:80
void displayDrawTriangle(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3, uint16_t color)
Draw a triangle without infill between the three given points in the given color.
Definition display.c:549
void displaySetFontFill(display_t *display, uint16_t color)
Enables the _font_fill and sets the _font_fill_color in the display handle.
Definition display.c:985
void displayDrawRect(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
Draw a filled rectangle.
Definition display.c:474
void displayUnsetFontFill(display_t *display)
Sets the _font_fill parameter to false in the display handle, turns off the font fill.
Definition display.c:993
void display_init(display_t *display)
Initialize the display display.
Definition display.c:297
uint16_t rgb_conv(uint16_t r, uint16_t g, uint16_t b)
RGB conversion for generating a color.
Definition display.c:774
void displayDisplayOff(display_t *display)
Turn off the display.
Definition display.c:399
void displayDrawLine(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
Draw a line from two coordinates.
Definition display.c:421
void displayInversionOff(display_t *display)
Turn off inversion of the colors.
Definition display.c:1028
void displayDrawRoundRect(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t r, uint16_t color)
Draw a rectangle with rounded angles.
Definition display.c:704
void displayInversionOn(display_t *display)
Turn on inversion of the colors.
Definition display.c:1035
int displayDrawChar(display_t *display, FontxFile *fxs, uint16_t x, uint16_t y, uint8_t ascii, uint16_t color)
Draws a character on the given coordinates of the display.
Definition display.c:778
void displayBacklightOn(display_t *display)
Turn on the display backlight.
Definition display.c:1019
void displayDrawCircle(display_t *display, uint16_t x_center, uint16_t y_center, uint16_t r, uint16_t color)
Draw a circle without infill on the display.
Definition display.c:617
void displayFillScreen(display_t *display, uint16_t color)
Fill entire display with a single color using the ldcDrawFillRect function.
Definition display.c:413
void displayBacklightOff(display_t *display)
Turn off the display backlight.
Definition display.c:1010
void displayDisplayOn(display_t *display)
Initialize DISPLAY screen.
Definition display.c:406
void displayUnsetFontUnderLine(display_t *display)
Turns off _font_underline in the display handle.
Definition display.c:1003
void displayDrawPixel(display_t *display, uint16_t x, uint16_t y, uint16_t color)
Draw a single pixel to the display.
Definition display.c:313
colors
Colors that can be used with the display.
Definition display.h:85
void displayDrawRectAngle(display_t *display, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color)
Draws a rectangle with rounded corners at a specified angle on the display.
Definition display.c:492
void displayDrawFillCircle(display_t *display, uint16_t x_center, uint16_t y_center, uint16_t r, uint16_t color)
Draw a circle with infill on the display.
Definition display.c:658
void displayDrawTriangleCenter(display_t *display, uint16_t xc, uint16_t yc, uint16_t w, uint16_t h, uint16_t angle, uint16_t color)
Draws a triangle at a specified angle on the display.
Definition display.c:576
@ TEXT_DIRECTION180
Definition display.h:103
@ TEXT_DIRECTION90
Definition display.h:102
@ TEXT_DIRECTION270
Definition display.h:104
@ TEXT_DIRECTION0
Definition display.h:101
bool GetFontx(FontxFile *fxs, uint8_t ascii, uint8_t *pGlyph, uint8_t *pw, uint8_t *ph)
Gets the glyph data for the specified ASCII character.
Definition fontx.c:98
void gpio_reset_pin(const pin_t pin)
Function is currently a no-op placeholder for arduino compatibility.
Definition gpio.c:55
void gpio_set_direction(const pin_t pin, const gpio_direction_t dir)
Set the GPIO pin as in input or output.
Definition gpio.c:81
gpio_level_t
Definition gpio.h:91
void gpio_set_level(const pin_t pin, const gpio_level_t level)
Set the level of the output GPIO pin. If the pin is configured as input, this function does nothing.
Definition gpio.c:104
@ GPIO_DIR_OUTPUT
Definition gpio.h:85
@ GPIO_LEVEL_LOW
Definition gpio.h:93
@ GPIO_LEVEL_HIGH
Definition gpio.h:95
#define pynq_error(...)
Definition log.h:118
void switchbox_set_pin(const pin_t pin_number, const uint8_t pin_type)
Set the type of a switch pin.
Definition switchbox.c:128
@ SWB_SPI1_MOSI
Definition switchbox.h:83
@ SWB_SPI1_SS
Definition switchbox.h:85
@ SWB_GPIO
Definition switchbox.h:63
@ SWB_SPI1_CLK
Definition switchbox.h:79
void sleep_msec(int msec)
Wait for msec milliseconds.
Definition util.c:32
Struct representing a font file.
Definition fontx.h:28
Internal type, do not use. Type of display that stores parameters for usage in different functions.
Definition display.h:112
uint16_t _font_fill_color
Definition display.h:119
uint16_t _font_fill
Definition display.h:118
uint16_t _offsety
Definition display.h:116
uint16_t _width
Definition display.h:113
uint16_t _font_direction
Definition display.h:117
int16_t _bl
Definition display.h:123
int16_t _dc
Definition display.h:122
uint16_t _font_underline_color
Definition display.h:121
uint16_t _font_underline
Definition display.h:120
uint16_t _height
Definition display.h:114
uint16_t _offsetx
Definition display.h:115