硬汉嵌入式论坛

 找回密码
 立即注册
查看: 3993|回复: 6
收起左侧

[LVGL] lvgl移植不必emWin难,视觉效果更前卫

[复制链接]

3

主题

338

回帖

347

积分

高级会员

积分
347
发表于 2021-10-26 10:59:50 | 显示全部楼层 |阅读模式
在ESP32上移植了lvgl8.0.2,特地自己从头移植而不用github上的lv_port_esp32项目;因为之前在电脑上做了个纯win32的lvgl模拟器了,对移植那点活的认知就很清楚。
微信图片_20211026104638.jpg
当下,ESP32是性价比最高的MCU。
微信图片_20211026104633.jpg

回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
107221
QQ
发表于 2021-10-26 11:05:45 | 显示全部楼层
谢谢楼主分享。
回复

使用道具 举报

3

主题

338

回帖

347

积分

高级会员

积分
347
 楼主| 发表于 2021-10-26 11:11:48 | 显示全部楼层
移植代码,就这么点:
  1. /* SPI Master example

  2.    This example code is in the Public Domain (or CC0 licensed, at your option.)

  3.    Unless required by applicable law or agreed to in writing, this
  4.    software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5.    CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "sdkconfig.h"
  11. #include "freertos/FreeRTOS.h"
  12. #include "freertos/event_groups.h"
  13. #include "freertos/portmacro.h"
  14. #include "esp_system.h"
  15. #include "esp_task.h"
  16. #include "driver/spi_master.h"
  17. #include "driver/gpio.h"
  18. #include "lvgl/lvgl.h"
  19. #include "lv_demos/lv_demo.h"
  20. #include "app.h"

  21. #define LCD_PANEL_W     (320)
  22. #define LCD_PANEL_H     (240)

  23. #define DISP_BUF_SIZE   (LCD_PANEL_W*10)

  24. #define LENOF(ar)       (sizeof(ar)/sizeof(ar[0]))

  25. /*
  26. This code displays some fancy graphics on the 320x240 LCD on an ESP-WROVER_KIT board.
  27. This example demonstrates the use of both spi_device_transmit as well as
  28. spi_device_queue_trans/spi_device_get_trans_result and pre-transmit callbacks.

  29. Some info about the ILI9341/ST7789V: It has an C/D line, which is connected to a GPIO here. It expects this
  30. line to be low for a command and high for data. We use a pre-transmit callback here to control that
  31. line: every transaction has as the user-definable argument the needed state of the D/C line and just
  32. before the transaction is sent, the callback will set this line to the correct state.
  33. */

  34. #define LCD_HOST        HSPI_HOST
  35. #define DMA_CHAN        2

  36. #define PIN_NUM_BCKL    5

  37. #define PIN_NUM_CS      22
  38. #define PIN_NUM_DC      21
  39. #define PIN_NUM_RST     18
  40. #define PIN_NUM_MISO    17
  41. #define PIN_NUM_MOSI    23
  42. #define PIN_NUM_CLK     19

  43. //To speed up transfers, every SPI transfer sends a bunch of lines. This define specifies how many. More means more memory use,
  44. //but less overhead for setting up / finishing transfers. Make sure LCD_PANEL_H is dividable by this.
  45. #define PARALLEL_LINES  16

  46. /*
  47. The LCD needs a bunch of command/argument values to be initialized. They are stored in this struct.
  48. */
  49. typedef struct {
  50.   uint8_t cmd;
  51.   uint8_t data[16];
  52.   uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
  53. } lcd_init_cmd_t;

  54. //Place data into DRAM. Constant data gets placed into DROM by default, which is not accessible by DMA.
  55. DRAM_ATTR static const lcd_init_cmd_t lcm_init_cmds[] = {
  56.   /* Power contorl B, power control = 0, DC_ENA = 1 */
  57.   {0xCF, {0x00, 0x83, 0x30}, 3},
  58.   /* Power on sequence control,
  59.    * cp1 keeps 1 frame, 1st frame enable
  60.    * vcl = 0, ddvdh=3, vgh=1, vgl=2
  61.    * DDVDH_ENH=1
  62.    */
  63.   {0xED, {0x64, 0x03, 0x12, 0x81}, 4},
  64.   /* Driver timing control A,
  65.    * non-overlap=default +1
  66.    * EQ=default - 1, CR=default
  67.    * pre-charge=default - 1
  68.    */
  69.   {0xE8, {0x85, 0x01, 0x79}, 3},
  70.   /* Power control A, Vcore=1.6V, DDVDH=5.6V */
  71.   {0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
  72.   /* Pump ratio control, DDVDH=2xVCl */
  73.   {0xF7, {0x20}, 1},
  74.   /* Driver timing control, all=0 unit */
  75.   {0xEA, {0x00, 0x00}, 2},
  76.   /* Power control 1, GVDD=4.75V */
  77.   {0xC0, {0x26}, 1},
  78.   /* Power control 2, DDVDH=VCl*2, VGH=VCl*7, VGL=-VCl*3 */
  79.   {0xC1, {0x11}, 1},
  80.   /* VCOM control 1, VCOMH=4.025V, VCOML=-0.950V */
  81.   {0xC5, {0x35, 0x3E}, 2},
  82.   /* VCOM control 2, VCOMH=VMH-2, VCOML=VML-2 */
  83.   {0xC7, {0xBE}, 1},
  84.   /* Memory access contorl, MX=MY=0, MV=1, ML=0, BGR=1, MH=0 */
  85.   {0x36, {0xF8}, 1},
  86.   /* Pixel format, 16bits/pixel for RGB/MCU interface */
  87.   {0x3A, {0x55}, 1},
  88.   /* Frame rate control, f=fosc, 70Hz fps */
  89.   {0xB1, {0x00, 0x1B}, 2},
  90.   /* Enable 3G, disabled */
  91.   {0xF2, {0x08}, 1},
  92.   /* Gamma set, curve 1 */
  93.   {0x26, {0x01}, 1},
  94.   /* Positive gamma correction */
  95.   {0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0x87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15},
  96.   /* Negative gamma correction */
  97.   {0xE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15},
  98.   /* Column address set, SC=0, EC=0xEF */
  99.   {0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},
  100.   /* Page address set, SP=0, EP=0x013F */
  101.   {0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
  102.   /* Memory write */
  103.   {0x2C, {0}, 0},
  104.   /* Entry mode set, Low vol detect disabled, normal display */
  105.   {0xB7, {0x07}, 1},
  106.   /* Display function control */
  107.   {0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
  108.   /* Sleep out */
  109.   {0x11, {0}, 0x80},
  110.   /* Display on */
  111.   {0x29, {0}, 0x80},
  112.   {0, {0}, 0xff},
  113. };

  114. /* Send a command to the LCD. Uses spi_device_polling_transmit, which waits
  115. * until the transfer is complete.
  116. *
  117. * Since command transactions are usually small, they are handled in polling
  118. * mode for higher speed. The overhead of interrupt transactions is more than
  119. * just waiting for the transaction to complete.
  120. */
  121. static void IRAM_ATTR lcd_cmd(spi_device_handle_t spi, const uint8_t cmd)
  122. {
  123.   esp_err_t ret;
  124.   spi_transaction_t t;
  125.   memset(&t, 0, sizeof(t));       //Zero out the transaction
  126.   t.length = 8;                   //Command is 8 bits
  127.   t.tx_buffer = &cmd;             //The data is the cmd itself
  128.   t.user = (void*)0;              //D/C needs to be set to 0
  129.   ret = spi_device_polling_transmit(spi, &t); //Transmit!
  130.   assert(ret == ESP_OK);          //Should have had no issues.
  131. }

  132. /* Send data to the LCD. Uses spi_device_polling_transmit, which waits until the
  133. * transfer is complete.
  134. *
  135. * Since data transactions are usually small, they are handled in polling
  136. * mode for higher speed. The overhead of interrupt transactions is more than
  137. * just waiting for the transaction to complete.
  138. */
  139. static void IRAM_ATTR lcd_data(spi_device_handle_t spi, const uint8_t* data, int len)
  140. {
  141.   esp_err_t ret;
  142.   spi_transaction_t t;
  143.   if (len == 0)
  144.     return;             //no need to send anything
  145.   memset(&t, 0, sizeof(t));       //Zero out the transaction
  146.   t.length = len * 8;             //Len is in bytes, transaction length is in bits.
  147.   t.tx_buffer = data;             //Data
  148.   t.user = (void*)1;              //D/C needs to be set to 1
  149.   ret = spi_device_polling_transmit(spi, &t); //Transmit!
  150.   assert(ret == ESP_OK);          //Should have had no issues.
  151. }

  152. //This function is called (in irq context!) just before a transmission starts. It will
  153. //set the D/C line to the value indicated in the user field.
  154. static void IRAM_ATTR lcd_spi_pre_transfer_callback(spi_transaction_t* t)
  155. {
  156.   int dc = (int)t->user;
  157.   gpio_set_level(PIN_NUM_DC, dc);
  158. }

  159. //Initialize the display
  160. static void lcd_init(spi_device_handle_t spi)
  161. {
  162.   const lcd_init_cmd_t* lcd_init_cmds;
  163.   int cmd = 0;

  164.   //Initialize non-SPI GPIOs
  165.   gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT);
  166.   gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT);
  167.   gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT);

  168.   //Reset the display
  169.   gpio_set_level(PIN_NUM_RST, 0);
  170.   vTaskDelay(100 / portTICK_RATE_MS);
  171.   gpio_set_level(PIN_NUM_RST, 1);
  172.   vTaskDelay(100 / portTICK_RATE_MS);

  173.   //Send all the commands
  174.   lcd_init_cmds = lcm_init_cmds;
  175.   while (lcd_init_cmds[cmd].databytes != 0xff) {
  176.     lcd_cmd(spi, lcd_init_cmds[cmd].cmd);
  177.     lcd_data(spi, lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes & 0x1F);
  178.     if (lcd_init_cmds[cmd].databytes & 0x80) {
  179.       vTaskDelay(100 / portTICK_RATE_MS);
  180.     }
  181.     cmd++;
  182.   }

  183.   ///Enable backlight
  184.   gpio_set_level(PIN_NUM_BCKL, 1);
  185. }

  186. static void IRAM_ATTR send_line_finish(spi_device_handle_t spi)
  187. {
  188.   spi_transaction_t* rtrans;
  189.   esp_err_t ret;
  190.   //Wait for all 6 transactions to be done and get back the results.
  191.   for (int x = 0; x < 6; x++) {
  192.     ret = spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
  193.     assert(ret == ESP_OK);
  194.     //We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though.
  195.   }
  196. }

  197. static void IRAM_ATTR lv_simulator_disp_flush_callback(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_p)
  198. {
  199.   static bool need_wait = false;
  200.   static spi_transaction_t trans[6];
  201.   size_t count;

  202.   if (need_wait) {
  203.     send_line_finish(disp_drv->user_data);
  204.   }
  205.   if (color_p) {
  206.     esp_err_t ret;
  207.     int x;
  208.     for (x = 0; x < 6; x++) {
  209.       memset(&trans[x], 0, sizeof(spi_transaction_t));
  210.       if ((x & 1) == 0) {
  211.         //Even transfers are commands
  212.         trans[x].length = 8;
  213.         trans[x].user = (void*)0;
  214.       } else {
  215.         //Odd transfers are data
  216.         trans[x].length = 8 * 4;
  217.         trans[x].user = (void*)1;
  218.       }
  219.       trans[x].flags = SPI_TRANS_USE_TXDATA;
  220.     }
  221.     count = (area->x2 - area->x1 + 1) * (area->y2 - area->y1 + 1);
  222.     trans[0].tx_data[0] = 0x2A;               //Column Address Set
  223.     trans[1].tx_data[0] = (area->x1 >> 8);    //Start Col High
  224.     trans[1].tx_data[1] = (area->x1 & 0xFF);  //Start Col Low
  225.     trans[1].tx_data[2] = (area->x2 >> 8);    //End Col High
  226.     trans[1].tx_data[3] = (area->x2 & 0xFF);  //End Col Low
  227.     trans[2].tx_data[0] = 0x2B;               //Page address set
  228.     trans[3].tx_data[0] = (area->y1 >> 8);    //Start page high
  229.     trans[3].tx_data[1] = (area->y1 & 0xFF);  //start page low
  230.     trans[3].tx_data[2] = (area->y2 >> 8);    //end page high
  231.     trans[3].tx_data[3] = (area->y2 & 0xFF);  //end page low
  232.     trans[4].tx_data[0] = 0x2C;               //memory write
  233.     trans[5].tx_buffer  = color_p;            //finally send the line data
  234.     trans[5].length = 16 * count;             //Data length, in bits
  235.     trans[5].flags = 0;   //undo SPI_TRANS_USE_TXDATA flag
  236.     //Queue all transactions.
  237.     for (x = 0; x < 6; x++) {
  238.       ret = spi_device_queue_trans(disp_drv->user_data, &trans[x], portMAX_DELAY);
  239.       assert(ret == ESP_OK);
  240.     }
  241.     need_wait = true;
  242.     lv_disp_flush_ready(disp_drv);
  243.   }
  244. }

  245. static void IRAM_ATTR lv_simulator_init(spi_device_handle_t spi)
  246. {
  247.   static lv_disp_draw_buf_t display_buffer;
  248.   static lv_color_t buf1[DISP_BUF_SIZE];
  249.   static lv_color_t buf2[DISP_BUF_SIZE];
  250.   lv_disp_draw_buf_init(&display_buffer, buf1, buf2, DISP_BUF_SIZE);

  251.   static lv_disp_drv_t display_driver;
  252.   lv_disp_drv_init(&display_driver);
  253.   display_driver.user_data = spi;
  254.   display_driver.hor_res = LCD_PANEL_W;
  255.   display_driver.ver_res = LCD_PANEL_H;
  256.   display_driver.draw_buf = &display_buffer;
  257.   display_driver.flush_cb = lv_simulator_disp_flush_callback;
  258.   lv_disp_drv_register(&display_driver);
  259. }
  260. static TaskHandle_t thread_handle;
  261. static StaticTask_t thread_buffer;
  262. static StackType_t  thread_statck[ 3072 + TASK_EXTRA_STACK_SIZE ];
  263. static void thread_function(void* pvParameter);
  264. void app_main(void)
  265. {
  266.   thread_handle = xTaskCreateStaticPinnedToCore(thread_function,
  267.                                                 "lvgl",
  268.                                                 LENOF(thread_statck),
  269.                                                 NULL,
  270.                                                 ESP_TASKD_EVENT_PRIO - 1,
  271.                                                 thread_statck,
  272.                                                 &thread_buffer,
  273.                                                 1);

  274. }

  275. uint32_t IRAM_ATTR glory_systick(void)
  276. {
  277.   return (uint32_t)((uint64_t)esp_timer_get_time() / 1000ul);
  278. }

  279. static void thread_function(void* pvParameter)
  280. {
  281.   esp_err_t ret;
  282.   spi_device_handle_t spi;
  283.   spi_bus_config_t buscfg = {
  284.     .miso_io_num = -1,
  285.     .mosi_io_num = PIN_NUM_MOSI,
  286.     .sclk_io_num = PIN_NUM_CLK,
  287.     .quadwp_io_num = -1,
  288.     .quadhd_io_num = -1,
  289.     .max_transfer_sz = PARALLEL_LINES * LCD_PANEL_W * 2 + 8
  290.   };
  291.   spi_device_interface_config_t devcfg = {
  292.     .clock_speed_hz = 40 * 1000 * 1000,     //Clock out at 40 MHz
  293.     .mode = 0,                              //SPI mode 0
  294.     .spics_io_num = PIN_NUM_CS,             //CS pin
  295.     .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE,
  296.     .queue_size = 7,                        //We want to be able to queue 7 transactions at a time
  297.     .pre_cb = lcd_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
  298.   };
  299.   //Initialize the SPI bus
  300.   ret = spi_bus_initialize(LCD_HOST, &buscfg, DMA_CHAN);
  301.   ESP_ERROR_CHECK(ret);
  302.   //Attach the LCD to the SPI bus
  303.   ret = spi_bus_add_device(LCD_HOST, &devcfg, &spi);
  304.   ESP_ERROR_CHECK(ret);
  305.   //Initialize the LCD
  306.   lcd_init(spi);
  307.   /*Initialize LittlevGL*/
  308.   lv_init();
  309.   /* Initialize drivers */
  310.   lv_simulator_init(spi);
  311.   /*Run the demo*/
  312.   //lv_demo_widgets();
  313.   lv_demo_stress();
  314.   //lv_demo_music();
  315.   //lv_demo_benchmark();

  316.   while (true) {
  317.     lv_task_handler();
  318.     vTaskDelay(1);
  319.   }
  320. }
复制代码


回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
发表于 2021-11-16 21:41:28 | 显示全部楼层
在吗楼主,我移植ESP32 arduino 版本的LVGL文件系统一直有问题,请问您那边有办法解决吗
回复

使用道具 举报

0

主题

6

回帖

6

积分

新手上路

积分
6
发表于 2021-11-16 21:42:16 | 显示全部楼层
在吗楼主,我这边使用arduino移植LVGL的文件系统到ESP32上一直有问题,请问您解决了吗
回复

使用道具 举报

19

主题

150

回帖

207

积分

高级会员

积分
207
发表于 2021-12-9 11:16:37
好厉害,慢慢消化下。

0

主题

28

回帖

28

积分

新手上路

积分
28
发表于 2022-4-8 16:03:00 | 显示全部楼层
谢谢分享,学习学习。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-22 10:25 , Processed in 0.172832 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表