1
+ /*
2
+ * Visual tests for framebuffer modes that are not commonly used by the high-level API.
3
+ * Currently, includes 2 pixel per byte (ppB) with static origin color and 8ppB with static origin
4
+ * color.
5
+ *
6
+ * After running this, you should see two identical test images, with a "ladder" of black triangles
7
+ * next to a black rectangle with a ladder of white triangles on it.
8
+ */
9
+
10
+ #include <esp_heap_caps.h>
11
+ #include <esp_log.h>
12
+ #include <esp_sleep.h>
13
+ #include <esp_timer.h>
14
+ #include <esp_types.h>
15
+ #include <esp_assert.h>
16
+ #include <freertos/FreeRTOS.h>
17
+ #include <freertos/task.h>
18
+ #include <inttypes.h>
19
+ #include <stdint.h>
20
+ #include <stdio.h>
21
+ #include <stdlib.h>
22
+ #include <string.h>
23
+
24
+ #include <epdiy.h>
25
+
26
+ #include "sdkconfig.h"
27
+
28
+ #define WAVEFORM EPD_BUILTIN_WAVEFORM
29
+
30
+ // choose the default demo board depending on the architecture
31
+ #ifdef CONFIG_IDF_TARGET_ESP32
32
+ #define DEMO_BOARD epd_board_v6
33
+ #elif defined(CONFIG_IDF_TARGET_ESP32S3 )
34
+ #define DEMO_BOARD epd_board_v7
35
+ #endif
36
+
37
+ // Singular framebuffer to use for all of the tests.
38
+ // Allocated for 2ppB, the least compact that we test here.
39
+ uint8_t * framebuffer ;
40
+ int fb_size ;
41
+
42
+ static inline void checkError (enum EpdDrawError err ) {
43
+ if (err != EPD_DRAW_SUCCESS ) {
44
+ ESP_LOGE ("demo" , "draw error: %X" , err );
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Clears the screen to white and resets the framebuffer.
50
+ */
51
+ void clear () {
52
+ epd_poweron ();
53
+ epd_clear ();
54
+ epd_poweroff ();
55
+ memset (framebuffer , 0xFF , fb_size );
56
+ }
57
+
58
+ /**
59
+ * Draw triangles at varying alignments into the framebuffer in 8ppB mode.
60
+ * start_line, start_column specify the start position.
61
+ * The bits that belong to a triangle are flipped, i.e., it is drawn at the
62
+ * inverse color to the background it is drawn onto.
63
+ */
64
+ void draw_8bpp_triangles (int start_line , int start_column ) {
65
+ start_column /= 8 ;
66
+ int line_bytes = epd_width () / 8 ;
67
+
68
+ for (int align = 0 ; align < 16 ; align ++ ) {
69
+ for (int height = 0 ; height < 16 ; height ++ ) {
70
+ for (int len = 0 ; len <= height ; len ++ ) {
71
+ int line = (start_line + 16 * align + height );
72
+ int column = align + len ;
73
+ uint8_t * line_address = framebuffer + (line_bytes * line );
74
+ * (line_address + start_column + column / 8 ) ^= 1 << (column % 8 );
75
+ }
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Draw triangles at varying alignments into the framebuffer in 2ppB mode.
82
+ * start_line, start_column specify the start position.
83
+ * color specifies the color to draw in.
84
+ */
85
+ void draw_2bpp_triangles (int start_line , int start_column , uint8_t color ) {
86
+ int height = 16 ;
87
+
88
+ for (int align = 0 ; align < 16 ; align ++ ) {
89
+ int x0 = start_column + align ;
90
+ int y0 = start_line + height * align ;
91
+ int x1 = x0 ;
92
+ int y1 = y0 + height - 1 ;
93
+ int x2 = x0 + height - 1 ;
94
+ int y2 = y0 + height - 1 ;
95
+
96
+ epd_fill_triangle (x0 , y0 , x1 , y1 , x2 , y2 , color , framebuffer );
97
+ }
98
+ }
99
+
100
+ void test_8ppB () {
101
+ EpdRect area = epd_full_screen ();
102
+ enum EpdDrawMode mode ;
103
+
104
+ // bytes in a line in 8ppB mode
105
+ int line_bytes = epd_width () / 8 ;
106
+
107
+ int start_line = 100 ;
108
+
109
+ // draw differently aligned black triangles to check for uniformity
110
+ draw_8bpp_triangles (start_line , 80 );
111
+
112
+ int black_start_column = 160 ;
113
+
114
+ // draw a black area
115
+ for (int line = 0 ; line < 300 ; line ++ ) {
116
+ uint8_t * line_address = framebuffer + (line_bytes * (start_line + line ));
117
+ memset (line_address + black_start_column / 8 , 0 , 32 );
118
+ }
119
+
120
+ // update the display. In the first update, white pixels are no-opps,
121
+ // in the second update, black pixels are no-ops.
122
+ epd_poweron ();
123
+ mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_WHITE ;
124
+ checkError (epd_draw_base (area , framebuffer , area , mode , 25 , NULL , NULL , & epdiy_ED047TC2 ));
125
+ epd_poweroff ();
126
+
127
+ // draw white triangles on the black background
128
+ draw_8bpp_triangles (start_line , black_start_column + 16 );
129
+
130
+ epd_poweron ();
131
+ mode = MODE_PACKING_8PPB | MODE_DU | PREVIOUSLY_BLACK ;
132
+ checkError (epd_draw_base (area , framebuffer , area , mode , 25 , NULL , NULL , & epdiy_ED047TC2 ));
133
+ epd_poweroff ();
134
+ }
135
+
136
+ void test_2ppB () {
137
+ EpdRect area = epd_full_screen ();
138
+ enum EpdDrawMode mode ;
139
+ int start_column = 500 ;
140
+ int start_line = 100 ;
141
+
142
+ // draw differently aligned black triangles to check for uniformity
143
+ draw_2bpp_triangles (start_line , start_column , 0 );
144
+
145
+ int black_start_column = start_column + 60 ;
146
+
147
+ // draw a black area
148
+ EpdRect black_area = { .x = black_start_column , .y = 100 , .width = 256 , .height = 300 };
149
+ epd_fill_rect (black_area , 0 , framebuffer );
150
+
151
+ // Do not overdraw the 8ppB image
152
+ uint8_t * drawn_columns = malloc (epd_width () / 2 );
153
+ assert (drawn_columns != NULL );
154
+ memset (drawn_columns , 0 , epd_width () / 2 );
155
+ memset (drawn_columns + start_column / 2 , 255 , (epd_width () - start_column ) / 2 );
156
+
157
+ // update the display. In the first update, white pixels are no-opps,
158
+ // in the second update, black pixels are no-ops.
159
+ epd_poweron ();
160
+ mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_WHITE ;
161
+ checkError (
162
+ epd_draw_base (area , framebuffer , area , mode , 25 , NULL , drawn_columns , & epdiy_ED047TC2 )
163
+ );
164
+ epd_poweroff ();
165
+
166
+ // draw white triangles on the black background
167
+ draw_2bpp_triangles (start_line , black_start_column + 16 , 255 );
168
+
169
+ epd_poweron ();
170
+ mode = MODE_PACKING_2PPB | MODE_DU | PREVIOUSLY_BLACK ;
171
+ checkError (
172
+ epd_draw_base (area , framebuffer , area , mode , 25 , NULL , drawn_columns , & epdiy_ED047TC2 )
173
+ );
174
+ epd_poweroff ();
175
+
176
+ free (drawn_columns );
177
+ }
178
+
179
+ void app_main () {
180
+ epd_init (& DEMO_BOARD , & ED060XC3 , EPD_OPTIONS_DEFAULT );
181
+
182
+ // Set VCOM for boards that allow to set this in software (in mV).
183
+ // This will print an error if unsupported. In this case,
184
+ // set VCOM using the hardware potentiometer and delete this line.
185
+ epd_set_vcom (2100 );
186
+
187
+ epd_set_lcd_pixel_clock_MHz (10 );
188
+
189
+ fb_size = epd_width () * epd_height () / 2 ;
190
+ framebuffer = heap_caps_aligned_alloc (16 , fb_size , MALLOC_CAP_SPIRAM );
191
+
192
+ clear ();
193
+
194
+ test_8ppB ();
195
+
196
+ memset (framebuffer , 0xFF , fb_size );
197
+
198
+ test_2ppB ();
199
+
200
+ printf ("going to sleep...\n" );
201
+ epd_deinit ();
202
+ esp_deep_sleep_start ();
203
+ }
0 commit comments