@@ -21,6 +21,49 @@ struct ili9xxx_data {
2121 enum display_orientation orientation ;
2222};
2323
24+ #ifdef CONFIG_ILI9XXX_READ
25+
26+ /* We set this LUT directly when reads are enabled,
27+ * so that we can be sure the bitshift to convert GRAM data back
28+ * to RGB565 will result in correct data
29+ */
30+ const uint8_t ili9xxx_rgb_lut [] = {
31+ 0 , 2 , 4 , 6 ,
32+ 8 , 10 , 12 , 14 ,
33+ 16 , 18 , 20 , 22 ,
34+ 24 , 26 , 28 , 30 ,
35+ 32 , 34 , 36 , 38 ,
36+ 40 , 42 , 44 , 46 ,
37+ 48 , 50 , 52 , 54 ,
38+ 56 , 58 , 60 , 62 ,
39+ 0 , 1 , 2 , 3 ,
40+ 4 , 5 , 6 , 7 ,
41+ 8 , 9 , 10 , 11 ,
42+ 12 , 13 , 14 , 15 ,
43+ 16 , 17 , 18 , 19 ,
44+ 20 , 21 , 22 , 23 ,
45+ 24 , 25 , 26 , 27 ,
46+ 28 , 29 , 30 , 31 ,
47+ 32 , 33 , 34 , 35 ,
48+ 36 , 37 , 38 , 39 ,
49+ 40 , 41 , 42 , 43 ,
50+ 44 , 45 , 46 , 47 ,
51+ 48 , 49 , 50 , 51 ,
52+ 52 , 53 , 54 , 55 ,
53+ 56 , 57 , 58 , 59 ,
54+ 60 , 61 , 62 , 63 ,
55+ 0 , 2 , 4 , 6 ,
56+ 8 , 10 , 12 , 14 ,
57+ 16 , 18 , 20 , 22 ,
58+ 24 , 26 , 28 , 30 ,
59+ 32 , 34 , 36 , 38 ,
60+ 40 , 42 , 44 , 46 ,
61+ 48 , 50 , 52 , 54 ,
62+ 56 , 58 , 60 , 62
63+ };
64+
65+ #endif
66+
2467int ili9xxx_transmit (const struct device * dev , uint8_t cmd , const void * tx_data ,
2568 size_t tx_len )
2669{
@@ -142,6 +185,93 @@ static int ili9xxx_write(const struct device *dev, const uint16_t x,
142185 return 0 ;
143186}
144187
188+ #ifdef CONFIG_ILI9XXX_READ
189+
190+ static int ili9xxx_read (const struct device * dev , const uint16_t x ,
191+ const uint16_t y ,
192+ const struct display_buffer_descriptor * desc , void * buf )
193+ {
194+ const struct ili9xxx_config * config = dev -> config ;
195+ struct ili9xxx_data * data = dev -> data ;
196+ struct display_buffer_descriptor mipi_desc ;
197+ int r ;
198+ uint32_t gram_data , nbr_of_reads ;
199+ uint16_t * read_data_start = (uint16_t * )buf ;
200+
201+ if (data -> pixel_format != PIXEL_FORMAT_RGB_565 ) {
202+ /* Only RGB565 can be supported, see note below */
203+ return - ENOTSUP ;
204+ }
205+
206+ __ASSERT (desc -> width <= desc -> pitch , "Pitch is smaller than width" );
207+ __ASSERT ((desc -> pitch * data -> bytes_per_pixel * desc -> height ) <=
208+ desc -> buf_size ,
209+ "Output buffer to small" );
210+
211+ LOG_DBG ("Reading %dx%d (w,h) @ %dx%d (x,y)" , desc -> width , desc -> height ,
212+ x , y );
213+
214+ r = ili9xxx_set_mem_area (dev , x , y , desc -> width , desc -> height );
215+ if (r < 0 ) {
216+ return r ;
217+ }
218+
219+ /*
220+ * ILI9XXX stores all pixel data in graphics ram (GRAM) as 18 bit
221+ * values. When using RGB565 pixel format, pixels are converted to
222+ * 18 bit values via a lookup table. When using RGB888 format, the
223+ * lower 2 bits of each pixel are simply dropped. When reading pixels,
224+ * the response format will always look like so:
225+ * | R[5:0] | x | x | G[5:0] | x | x | B[5:0] | x | x |
226+ * Where x represents "don't care". The internal format of the
227+ * ILI9XXX graphics RAM results in the following restrictions:
228+ * - RGB888 mode can't be supported.
229+ * - we can only read one pixel at once (since we need to do
230+ * byte manipulation on the output)
231+ */
232+
233+ /* Setup MIPI descriptor to read 3 bytes (one pixel in GRAM) */
234+ mipi_desc .width = 1 ;
235+ mipi_desc .height = 1 ;
236+ /* Per MIPI API, pitch must always match width */
237+ mipi_desc .pitch = 1 ;
238+
239+ nbr_of_reads = desc -> width * desc -> height ;
240+
241+ /* Initial read command should consist of RAMRD command, plus
242+ * 8 dummy clock cycles
243+ */
244+ uint8_t cmd [] = {ILI9XXX_RAMRD , 0xFF };
245+
246+ for (uint32_t read_cnt = 0 ; read_cnt < nbr_of_reads ; read_cnt ++ ) {
247+ r = mipi_dbi_command_read (config -> mipi_dev ,
248+ & config -> dbi_config ,
249+ cmd , sizeof (cmd ),
250+ (uint8_t * )& gram_data , 3 );
251+ if (r < 0 ) {
252+ return r ;
253+ }
254+
255+ /* Bitshift the graphics RAM data to RGB565.
256+ * For more details on the formatting of this data,
257+ * see "Read data through 4-line SPI mode" diagram
258+ * on page 64 of datasheet.
259+ */
260+ read_data_start [read_cnt ] =
261+ ((gram_data & 0xF80000 ) >> 11 ) | /* Blue */
262+ ((gram_data & 0x1C00 ) << 3 ) | /* Green */
263+ ((gram_data & 0xE000 ) >> 13 ) | /* Green */
264+ (gram_data & 0xF8 ); /* Red */
265+
266+ /* After first read, we should use read memory continue command */
267+ cmd [0 ] = ILI9XXX_RAMRD_CONT ;
268+ }
269+
270+ return 0 ;
271+ }
272+
273+ #endif
274+
145275static int ili9xxx_display_blanking_off (const struct device * dev )
146276{
147277 LOG_DBG ("Turning display blanking off" );
@@ -321,6 +451,11 @@ static int ili9xxx_init(const struct device *dev)
321451 return r ;
322452 }
323453
454+ #ifdef CONFIG_ILI9XXX_READ
455+ /* Set RGB LUT table to enable display read API */
456+ ili9xxx_transmit (dev , ILI9XXX_RGBSET , ili9xxx_rgb_lut , sizeof (ili9xxx_rgb_lut ));
457+ #endif
458+
324459 k_sleep (K_MSEC (ILI9XXX_RESET_WAIT_TIME ));
325460
326461 ili9xxx_display_blanking_on (dev );
@@ -344,6 +479,9 @@ static const struct display_driver_api ili9xxx_api = {
344479 .blanking_on = ili9xxx_display_blanking_on ,
345480 .blanking_off = ili9xxx_display_blanking_off ,
346481 .write = ili9xxx_write ,
482+ #ifdef CONFIG_ILI9XXX_READ
483+ .read = ili9xxx_read ,
484+ #endif
347485 .get_capabilities = ili9xxx_get_capabilities ,
348486 .set_pixel_format = ili9xxx_set_pixel_format ,
349487 .set_orientation = ili9xxx_set_orientation ,
0 commit comments