#include #include #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_timer.h" #include "esp_lcd_panel_io_i80_hub75.h" #include "esp_lcd_panel_ops.h" #include "driver/gpio.h" #include "esp_err.h" #include "esp_log.h" #include "esp_rom_sys.h" static const char *TAG = "led matrix"; #define HUB75_CLOCK_HZ (10 * 1000 * 1000) #define HUB75_COL_COUNT (64) #define HUB75_ROW_COUNT (32) #define HUB75_COL_UNIT_COUNT (32) /* 实际扫描的时候送入数据的列数 */ #define HUB75_SCAN_LINE_CNT (16) /* 多少扫的 */ #define HUB75_LINE_ADDR_A_PIN_NUM 33 #define HUB75_LINE_ADDR_B_PIN_NUM 34 #define HUB75_LINE_ADDR_C_PIN_NUM 35 #define HUB75_LINE_ADDR_D_PIN_NUM 36 #define HUB75_LAT_PIN_NUM 8 #define HUB75_OE_PIN_NUM 21 #define HUB75_CLK_PIN_NUM 7 #define HUB75_G0 1 #define HUB75_R0 2 #define HUB75_B0 3 #define HUB75_G1 4 #define HUB75_R1 5 #define HUB75_B1 6 #define HUB75_G2 37 #define HUB75_R2 38 #define HUB75_B2 39 #define HUB75_G3 40 #define HUB75_R3 41 #define HUB75_B3 42 //#define LVGL_TICK_PERIOD_MS 2 #define LINE_SCAN_LOOP_PERIOD_MS 1000 /* 暂时测试用 */ #define LINE_SCAN_CNT 8 /* 用于全彩显示,RGB323色彩,最宽3bit取值0-7,需要扫描8次进行灰度调节 */ #define PSRAM_DATA_ALIGNMENT 64 #define get_rgb_one_value(n, x) (n < (x) ? 1 : 0) /* 判断r、g、b其中一个本次是否应该点亮 */ /* 输入一个byte,从高到低:r 3bit, g 2bit, b 3bit */ /* 输出一个3bit值,从高到低:b, g, r */ #define get_rgb_value(n, x) (get_rgb_one_value(n, (x >> 5) & 0x07) | (get_rgb_one_value(n, (x >> 3) & 0x03) << 1) | (get_rgb_one_value(n, x & 0x07) << 2)) typedef unsigned char uint8_t; typedef unsigned short int uint16_t; uint8_t ledbuf[HUB75_ROW_COUNT][HUB75_COL_COUNT]; static int line = 0; /* 本次扫描行,32行16扫,一次显示两行 */ void get_one_line(int *line_ret, uint16_t *line_data) { int i; static int line_scan_cnt = 0; /* 本行已经扫描多少次,8次 */ /* 准备一行数据 */ for (i = 0; i < HUB75_COL_UNIT_COUNT; i++) { /* 后面的注释为bit从低到高,对应i80总线的数据线 */ line_data[i] = get_rgb_value(line_scan_cnt, ledbuf[line][i]) | /* r0, g0, b0 */ (get_rgb_value(line_scan_cnt, ledbuf[line + HUB75_SCAN_LINE_CNT][i]) << 3) | /* r1, g1, b1 */ (get_rgb_value(line_scan_cnt, ledbuf[line][i + HUB75_COL_UNIT_COUNT]) << 6) | /* r2, g2, b2 */ (get_rgb_value(line_scan_cnt, ledbuf[line + HUB75_SCAN_LINE_CNT][i + HUB75_COL_UNIT_COUNT]) << 9); /* r3, g3, b3 */ } *line_ret = line; /* 更新索引 */ line_scan_cnt++; if (line_scan_cnt >= HUB75_SCAN_LINE_CNT) line ++; if (line >= HUB75_SCAN_LINE_CNT) { line = 0; line_scan_cnt = 0; } } static void line_scan_loop_cb(void *args) { int line; uint16_t line_data[HUB75_COL_UNIT_COUNT]; esp_lcd_panel_io_handle_t io_handle = (esp_lcd_panel_io_handle_t)args; get_one_line(&line, line_data); esp_lcd_panel_io_tx_color(io_handle, -1, line_data, sizeof(line_data)); /* 发送行数据 */ } static bool line_trans_done_cb(esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_event_data_t *edata, void *user_ctx) { // gpio_set_level(HUB75_OE_PIN_NUM, 1); /* 失能显示 */ // gpio_set_level(HUB75_LINE_ADDR_A_PIN_NUM, line & 1); /* 行地址,A是低位(待求证) */ // gpio_set_level(HUB75_LINE_ADDR_B_PIN_NUM, (line >> 1) & 1); // gpio_set_level(HUB75_LINE_ADDR_C_PIN_NUM, (line >> 2) & 1); // gpio_set_level(HUB75_LINE_ADDR_D_PIN_NUM, (line >> 3) & 1); // gpio_set_level(HUB75_LAT_PIN_NUM, 1); /* 锁存拉高 */ // vTaskDelay(pdMS_TO_TICKS(1)); // gpio_set_level(HUB75_LAT_PIN_NUM, 0); /* 拉低锁存,下降沿锁存 */ // gpio_set_level(HUB75_OE_PIN_NUM, 0); /* 使能显示 */ // ESP_LOGI(TAG, "line trans done"); return false; } void app_main(void) { /* 8080总线配置 */ ESP_LOGI(TAG, "Initialize Intel 8080 bus"); esp_lcd_i80_hub75_bus_handle_t i80_bus = NULL; esp_lcd_i80_hub75_bus_config_t bus_config = { .clk_src = HUB75_CLK_PIN_NUM, .dc_gpio_num = -1, .wr_gpio_num = HUB75_CLK_PIN_NUM, .data_gpio_nums = { HUB75_R0, HUB75_G0, HUB75_B0, HUB75_R1, HUB75_G1, HUB75_B1, HUB75_R2, HUB75_G2, HUB75_B2, HUB75_R3, HUB75_G3, HUB75_B3, -1, -1, -1, -1, }, .bus_width = 16, .max_transfer_bytes = HUB75_COL_COUNT * sizeof(uint16_t), /* 每次发一行 */ .psram_trans_align = PSRAM_DATA_ALIGNMENT, .sram_trans_align = 4, }; ESP_ERROR_CHECK(esp_lcd_new_i80_hub75_bus(&bus_config, &i80_bus)); /* 8080IO设备申请 */ esp_lcd_panel_io_handle_t io_handle = NULL; esp_lcd_panel_io_i80_hub75_config_t io_config = { .cs_gpio_num = -1, .pclk_hz = HUB75_CLOCK_HZ, .trans_queue_depth = 10, // .dc_levels = { // .dc_idle_level = 0, // .dc_cmd_level = 0, // .dc_dummy_level = 0, // .dc_data_level = 1, // }, .flags = { // .swap_color_bytes = !LV_COLOR_16_SWAP, // Swap can be done in LvGL (default) or DMA .pclk_idle_low = 1, }, .on_color_trans_done = NULL, .user_ctx = NULL, .lcd_cmd_bits = 0, .lcd_param_bits = 0, }; ESP_ERROR_CHECK(esp_lcd_new_panel_io_i80_hub75(i80_bus, &io_config, &io_handle)); /* 控制引脚GPIO初始化 */ gpio_config_t io_conf = { .mode = GPIO_MODE_OUTPUT, .pin_bit_mask = (1ULL << HUB75_LAT_PIN_NUM) | (1ULL << HUB75_OE_PIN_NUM) | (1ULL << HUB75_LINE_ADDR_A_PIN_NUM) | (1ULL << HUB75_LINE_ADDR_B_PIN_NUM) | (1ULL << HUB75_LINE_ADDR_C_PIN_NUM) | (1ULL << HUB75_LINE_ADDR_D_PIN_NUM), }; ESP_ERROR_CHECK(gpio_config(&io_conf)); // /* 定时进行行扫描 */ // ESP_LOGI(TAG, "Create a timer to do line scan"); // const esp_timer_create_args_t periodic_timer_args = { // .callback = line_scan_loop_cb, // .arg = io_handle, // .name = "line_scan_loop" // }; // esp_timer_handle_t line_scan_loop_timer = NULL; // ESP_ERROR_CHECK(esp_timer_create(&periodic_timer_args, &line_scan_loop_timer)); // ESP_ERROR_CHECK(esp_timer_start_periodic(line_scan_loop_timer, LINE_SCAN_LOOP_PERIOD_MS * 1000)); // gpio_set_level(HUB75_OE_PIN_NUM, 1); /* 使能显示 */ while (1) { /* 测试,发送一次数据 */ ESP_LOGI(TAG, "Test send data to LCD"); /* HUB75_COL_COUNT */ int i = 0; uint16_t color_data[128] = {0}; // for (i = 0; i < 64; i++) color_data[0] = 0x9; /* 红 */ color_data[1] = 0x12; /* 绿 */ color_data[2] = 0x24; /* 蓝 */ color_data[64 + 0] = 0x24; /* 红 */ color_data[64 + 1] = 0x12; /* 绿 */ color_data[64 + 2] = 0x9; /* 蓝 */ esp_lcd_panel_io_tx_color(io_handle, -1, color_data, sizeof(color_data)); vTaskDelay(pdMS_TO_TICKS(1000)); ESP_LOGI(TAG, "line trans done"); gpio_set_level(HUB75_OE_PIN_NUM, 1); /* 失能显示 */ gpio_set_level(HUB75_LAT_PIN_NUM, 1); /* 锁存拉高 */ vTaskDelay(pdMS_TO_TICKS(1)); gpio_set_level(HUB75_LAT_PIN_NUM, 0); /* 拉低锁存,下降沿锁存 */ gpio_set_level(HUB75_LINE_ADDR_A_PIN_NUM, line & 1); /* 行地址,A是低位(待求证) */ gpio_set_level(HUB75_LINE_ADDR_B_PIN_NUM, (line >> 1) & 1); gpio_set_level(HUB75_LINE_ADDR_C_PIN_NUM, (line >> 2) & 1); gpio_set_level(HUB75_LINE_ADDR_D_PIN_NUM, (line >> 3) & 1); line ++; gpio_set_level(HUB75_OE_PIN_NUM, 0); /* 使能显示 */ vTaskDelay(pdMS_TO_TICKS(1000)); } }