lcd_st7701.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #include "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 "lvgl_port.h"
  11. #include "esp_lcd_touch_ft5x06.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. //{0x36, (uint8_t[]) {0x01}, 1, 0},
  118. // 退出睡眠模式和开启显示的命令保持不变
  119. {0x11, (uint8_t[]) {0x00}, 0, 120}, // Sleep Out
  120. {0x29, (uint8_t[]) {0x00}, 0, 0}, // Display On
  121. #endif
  122. };
  123. static void spi_soft_init(void) {
  124. gpio_config_t io_conf1 = {
  125. .mode = GPIO_MODE_OUTPUT,
  126. .pin_bit_mask = 1ULL << LCD_IO_SPI_CS,
  127. };
  128. gpio_config(&io_conf1);
  129. gpio_set_level(LCD_IO_SPI_CS, 1);
  130. gpio_config_t io_conf2 = {
  131. .mode = GPIO_MODE_OUTPUT,
  132. .pin_bit_mask = 1ULL << LCD_IO_SPI_SCL,
  133. };
  134. gpio_config(&io_conf2);
  135. gpio_set_level(LCD_IO_SPI_SCL, 1);
  136. gpio_config_t io_conf3 = {
  137. .mode = GPIO_MODE_OUTPUT,
  138. .pin_bit_mask = 1ULL << LCD_IO_SPI_SDA,
  139. };
  140. gpio_config(&io_conf3);
  141. gpio_set_level(LCD_IO_SPI_SDA, 1);
  142. }
  143. static void spi_soft_write_9bits(uint16_t data) {
  144. uint8_t i;
  145. LCD_CS_Clr();
  146. for (i = 0; i < 9; i++) {
  147. LCD_SCK_Clr();
  148. if (data & 0x100) LCD_SDA_Set();
  149. else
  150. LCD_SDA_Clr();
  151. LCD_SCK_Set();
  152. data <<= 1;
  153. }
  154. LCD_CS_Set();;
  155. }
  156. static void st7701_write_cmd(uint8_t cmd) {
  157. uint16_t temp = 0;
  158. temp = temp | cmd;
  159. spi_soft_write_9bits(temp);
  160. }
  161. static void st7701_write_data(uint8_t data) {
  162. uint16_t temp = 0x100;
  163. temp = temp | data;
  164. spi_soft_write_9bits(temp);
  165. }
  166. IRAM_ATTR static bool
  167. rgb_lcd_on_vsync_event(esp_lcd_panel_handle_t panel, const esp_lcd_rgb_panel_event_data_t *edata, void *user_ctx) {
  168. // 最小化中断处理时间
  169. return lvgl_port_notify_rgb_vsync();
  170. }
  171. esp_err_t lcd_st7701_init(void) {
  172. // 配置背光GPIO
  173. if (PIN_NUM_BK_LIGHT >= 0) {
  174. gpio_config_t bk_gpio_config = {
  175. .mode = GPIO_MODE_OUTPUT,
  176. .pin_bit_mask = 1ULL << PIN_NUM_BK_LIGHT};
  177. ESP_ERROR_CHECK(gpio_config(&bk_gpio_config));
  178. }
  179. // 安装3线SPI面板IO
  180. ESP_LOGI(TAG, "Install 3-wire SPI panel IO");
  181. spi_line_config_t line_config = {
  182. .cs_io_type = IO_TYPE_GPIO,
  183. .cs_gpio_num = LCD_IO_SPI_CS,
  184. .scl_io_type = IO_TYPE_GPIO,
  185. .scl_gpio_num = LCD_IO_SPI_SCL,
  186. .sda_io_type = IO_TYPE_GPIO,
  187. .sda_gpio_num = LCD_IO_SPI_SDA,
  188. .io_expander = NULL,
  189. };
  190. esp_lcd_panel_io_3wire_spi_config_t io_config = ST7701_PANEL_IO_3WIRE_SPI_CONFIG(line_config, 0);
  191. esp_lcd_panel_io_handle_t io_handle = NULL;
  192. ESP_ERROR_CHECK(esp_lcd_new_panel_io_3wire_spi(&io_config, &io_handle));
  193. for (int i = 0; i < sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]); i++) {
  194. st7701_write_cmd(lcd_init_cmds[i].cmd);
  195. for (int n = 0; n < lcd_init_cmds[i].data_bytes; n++) {
  196. st7701_write_data(((uint8_t *) lcd_init_cmds[i].data)[n]);
  197. }
  198. vTaskDelay(pdMS_TO_TICKS(lcd_init_cmds[i].delay_ms));
  199. }
  200. // 安装RGB面板
  201. ESP_LOGI(TAG, "Install ST7701 panel driver");
  202. esp_lcd_panel_handle_t lcd_handle = NULL;
  203. esp_lcd_rgb_panel_config_t rgb_config = {
  204. .clk_src = LCD_CLK_SRC_DEFAULT,
  205. .psram_trans_align = 64,
  206. .data_width = RGB_DATA_WIDTH,
  207. .bits_per_pixel = RGB_BIT_PER_PIXEL,
  208. .de_gpio_num = LCD_IO_RGB_DE,
  209. .pclk_gpio_num = LCD_IO_RGB_PCLK,
  210. .vsync_gpio_num = LCD_IO_RGB_VSYNC,
  211. .hsync_gpio_num = LCD_IO_RGB_HSYNC,
  212. .disp_gpio_num = LCD_IO_RGB_DISP,
  213. .data_gpio_nums = {
  214. LCD_IO_RGB_DATA0,
  215. LCD_IO_RGB_DATA1,
  216. LCD_IO_RGB_DATA2,
  217. LCD_IO_RGB_DATA3,
  218. LCD_IO_RGB_DATA4,
  219. LCD_IO_RGB_DATA5,
  220. LCD_IO_RGB_DATA6,
  221. LCD_IO_RGB_DATA7,
  222. LCD_IO_RGB_DATA8,
  223. LCD_IO_RGB_DATA9,
  224. LCD_IO_RGB_DATA10,
  225. LCD_IO_RGB_DATA11,
  226. LCD_IO_RGB_DATA12,
  227. LCD_IO_RGB_DATA13,
  228. LCD_IO_RGB_DATA14,
  229. LCD_IO_RGB_DATA15,
  230. },
  231. .timings = ST7701_480_480_PANEL_60HZ_RGB_TIMING(),
  232. .flags.fb_in_psram = 1,
  233. .num_fbs = LVGL_PORT_LCD_RGB_BUFFER_NUMS,
  234. .bounce_buffer_size_px = RGB_BOUNCE_BUFFER_SIZE,
  235. };
  236. rgb_config.timings.h_res = LCD_H_RES;
  237. rgb_config.timings.v_res = LCD_V_RES;
  238. st7701_vendor_config_t vendor_config = {
  239. .rgb_config = &rgb_config,
  240. .init_cmds = lcd_init_cmds,
  241. .init_cmds_size = sizeof(lcd_init_cmds) / sizeof(lcd_init_cmds[0]),
  242. .flags = {
  243. .auto_del_panel_io = 0,
  244. .mirror_by_cmd = 1,
  245. },
  246. };
  247. const esp_lcd_panel_dev_config_t panel_config = {
  248. .reset_gpio_num = LCD_IO_RST,
  249. .rgb_ele_order = LCD_RGB_ELEMENT_ORDER_RGB,
  250. .bits_per_pixel = LCD_BIT_PER_PIXEL,
  251. .vendor_config = &vendor_config,
  252. };
  253. ESP_ERROR_CHECK(esp_lcd_new_panel_st7701(io_handle, &panel_config, &lcd_handle));
  254. ESP_ERROR_CHECK(esp_lcd_panel_reset(lcd_handle));
  255. ESP_ERROR_CHECK(esp_lcd_panel_init(lcd_handle));
  256. esp_lcd_panel_disp_on_off(lcd_handle, true);
  257. // 初始化I2C
  258. ESP_LOGI(TAG, "Initialize I2C");
  259. const i2c_config_t i2c_conf = {
  260. .mode = I2C_MODE_MASTER,
  261. .sda_io_num = PIN_NUM_TOUCH_SDA,
  262. .scl_io_num = PIN_NUM_TOUCH_SCL,
  263. .sda_pullup_en = GPIO_PULLUP_ENABLE,
  264. .scl_pullup_en = GPIO_PULLUP_ENABLE,
  265. .master.clk_speed = 400000,
  266. };
  267. ESP_ERROR_CHECK(i2c_param_config(TOUCH_HOST, &i2c_conf));
  268. ESP_ERROR_CHECK(i2c_driver_install(TOUCH_HOST, i2c_conf.mode, 0, 0, 0));
  269. // 初始化触摸控制器
  270. #ifdef SCREEN_FACTORY_HM
  271. ESP_LOGI(TAG, "Initialize touch controller GT911");
  272. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  273. esp_lcd_panel_io_i2c_config_t tp_io_config = ESP_LCD_TOUCH_IO_I2C_GT911_CONFIG();
  274. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
  275. #endif
  276. #ifdef SCREEN_FACTORY_YY
  277. ESP_LOGI(TAG, "Initialize touch controller FT5x06");
  278. esp_lcd_panel_io_handle_t tp_io_handle = NULL;
  279. esp_lcd_panel_io_i2c_config_t tp_io_config = {
  280. .dev_addr = ESP_LCD_TOUCH_IO_I2C_FT5x06_ADDRESS,
  281. .control_phase_bytes = 1,
  282. .dc_bit_offset = 0,
  283. .lcd_cmd_bits = 8,
  284. .flags = {
  285. .disable_control_phase = 1,
  286. }};
  287. ESP_ERROR_CHECK(esp_lcd_new_panel_io_i2c((esp_lcd_i2c_bus_handle_t) TOUCH_HOST, &tp_io_config, &tp_io_handle));
  288. #endif
  289. esp_lcd_touch_config_t tp_cfg = {
  290. .x_max = LCD_H_RES,
  291. .y_max = LCD_V_RES,
  292. .rst_gpio_num = PIN_NUM_TOUCH_RST,
  293. .int_gpio_num = PIN_NUM_TOUCH_INT,
  294. .levels = {
  295. .reset = 0,
  296. .interrupt = 0,
  297. },
  298. .flags = {
  299. .swap_xy = 0,
  300. .mirror_x = 0,
  301. .mirror_y = 0,
  302. },
  303. };
  304. ESP_LOGI(TAG, "Create touch handle");
  305. esp_lcd_touch_handle_t tp = NULL;
  306. #ifdef SCREEN_FACTORY_HM
  307. ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_gt911(tp_io_handle, &tp_cfg, &tp));
  308. #endif
  309. #ifdef SCREEN_FACTORY_YY
  310. ESP_ERROR_CHECK(esp_lcd_touch_new_i2c_ft5x06(tp_io_handle, &tp_cfg, &tp));
  311. #endif
  312. assert(tp != NULL);
  313. // 初始化LVGL
  314. ESP_ERROR_CHECK(lvgl_port_init(lcd_handle, tp));
  315. // 注册RGB面板事件回调
  316. esp_lcd_rgb_panel_event_callbacks_t cbs = {
  317. #if RGB_BOUNCE_BUFFER_SIZE > 0
  318. .on_bounce_frame_finish = rgb_lcd_on_vsync_event,
  319. #else
  320. .on_vsync = rgb_lcd_on_vsync_event,
  321. #endif
  322. };
  323. esp_lcd_rgb_panel_register_event_callbacks(lcd_handle, &cbs, NULL);
  324. return ESP_OK;
  325. }
  326. esp_err_t lcd_st7701_backlight_on(void) {
  327. if (PIN_NUM_BK_LIGHT >= 0) {
  328. st7701_write_cmd(0x11);
  329. vTaskDelay(120);
  330. st7701_write_cmd(0x29);
  331. ESP_LOGI(TAG, "Turn on LCD backlight");
  332. backlight_status = true;
  333. return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_ON_LEVEL);
  334. }
  335. return ESP_OK;
  336. }
  337. bool lcd_st7701_get_blacklight() {
  338. return backlight_status;
  339. }
  340. esp_err_t lcd_st7701_backlight_off(void) {
  341. if (PIN_NUM_BK_LIGHT >= 0) {
  342. st7701_write_cmd(0x10);
  343. vTaskDelay(120);
  344. st7701_write_cmd(0x28);
  345. ESP_LOGI(TAG, "Turn off LCD backlight");
  346. backlight_status = false;
  347. return gpio_set_level(PIN_NUM_BK_LIGHT, LCD_BK_LIGHT_OFF_LEVEL);
  348. }
  349. return ESP_OK;
  350. }