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