lcd_st7701.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. #include "lcd_st7701.h"
  2. #include "esp_log.h"
  3. #include "esp_heap_caps.h"
  4. #include "driver/i2c.h"
  5. #include "driver/spi_master.h"
  6. #include "esp_lcd_panel_ops.h"
  7. #include "esp_lcd_panel_io.h"
  8. #include "esp_lcd_panel_io_additions.h"
  9. #include "esp_lcd_st7701.h"
  10. #include "esp_lcd_touch.h"
  11. #include "lvgl_port.h"
  12. static const char *TAG = "lcd_st7701";
  13. static bool backlight_status = false;
  14. #define SCREEN_FACTORY_YY // 鱼鹰屏
  15. // #define SCREEN_FACTORY_HM // 禾木屏
  16. #ifdef SCREEN_FACTORY_HM
  17. #include "esp_lcd_touch_gt911.h"
  18. #endif
  19. #ifdef SCREEN_FACTORY_YY
  20. #include "esp_lcd_touch_ft5x06.h"
  21. #endif
  22. // LCD初始化命令
  23. static const st7701_lcd_init_cmd_t lcd_init_cmds[] = {
  24. // {cmd, { data }, data_size, delay_ms}
  25. #ifdef SCREEN_FACTORY_HM
  26. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
  27. {0xC0, (uint8_t[]) {0x3B, 0x00}, 2, 0},
  28. {0xC1, (uint8_t[]) {0x0D, 0x02}, 2, 0},
  29. {0xC2, (uint8_t[]) {0x31, 0x05}, 2, 0},
  30. {0xCD, (uint8_t[]) {0x08}, 1, 0},
  31. {0xB0,
  32. (uint8_t[]) {0x00, 0x11, 0x18, 0x0E, 0x11, 0x06, 0x07, 0x08, 0x07, 0x22, 0x04, 0x12, 0x0F, 0xAA, 0x31, 0x18},
  33. 16, 0},
  34. {0xB1,
  35. (uint8_t[]) {0x00, 0x11, 0x19, 0x0E, 0x12, 0x07, 0x08, 0x08, 0x08, 0x22, 0x04, 0x11, 0x11, 0xA9, 0x32, 0x18},
  36. 16, 0},
  37. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
  38. {0xB0, (uint8_t[]) {0x60}, 1, 0},
  39. {0xB1, (uint8_t[]) {0x32}, 1, 0},
  40. {0xB2, (uint8_t[]) {0x07}, 1, 0},
  41. {0xB3, (uint8_t[]) {0x80}, 1, 0},
  42. {0xB5, (uint8_t[]) {0x49}, 1, 0},
  43. {0xB7, (uint8_t[]) {0x85}, 1, 0},
  44. {0xB8, (uint8_t[]) {0x21}, 1, 0},
  45. {0xC1, (uint8_t[]) {0x78}, 1, 0},
  46. {0xC2, (uint8_t[]) {0x78}, 1, 0},
  47. {0xE0, (uint8_t[]) {0x00, 0x1B, 0x02}, 3, 0},
  48. {0xE1, (uint8_t[]) {0x08, 0xA0, 0x00, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0},
  49. {0xE2, (uint8_t[]) {0x11, 0x11, 0x44, 0x44, 0xED, 0xA0, 0x00, 0x00, 0xEC, 0xA0, 0x00, 0x00}, 12, 0},
  50. {0xE3, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
  51. {0xE4, (uint8_t[]) {0x44, 0x44}, 2, 0},
  52. {0xE5,
  53. (uint8_t[]) {0x0A, 0xE9, 0xD8, 0xA0, 0x0C, 0xEB, 0xD8, 0xA0, 0x0E, 0xED, 0xD8, 0xA0, 0x10, 0xEF, 0xD8, 0xA0},
  54. 16, 0},
  55. {0xE6, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
  56. {0xE7, (uint8_t[]) {0x44, 0x44}, 2, 0},
  57. {0xE8,
  58. (uint8_t[]) {0x09, 0xE8, 0xD8, 0xA0, 0x0B, 0xEA, 0xD8, 0xA0, 0x0D, 0xEC, 0xD8, 0xA0, 0x0F, 0xEE, 0xD8, 0xA0},
  59. 16, 0},
  60. {0xEB, (uint8_t[]) {0x02, 0x00, 0xE4, 0xE4, 0x88, 0x00, 0x40}, 7, 0},
  61. {0xEC, (uint8_t[]) {0x3C, 0x00}, 2, 0},
  62. {0xED,
  63. (uint8_t[]) {0xAB, 0x89, 0x76, 0x54, 0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 0x45, 0x67, 0x98, 0xBA},
  64. 16, 0},
  65. {0x36, (uint8_t[]) {0x00}, 1, 0},
  66. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
  67. {0xE5, (uint8_t[]) {0xE4}, 1, 0},
  68. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x00}, 5, 0},
  69. {0x3A, (uint8_t[]) {0x60}, 1, 0},
  70. {0x20, (uint8_t[]) {}, 0, 0},
  71. {0x11, (uint8_t[]) {}, 0, 100},
  72. {0x29, (uint8_t[]) {}, 0, 50}
  73. #endif
  74. #ifdef SCREEN_FACTORY_YY
  75. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x13}, 5, 0},
  76. {0xEF, (uint8_t[]) {0x08}, 1, 0},
  77. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x10}, 5, 0},
  78. {0xC0, (uint8_t[]) {0x3B, 0x00}, 2, 0},
  79. {0xC1, (uint8_t[]) {0x0B, 0x02}, 2, 0},
  80. {0xC2, (uint8_t[]) {0x37, 0x02}, 2, 0},
  81. {0xCC, (uint8_t[]) {0x10}, 1, 0},
  82. {0xB0,
  83. (uint8_t[]) {0x00, 0x0F, 0x16, 0x0E, 0x11, 0x07, 0x09, 0x09, 0x08, 0x23, 0x05, 0x11, 0x0F, 0x28, 0x2D, 0x18},
  84. 16, 0},
  85. {0xB1,
  86. (uint8_t[]) {0x00, 0x0F, 0x16, 0x0E, 0x11, 0x07, 0x09, 0x08, 0x09, 0x23, 0x05, 0x11, 0x0F, 0x28, 0x2D, 0x18},
  87. 16, 0},
  88. {0xFF, (uint8_t[]) {0x77, 0x01, 0x00, 0x00, 0x11}, 5, 0},
  89. {0xB0, (uint8_t[]) {0x4D}, 1, 0},
  90. {0xB1, (uint8_t[]) {0x33}, 1, 0},
  91. {0xB2, (uint8_t[]) {0x87}, 1, 0},
  92. {0xB5, (uint8_t[]) {0x4B}, 1, 0},
  93. {0xB7, (uint8_t[]) {0x8C}, 1, 0},
  94. {0xB8, (uint8_t[]) {0x20}, 1, 0},
  95. {0xC1, (uint8_t[]) {0x78}, 1, 0},
  96. {0xC2, (uint8_t[]) {0x78}, 1, 0},
  97. {0xD0, (uint8_t[]) {0x88}, 1, 0},
  98. {0xE0, (uint8_t[]) {0x00, 0x00, 0x02}, 3, 0},
  99. {0xE1, (uint8_t[]) {0x02, 0xF0, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x44, 0x44}, 11, 0},
  100. {0xE2, (uint8_t[]) {0x10, 0x10, 0x40, 0x40, 0xF2, 0xF0, 0x00, 0x00, 0xF2, 0xF0, 0x00, 0x00}, 12, 0},
  101. {0xE3, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
  102. {0xE4, (uint8_t[]) {0x44, 0x44}, 2, 0},
  103. {0xE5,
  104. (uint8_t[]) {0x07, 0xEF, 0xF0, 0xF0, 0x09, 0xF1, 0xF0, 0xF0, 0x03, 0xF3, 0xF0, 0xF0, 0x05, 0xED, 0xF0, 0xF0},
  105. 16, 0},
  106. {0xE6, (uint8_t[]) {0x00, 0x00, 0x11, 0x11}, 4, 0},
  107. {0xE7, (uint8_t[]) {0x44, 0x44}, 2, 0},
  108. {0xE8,
  109. (uint8_t[]) {0x08, 0xF0, 0xF0, 0xF0, 0x0A, 0xF2, 0xF0, 0xF0, 0x04, 0xF4, 0xF0, 0xF0, 0x06, 0xEE, 0xF0, 0xF0},
  110. 16, 0},
  111. {0xEB, (uint8_t[]) {0x00, 0x00, 0xE4, 0xE4, 0x44, 0x88, 0x40}, 7, 0},
  112. {0xEC, (uint8_t[]) {0x78, 0x00}, 2, 0},
  113. {0xED,
  114. (uint8_t[]) {0x20, 0xF9, 0x87, 0x76, 0x65, 0x54, 0x4F, 0xFF, 0xFF, 0xF4, 0x45, 0x56, 0x67, 0x78, 0x9F, 0x02},
  115. 16, 0},
  116. {0xEF, (uint8_t[]) {0x10, 0x0D, 0x04, 0x08, 0x3F, 0x1F}, 6, 0},
  117. // 退出睡眠模式和开启显示的命令保持不变
  118. {0x11, (uint8_t[]) {0x00}, 0, 120}, // Sleep Out
  119. {0x29, (uint8_t[]) {0x00}, 0, 0}, // Display On
  120. #endif
  121. };
  122. static void spi_soft_init(void) {
  123. gpio_config_t io_conf1 = {
  124. .mode = GPIO_MODE_OUTPUT,
  125. .pin_bit_mask = 1ULL << LCD_IO_SPI_CS,
  126. };
  127. gpio_config(&io_conf1);
  128. gpio_set_level(LCD_IO_SPI_CS, 1);
  129. gpio_config_t io_conf2 = {
  130. .mode = GPIO_MODE_OUTPUT,
  131. .pin_bit_mask = 1ULL << LCD_IO_SPI_SCL,
  132. };
  133. gpio_config(&io_conf2);
  134. gpio_set_level(LCD_IO_SPI_SCL, 1);
  135. gpio_config_t io_conf3 = {
  136. .mode = GPIO_MODE_OUTPUT,
  137. .pin_bit_mask = 1ULL << LCD_IO_SPI_SDA,
  138. };
  139. gpio_config(&io_conf3);
  140. gpio_set_level(LCD_IO_SPI_SDA, 1);
  141. }
  142. static void spi_soft_write_9bits(uint16_t data) {
  143. uint8_t i;
  144. LCD_CS_Clr();
  145. for (i = 0; i < 9; i++) {
  146. LCD_SCK_Clr();
  147. if (data & 0x100) LCD_SDA_Set();
  148. else
  149. LCD_SDA_Clr();
  150. LCD_SCK_Set();
  151. data <<= 1;
  152. }
  153. LCD_CS_Set();;
  154. }
  155. static void st7701_write_cmd(uint8_t cmd) {
  156. uint16_t temp = 0;
  157. temp = temp | cmd;
  158. spi_soft_write_9bits(temp);
  159. }
  160. static void st7701_write_data(uint8_t data) {
  161. uint16_t temp = 0x100;
  162. temp = temp | data;
  163. spi_soft_write_9bits(temp);
  164. }
  165. IRAM_ATTR static bool
  166. rgb_lcd_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) {
  167. // 最小化中断处理时间
  168. return lvgl_port_notify_rgb_vsync();
  169. }
  170. esp_err_t lcd_st7701_init(void) {
  171. // 配置背光GPIO
  172. if (PIN_NUM_BK_LIGHT >= 0) {
  173. gpio_config_t bk_gpio_config = {
  174. .mode = GPIO_MODE_OUTPUT,
  175. .pin_bit_mask = 1ULL << PIN_NUM_BK_LIGHT};
  176. ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
  177. }
  178. // 安装3线SPI面板IO
  179. ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
  180. spi_line_config_t line_config = {
  181. .cs_io_type = IO_TYPE_GPIO,
  182. .cs_gpio_num = LCD_IO_SPI_CS,
  183. .scl_io_type = IO_TYPE_GPIO,
  184. .scl_gpio_num = LCD_IO_SPI_SCL,
  185. .sda_io_type = IO_TYPE_GPIO,
  186. .sda_gpio_num = LCD_IO_SPI_SDA,
  187. .io_expander = NULL,
  188. };
  189. esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
  190. esp_lcd_panel_io_handle_t io_handle = NULL;
  191. ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, &io_handle));
  192. for (int i = 0; i < sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]); i++) {
  193. st7701_write_cmd(lcd_init_cmds[i].cmd);
  194. for (int n = 0; n < lcd_init_cmds[i].data_bytes; n++) {
  195. st7701_write_data(((uint8_t *) lcd_init_cmds[i].data)[n]);
  196. }
  197. vTaskDelay(pdMS_TO_TICKS(lcd_init_cmds[i].delay_ms));
  198. }
  199. // 安装RGB面板
  200. ESP_LOGI(TAG, "Install ST7701 panel driver");
  201. esp_lcd_panel_handle_t lcd_handle = NULL;
  202. esp_lcd_rgb_panel_config_t rgb_config = {
  203. .clk_src = LCD_CLK_SRC_DEFAULT,
  204. .psram_trans_align = 64,
  205. .data_width = RGB_DATA_WIDTH,
  206. .bits_per_pixel = RGB_BIT_PER_PIXEL,
  207. .de_gpio_num = LCD_IO_RGB_DE,
  208. .pclk_gpio_num = LCD_IO_RGB_PCLK,
  209. .vsync_gpio_num = LCD_IO_RGB_VSYNC,
  210. .hsync_gpio_num = LCD_IO_RGB_HSYNC,
  211. .disp_gpio_num = LCD_IO_RGB_DISP,
  212. .data_gpio_nums = {
  213. LCD_IO_RGB_DATA0,
  214. LCD_IO_RGB_DATA1,
  215. LCD_IO_RGB_DATA2,
  216. LCD_IO_RGB_DATA3,
  217. LCD_IO_RGB_DATA4,
  218. LCD_IO_RGB_DATA5,
  219. LCD_IO_RGB_DATA6,
  220. LCD_IO_RGB_DATA7,
  221. LCD_IO_RGB_DATA8,
  222. LCD_IO_RGB_DATA9,
  223. LCD_IO_RGB_DATA10,
  224. LCD_IO_RGB_DATA11,
  225. LCD_IO_RGB_DATA12,
  226. LCD_IO_RGB_DATA13,
  227. LCD_IO_RGB_DATA14,
  228. LCD_IO_RGB_DATA15,
  229. },
  230. .timings = ST7701_480_480_PANEL_60HZ_RGB_TIMING(),
  231. .flags.fb_in_psram = 1,
  232. .num_fbs = LVGL_PORT_LCD_RGB_BUFFER_NUMS,
  233. .bounce_buffer_size_px = RGB_BOUNCE_BUFFER_SIZE,
  234. };
  235. rgb_config.timings.h_res = LCD_H_RES;
  236. rgb_config.timings.v_res = LCD_V_RES;
  237. st7701_vendor_config_t vendor_config = {
  238. .rgb_config = &rgb_config,
  239. .init_cmds = lcd_init_cmds,
  240. .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
  241. .flags = {
  242. .auto_del_panel_io = 0,
  243. .mirror_by_cmd = 1,
  244. },
  245. };
  246. const esp_lcd_panel_dev_config_t panel_config = {
  247. .reset_gpio_num = LCD_IO_RST,
  248. .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
  249. .bits_per_pixel = LCD_BIT_PER_PIXEL,
  250. .vendor_config = &vendor_config,
  251. };
  252. ESP_ERROR_CHECK(esp_lcd_new_panel_st7701(io_handle, &panel_config, &lcd_handle));
  253. ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_handle));
  254. ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_handle));
  255. esp_lcd_panel_disp_on_off(lcd_handle, true);
  256. // 初始化I2C
  257. ESP_LOGI(TAG, "Initialize I2C");
  258. const i2c_config_t i2c_conf = {
  259. .mode = I2C_MODE_MASTER,
  260. .sda_io_num = PIN_NUM_TOUCH_SDA,
  261. .scl_io_num = PIN_NUM_TOUCH_SCL,
  262. .sda_pullup_en = GPIO_PULLUP_ENABLE,
  263. .scl_pullup_en = GPIO_PULLUP_ENABLE,
  264. .master.clk_speed = 400000,
  265. };
  266. ESP_ERROR_CHECK(i2c_param_config(TOUCH_HOST, &i2c_conf));
  267. ESP_ERROR_CHECK(i2c_driver_install(TOUCH_HOST, i2c_conf.mode, 0, 0, 0));
  268. // 初始化触摸控制器
  269. #ifdef SCREEN_FACTORY_HM
  270. ESP_LOGI(TAG, "Initialize touch controller GT911");
  271. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  272. esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
  273. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
  274. #endif
  275. #ifdef SCREEN_FACTORY_YY
  276. ESP_LOGI(TAG, "Initialize touch controller FT5x06");
  277. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  278. esp_lcd_panel_io_i2c_config_t tp_io_config = {
  279. .dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
  280. .control_phase_bytes = 1,
  281. .dc_bit_offset = 0,
  282. .lcd_cmd_bits = 8,
  283. .flags = {
  284. .disable_control_phase = 1,
  285. }};
  286. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
  287. #endif
  288. esp_lcd_touch_config_t tp_cfg = {
  289. .x_max = LCD_H_RES,
  290. .y_max = LCD_V_RES,
  291. .rst_gpio_num = PIN_NUM_TOUCH_RST,
  292. .int_gpio_num = PIN_NUM_TOUCH_INT,
  293. .levels = {
  294. .reset = 0,
  295. .interrupt = 0,
  296. },
  297. .flags = {
  298. .swap_xy = 0,
  299. .mirror_x = 0,
  300. .mirror_y = 0,
  301. },
  302. };
  303. ESP_LOGI(TAG, "Create touch handle");
  304. esp_lcd_touch_handle_t tp = NULL;
  305. #ifdef SCREEN_FACTORY_HM
  306. ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
  307. #endif
  308. #ifdef SCREEN_FACTORY_YY
  309. ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
  310. #endif
  311. assert(tp != NULL);
  312. // 初始化LVGL
  313. ESP_ERROR_CHECK(lvgl_port_init(lcd_handle, tp));
  314. // 注册RGB面板事件回调
  315. esp_lcd_rgb_panel_event_callbacks_t cbs = {
  316. #if RGB_BOUNCE_BUFFER_SIZE > 0
  317. .on_bounce_frame_finish = rgb_lcd_on_vsync_event,
  318. #else
  319. .on_vsync = rgb_lcd_on_vsync_event,
  320. #endif
  321. };
  322. esp_lcd_rgb_panel_register_event_callbacks(lcd_handle, &cbs, NULL);
  323. return ESP_OK;
  324. }
  325. esp_err_t lcd_st7701_backlight_on(void) {
  326. if (PIN_NUM_BK_LIGHT >= 0) {
  327. st7701_write_cmd(0x11);
  328. vTaskDelay(120);
  329. st7701_write_cmd(0x29);
  330. ESP_LOGI(TAG, "Turn on LCD backlight");
  331. backlight_status = true;
  332. return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_ON_LEVEL);
  333. }
  334. return ESP_OK;
  335. }
  336. bool lcd_st7701_get_blacklight() {
  337. return backlight_status;
  338. }
  339. esp_err_t lcd_st7701_backlight_off(void) {
  340. if (PIN_NUM_BK_LIGHT >= 0) {
  341. st7701_write_cmd(0x10);
  342. vTaskDelay(120);
  343. st7701_write_cmd(0x28);
  344. ESP_LOGI(TAG, "Turn off LCD backlight");
  345. backlight_status = false;
  346. return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_OFF_LEVEL);
  347. }
  348. return ESP_OK;
  349. }