|
25 | 25 | #include "py/runtime.h" |
26 | 26 | #include "py/objarray.h" |
27 | 27 | #include "py/binary.h" |
| 28 | + #include "py/objint.h" |
| 29 | + #include "py/objstr.h" |
| 30 | + #include "py/objtype.h" |
| 31 | + #include "py/objexcept.h" |
28 | 32 |
|
29 | 33 | // stdlib includes |
30 | 34 | #include <string.h> |
31 | 35 |
|
32 | 36 | #define DEFAULT_STACK_SIZE (5 * 1024) |
33 | 37 |
|
34 | | - |
35 | | - typedef struct { |
36 | | - esp_lcd_panel_t base; // Base class of generic lcd panel |
37 | | - int panel_id; // LCD panel ID |
38 | | - lcd_hal_context_t hal; // Hal layer object |
39 | | - size_t data_width; // Number of data lines |
40 | | - size_t fb_bits_per_pixel; // Frame buffer color depth, in bpp |
41 | | - size_t num_fbs; // Number of frame buffers |
42 | | - size_t output_bits_per_pixel; // Color depth seen from the output data line. Default to fb_bits_per_pixel, but can be changed by YUV-RGB conversion |
43 | | - size_t sram_trans_align; // Alignment for framebuffer that allocated in SRAM |
44 | | - size_t psram_trans_align; // Alignment for framebuffer that allocated in PSRAM |
45 | | - int disp_gpio_num; // Display control GPIO, which is used to perform action like "disp_off" |
46 | | - intr_handle_t intr; // LCD peripheral interrupt handle |
47 | | - esp_pm_lock_handle_t pm_lock; // Power management lock |
48 | | - size_t num_dma_nodes; // Number of DMA descriptors that used to carry the frame buffer |
49 | | - uint8_t *fbs[3]; // Frame buffers |
50 | | - uint8_t cur_fb_index; // Current frame buffer index |
51 | | - uint8_t bb_fb_index; // Current frame buffer index which used by bounce buffer |
52 | | - } rgb_panel_t; |
53 | | - |
54 | | - |
55 | | - static bool rgb_bus_trans_done_cb(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) |
56 | | - { |
57 | | - LCD_UNUSED(edata); |
58 | | - LCD_UNUSED(panel); |
59 | | - // rgb_panel_t *rgb_panel = __containerof(panel, rgb_panel_t, base); |
60 | | - mp_lcd_rgb_bus_obj_t *self = (mp_lcd_rgb_bus_obj_t *)user_ctx; |
61 | | - |
62 | | - if (rgb_bus_event_isset_from_isr(&self->swap_bufs)) { |
63 | | - rgb_bus_event_clear_from_isr(&self->swap_bufs); |
64 | | - uint8_t *idle_fb = self->idle_fb; |
65 | | - self->idle_fb = self->active_fb; |
66 | | - self->active_fb = idle_fb; |
67 | | - rgb_bus_lock_release_from_isr(&self->swap_lock); |
68 | | - } |
69 | | - |
70 | | - return false; |
71 | | - } |
72 | | - |
73 | | - esp_lcd_rgb_panel_event_callbacks_t callbacks = { .on_vsync = rgb_bus_trans_done_cb }; |
74 | | - |
75 | 38 | mp_lcd_err_t rgb_del(mp_obj_t obj); |
76 | 39 | mp_lcd_err_t rgb_init(mp_obj_t obj, uint16_t width, uint16_t height, uint8_t bpp, uint32_t buffer_size, bool rgb565_byte_swap, uint8_t cmd_bits, uint8_t param_bits); |
77 | 40 | mp_lcd_err_t rgb_get_lane_count(mp_obj_t obj, uint8_t *lane_count); |
|
292 | 255 |
|
293 | 256 | rgb_bus_lock_delete(&self->copy_lock); |
294 | 257 | rgb_bus_lock_delete(&self->tx_color_lock); |
295 | | - rgb_bus_lock_delete(&self->swap_lock); |
296 | 258 |
|
| 259 | + rgb_bus_event_clear(&self->swap_bufs); |
297 | 260 | rgb_bus_event_delete(&self->swap_bufs); |
298 | 261 | rgb_bus_event_delete(&self->copy_task_exit); |
299 | 262 |
|
|
440 | 403 | self->panel_io_config.flags.fb_in_psram = 1; |
441 | 404 | self->panel_io_config.flags.double_fb = 1; |
442 | 405 |
|
| 406 | + rgb_bus_lock_init(&self->copy_lock); |
| 407 | + rgb_bus_lock_init(&self->tx_color_lock); |
| 408 | + rgb_bus_event_init(&self->copy_task_exit); |
| 409 | + rgb_bus_event_init(&self->swap_bufs); |
| 410 | + rgb_bus_event_set(&self->swap_bufs); |
| 411 | + rgb_bus_lock_init(&self->init_lock); |
| 412 | + rgb_bus_lock_acquire(&self->init_lock, -1); |
| 413 | + |
| 414 | + |
| 415 | + #if LCD_RGB_OPTIMUM_FB_SIZE |
| 416 | + rgb_bus_lock_init(&self->optimum_fb.lock); |
| 417 | + rgb_bus_lock_acquire(&self->optimum_fb.lock, -1); |
| 418 | + self->optimum_fb.samples = (uint16_t *)malloc(sizeof(uint16_t) * 255); |
| 419 | + self->optimum_fb.curr_index = 254; |
| 420 | + #endif |
| 421 | + |
443 | 422 | #if CONFIG_LCD_ENABLE_DEBUG_LOG |
444 | 423 | mp_printf(&mp_plat_print, "h_res=%lu\n", self->panel_io_config.timings.h_res); |
445 | 424 | mp_printf(&mp_plat_print, "v_res=%lu\n", self->panel_io_config.timings.v_res); |
446 | 425 | mp_printf(&mp_plat_print, "bits_per_pixel=%d\n", self->panel_io_config.bits_per_pixel); |
447 | 426 | mp_printf(&mp_plat_print, "rgb565_byte_swap=%d\n", self->rgb565_byte_swap); |
448 | 427 | #endif |
449 | | - mp_lcd_err_t ret = esp_lcd_new_rgb_panel(&self->panel_io_config, &self->panel_handle); |
450 | | - if (ret != 0) { |
451 | | - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%d(esp_lcd_new_rgb_panel)"), ret); |
452 | | - return ret; |
453 | | - } |
454 | | - |
455 | | - if (self->panel_io_config.flags.double_fb) { |
456 | | - ret = esp_lcd_rgb_panel_register_event_callbacks(self->panel_handle, &callbacks, self); |
457 | | - if (ret != 0) { |
458 | | - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%d(esp_lcd_rgb_panel_register_event_callbacks)"), ret); |
459 | | - return ret; |
460 | | - } |
461 | | - } |
462 | | - |
463 | | - ret = esp_lcd_panel_reset(self->panel_handle); |
464 | | - if (ret != 0) { |
465 | | - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%d(esp_lcd_panel_reset)"), ret); |
466 | | - return ret; |
467 | | - } |
468 | | - |
469 | | - ret = esp_lcd_panel_init(self->panel_handle); |
470 | | - if (ret != 0) { |
471 | | - mp_raise_msg_varg(&mp_type_ValueError, MP_ERROR_TEXT("%d(esp_lcd_panel_init)"), ret); |
472 | | - return ret; |
473 | | - } |
474 | | - |
475 | | - rgb_panel_t *rgb_panel = __containerof((esp_lcd_panel_t *)self->panel_handle, rgb_panel_t, base); |
476 | | - |
477 | | - self->active_fb = rgb_panel->fbs[1]; |
478 | | - self->idle_fb = rgb_panel->fbs[0]; |
479 | | - |
480 | | - rgb_bus_lock_init(&self->copy_lock); |
481 | | - rgb_bus_lock_init(&self->tx_color_lock); |
482 | | - rgb_bus_event_init(&self->copy_task_exit); |
483 | | - rgb_bus_event_init(&self->swap_bufs); |
484 | | - rgb_bus_lock_init(&self->swap_lock); |
485 | 428 |
|
486 | 429 | xTaskCreatePinnedToCore( |
487 | 430 | rgb_bus_copy_task, "rgb_task", DEFAULT_STACK_SIZE / sizeof(StackType_t), |
488 | 431 | self, ESP_TASK_PRIO_MAX - 1, &self->copy_task_handle, 0); |
489 | 432 |
|
490 | | - return LCD_OK; |
| 433 | + rgb_bus_lock_acquire(&self->init_lock, -1); |
| 434 | + rgb_bus_lock_release(&self->init_lock); |
| 435 | + rgb_bus_lock_delete(&self->init_lock); |
| 436 | + |
| 437 | + if (self->init_err != LCD_OK) { |
| 438 | + mp_raise_msg_varg(&mp_type_ValueError, self->init_err_msg, self->init_err); |
| 439 | + return self->init_err; |
| 440 | + } else { |
| 441 | + return LCD_OK; |
| 442 | + } |
491 | 443 | } |
492 | 444 |
|
493 | 445 |
|
|
528 | 480 | return LCD_OK; |
529 | 481 | } |
530 | 482 |
|
| 483 | +#if LCD_RGB_OPTIMUM_FB_SIZE |
| 484 | + |
| 485 | + static void rgb_bus_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) |
| 486 | + { |
| 487 | + mp_lcd_rgb_bus_obj_t *self = MP_OBJ_TO_PTR(self_in); |
| 488 | + |
| 489 | + if (attr == MP_QSTR_avg_flushes_per_update) { |
| 490 | + if (dest[0] == MP_OBJ_NULL) { |
| 491 | + uint32_t total = 0; |
| 492 | + |
| 493 | + rgb_bus_lock_acquire(&self->optimum_fb.lock, -1); |
| 494 | + for (uint8_t i=0;i<self->optimum_fb.sample_count;i++) { |
| 495 | + total += (uint32_t)self->optimum_fb.samples[i]; |
| 496 | + } |
| 497 | + |
| 498 | + uint16_t avg = (uint16_t)(total / (uint32_t)self->optimum_fb.sample_count); |
| 499 | + |
| 500 | + rgb_bus_lock_release(&self->optimum_fb.lock); |
| 501 | + |
| 502 | + dest[0] = mp_obj_new_int_from_uint(avg); |
| 503 | + } else if (dest[1]) { |
| 504 | + uint16_t value = (uint16_t)mp_obj_get_int_truncated(dest[1]); |
| 505 | + |
| 506 | + if (value == 0) { |
| 507 | + rgb_bus_lock_acquire(&self->optimum_fb.lock, -1); |
| 508 | + for (uint8_t i=0;i<self->optimum_fb.sample_count;i++) { |
| 509 | + self->optimum_fb.samples[i] = 0; |
| 510 | + } |
| 511 | + |
| 512 | + self->optimum_fb.sample_count = 0; |
| 513 | + self->optimum_fb.curr_index = 254; |
| 514 | + rgb_bus_lock_release(&self->optimum_fb.lock); |
| 515 | + |
| 516 | + dest[0] = MP_OBJ_NULL; |
| 517 | + } |
| 518 | + } |
| 519 | + } else if (dest[0] == MP_OBJ_NULL) { |
| 520 | + const mp_obj_type_t *type = mp_obj_get_type(self_in); |
| 521 | + while (MP_OBJ_TYPE_HAS_SLOT(type, locals_dict)) { |
| 522 | + // generic method lookup |
| 523 | + // this is a lookup in the object (ie not class or type) |
| 524 | + assert(MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->base.type == &mp_type_dict); // MicroPython restriction, for now |
| 525 | + mp_map_t *locals_map = &MP_OBJ_TYPE_GET_SLOT(type, locals_dict)->map; |
| 526 | + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); |
| 527 | + if (elem != NULL) { |
| 528 | + mp_convert_member_lookup(self_in, type, elem->value, dest); |
| 529 | + break; |
| 530 | + } |
| 531 | + if (MP_OBJ_TYPE_GET_SLOT_OR_NULL(type, parent) == NULL) break; |
| 532 | + // search parents |
| 533 | + type = MP_OBJ_TYPE_GET_SLOT(type, parent); |
| 534 | + } |
| 535 | + } |
| 536 | + } |
| 537 | +#endif |
| 538 | + |
531 | 539 | MP_DEFINE_CONST_OBJ_TYPE( |
532 | 540 | mp_lcd_rgb_bus_type, |
533 | 541 | MP_QSTR_RGBBus, |
534 | 542 | MP_TYPE_FLAG_NONE, |
535 | 543 | make_new, mp_lcd_rgb_bus_make_new, |
| 544 | + #if LCD_RGB_OPTIMUM_FB_SIZE |
| 545 | + attr, rgb_bus_attr, |
| 546 | + #endif |
536 | 547 | locals_dict, (mp_obj_dict_t *)&mp_lcd_bus_locals_dict |
537 | 548 | ); |
| 549 | + |
538 | 550 | #else |
539 | 551 | #include "../common_src/rgb_bus.c" |
540 | 552 |
|
|
0 commit comments