├── .gitignore ├── .vscode └── extensions.json ├── README.md ├── README_CN.md ├── doc └── media │ ├── 2022-09-23-10-21-02.png │ ├── 2022-09-23-10-44-12.png │ └── 2022-09-23-10-57-18.png ├── include └── README ├── lib └── README ├── platformio.ini ├── src ├── main.cpp └── mouse_cursor_icon.c └── test └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode/.browse.c_cpp.db* 3 | .vscode/c_cpp_properties.json 4 | .vscode/launch.json 5 | .vscode/ipch 6 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See http://go.microsoft.com/fwlink/?LinkId=827846 3 | // for the documentation about the extensions.json format 4 | "recommendations": [ 5 | "platformio.platformio-ide" 6 | ], 7 | "unwantedRecommendations": [ 8 | "ms-vscode.cpptools-extension-pack" 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A LVGL8 Demo based on RP2040 2 | 3 | [Chinese 中文](./README_CN.md) 4 | 5 | ## Structure 6 | 7 | ### Hardware 8 | 9 | * RP2040 10 | * 3.5" TFT screen with ILI9488 [Screen more details](http://www.lcdwiki.com/3.5inch_SPI_Module_ILI9488_SKU:MSP3520) 11 | * Resistance touch with XPT2046 12 | 13 | [Taobao CHINA purchase link](https://item.taobao.com/item.htm?id=38842179442&_u=nlcjfo14a4). No body gives money for this ads. :) 14 | 15 | ### Software 16 | 17 | * VS Code 18 | * PlatformIO 19 | * [eSPI](https://github.com/Bodmer/TFT_eSPI) 20 | * [LVGL 8.3](https://github.com/lvgl/lvgl) 21 | * [XPT2046 Driver](https://github.com/PaulStoffregen/XPT2046_Touchscreen) 22 | 23 | ## Performance 24 | 25 | ![Performance](doc/media/2022-09-23-10-21-02.png) 26 | 27 | ## Settings 28 | 29 | ### eSPI 30 | 31 | ~~~ini 32 | ; Platformio.ini 33 | 34 | -DILI9488_DRIVER=1 35 | -DTFT_WIDTH=480 36 | -DTFT_HEIGHT=320 37 | -DTFT_MOSI=11 38 | -DTFT_SCLK=10 39 | -DTFT_CS=9 40 | -DTFT_DC=8 41 | -DTFT_RST=12 42 | ~~~ 43 | 44 | As a PlatformIO project, most eSPI settings are defined on platformio.ini. Please check if you want to modify them. 45 | 46 | **NOTE**: I use SPI channel 1 instead of channel 0, so I must write below in platformio.ini. 47 | 48 | ~~~ini 49 | ; Platformio.ini 50 | 51 | -DTFT_SPI_PORT=1 52 | ~~~ 53 | 54 | ### XPT2046 55 | 56 | Acorrding to [the author's description](https://github.com/PaulStoffregen/XPT2046_Touchscreen), we just need define CS PIN for XPT2046 driver, and others PINS are automatically defined. 57 | 58 | ![XPT2046](doc/media/2022-09-23-10-44-12.png) 59 | 60 | ~~~C 61 | // main.cpp 62 | 63 | #define CS_PIN 17 64 | ~~~ 65 | 66 | Then, we need connect the wires: 67 | 68 | * TOUCH_RX GP16 69 | * TOUCH_CS GP17(connect not in this photo) 70 | * TOUCH_SCK GP18 71 | * TOUCH_TX GP19 72 | 73 | ![connect](doc/media/2022-09-23-10-57-18.png) 74 | 75 | ### Back lighting 76 | 77 | We need set back lighting as a NONE-ZERO constant, or set int between 0 and 255. If you set nothing to it, you will see nothing display. As the demo, I set 150. 78 | 79 | ~~~C 80 | // main.cpp 81 | 82 | #define TFT_BL 13 83 | uint8_t TftBackground = 150; 84 | ~~~ 85 | -------------------------------------------------------------------------------- /README_CN.md: -------------------------------------------------------------------------------- 1 | # 一款基于RP2040的LVGL8演示例程 2 | 3 | [English 英文](./README.md) 4 | 5 | ## 接口 6 | 7 | ### 硬件 8 | 9 | * RP2040 10 | * 3.5寸TFT屏幕,使用ILI9488驱动 [屏幕更多信息](http://www.lcdwiki.com/zh/3.5inch_SPI_Module_ILI9488_SKU:MSP3520) 11 | * 电阻触摸基于XPT2046 12 | 13 | [淘宝链接](https://item.taobao.com/item.htm?id=38842179442&_u=nlcjfo14a4). 店主并未给我一毛钱的赞助 :) 14 | 15 | ### 软件 16 | 17 | * VS Code 18 | * PlatformIO 19 | * [eSPI](https://github.com/Bodmer/TFT_eSPI) 20 | * [LVGL 8.3](https://github.com/lvgl/lvgl) 21 | * [XPT2046 Driver](https://github.com/PaulStoffregen/XPT2046_Touchscreen) 22 | 23 | ## 展示 24 | 25 | ![Performance](doc/media/2022-09-23-10-21-02.png) 26 | 27 | ## 设置 28 | 29 | ### eSPI 30 | 31 | ~~~ini 32 | ; Platformio.ini 33 | 34 | -DILI9488_DRIVER=1 35 | -DTFT_WIDTH=480 36 | -DTFT_HEIGHT=320 37 | -DTFT_MOSI=11 38 | -DTFT_SCLK=10 39 | -DTFT_CS=9 40 | -DTFT_DC=8 41 | -DTFT_RST=12 42 | ~~~ 43 | 44 | 作为PlatfromIO的工程,大部分eSPI设置都在platformio.ini中。如果你要修改可以在这个文件中找到对应项。 45 | 46 | **注意**: 我用SPI通道1而不是通道0,所以我必须在platformio.ini中添加如下语句: 47 | 48 | ~~~ini 49 | ; Platformio.ini 50 | 51 | -DTFT_SPI_PORT=1 52 | ~~~ 53 | 54 | ### XPT2046 55 | 56 | 根据[作者描述](https://github.com/PaulStoffregen/XPT2046_Touchscreen), 我们只需定义CS PIN就可以驱动XPT2046了,而其他PINS都会被自动定义。 57 | 58 | ![XPT2046](doc/media/2022-09-23-10-44-12.png) 59 | 60 | ~~~C 61 | // main.cpp 62 | 63 | #define CS_PIN 17 64 | ~~~ 65 | 66 | 然后,我们需要连接接线: 67 | 68 | * TOUCH_RX GP16 69 | * TOUCH_CS GP17(连接不在图中) 70 | * TOUCH_SCK GP18 71 | * TOUCH_TX GP19 72 | 73 | ![connect](doc/media/2022-09-23-10-57-18.png) 74 | 75 | ### 背光 76 | 77 | 我们需要给背光一个非零常量,或一个0-255的变量。如果你啥也不设置,那你啥也看不见。例程中我设置了150。 78 | 79 | ~~~C 80 | // main.cpp 81 | 82 | #define TFT_BL 13 83 | uint8_t TftBackground = 150; 84 | ~~~ 85 | -------------------------------------------------------------------------------- /doc/media/2022-09-23-10-21-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnkoala/rp2040-eSPI-lvgl/3b3deb3b2a9e1466d7e1657df2ccdd441bb15bd9/doc/media/2022-09-23-10-21-02.png -------------------------------------------------------------------------------- /doc/media/2022-09-23-10-44-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnkoala/rp2040-eSPI-lvgl/3b3deb3b2a9e1466d7e1657df2ccdd441bb15bd9/doc/media/2022-09-23-10-44-12.png -------------------------------------------------------------------------------- /doc/media/2022-09-23-10-57-18.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cnkoala/rp2040-eSPI-lvgl/3b3deb3b2a9e1466d7e1657df2ccdd441bb15bd9/doc/media/2022-09-23-10-57-18.png -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env:pico] 12 | platform = raspberrypi 13 | board = pico 14 | framework = arduino 15 | lib_deps = 16 | bodmer/TFT_eSPI@^2.4.75 17 | paulstoffregen/XPT2046_Touchscreen@0.0.0-alpha+sha.26b691b2c8 18 | lvgl/lvgl@^8.3.1 19 | build_flags = 20 | -Os 21 | -DCORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_DEBUG 22 | -DUSER_SETUP_LOADED=1 23 | 24 | -DILI9488_DRIVER=1 25 | -DTFT_WIDTH=480 26 | -DTFT_HEIGHT=320 27 | -DTFT_MOSI=11 28 | -DTFT_SCLK=10 29 | -DTFT_CS=9 30 | -DTFT_DC=8 31 | -DTFT_RST=12 32 | -DTFT_SPI_PORT=1 33 | -DLOAD_GLCD=1 34 | -DLOAD_FONT2=1 35 | -DLOAD_FONT4=1 36 | -DLOAD_FONT6=1 37 | -DLOAD_FONT7=1 38 | -DLOAD_FONT8=1 39 | -DLOAD_GFXFF=1 40 | -DSMOOTH_FONT=1 41 | -DSPI_FREQUENCY=40000000 42 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /*Change to your screen resolution*/ 7 | static const uint16_t screenWidth = 480; 8 | static const uint16_t screenHeight = 320; 9 | 10 | #define TFT_BL 13 11 | uint8_t TftBackground = 150; 12 | 13 | static lv_disp_draw_buf_t draw_buf; 14 | static lv_color_t buf[screenWidth * 10]; 15 | 16 | /* I added this varies */ 17 | 18 | uint16_t rawPointMinX = 168; 19 | uint16_t rawPointMaxX = 3700; 20 | uint16_t rawPointMinY = 378; 21 | uint16_t rawPointMaxY = 3700; 22 | uint16_t screenPointX; 23 | uint16_t screenPointY; 24 | lv_obj_t *labelPoint; 25 | lv_indev_t *mouse_indev; 26 | lv_obj_t *cursor_obj; 27 | lv_indev_drv_t indev_drv; 28 | 29 | lv_obj_t *roller1; 30 | 31 | TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */ 32 | 33 | #define CS_PIN 17 34 | 35 | // XPT2046_Touchscreen ts(CS_PIN); 36 | // #define TIRQ_PIN 22 37 | XPT2046_Touchscreen ts(CS_PIN); // Param 2 - NULL - No interrupts 38 | // XPT2046_Touchscreen ts(CS_PIN, 255); // Param 2 - 255 - No interrupts 39 | // XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); // Param 2 - Touch IRQ Pin - interrupt enabled polling 40 | 41 | #if LV_USE_LOG != 0 42 | /* Serial debugging */ 43 | void my_print(const char *buf) 44 | { 45 | Serial.printf(buf); 46 | Serial.flush(); 47 | } 48 | #endif 49 | 50 | void event_handler(lv_event_t *e) 51 | { 52 | lv_event_code_t code = lv_event_get_code(e); 53 | lv_obj_t *obj = lv_event_get_target(e); 54 | if (code == LV_EVENT_VALUE_CHANGED) 55 | { 56 | char buf[32]; 57 | lv_roller_get_selected_str(obj, buf, sizeof(buf)); 58 | LV_LOG_USER("Selected month: %s\n", buf); 59 | } 60 | } 61 | 62 | /* Display flushing */ 63 | void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) 64 | { 65 | uint32_t w = (area->x2 - area->x1 + 1); 66 | uint32_t h = (area->y2 - area->y1 + 1); 67 | 68 | tft.startWrite(); 69 | tft.setAddrWindow(area->x1, area->y1, w, h); 70 | tft.pushColors((uint16_t *)&color_p->full, w * h, true); 71 | tft.endWrite(); 72 | 73 | lv_disp_flush_ready(disp); 74 | } 75 | void touch_xpt2046_init(void) 76 | { 77 | ts.begin(); 78 | ts.setRotation(3); 79 | } 80 | /*Read the touchpad*/ 81 | void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) 82 | { 83 | if (ts.touched()) 84 | { 85 | data->state = LV_INDEV_STATE_PR; 86 | TS_Point p = ts.getPoint(); 87 | /*Set the coordinates*/ 88 | 89 | screenPointX = screenWidth * (p.x - rawPointMinX) / (rawPointMaxX - rawPointMinX); 90 | screenPointY = screenHeight * (p.y - rawPointMinY) / (rawPointMaxY - rawPointMinY); 91 | 92 | data->point.x = screenPointX; 93 | data->point.y = screenPointY; 94 | // data->point.x = p.x; 95 | // data->point.y = p.y; 96 | 97 | // Serial.print("touch x "); 98 | // Serial.print(p.x); 99 | 100 | // Serial.print(", touch y "); 101 | // Serial.println(p.y); 102 | } 103 | else 104 | { 105 | data->state = LV_INDEV_STATE_REL; 106 | } 107 | } 108 | 109 | void setup() 110 | { 111 | 112 | /* tft backgroud lighting setting */ 113 | pinMode(TFT_BL, OUTPUT); 114 | analogWrite(TFT_BL, TftBackground); 115 | 116 | Serial.begin(115200); /* prepare for possible serial debug */ 117 | 118 | String LVGL_Arduino = "LVGL ver: "; 119 | LVGL_Arduino += String('V') + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch(); 120 | 121 | Serial.println(LVGL_Arduino); 122 | Serial.println("I am LVGL_Arduino"); 123 | 124 | lv_init(); 125 | 126 | #if LV_USE_LOG != 0 127 | lv_log_register_print_cb(my_print); /* register print function for debugging */ 128 | #endif 129 | 130 | tft.begin(); /* TFT init */ 131 | tft.setRotation(1); /* Landscape orientation, flipped */ 132 | 133 | touch_xpt2046_init(); 134 | 135 | lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10); 136 | 137 | /*Initialize the display*/ 138 | static lv_disp_drv_t disp_drv; 139 | lv_disp_drv_init(&disp_drv); 140 | /*Change the following line to your display resolution*/ 141 | disp_drv.hor_res = screenWidth; 142 | disp_drv.ver_res = screenHeight; 143 | disp_drv.flush_cb = my_disp_flush; 144 | disp_drv.draw_buf = &draw_buf; 145 | lv_disp_drv_register(&disp_drv); 146 | 147 | /*Initialize the input device driver*/ 148 | // static lv_indev_drv_t indev_drv; 149 | lv_indev_drv_init(&indev_drv); 150 | indev_drv.type = LV_INDEV_TYPE_POINTER; 151 | indev_drv.read_cb = my_touchpad_read; 152 | // lv_indev_drv_register(&indev_drv); 153 | 154 | /* add a cursor */ 155 | mouse_indev = lv_indev_drv_register(&indev_drv); 156 | // LV_IMG_DECLARE(mouse_cursor_icon); /*Declare the image source.*/ 157 | cursor_obj = lv_img_create(lv_scr_act()); /*Create an image object for the cursor */ 158 | lv_img_set_src(cursor_obj, LV_SYMBOL_GPS); /*Set the image source*/ 159 | lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/ 160 | 161 | /* Create simple label */ 162 | lv_obj_t *label = lv_label_create(lv_scr_act()); 163 | lv_label_set_text(label, LVGL_Arduino.c_str()); 164 | lv_obj_align(label, LV_ALIGN_CENTER, 0, 0); 165 | 166 | labelPoint = lv_label_create(lv_scr_act()); 167 | lv_label_set_text_fmt(labelPoint, "Point:%d, %d", screenPointX, screenPointY); 168 | lv_obj_align(labelPoint, LV_ALIGN_CENTER, 0, 50); 169 | 170 | roller1 = lv_roller_create(lv_scr_act()); 171 | lv_roller_set_options(roller1, 172 | "Welcome\n" 173 | "My\n" 174 | "Program", 175 | LV_ROLLER_MODE_INFINITE); 176 | 177 | lv_roller_set_visible_row_count(roller1, 4); 178 | lv_obj_center(roller1); 179 | lv_obj_add_event_cb(roller1, event_handler, LV_EVENT_ALL, NULL); 180 | lv_obj_align(roller1, LV_ALIGN_LEFT_MID, 10, 0); 181 | 182 | Serial.println("Setup done"); 183 | } 184 | 185 | void loop() 186 | { 187 | lv_label_set_text_fmt(labelPoint, "%d, %d", screenPointX, screenPointY); 188 | // lv_indev_set_cursor(mouse_indev, cursor_obj); /*Connect the image object to the driver*/ 189 | lv_timer_handler(); /* let the GUI do its work */ 190 | delay(10); 191 | } -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PlatformIO Test Runner and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PlatformIO Unit Testing: 11 | - https://docs.platformio.org/en/latest/advanced/unit-testing/index.html 12 | --------------------------------------------------------------------------------