libpynq (release 5EWC0-2023 version 0.2.6 of 2023-10-24 17:28)
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) {
303 display_set_flip(display, true, true);
304}
305
306void display_destroy(display_t *display __attribute__((unused))) {
307 if (display == NULL || display->_width != DISPLAY_WIDTH) {
308 pynq_error("display_destroy: display has not been initialized\n");
309 }
310 // if channel is open
311 if (spi0 != NULL) {
312 (void)arm_shared_close(&spi0_handle);
313 spi0 = NULL;
314 }
315}
316
317void displayDrawPixel(display_t *display, uint16_t x, uint16_t y,
318 uint16_t color) {
319 if (display == NULL || display->_width != DISPLAY_WIDTH) {
320 pynq_error("displayDrawPixel: display has not been initialized\n");
321 }
322 if (x >= display->_width || y >= display->_height) {
323 pynq_error("displayDrawPixel: x=%d y=%d outside screen boundaries\n", x, y);
324 }
325 uint16_t _x = x + display->_offsetx;
326 uint16_t _y = y + display->_offsety;
327
328 spi_master_write_command(display, 0x2A); // set column(x) address
329 spi_master_write_addr(display, _x, _x);
330 spi_master_write_command(display, 0x2B); // set Page(y) address
331 spi_master_write_addr(display, _y, _y);
332 spi_master_write_command(display, 0x2C); // memory write
333 spi_master_write_data_word(display, color);
334}
335
336void displayDrawMultiPixels(display_t *display, uint16_t x, uint16_t y,
337 uint16_t size, uint16_t *colors) {
338 if (display == NULL || display->_width != DISPLAY_WIDTH) {
339 pynq_error("displayDrawMultiPixels: display has not been initialized\n");
340 }
341 if (x > display->_width || x + size > display->_width ||
342 y >= display->_height) {
344 "displayDrawMultiPixels: x=%d y=%d size=%d outside screen boundaries\n",
345 x, y, size);
346 }
347
348 uint16_t _x1 = x + display->_offsetx;
349 uint16_t _x2 = _x1 + size;
350 uint16_t _y1 = y + display->_offsety;
351 uint16_t _y2 = _y1;
352
353 spi_master_write_command(display, 0x2A); // set column(x) address
354 spi_master_write_addr(display, _x1, _x2);
355 spi_master_write_command(display, 0x2B); // set Page(y) address
356 spi_master_write_addr(display, _y1, _y2);
357 spi_master_write_command(display, 0x2C); // memory write
358 spi_master_write_colors(display, colors, size);
359}
360
361void displayDrawFillRect(display_t *display, uint16_t x1, uint16_t y1,
362 uint16_t x2, uint16_t y2, uint16_t color) {
363 if (display == NULL || display->_width != DISPLAY_WIDTH) {
364 pynq_error("displayDrawPixel: display has not been initialized\n");
365 }
366 if (x1 >= display->_width || x2 >= display->_width ||
367 y1 >= display->_height || y2 >= display->_height) {
368 pynq_error("displayDrawFillRect: x1=%d y1=%d x2=%d y2=%d outside screen "
369 "boundaries\n",
370 x1, y1, x2, y2);
371 }
372 // swapping points so that it is always plotted from x1 y1 bottom left, x2 y2
373 // top right
374 uint16_t x1_temp = x1, x2_temp = x2;
375 uint16_t y1_temp = y1, y2_temp = y2;
376 if (x1 > x2) {
377 x1 = x2_temp;
378 x2 = x1_temp;
379 }
380
381 if (y1 > y2) {
382 y1 = y2_temp;
383 y2 = y1_temp;
384 }
385
386 // printf("offset(x)=%d offset(y)=%d",display->_offsetx,display->_offsety);
387 uint16_t _x1 = x1 + display->_offsetx;
388 uint16_t _x2 = x2 + display->_offsetx;
389 uint16_t _y1 = y1 + display->_offsety;
390 uint16_t _y2 = y2 + display->_offsety;
391
392 spi_master_write_command(display, 0x2A); // set column(x) address
393 spi_master_write_addr(display, _x1, _x2);
394 spi_master_write_command(display, 0x2B); // set Page(y) address
395 spi_master_write_addr(display, _y1, _y2);
396 spi_master_write_command(display, 0x2C); // memory write
397 for (int i = _x1; i <= _x2; i++) {
398 uint16_t size = _y2 - _y1 + 1;
399 spi_master_write_color(display, color, size);
400 }
401}
402
404 if (display == NULL || display->_width != DISPLAY_WIDTH) {
405 pynq_error("displayDisplayOff: display has not been initialized\n");
406 }
407 spi_master_write_command(display, 0x28); // display off
408}
409
411 if (display == NULL || display->_width != DISPLAY_WIDTH) {
412 pynq_error("displayDisplayOn: display has not been initialized\n");
413 }
414 spi_master_write_command(display, 0x29); // display on
415}
416
417void displayFillScreen(display_t *display, uint16_t color) {
418 if (display == NULL || display->_width != DISPLAY_WIDTH) {
419 pynq_error("displayFillScreen: display has not been initialized\n");
420 }
421 displayDrawFillRect(display, 0, 0, display->_width - 1, display->_height - 1,
422 color);
423}
424
425void displayDrawLine(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2,
426 uint16_t y2, uint16_t color) {
427 if (display == NULL || display->_width != DISPLAY_WIDTH) {
428 pynq_error("displayDrawLine: display has not been initialized\n");
429 }
430 if (x1 >= display->_width || y1 >= display->_height) {
431 pynq_error("displayDrawLine: x1=%d y1=%d outside screen boundaries\n", x1,
432 y1);
433 } else if (x2 >= display->_width || y2 >= display->_height) {
434 pynq_error("displayDrawLine: x2=%d y2=%d outside screen boundaries\n", x2,
435 y2);
436 }
437 int i;
438 int dx, dy;
439 int sx, sy;
440 int E;
441
442 /* distance between two points */
443 dx = (x2 > x1) ? x2 - x1 : x1 - x2;
444 dy = (y2 > y1) ? y2 - y1 : y1 - y2;
445
446 /* direction of two point */
447 sx = (x2 > x1) ? 1 : -1;
448 sy = (y2 > y1) ? 1 : -1;
449
450 /* inclination < 1 */
451 if (dx > dy) {
452 E = -dx;
453 for (i = 0; i <= dx; i++) {
454 displayDrawPixel(display, x1, y1, color);
455 x1 += sx;
456 E += 2 * dy;
457 if (E >= 0) {
458 y1 += sy;
459 E -= 2 * dx;
460 }
461 }
462
463 /* inclination >= 1 */
464 } else {
465 E = -dy;
466 for (i = 0; i <= dy; i++) {
467 displayDrawPixel(display, x1, y1, color);
468 y1 += sy;
469 E += 2 * dx;
470 if (E >= 0) {
471 x1 += sx;
472 E -= 2 * dy;
473 }
474 }
475 }
476}
477
478void displayDrawRect(display_t *display, uint16_t x1, uint16_t y1, uint16_t x2,
479 uint16_t y2, uint16_t color) {
480 if (display == NULL || display->_width != DISPLAY_WIDTH) {
481 pynq_error("displayDrawRect: display has not been initialized\n");
482 }
483 if (x1 >= display->_width || y1 >= display->_height) {
484 pynq_error("displayDrawRect: x1=%d y1=%d outside screen boundaries\n", x1,
485 y1);
486 } else if (x2 >= display->_width || y2 >= display->_height) {
487 pynq_error("displayDrawRect: x2=%d y2=%d outside screen boundaries\n", x2,
488 y2);
489 }
490 displayDrawLine(display, x1, y1, x2, y1, color);
491 displayDrawLine(display, x2, y1, x2, y2, color);
492 displayDrawLine(display, x2, y2, x1, y2, color);
493 displayDrawLine(display, x1, y2, x1, y1, color);
494}
495
496void displayDrawRectAngle(display_t *display, uint16_t xc, uint16_t yc,
497 uint16_t w, uint16_t h, uint16_t angle,
498 uint16_t color) {
499 double xd, yd, rd;
500 int x1, y1;
501 int x2, y2;
502 int x3, y3;
503 int x4, y4;
504 rd = -angle * M_PI / 180.0;
505 xd = 0.0 - w / 2;
506 yd = h / 2;
507 x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
508 y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
509
510 yd = 0.0 - yd;
511 x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
512 y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
513
514 xd = w / 2;
515 yd = h / 2;
516 x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
517 y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
518
519 yd = 0.0 - yd;
520 x4 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
521 y4 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
522
523 if (display == NULL || display->_width != DISPLAY_WIDTH) {
524 pynq_error("displayDrawRectAngle: display has not been initialized\n");
525 }
526 if (x1 >= display->_width || y1 >= display->_height) {
527 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
528 x1, y1);
529 } else if (x2 >= display->_width || y2 >= display->_height) {
530 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
531 x2, y2);
532 } else if (x3 >= display->_width || y3 >= display->_height) {
533 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
534 x3, y3);
535 } else if (x4 >= display->_width || y4 >= display->_height) {
536 pynq_error("displayDrawRectAngle: x4=%d y4=%d outside screen boundaries\n",
537 x4, y4);
538 }
539
540 displayDrawLine(display, x1, y1, x2, y2, color);
541 displayDrawLine(display, x1, y1, x3, y3, color);
542 displayDrawLine(display, x2, y2, x4, y4, color);
543 displayDrawLine(display, x3, y3, x4, y4, color);
544}
545
546// x1: First X coordinate of triangle point
547// y1: First Y coordinate of triangle point
548// x2: Second X coordinate of triangle point
549// y2: Second Y coordinate of triangle point
550// x3: Third X coordinate of triangle point
551// y3: Third Y coordinate of triangle point
552// color:color
553void displayDrawTriangle(display_t *display, uint16_t x1, uint16_t y1,
554 uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3,
555 uint16_t color) {
556 if (display == NULL || display->_width != DISPLAY_WIDTH) {
557 pynq_error("displayDrawTriangle: display has not been initialized\n");
558 }
559 if (x1 >= display->_width || y1 >= display->_height) {
560 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
561 x1, y1);
562 } else if (x2 >= display->_width || y2 >= display->_height) {
563 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
564 x2, y2);
565 } else if (x3 >= display->_width || y3 >= display->_height) {
566 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
567 x3, y3);
568 }
569
570 // draw the lines for the basic triangle
571 displayDrawLine(display, x1, y1, x2, y2, color);
572 displayDrawLine(display, x2, y2, x3, y3, color);
573 displayDrawLine(display, x3, y3, x1, y1, color);
574}
575
576// when the origin is (0, 0), the point (x1, y1) after rotating the point (x, y)
577// by the angle is obtained by the following calculation.
578// x1 = x * cos(angle) - y * sin(angle)
579// y1 = x * sin(angle) + y * cos(angle)
580void displayDrawTriangleCenter(display_t *display, uint16_t xc, uint16_t yc,
581 uint16_t w, uint16_t h, uint16_t angle,
582 uint16_t color) {
583 double xd, yd, rd;
584 int x1, y1;
585 int x2, y2;
586 int x3, y3;
587 rd = -angle * M_PI / 180.0;
588 xd = 0.0;
589 yd = h / 2;
590 x1 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
591 y1 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
592
593 xd = w / 2;
594 yd = 0.0 - yd;
595 x2 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
596 y2 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
597
598 xd = 0.0 - w / 2;
599 x3 = (int)(xd * cos(rd) - yd * sin(rd) + xc);
600 y3 = (int)(xd * sin(rd) + yd * cos(rd) + yc);
601
602 if (display == NULL || display->_width != DISPLAY_WIDTH) {
603 pynq_error("displayDrawTriangleCenter: display has not been initialized\n");
604 }
605 if (x1 >= display->_width || y1 >= display->_height) {
606 pynq_error("displayDrawRectAngle: x1=%d y1=%d outside screen boundaries\n",
607 x1, y1);
608 } else if (x2 >= display->_width || y2 >= display->_height) {
609 pynq_error("displayDrawRectAngle: x2=%d y2=%d outside screen boundaries\n",
610 x2, y2);
611 } else if (x3 >= display->_width || y3 >= display->_height) {
612 pynq_error("displayDrawRectAngle: x3=%d y3=%d outside screen boundaries\n",
613 x3, y3);
614 }
615
616 displayDrawLine(display, x1, y1, x2, y2, color);
617 displayDrawLine(display, x1, y1, x3, y3, color);
618 displayDrawLine(display, x2, y2, x3, y3, color);
619}
620
621void displayDrawCircle(display_t *display, uint16_t x_center, uint16_t y_center,
622 uint16_t r, uint16_t color) {
623 if (display == NULL || display->_width != DISPLAY_WIDTH) {
624 pynq_error("displayDrawCircle: display has not been initialized\n");
625 }
626 if (r == 0) {
628 "displayDrawCircle: x_center=%d y_center=%d r=%d r cannot be 0\n",
629 x_center, y_center, r);
630 }
631
632 int x_max = x_center + r, x_min = x_center - r, y_max = y_center + r,
633 y_min = y_center - r;
634
635 if (x_max >= display->_width || x_min < 0 || y_max >= display->_height ||
636 y_min < 0) {
637 pynq_error("displayDrawCircle: x_center=%d y_center=%d r=%d outside screen "
638 "boundaries\n",
639 x_center, y_center, r);
640 }
641
642 int x;
643 int y;
644 int err;
645 int old_err;
646
647 x = 0;
648 y = -r;
649 err = 2 - 2 * r;
650 do {
651 displayDrawPixel(display, x_center - x, y_center + y, color);
652 displayDrawPixel(display, x_center - y, y_center - x, color);
653 displayDrawPixel(display, x_center + x, y_center - y, color);
654 displayDrawPixel(display, x_center + y, y_center + x, color);
655 if ((old_err = err) <= x)
656 err += ++x * 2 + 1;
657 if (old_err > y || err > x)
658 err += ++y * 2 + 1;
659 } while (y < 0);
660}
661
662void displayDrawFillCircle(display_t *display, uint16_t x_center,
663 uint16_t y_center, uint16_t r, uint16_t color) {
664 if (display == NULL || display->_width != DISPLAY_WIDTH) {
665 pynq_error("displayDrawFillCircle: display has not been initialized\n");
666 }
667 if (r == 0) {
669 "displayDrawFillCircle: x_center=%d y_center=%d r=%d r cannot be 0\n",
670 x_center, y_center, r);
671 }
672
673 int x_max = x_center + r, x_min = x_center - r, y_max = y_center + r,
674 y_min = y_center - r;
675
676 if (x_max >= display->_width || x_min < 0 || y_max >= display->_height ||
677 y_min < 0) {
678 pynq_error("displayDrawFillCircle: x_center=%d y_center=%d r=%d outside "
679 "screen boundaries\n",
680 x_center, y_center, r);
681 }
682
683 int x;
684 int y;
685 int err;
686 int old_err;
687 int ChangeX;
688
689 x = 0;
690 y = -r;
691 err = 2 - 2 * r;
692 ChangeX = 1;
693 do {
694 if (ChangeX) {
695 displayDrawLine(display, x_center - x, y_center - y, x_center - x,
696 y_center + y, color);
697 displayDrawLine(display, x_center + x, y_center - y, x_center + x,
698 y_center + y, color);
699 } // endif
700 ChangeX = (old_err = err) <= x;
701 if (ChangeX)
702 err += ++x * 2 + 1;
703 if (old_err > y || err > x)
704 err += ++y * 2 + 1;
705 } while (y <= 0);
706}
707
708void displayDrawRoundRect(display_t *display, uint16_t x1, uint16_t y1,
709 uint16_t x2, uint16_t y2, uint16_t r,
710 uint16_t color) {
711 if (display == NULL || display->_width != DISPLAY_WIDTH) {
712 pynq_error("displayDrawRoundRect: display has not been initialized\n");
713 }
714 if (r == 0) {
715 pynq_error("displayDrawRoundRect: x_center=%d x1=%d y1=%d r cannot be 0\n",
716 x1, y1, r);
717 } else if (x1 >= display->_width || y1 >= display->_height) {
718 pynq_error("displayDrawRoundRect: x1=%d y1=%d outside screen boundaries\n",
719 x1, y1);
720 } else if (x2 >= display->_width || y2 >= display->_height) {
721 pynq_error("displayDrawRoundRect: x2=%d y2=%d outside screen boundaries\n",
722 x2, y2);
723 }
724 int x;
725 int y;
726 int err;
727 int old_err;
728 unsigned char temp;
729
730 if (x1 > x2) {
731 temp = x1;
732 x1 = x2;
733 x2 = temp;
734 }
735
736 if (y1 > y2) {
737 temp = y1;
738 y1 = y2;
739 y2 = temp;
740 }
741
742 if (_DEBUG_)
743 printf("x1=%d x2=%d delta=%d r=%d", x1, x2, x2 - x1, r);
744 if (_DEBUG_)
745 printf("y1=%d y2=%d delta=%d r=%d", y1, y2, y2 - y1, r);
746 if (x2 - x1 < r)
747 return; // TODO add 20190517?
748 if (y2 - y1 < r)
749 return; // TODO add 20190517?
750
751 x = 0;
752 y = -r;
753 err = 2 - 2 * r;
754
755 do {
756 if (x) {
757 displayDrawPixel(display, x1 + r - x, y1 + r + y, color);
758 displayDrawPixel(display, x2 - r + x, y1 + r + y, color);
759 displayDrawPixel(display, x1 + r - x, y2 - r - y, color);
760 displayDrawPixel(display, x2 - r + x, y2 - r - y, color);
761 }
762 if ((old_err = err) <= x)
763 err += ++x * 2 + 1;
764 if (old_err > y || err > x)
765 err += ++y * 2 + 1;
766 } while (y < 0);
767
768 if (_DEBUG_)
769 printf("x1+r=%d x2-r=%d", x1 + r, x2 - r);
770 displayDrawLine(display, x1 + r, y1, x2 - r, y1, color);
771 displayDrawLine(display, x1 + r, y2, x2 - r, y2, color);
772 if (_DEBUG_)
773 printf("y1+r=%d y2-r=%d", y1 + r, y2 - r);
774 displayDrawLine(display, x1, y1 + r, x1, y2 - r, color);
775 displayDrawLine(display, x2, y1 + r, x2, y2 - r, color);
776}
777
778uint16_t rgb_conv(uint16_t r, uint16_t g, uint16_t b) {
779 return (((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3));
780}
781
782int displayDrawChar(display_t *display, FontxFile *fxs, uint16_t x, uint16_t y,
783 uint8_t ascii, uint16_t color) {
784 uint16_t xx, yy, bit, ofs;
785 unsigned char fonts[128]; // font pattern
786 unsigned char pw, ph;
787 int h, w;
788 uint16_t mask;
789 bool rc = GetFontx(fxs, ascii, fonts, &pw, &ph);
790
791 if (display == NULL || display->_width != DISPLAY_WIDTH) {
792 pynq_error("displayDrawChar: display has not been initialized\n");
793 }
794 if (_DEBUG_) {
795 printf("_font_direction=%d\n", display->_font_direction);
796 printf("GetFontx rc=%d pw=%d ph=%d\n", rc, pw, ph);
797 }
798
799 if (!rc) {
800 pynq_error("displayDrawChar: cannot get font from font file\n");
801 }
802
803 switch (display->_font_direction) {
804 case TEXT_DIRECTION0:
805 if (x + pw >= display->_width || y + ph >= display->_height) {
806 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
807 "direction=%d outside screen boundaries\n",
808 x, y, ph, pw, display->_font_direction);
809 }
810 break;
811 case TEXT_DIRECTION90:
812 if (x + ph >= display->_height || y + pw >= display->_width) {
813 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
814 "direction=%d outside screen boundaries\n",
815 x, y, ph, pw, display->_font_direction);
816 }
817 break;
819 if (x - pw <= 0 || y - ph <= 0) {
820 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
821 "direction=%d outside screen boundaries\n",
822 x, y, ph, pw, display->_font_direction);
823 }
824 break;
826 if (x - ph <= 0 || y - pw <= 0) {
827 pynq_error("displayDrawChar: x=%d y=%d for font height=%d width=%d and "
828 "direction=%d outside screen boundaries\n",
829 x, y, ph, pw, display->_font_direction);
830 }
831 break;
832 }
833
834 int16_t xd1 = 0, yd1 = 0, xd2 = 0, yd2 = 0;
835 uint16_t xss = 0, yss = 0;
836 int16_t xsd = 0, ysd = 0, next = 0;
837 uint16_t x0 = 0, x1 = 0, y0 = 0, y1 = 0;
838 if (display->_font_direction == 0) {
839 xd1 = +1;
840 yd1 = +1; //-1;
841 xd2 = 0;
842 yd2 = 0;
843 xss = x;
844 yss = y - (ph - 1);
845 xsd = 1;
846 ysd = 0;
847 next = x + pw;
848
849 x0 = x;
850 y0 = y - (ph - 1);
851 x1 = x + (pw - 1);
852 y1 = y;
853 } else if (display->_font_direction == 2) {
854 xd1 = -1;
855 yd1 = -1; //+1;
856 xd2 = 0;
857 yd2 = 0;
858 xss = x;
859 yss = y + ph + 1;
860 xsd = 1;
861 ysd = 0;
862 next = x - pw;
863
864 x0 = x - (pw - 1);
865 y0 = y;
866 x1 = x;
867 y1 = y + (ph - 1);
868 } else if (display->_font_direction == 1) {
869 xd1 = 0;
870 yd1 = 0;
871 xd2 = -1;
872 yd2 = +1; //-1;
873 xss = x + ph;
874 yss = y;
875 xsd = 0;
876 ysd = 1;
877 next = y + pw; // y - pw;
878
879 x0 = x;
880 y0 = y;
881 x1 = x + (ph - 1);
882 y1 = y + (pw - 1);
883 } else if (display->_font_direction == 3) {
884 xd1 = 0;
885 yd1 = 0;
886 xd2 = +1;
887 yd2 = -1; //+1;
888 xss = x - (ph - 1);
889 yss = y;
890 xsd = 0;
891 ysd = 1;
892 next = y - pw; // y + pw;
893
894 x0 = x - (ph - 1);
895 y0 = y - (pw - 1);
896 x1 = x;
897 y1 = y;
898 }
899
900 // TODO: fix the problem of underflow properly some time
901 if (display->_font_fill && x0 < DISPLAY_WIDTH && y0 < DISPLAY_HEIGHT &&
902 x1 < DISPLAY_WIDTH && y1 < DISPLAY_HEIGHT) {
903 displayDrawFillRect(display, x0, y0, x1, y1, display->_font_fill_color);
904 }
905
906 int bits;
907 if (_DEBUG_)
908 printf("xss=%d yss=%d\n", xss, yss);
909 ofs = 0;
910 yy = yss;
911 xx = xss;
912 for (h = 0; h < ph; h++) {
913 if (xsd)
914 xx = xss;
915 if (ysd)
916 yy = yss;
917 bits = pw;
918 for (w = 0; w < ((pw + 4) / 8); w++) {
919 mask = 0x80;
920 for (bit = 0; bit < 8; bit++) {
921 bits--;
922 if (bits < 0)
923 continue;
924 // TODO: fix the problem of underflow properly some time
925 if (fonts[ofs] & mask && xx < DISPLAY_WIDTH && yy < DISPLAY_HEIGHT) {
926 displayDrawPixel(display, xx, yy, color);
927 }
928 // TODO: fix the problem of underflow properly some time
929 if (h == (ph - 2) && display->_font_underline && xx < DISPLAY_WIDTH &&
930 yy < DISPLAY_HEIGHT)
931 displayDrawPixel(display, xx, yy, display->_font_underline_color);
932 // TODO: fix the problem of underflow properly some time
933 if (h == (ph - 1) && display->_font_underline && xx < DISPLAY_WIDTH &&
934 yy < DISPLAY_HEIGHT)
935 displayDrawPixel(display, xx, yy, display->_font_underline_color);
936 xx = xx + xd1;
937 yy = yy + yd2;
938 mask = mask >> 1;
939 }
940 ofs++;
941 }
942 yy = yy + yd1;
943 xx = xx + xd2;
944 }
945
946 if (next < 0)
947 next = 0;
948 return next;
949}
950
951int displayDrawString(display_t *display, FontxFile *fx, uint16_t x, uint16_t y,
952 uint8_t *ascii, uint16_t color) {
953 int length = strlen((char *)ascii);
954 if (display == NULL || display->_width != DISPLAY_WIDTH) {
955 pynq_error("displayDrawString: display has not been initialized\n");
956 }
957 if (_DEBUG_)
958 printf("displayDrawString length=%d\n", length);
959 for (int i = 0; i < length; i++) {
960 if (_DEBUG_)
961 printf("ascii[%d]=%x x=%d y=%d\n", i, ascii[i], x, y);
962 if (display->_font_direction == 0)
963 x = displayDrawChar(display, fx, x, y, ascii[i], color);
964 if (display->_font_direction == 1)
965 y = displayDrawChar(display, fx, x, y, ascii[i], color);
966 if (display->_font_direction == 2)
967 x = displayDrawChar(display, fx, x, y, ascii[i], color);
968 if (display->_font_direction == 3)
969 y = displayDrawChar(display, fx, x, y, ascii[i], color);
970 }
971 if (display->_font_direction == 0)
972 return x;
973 if (display->_font_direction == 2)
974 return x;
975 if (display->_font_direction == 1)
976 return y;
977 if (display->_font_direction == 3)
978 return y;
979 return 0;
980}
981
982void displaySetFontDirection(display_t *display, uint16_t dir) {
983 if (display == NULL || display->_width != DISPLAY_WIDTH) {
984 pynq_error("displaySetFontDirection: display has not been initialized\n");
985 }
986 display->_font_direction = dir;
987}
988
989void displaySetFontFill(display_t *display, uint16_t color) {
990 if (display == NULL || display->_width != DISPLAY_WIDTH) {
991 pynq_error("displaySetFontFill: display has not been initialized\n");
992 }
993 display->_font_fill = true;
994 display->_font_fill_color = color;
995}
996
997void displayUnsetFontFill(display_t *display) { display->_font_fill = false; }
998
999void displaySetFontUnderLine(display_t *display, uint16_t color) {
1000 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1001 pynq_error("displaySetFontUnderLine: display has not been initialized\n");
1002 }
1003 display->_font_underline = true;
1004 display->_font_underline_color = color;
1005}
1006
1008 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1009 pynq_error("displayUnsetFontUnderLine: display has not been initialized\n");
1010 }
1011 display->_font_underline = false;
1012}
1013
1015 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1016 pynq_error("displayBacklightOff: display has not been initialized\n");
1017 }
1018 if (display->_bl >= 0) {
1019 gpio_set_level(display->_bl, 0);
1020 }
1021}
1022
1024 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1025 pynq_error("displayBacklightOn: display has not been initialized\n");
1026 }
1027 if (display->_bl >= 0) {
1028 gpio_set_level(display->_bl, 1);
1029 }
1030}
1031
1033 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1034 pynq_error("displayInversionOff: display has not been initialized\n");
1035 }
1036 spi_master_write_command(display, 0x21); // display Inversion Off
1037}
1038
1040 if (display == NULL || display->_width != DISPLAY_WIDTH) {
1041 pynq_error("displayInversionOn: display has not been initialized\n");
1042 }
1043 spi_master_write_command(display, 0x20); // display Inversion On
1044}
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:306
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:336
#define M_PI
Definition display.c:44
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:951
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:361
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:999
void displaySetFontDirection(display_t *display, uint16_t dir)
Changes the direction the characters will be printed.
Definition display.c:982
#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:553
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:989
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:478
void displayUnsetFontFill(display_t *display)
Sets the _font_fill parameter to false in the display handle, turns off the font fill.
Definition display.c:997
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:778
void displayDisplayOff(display_t *display)
Turn off the display.
Definition display.c:403
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:425
void displayInversionOff(display_t *display)
Turn off inversion of the colors.
Definition display.c:1032
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:708
void displayInversionOn(display_t *display)
Turn on inversion of the colors.
Definition display.c:1039
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:782
void displayBacklightOn(display_t *display)
Turn on the display backlight.
Definition display.c:1023
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:621
void displayFillScreen(display_t *display, uint16_t color)
Fill entire display with a single color using the ldcDrawFillRect function.
Definition display.c:417
void displayBacklightOff(display_t *display)
Turn off the display backlight.
Definition display.c:1014
void displayDisplayOn(display_t *display)
Initialize DISPLAY screen.
Definition display.c:410
void displayUnsetFontUnderLine(display_t *display)
Turns off _font_underline in the display handle.
Definition display.c:1007
void displayDrawPixel(display_t *display, uint16_t x, uint16_t y, uint16_t color)
Draw a single pixel to the display.
Definition display.c:317
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:496
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:662
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:580
@ 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:98
void gpio_set_direction(const io_t pin, const gpio_direction_t dir)
Set the IO pin as in input or output.
Definition gpio.c:81
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:104
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:55
@ 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
void switchbox_set_pin(const io_t pin_number, const io_configuration_t io_type)
Set the type of a switch pin.
Definition switchbox.c:126
@ 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: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: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