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