3535#include "esp_private/esp_dma_utils.h"
3636#include "esp_private/periph_ctrl.h"
3737#include "esp_private/gpio.h"
38+ #include "esp_private/esp_gpio_reserve.h"
3839#include "esp_psram.h"
3940#include "esp_lcd_common.h"
4041#include "esp_cache.h"
@@ -90,6 +91,7 @@ static esp_err_t lcd_rgb_panel_select_clock_src(esp_rgb_panel_t *rgb_panel, lcd_
9091static esp_err_t lcd_rgb_create_dma_channel (esp_rgb_panel_t * rgb_panel );
9192static esp_err_t lcd_rgb_panel_init_trans_link (esp_rgb_panel_t * rgb_panel );
9293static esp_err_t lcd_rgb_panel_configure_gpio (esp_rgb_panel_t * rgb_panel , const esp_lcd_rgb_panel_config_t * panel_config );
94+ static void lcd_rgb_panel_release_gpio (esp_rgb_panel_t * rgb_panel );
9395static void lcd_rgb_panel_start_transmission (esp_rgb_panel_t * rgb_panel );
9496static void rgb_lcd_default_isr_handler (void * args );
9597
@@ -102,7 +104,6 @@ struct esp_rgb_panel_t {
102104 size_t num_fbs ; // Number of frame buffers
103105 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
104106 size_t dma_burst_size ; // DMA transfer burst size
105- int disp_gpio_num ; // Display control GPIO, which is used to perform action like "disp_off"
106107 intr_handle_t intr ; // LCD peripheral interrupt handle
107108#if CONFIG_PM_ENABLE
108109 esp_pm_lock_handle_t pm_lock ; // Power management lock
@@ -122,7 +123,13 @@ struct esp_rgb_panel_t {
122123 uint8_t bb_fb_index ; // Current frame buffer index which used by bounce buffer
123124 size_t int_mem_align ; // DMA buffer alignment for internal memory
124125 size_t ext_mem_align ; // DMA buffer alignment for external memory
126+ int hsync_gpio_num ; // GPIO used for HSYNC signal
127+ int vsync_gpio_num ; // GPIO used for VSYNC signal
128+ int de_gpio_num ; // GPIO used for DE signal, set to -1 if it's not used
129+ int pclk_gpio_num ; // GPIO used for PCLK signal, set to -1 if it's not used
130+ int disp_gpio_num ; // GPIO used for display control signal, set to -1 if it's not used
125131 int data_gpio_nums [SOC_LCDCAM_RGB_DATA_WIDTH ]; // GPIOs used for data lines, we keep these GPIOs for action like "invert_color"
132+ uint64_t gpio_reserve_mask ; // GPIOs reserved by this panel, used to revoke the GPIO reservation when the panel is deleted
126133 uint32_t src_clk_hz ; // Peripheral source clock resolution
127134 esp_lcd_rgb_timing_t timings ; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
128135 int bounce_pos_px ; // Position in whatever source material is used for the bounce buffer, in pixels
@@ -198,6 +205,8 @@ static esp_err_t lcd_rgb_panel_alloc_frame_buffers(esp_rgb_panel_t *rgb_panel)
198205
199206static esp_err_t lcd_rgb_panel_destroy (esp_rgb_panel_t * rgb_panel )
200207{
208+ // ensure the HW state machine is stopped
209+ lcd_ll_stop (rgb_panel -> hal .dev );
201210 LCD_CLOCK_SRC_ATOMIC () {
202211 lcd_ll_enable_clock (rgb_panel -> hal .dev , false);
203212 }
@@ -209,6 +218,8 @@ static esp_err_t lcd_rgb_panel_destroy(esp_rgb_panel_t *rgb_panel)
209218 }
210219 lcd_com_remove_device (LCD_COM_DEVICE_TYPE_RGB , rgb_panel -> panel_id );
211220 }
221+ // release the GPIOs
222+ lcd_rgb_panel_release_gpio (rgb_panel );
212223 if (rgb_panel -> dma_chan ) {
213224 gdma_disconnect (rgb_panel -> dma_chan );
214225 gdma_del_channel (rgb_panel -> dma_chan );
@@ -356,10 +367,14 @@ esp_err_t esp_lcd_new_rgb_panel(const esp_lcd_rgb_panel_config_t *rgb_panel_conf
356367 ESP_GOTO_ON_ERROR (ret , err , TAG , "configure GPIO failed" );
357368 // fill other rgb panel runtime parameters
358369 memcpy (rgb_panel -> data_gpio_nums , rgb_panel_config -> data_gpio_nums , sizeof (rgb_panel -> data_gpio_nums ));
370+ rgb_panel -> disp_gpio_num = rgb_panel_config -> disp_gpio_num ;
371+ rgb_panel -> de_gpio_num = rgb_panel_config -> de_gpio_num ;
372+ rgb_panel -> hsync_gpio_num = rgb_panel_config -> hsync_gpio_num ;
373+ rgb_panel -> vsync_gpio_num = rgb_panel_config -> vsync_gpio_num ;
374+ rgb_panel -> pclk_gpio_num = rgb_panel_config -> pclk_gpio_num ;
359375 rgb_panel -> timings = rgb_panel_config -> timings ;
360376 rgb_panel -> data_width = rgb_panel_config -> data_width ;
361377 rgb_panel -> output_bits_per_pixel = fb_bits_per_pixel ; // by default, the output bpp is the same as the frame buffer bpp
362- rgb_panel -> disp_gpio_num = rgb_panel_config -> disp_gpio_num ;
363378 rgb_panel -> flags .disp_en_level = !rgb_panel_config -> flags .disp_active_low ;
364379 rgb_panel -> spinlock = (portMUX_TYPE )portMUX_INITIALIZER_UNLOCKED ;
365380 // fill function table
@@ -742,47 +757,92 @@ static esp_err_t rgb_panel_disp_on_off(esp_lcd_panel_t *panel, bool on_off)
742757
743758static esp_err_t lcd_rgb_panel_configure_gpio (esp_rgb_panel_t * rgb_panel , const esp_lcd_rgb_panel_config_t * panel_config )
744759{
760+ uint64_t gpio_reserve_mask = 0 ;
745761 int panel_id = rgb_panel -> panel_id ;
746762 // Set the number of output data lines
747763 lcd_ll_set_data_wire_width (rgb_panel -> hal .dev , panel_config -> data_width );
748764 // connect peripheral signals via GPIO matrix
749765 for (size_t i = 0 ; i < panel_config -> data_width ; i ++ ) {
750766 if (panel_config -> data_gpio_nums [i ] >= 0 ) {
751- gpio_func_sel (panel_config -> data_gpio_nums [i ], PIN_FUNC_GPIO );
752- esp_rom_gpio_connect_out_signal ( panel_config -> data_gpio_nums [ i ],
753- lcd_periph_rgb_signals . panels [ panel_id ]. data_sigs [ i ], false, false );
767+ gpio_matrix_output (panel_config -> data_gpio_nums [i ],
768+ lcd_periph_rgb_signals . panels [ panel_id ]. data_sigs [ i ], false, false);
769+ gpio_reserve_mask |= ( 1 << panel_config -> data_gpio_nums [ i ] );
754770 }
755771 }
756772 if (panel_config -> hsync_gpio_num >= 0 ) {
757- gpio_func_sel (panel_config -> hsync_gpio_num , PIN_FUNC_GPIO );
758- esp_rom_gpio_connect_out_signal ( panel_config -> hsync_gpio_num ,
759- lcd_periph_rgb_signals . panels [ panel_id ]. hsync_sig , false, false );
773+ gpio_matrix_output (panel_config -> hsync_gpio_num ,
774+ lcd_periph_rgb_signals . panels [ panel_id ]. hsync_sig , false, false);
775+ gpio_reserve_mask |= ( 1 << panel_config -> hsync_gpio_num );
760776 }
761777 if (panel_config -> vsync_gpio_num >= 0 ) {
762- gpio_func_sel (panel_config -> vsync_gpio_num , PIN_FUNC_GPIO );
763- esp_rom_gpio_connect_out_signal ( panel_config -> vsync_gpio_num ,
764- lcd_periph_rgb_signals . panels [ panel_id ]. vsync_sig , false, false );
778+ gpio_matrix_output (panel_config -> vsync_gpio_num ,
779+ lcd_periph_rgb_signals . panels [ panel_id ]. vsync_sig , false, false);
780+ gpio_reserve_mask |= ( 1 << panel_config -> vsync_gpio_num );
765781 }
766782 // PCLK may not be necessary in some cases (i.e. VGA output)
767783 if (panel_config -> pclk_gpio_num >= 0 ) {
768- gpio_func_sel (panel_config -> pclk_gpio_num , PIN_FUNC_GPIO );
769- esp_rom_gpio_connect_out_signal ( panel_config -> pclk_gpio_num ,
770- lcd_periph_rgb_signals . panels [ panel_id ]. pclk_sig , false, false );
784+ gpio_matrix_output (panel_config -> pclk_gpio_num ,
785+ lcd_periph_rgb_signals . panels [ panel_id ]. pclk_sig , false, false);
786+ gpio_reserve_mask |= ( 1 << panel_config -> pclk_gpio_num );
771787 }
772788 // DE signal might not be necessary for some RGB LCD
773789 if (panel_config -> de_gpio_num >= 0 ) {
774- gpio_func_sel (panel_config -> de_gpio_num , PIN_FUNC_GPIO );
775- esp_rom_gpio_connect_out_signal ( panel_config -> de_gpio_num ,
776- lcd_periph_rgb_signals . panels [ panel_id ]. de_sig , false, false );
790+ gpio_matrix_output (panel_config -> de_gpio_num ,
791+ lcd_periph_rgb_signals . panels [ panel_id ]. de_sig , false, false);
792+ gpio_reserve_mask |= ( 1 << panel_config -> de_gpio_num );
777793 }
778794 // disp enable GPIO is optional, it is a general purpose output GPIO
779795 if (panel_config -> disp_gpio_num >= 0 ) {
780- gpio_func_sel (panel_config -> disp_gpio_num , PIN_FUNC_GPIO );
781- gpio_output_enable (panel_config -> disp_gpio_num );
796+ gpio_matrix_output (panel_config -> disp_gpio_num ,
797+ lcd_periph_rgb_signals .panels [panel_id ].disp_sig , false, false);
798+ gpio_reserve_mask |= (1 << panel_config -> disp_gpio_num );
799+ }
800+
801+ // reserve the GPIOs
802+ uint64_t busy_mask = esp_gpio_reserve (gpio_reserve_mask );
803+ uint64_t conflict_mask = busy_mask & gpio_reserve_mask ;
804+ for (; conflict_mask > 0 ;) {
805+ uint8_t pos = __builtin_ctzll (conflict_mask );
806+ conflict_mask &= ~(1ULL << pos );
807+ ESP_LOGW (TAG , "GPIO %d is not usable, maybe is reserved by others" , pos );
782808 }
809+
810+ rgb_panel -> gpio_reserve_mask = gpio_reserve_mask ;
783811 return ESP_OK ;
784812}
785813
814+ static void lcd_rgb_panel_release_gpio (esp_rgb_panel_t * rgb_panel )
815+ {
816+ if (rgb_panel -> gpio_reserve_mask ) {
817+ // disconnect the GPIOs from the LCD signals
818+ for (size_t i = 0 ; i < rgb_panel -> data_width ; i ++ ) {
819+ if (rgb_panel -> data_gpio_nums [i ] >= 0 ) {
820+ gpio_output_disable (rgb_panel -> data_gpio_nums [i ]);
821+ }
822+ }
823+ if (rgb_panel -> hsync_gpio_num >= 0 ) {
824+ gpio_output_disable (rgb_panel -> hsync_gpio_num );
825+ }
826+ if (rgb_panel -> vsync_gpio_num >= 0 ) {
827+ gpio_output_disable (rgb_panel -> vsync_gpio_num );
828+ }
829+ // PCLK may not be necessary in some cases (i.e. VGA output)
830+ if (rgb_panel -> pclk_gpio_num >= 0 ) {
831+ gpio_output_disable (rgb_panel -> pclk_gpio_num );
832+ }
833+ // DE signal might not be necessary for some RGB LCD
834+ if (rgb_panel -> de_gpio_num >= 0 ) {
835+ gpio_output_disable (rgb_panel -> de_gpio_num );
836+ }
837+ // disp enable GPIO is optional, it is a general purpose output GPIO
838+ if (rgb_panel -> disp_gpio_num >= 0 ) {
839+ gpio_output_disable (rgb_panel -> disp_gpio_num );
840+ }
841+ // release the IOs so they can be used by others again
842+ esp_gpio_revoke (rgb_panel -> gpio_reserve_mask );
843+ }
844+ }
845+
786846static esp_err_t lcd_rgb_panel_select_clock_src (esp_rgb_panel_t * rgb_panel , lcd_clock_source_t clk_src )
787847{
788848 // get clock source frequency
0 commit comments