基于NXP iMX8MP處理器M7核心LVGL移植

By Toradex胡珊逢


LVGL (Light and Versatile Graphics Library)是一個輕量級的開源圖形庫闷叉,采用?C?或者?MicroPython?語言開發(fā)消痛〉Eィ可以在資源有限的?MCU?上輕松地繪制圖形界面。Verdin iMX8M Plus?模塊的處理器除了?Cortex-A53?核心外榄鉴,還具有一個?Cortex-M7?核心加勤,其可以運行諸如?FreeRTOS?的實時操作系統(tǒng)。本文接下來就將介紹如何移植LVGL?到Verdin iMX8M Plus?的Cortex-M7?核上扰才。


本次演示采用一塊SPI?接口的LCD?允懂,屏幕控制器為?ILI9341。除了VCC?衩匣、GND?和背光外蕾总,和Verdin iMX8M Plus?連接的引腳主要有下面四個。

ILI9341Verdin iMX8M Plus

CSSPI?片選ECSPI1_SS0SODIMM202

RESET復位GPIO1_IO001SODIMM208

DC命令/數(shù)據(jù)GPIO1_IO00SODIMM206

MOSISPI MOSIECSPI1_MOSISODIMM200

SCKSPI?時鐘ECSPI1_SCLKSODIMM196

表一:Verdin iMX8M Plus?連接 ?ILI9341


注意?Verdin iMX8M Plus?的?SoC?使用?1.8V IO琅捏,在連接?SPI LCD?時需要使用?3.3V – 1.8V?電壓轉(zhuǎn)換電路生百。


LVGL?庫分為兩部分。第一部分是圖形實現(xiàn)柄延,包括繪制各類形狀蚀浆、色彩管理、動畫事件、定時器等市俊,第二部分是硬件驅(qū)動實現(xiàn)?lvgl_drivers杨凑。LVGL?將每一幀繪制好的圖片數(shù)據(jù)保存在RAM?中,lvgl_drivers?負責將數(shù)據(jù)傳輸?shù)酵獠匡@示設備摆昧。lvgl_drivers?支持多種顯示器撩满,如?TFT、電子墨水屏绅你、OLED?等伺帘。這里是?lvgl_drivers?支持的常見顯示控制器。LVGL?移植時通常只需要修改?lvgl_drivers忌锯。例如在本次演示使用了SPI?接口的顯示屏曼追。Verdin iMX8M Plus?可以提供連接顯示屏所需的SPI Master?功能。移植任務主要是適配lvgl_drivers?中ILI9341?的SPI?數(shù)據(jù)傳輸以及LVGL?圖形庫的幾個重要定時任務汉规。


首先安裝iMX8M Plus M7?開發(fā)所需的?SDK礼殊,如?SDK_2_12_1_MIMX8ML8xxxKZ。將該工程下載到SDK?安裝目錄的SDK_2_12_1_MIMX8ML8xxxKZ/boards/evkmimx8mp/rtos_examples/freertos_ecspi/?位置针史。這個工程已經(jīng)包含了下面提到的修改內(nèi)容晶伦。


在工程目錄的armgcc/CmakeLists.txt?添加lvgl?和?lvgl_drivers。這里指定v8.3.7啄枕,其他的版本可能發(fā)生API?變更婚陪,需要做對應的修改。設置?lvgl?和?lvgl_drivers?的?github?下載源频祝。

---------------------------------------

# Fetch LVGL from GitHubFetchContent_Declare(lvgl GIT_REPOSITORY https://github.com/lvgl/lvgl.git GIT_TAG v8.3.7)FetchContent_MakeAvailable(lvgl)FetchContent_Declare(lv_drivers?????????????????????GIT_REPOSITORY https://github.com/lvgl/lv_drivers GIT_TAG v8.3.0)FetchContent_MakeAvailable(lv_drivers)

---------------------------------------


將lvgl::lvgl?和lvgl::drivers?編譯到工程中泌参。

---------------------------------------

target_link_libraries(${MCUX_SDK_PROJECT_NAME} PRIVATE lvgl::lvgl lvgl::drivers)

---------------------------------------


在?add_executable(${MCUX_SDK_PROJECT_NAME} ?添加下面兩個頭文件。

---------------------------------------

"${ProjDirPath}/../lv_drv_conf.h""${ProjDirPath}/../lv_conf.h"

---------------------------------------


設置變量LV_CONF_PATH常空,這是lvgl?的配置文件lv_conf.h沽一,里面包含屏幕分辨率和lvgl?圖形庫參數(shù)。

---------------------------------------

# Specify path to own LVGL config headerset(LV_CONF_PATH????${CMAKE_CURRENT_SOURCE_DIR}/../lv_conf.h????CACHE STRING "" FORCE)

---------------------------------------


FETCHCONTENT_UPDATES_DISCONNECTED?允許每次編譯的時候不必重新下載?lvgl?代碼漓糙。

---------------------------------------

SET(FETCHCONTENT_UPDATES_DISCONNECTED ON)

---------------------------------------


在工程目錄下的?lv_conf.h?設置SPI TFT?屏幕分辨率240*320铣缠。

---------------------------------------

#define LV_HOR_RES_MAX 240#define LV_VER_RES_MAX 320

---------------------------------------


在工程目錄下的?lv_drv_conf.h?設置?LVGL?硬件驅(qū)動相關(guān)參數(shù)。

LV_DRV_DELAY_US()?和?LV_DRV_DELAY_MS()?需要在自己的代碼中實現(xiàn)(位于freertos_ecspi_loopback.c)昆禽。

---------------------------------------

/*********************?* DELAY INTERFACE?*********************/#define LV_DRV_DELAY_INCLUDE ?<stdint.h> ???????????/*Dummy include by default*/#define LV_DRV_DELAY_US(us) ?LVGL_DELAY_MS((1)) ??????/*Delay the given number of microseconds*/#define LV_DRV_DELAY_MS(ms) ?LVGL_DELAY_MS((ms)) ??????/*Delay the given number of milliseconds*/

---------------------------------------


延時函數(shù)在每個平臺上的實現(xiàn)方法都不同蝗蛙,有的可以使用while()?或for()?循環(huán),在運行操作系統(tǒng)的平臺上可以利用系統(tǒng)提供的API醉鳖,例如Verdin iMX8M Plus M7?的FreeRTOS?中使用??vTaskDelay()捡硅。

---------------------------------------

void LVGL_DELAY_MS(uint8_t ms){?????vTaskDelay( ms / portTICK_PERIOD_MS );}

---------------------------------------


SPI TFT LCD?采用了?ILI9341?控制器,因此設置 ?USE_ILI9341?宏定義盗棵,以及分辨率參數(shù)壮韭。

---------------------------------------

#ifndef USE_ILI9341# ?define USE_ILI9341 ??????1#endif# ?define LV_HOR_RES ???????????240 ??????# ?define LV_VER_RES ???????????320 ???

---------------------------------------


除了上面的延時函數(shù)外北发,用于控制ILI9341?數(shù)據(jù)/命令引腳?的LV_DRV_DISP_CMD_DATA()?、復位ILI9341?的LV_DRV_DISP_RST()?和SPI?傳輸一個字節(jié)泰涂、多個字節(jié)的函數(shù)spi_transaction_one_byte(),spi_transaction_array ()也需要自己實現(xiàn)辐怕。在?lv_drv_conf.h?里定義 ?lv_diplay_cmd_data()?和?lv_diplay_reset()逼蒙。

---------------------------------------

#define LV_DRV_DISP_INCLUDE ????????<stdint.h> ??????????/*Dummy include by default*/#define LV_DRV_DISP_CMD_DATA(val) ?lv_diplay_cmd_data((val)) ???/*Set the command/data pin to 'val'*/#define LV_DRV_DISP_RST(val) ??????lv_diplay_reset((val)) ???/*Set the reset pin to 'val'*/

---------------------------------------


由于?iMX8M Plus?的?SPI?在收發(fā)時會自動控制?CS?引腳,因此?LV_DRV_DISP_SPI_CS(val)?可以設置為空函數(shù)寄疏。

---------------------------------------

#define LV_DRV_DISP_SPI_CS(val) ?????????/*spi_cs_set(val)*/ ????/*Set the SPI's Chip select to 'val'*/#define LV_DRV_DISP_SPI_WR_BYTE(data) ???spi_transaction_one_byte((data))/*spi_wr(data)*/ ???????/*Write a byte the SPI bus*/#define LV_DRV_DISP_SPI_WR_ARRAY(adr, n) spi_transaction_array((adr), (n))/*spi_wr_mem(adr, n)*/ ?/*Write 'n' bytes to SPI bus from 'adr'*/

---------------------------------------


在freertos_ecspi_loopback.c?中實現(xiàn)lv_diplay_cmd_data()?是牢,lv_diplay_reset(),spi_transaction_one_byte()陕截,spi_transaction_array()驳棱。

---------------------------------------

void lv_diplay_cmd_data(uint8_t val){????GPIO_PinWrite(GPIO_PAD, LCD_CMD_DATA, val);}void lv_diplay_reset(uint8_t val){????GPIO_PinWrite(GPIO_PAD, LCD_RESET, val);}

---------------------------------------


LCD_CMD_DATA ?和LCD_RESET?分別定義如下,用于控制ILI9341?的?命令/數(shù)據(jù)和復位引腳农曲。

---------------------------------------

#define GPIO_PAD ???????GPIO1#define LCD_CMD_DATA ???0U#define LCD_RESET ??????1U

---------------------------------------


SPI?數(shù)據(jù)傳輸采用列隊形式發(fā)送社搅。spi_transaction_one_byte()?和spi_transaction_array()?均采用xQueueSend()?將需要發(fā)送的數(shù)據(jù)加入到spi_queue?列隊中,該列隊長度為128?字節(jié)乳规。然后運行一個高優(yōu)先級的任務ecspi_task()?將數(shù)據(jù)從列隊中通過ECSPI_RTOS_Transfer()?發(fā)送到ILI9341?控制器形葬。由于發(fā)送數(shù)據(jù)的任務優(yōu)先級高于寫入列隊的,所以spi_queue?列隊中保存的數(shù)據(jù)會被很快發(fā)送出去暮的。

---------------------------------------

void spi_transaction_one_byte(uint8_t data){????BaseType_t xStatus;????uint32_t data_to_queue;????data_to_queue = (uint32_t)data;????xStatus = xQueueSend(spi_queue, &data_to_queue, portMAX_DELAY);????if( xStatus != pdPASS )????{????????PRINTF( "Could not send to the queue.\r\n" );????}}

---------------------------------------


本演示中笙以,采用不同優(yōu)先級的任務來實現(xiàn)相應的工作。優(yōu)先級數(shù)字越大便是優(yōu)先級越高冻辩。為了保證?SPI?及時發(fā)送到?ILI9341猖腕,將其設置為最高優(yōu)先級。

任務函數(shù)優(yōu)先級功能描述

draw_lvgl_ui2LVGL UI

lv_task_hander_task1調(diào)用?lv_task_handler

init_task3SPI恨闪、lv_init, hal_init?初始化

ecspi_task4發(fā)送?SPI?數(shù)據(jù)到ILI9341

vApplicationTickHookexecuted every tick調(diào)用?lv_tick_inc

表二:FreeRTOS?任務描述


draw_lvgl_ui()?中繪制需要顯示的?LVGL UI?內(nèi)容倘感,本演示中將顯示一個動態(tài)伸縮變化的彩色柱。


lv_task_hander_task()?將每隔?5ms?調(diào)用?lv_task_handler()咙咽,該函數(shù)會每?5ms?處理?lvgl?相關(guān)任務侠仇。


init_task()?中完成?SPI、ILI9341?的初始化犁珠,以及?LVGL?圖形庫的相關(guān)初始化逻炊。為了防止在初始化完成前調(diào)用lv_task_handler?和UI?繪制,該任務運行時使用?vTaskSuspend?暫時停止draw_lvgl_ui?和lv_task_hander_task?兩個任務犁享。但ecspi_task?繼續(xù)運行余素。

---------------------------------------

void init_task(void *pvParameters){????vTaskSuspend(xUITaskHandle); ?//suspend ui task untill init task finisded.????vTaskSuspend(xLVTaskHandle);????????spi_init();????ili9341_init();????lv_init();????hal_init();????PRINTF("Init finised. resume xUI and XLV tasks\r\n");????vTaskResume(xUITaskHandle);????vTaskResume(xLVTaskHandle);

---------------------------------------


vApplicationTickHook?并不是一個單獨的FreeRTOS?任務,而是在每個tick?都會被執(zhí)行炊昆。因此桨吊,lv_tick_inc?將在每2ms?運行威根。該函數(shù)向LVGL?動畫和其他任務提供已經(jīng)運行的時間信息,需要保證其運行的準確性和粒度视乐。

---------------------------------------

void vApplicationTickHook(void){????static uint32_t ulCount = 0;????ulCount++;????if (ulCount >= 2UL)????{????????lv_tick_inc(2); ??//calling every 2 milliseconds.????????ulCount = 0UL;????}}

---------------------------------------


修改?FreeRTOSConfig.h?中的下面參數(shù)洛搀,實現(xiàn)每個?TICK?為?1ms,以及啟用上面提到的TICK_HOOK佑淀。

---------------------------------------

#define configTICK_RATE_HZ ?????????????????????((TickType_t)1000)#define configUSE_TICK_HOOK ????????????????????1

---------------------------------------


由于LVGL?運行需要較大的RAM?空間留美,因此該演示的?M7?固件會被加載到DDR RAM?上運行。在編譯的時候使用build_ddr_release.sh?腳本伸刃。

---------------------------------------

export ARMGCC_DIR=/opt/gcc-arm-none-eabi-10.3-2021.10cd armgcc./build_ddr_release.sh

---------------------------------------


在?U-Boot?里面設置?m7bootddr?參數(shù)谎砾,將上面編譯好的?M7?固件加載到地址為?0x80000000?的?DDR RAM?中。

---------------------------------------

Verdin iMX8MP # print m7bootddrm7bootddr=tftp 0x80000000 m7.bin; dcache flush; bootaux 0x80000000

---------------------------------------


啟動時在?U-Boot?中運行下面命令捧颅。

---------------------------------------

run m7bootddr

---------------------------------------


運行效果如下景图。


總結(jié)

本文介紹為?Verdin iMX8M Plus M7?移植?LVGL?的步驟和創(chuàng)建對應 ?FreeRTOS?任務。在項目中需要為實際使用的外設和業(yè)務設置合適的任務優(yōu)先級碉哑,保證圖形流暢顯示以及數(shù)據(jù)及時處理挚币。在?device tree?也需要把?M7?所使用的外設禁用,避免和?Linux?系統(tǒng)的沖突扣典。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末忘晤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子激捏,更是在濱河造成了極大的恐慌设塔,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件远舅,死亡現(xiàn)場離奇詭異闰蛔,居然都是意外死亡,警方通過查閱死者的電腦和手機图柏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門序六,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蚤吹,你說我怎么就攤上這事例诀。” “怎么了裁着?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵繁涂,是天一觀的道長。 經(jīng)常有香客問我二驰,道長扔罪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任桶雀,我火速辦了婚禮矿酵,結(jié)果婚禮上唬复,老公的妹妹穿的比我還像新娘。我一直安慰自己全肮,他們只是感情好敞咧,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辜腺,像睡著了一般休建。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上哪自,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天丰包,我揣著相機與錄音禁熏,去河邊找鬼壤巷。 笑死,一個胖子當著我的面吹牛瞧毙,可吹牛的內(nèi)容都是我干的胧华。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼宙彪,長吁一口氣:“原來是場噩夢啊……” “哼矩动!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起释漆,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤悲没,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后男图,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體示姿,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年逊笆,在試婚紗的時候發(fā)現(xiàn)自己被綠了栈戳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡难裆,死狀恐怖子檀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乃戈,我是刑警寧澤褂痰,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站症虑,受9級特大地震影響脐恩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜侦讨,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一驶冒、第九天 我趴在偏房一處隱蔽的房頂上張望苟翻。 院中可真熱鬧,春花似錦骗污、人聲如沸崇猫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诅炉。三九已至,卻和暖如春屋厘,著一層夾襖步出監(jiān)牢的瞬間涕烧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工汗洒, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留议纯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓溢谤,卻偏偏與公主長得像瞻凤,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子世杀,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容