硬件資源介紹
SWM320是一款基于ARM Cortex-M4的32位微控制器,片上包含精度為1%以內(nèi)的 20MHz/40MHz時鐘,可通過PLL倍頻到120MHz 時鐘,提供多種內(nèi)置FLASH/SRAM大小可供選擇,支持ISP(在系統(tǒng)編程)操作及IAP(在應(yīng)用編程)。
外設(shè)串行總線包括:1個CAN接口、內(nèi)部疊封8MB SDRAM、多個UART接口、SPI 通信接口(支持主/從選擇)及I2C接口(支持主/從選擇)。
此外還包括1個32位看門狗定時器,6組32位通用定時器,1組32位專用脈沖寬度測量定時器,12通道16位的PWM發(fā)生器,2個8通道12位、1MSPS的逐次逼近型ADC模塊,1個SDIO接口模塊,TFT-LCD液晶驅(qū)動模塊以及RTC實時時鐘、SRAMC、NORFLC接口控制模塊,同時提供欠壓檢測及低電壓復(fù)位功能。
LittlevGL移植
LittlevGL概述
LittlevGL是一個免費的開放源代碼圖形庫,它提供創(chuàng)建嵌入式GUI所需的一切,它具有易于使用的圖形元素,精美的視覺效果和低內(nèi)存占用。強大的構(gòu)建塊按鈕,圖表,列表,滑塊,圖像等,帶有動畫,抗鋸齒,不透明度,平滑滾動的高級圖形,各種輸入設(shè)備的觸摸板,鼠標,鍵盤,編碼器等,多顯示器支持,即同時使用更多的TFT和單色顯示器,支持UTF-8編碼的多語言,完全可定制的圖形元素。
獨立于任何微控制器或顯示器使用的硬件,可擴展以使用較少的內(nèi)存(80kB閃存,12 kB RAM),支持操作系統(tǒng),外部存儲器和GPU,但不是必需的,即使使用單幀緩沖區(qū)操作,也具有高級圖形效果。
用C語言編寫,以實現(xiàn)最大的兼容性(與C++兼容),模擬器可在沒有嵌入式硬件的PC 上啟動嵌入式GUI設(shè)計,快速GUI設(shè)計的教程,示例,主題,在線和離線文檔,在 MIT 許可下免費和開源。
LittlevGL硬件要求
● 16、32或64位微控制器或處理器
● 建議時鐘頻率大于16MHz
● 閃存/ ROM:對于非常重要的組件,其大小大于64 kB(建議大于180 kB)
● 內(nèi)存:
● 靜態(tài)RAM使用量:大約8至16 kB,具體取決于所使用的功能和對象類型
● 堆棧:大于2kB(建議大于4kB)
● 動態(tài)數(shù)據(jù)(堆):大于4 KB(如果使用多個對象,則建議大于16 kB)。LV_MEM_SIZE 在lv_conf.h中設(shè)置
● 顯示緩沖區(qū):大于“水平分辨率”像素(建議大于10× “水平分辨率”)
● C99或更高版本的編譯器
● 基本的C(或C ++)知識:指針,結(jié)構(gòu),回調(diào)
LittlevGL移植
01、屏幕介紹
開發(fā)板板載的是一個RGB接口的屏幕JLT4301A,我們的板子使用的是RGB565接口。屏幕分辯率480*272,顯示方向為橫向。
觸摸采用的是 GT911的電容觸摸屏。
使用RGB屏,SDRAM是必須的,因為RGB屏需要使用顯存,例如480*272的RGB565 屏幕,一個像素占用2字節(jié)的顯存,總共需要480*272*2=261120 折合255KB的顯存,內(nèi)部RAM很顯然是不夠用的。那么RGB屏的驅(qū)動只需要使能背光、配置LCDC的外設(shè)以及顯存的地址就可以了。然后往屏幕填充內(nèi)容就是往對應(yīng)的顯存發(fā)送數(shù)據(jù)就可以了。不同 RGB 屏的配置參數(shù)可能不一樣,顯示方向也不一樣。
開發(fā)板使用的是電容觸摸屏,使用I2C進行通信,利用I2C初始化觸摸IC GT911后,我們就可以通過I2C讀出觸摸的絕對位置,跟屏幕是一一對應(yīng)的。
02、移植流程
LittlevGL 的移植過程也非常簡單,總結(jié)了以下幾個步驟:
1. 添加庫文件到工程
2. 配置屏幕大小以及顏色深度等跟顯示相關(guān)的參數(shù)
3. 分配一個顯示緩沖區(qū)并實現(xiàn)屏幕填充的接口
4. 實現(xiàn)輸入設(shè)備接口,讀取觸摸屏坐標
5. 實現(xiàn)文件系統(tǒng)接口,實現(xiàn)文件的讀取寫入
6. 提供一個滴答時鐘的接口 lv_tick_inc();
7. 完成庫的初始化以及接口的初始化 lv_init();lv_port_disp_init();lv_port_indev_init(); lv_port_fs_init;
8. 定期調(diào)用任務(wù)處理函數(shù),可設(shè)置為 5-10ms lv_task_handler();
03、源碼下載
LittlevGL 的源碼可以在GitHub 進行下載,https://github.com/littlevgl/lvgl,可以 clone 到本地也可以直接下載壓縮包。除了下載源碼以外,還可以下載example和drivers。example里面包含了各種應(yīng)用展示和控件使用示例,drivers 里面包含了一些液晶屏驅(qū)動接口示例。
共下載3個文件夾
打開源碼文件,里面包含了接口示例文件和配置示例文件,其中src文件夾下面又進行了分類,具體請查看源碼。
04、添加庫文件到工程
第一步,復(fù)制庫文件
復(fù)制lvgl文件夾到工程文件夾APP下面。
將lvgllv_conf_template.h文件復(fù)制一份并改名為lv_conf.h。這個文件是lvgl的配置文件,后面再介紹如何修改。
將lv_examples文件夾復(fù)制到工程文件夾下面,這里面包含了各種應(yīng)用和基礎(chǔ)示例,我們后面需要使用。
第二步,添加庫文件到工程
打開MDK工程,添加源碼,在lvglsrc文件夾下面有如下文件,我們在MDK里面添加全部文件即可。
然后在MDK里面再新建一個lvgl_porting文件夾和一個lvgl_demo文件夾,前者用于添加接口文件,后者用于我們后面添加示例文件,將 lvglportinglv_port_disp_template.c和lvglportinglv_port_indev_template.c,lvglportinglv_port_fs_template.c各復(fù)制一份,分別改名為lv_port_disp,c和lv_port_indev.c,lv_port_fs.c添加到MDK的lv_porting文件夾下面,后面再針對開發(fā)板的硬件進行對應(yīng)的修改。
05、移植文件的適配
lvgl的源碼中包含頭文件有完整路徑和簡單路徑兩種方式,在MDK里面我們直接使用簡單的頭文件包含形式。
/********************* * INCLUDES *********************/ #ifdef LV_CONF_INCLUDE_SIMPLE #include "lv_conf.h" #else #include "../../../lv_conf.h" #endif
我們使用簡單的頭文件包含,在MDK的宏定義里面添加LV_CONF_INCLUDE_SIMPLE 定義,如果后面還有l(wèi)vgl的頭文件路徑是MDK不能識別的,讀者根據(jù)實際情況修改為編譯器能識別的格式,后面不再對此修改做介紹。
修改lv_conf文件,在我們之前復(fù)制過來的配置示例文件默認是被注釋掉了。我們需要打開他。只需要將開頭的#if 0修改為#if 1即可,如果后續(xù)的文件中再出現(xiàn)這種開關(guān),讀者自行打開即可。
/** /* * COPY THIS FILE AS `lv_conf.h` NEXT TO the `lvgl` FOLDER */ #if 1 /*Set it to "1" to enable content*/ #ifndef LV_CONF_H #define LV_CONF_H /* clang-format off */ #include
配置屏幕的大小,我們的液晶屏是480*272
/* Maximal horizontal and vertical resolution to support by the library.*/ #define LV_HOR_RES_MAX (480) #define LV_VER_RES_MAX (272)
配置顏色位數(shù),我們使用RGB565模式,16位色
/* Color depth: * - 1: 1 byte per pixel * - 8: RGB233 * - 16: RGB565 * - 32: ARGB8888 */ #define LV_COLOR_DEPTH 16 /* Swap the 2 bytes of RGB565 color. * Useful if the display has a 8 bit interface (e.g. SPI)*/ #define LV_COLOR_16_SWAP 0
LVGL內(nèi)存配置,這里區(qū)別與繪圖緩沖區(qū),這里配置的是lvgl的控件等使用的內(nèi)存,需大于2KB,這里可以使用默認的32K配置,也可以將內(nèi)存定義100K,從而分配更多的內(nèi)存。
/* 1: use custom malloc/free, 0: use the built-in `lv_mem_alloc` and `lv_mem_free` */ #define LV_MEM_CUSTOM 0 #if LV_MEM_CUSTOM == 0 /* Size of the memory used by `lv_mem_alloc` in bytes (>= 2kB)*/ # define LV_MEM_SIZE (100 * 1024U)
GPU配置,這里關(guān)閉,我們使用LCD中斷進行buffer的填充
/* 1: Enable GPU interface*/ #define LV_USE_GPU 0
LOG接口配置,這里暫未使用,讀者在使用是可以將其配置為串口等
/*1: Enable the log module*/ #define LV_USE_LOG 0 #if LV_USE_LOG /* How important log should be added: * LV_LOG_LEVEL_TRACE A lot of logs to give detailed information * LV_LOG_LEVEL_INFO Log important events * LV_LOG_LEVEL_WARN Log if something unwanted happened but didn't cause a problem * LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail * LV_LOG_LEVEL_NONE Do not log anything */ # define LV_LOG_LEVEL LV_LOG_LEVEL_WARN /* 1: Print the log with 'printf'; * 0: user need to register a callback with `lv_log_register_print_cb`*/ # define LV_LOG_PRINTF 1 #endif /*LV_USE_LOG*/
06、配置植接口
LittlevGL繪制的過程需要有一個緩沖區(qū)disp_buf,lvgl內(nèi)部將位圖繪制到這個緩沖區(qū),緩沖區(qū)滿了以后調(diào)用flush_cb接口函數(shù)進行屏幕的填充,我們將這部分緩沖區(qū)的內(nèi)容通過LCD中斷搬運到液晶屏,當填充完成后,調(diào)用lv_disp_flush_ready函數(shù)通知庫繪制已經(jīng)完成,可以開始其他繪制過程。
LittlevGL已經(jīng)提供了一個示例文件,我們上面提到的復(fù)制文件也是使用他提供的文件,只需要我們修改幾個接口函數(shù)即可。
定義lvgl繪制的緩沖區(qū),這里需定義在外部SDRAM定義兩個全屏的緩沖區(qū)。
static lv_disp_buf_t disp_buf; #ifdef SWM_USING_SRAM static lv_color_t lcdbuf_1[LV_HOR_RES_MAX * LV_VER_RES_MAX] __attribute__((at(SRAMM_BASE))) = {0x00000000}; static lv_color_t lcdbuf_2[LV_HOR_RES_MAX * LV_VER_RES_MAX] __attribute__((at(SRAMM_BASE + 0x3FC00))) = {0x00000000}; #endif #ifdef SWM_USING_SDRAM static uint32_t lcdbuf_1[LV_HOR_RES_MAX * LV_VER_RES_MAX / 2] __attribute__((at(SDRAMM_BASE))) = {0x00000000}; static uint32_t lcdbuf_2[LV_HOR_RES_MAX * LV_VER_RES_MAX / 2] __attribute__((at(SDRAMM_BASE + 0x3FC00))) = {0x00000000}; #endif lv_disp_buf_init( disp_buf, lcdbuf_1, lcdbuf_2, LV_HOR_RES_MAX * LV_VER_RES_MAX); /*Initialize the display buffer*/
定義一個lv_disp_drv_t的變量并初始化。
lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init( disp_drv); /*Basic initialization*/
設(shè)置緩沖區(qū)。
/*Set a display buffer*/ disp_drv.buffer = disp_buf;
設(shè)置屏幕填充接口,這里的 disp_fluash 是一個函數(shù),在示例中已經(jīng)定義,我們直接對其修改就行了。
/*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = disp_flush;
注冊驅(qū)動程序。
/*Finally register the driver*/ lv_disp_drv_register( disp_drv);
修改disp_flush函數(shù)以適應(yīng)我們自己的硬件和屏幕。
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { LCD->SRCADDR = (uint32_t)disp_drv->buffer->buf_act; LCD_Start(LCD); /* IMPORTANT!!! * Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); }
07、配置輸入設(shè)備接口
lvgl支持鍵盤、鼠標、按鍵、觸摸屏作為輸入設(shè)備,我們這里僅僅使用觸摸屏進行輸入。
在lv_port_indev_template.c中,注冊一個觸摸屏設(shè)備需要以下步驟,我們只需要對觸摸屏讀取的回調(diào)函數(shù)進行修改即可。
/*Register a touchpad input device*/ lv_indev_drv_init( indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = touchpad_read; indev_touchpad = lv_indev_drv_register( indev_drv);
打開觸摸屏讀取的回調(diào)函數(shù)touchpad_read函數(shù)
* Will be called by the library to read the touchpad */ static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) { static lv_coord_t last_x = 0; static lv_coord_t last_y = 0; /*Save the pressed coordinates and the state*/ if (touchpad_is_pressed()) { touchpad_get_xy( last_x, last_y); data->state = LV_INDEV_STATE_PR; } else { data->state = LV_INDEV_STATE_REL; } /*Set the last pressed coordinates*/ data->point.x = last_x; data->point.y = last_y; /*Return `false` because we are not buffering and no more data to read*/ return false; }
從touchpad_read函數(shù)可以看出,用戶只需要完成兩個接口函數(shù)即可。這兩個函數(shù)的實現(xiàn)如下:
/*Return true is the touchpad is pressed*/ static bool touchpad_is_pressed(void) { /*Your code comes here*/ if(tp_dev.sta 0x80) { return true; } return false; } /*Get the x and y coordinates if the touchpad is pressed*/ static void touchpad_get_xy(lv_coord_t * x, lv_coord_t * y) { /*Your code comes here*/ (*x) = tp_dev.x[0]; (*y) = tp_dev.y[0]; }
08、配置文件系統(tǒng)接口
文件系統(tǒng)使用FATFS,對接前需要完成文件系統(tǒng)的掛載。
文件系統(tǒng)注冊。
void lv_port_fs_init(void) { /*---------------------------------------------------- * Initialize your storage device and File System * -------------------------------------------------*/ fs_init(); /*--------------------------------------------------- * Register the file system interface in LittlevGL *--------------------------------------------------*/ /* Add a simple drive to open images */ lv_fs_drv_t fs_drv; lv_fs_drv_init( fs_drv); /*Set up fields...*/ fs_drv.file_size = sizeof(file_t); fs_drv.letter = 'P'; fs_drv.open_cb = fs_open; fs_drv.close_cb = fs_close; fs_drv.read_cb = fs_read; fs_drv.write_cb = fs_write; fs_drv.seek_cb = fs_seek; fs_drv.tell_cb = fs_tell; fs_drv.free_space_cb = fs_free; fs_drv.size_cb = fs_size; fs_drv.remove_cb = fs_remove; fs_drv.rename_cb = fs_rename; fs_drv.trunc_cb = fs_trunc; fs_drv.rddir_size = sizeof(dir_t); fs_drv.dir_close_cb = fs_dir_close; fs_drv.dir_open_cb = fs_dir_open; fs_drv.dir_read_cb = fs_dir_read; lv_fs_drv_register( fs_drv); }
09、配置LittlevGL的嘀嗒心跳時鐘接口
LittlevGL的使用需要需要周期性的時鐘支持,用戶需要定期調(diào)用 lv_tick_inc(uint32_t tick_period)函數(shù),我們這里利用滴答定時器的1KHz去調(diào)用這個函數(shù)。在滴答定時器的中斷服務(wù)函數(shù)中添加lvgl時基函數(shù)。
uint8_t tick_indev = 0; void SysTick_Handler_cb(void) { lv_tick_inc(1); tick_indev++; if (tick_indev > 100) { tick_indev = 0; GT911_Scan(); } }
10、初始化
包含lvgl的初始化以及顯示和觸摸,文件系統(tǒng)接口的初始化。
lv_init(); lv_port_disp_init(); lv_port_indev_init(); lv_port_fs_init();
我們需要在主循環(huán)中周期性調(diào)用LittelvGL的任務(wù)處理函數(shù)。
while (1 == 1) { lv_task_handler(); }
然后就可以進行應(yīng)用的開發(fā)了。
來源:華芯微特32位MCU
免責(zé)聲明:本文為轉(zhuǎn)載文章,轉(zhuǎn)載此文目的在于傳遞更多信息,版權(quán)歸原作者所有。本文所用視頻、圖片、文字如涉及作品版權(quán)問題,請聯(lián)系小編進行處理
審核編輯 黃宇
-
微控制器
+關(guān)注
關(guān)注
48文章
7454瀏覽量
150854 -
LVGL
+關(guān)注
關(guān)注
1文章
79瀏覽量
2887
發(fā)布評論請先 登錄
相關(guān)推薦
評論