最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

Linux平臺(tái)下STM32移植RTThread+LVGL

2022-04-02 13:37 作者:神棍技術(shù)宅Leo  | 我要投稿

寫在前面,由于Leo醬是先寫的Markdown在復(fù)制過來的,格式可能有問題,請(qǐng)擔(dān)待,那個(gè)閃爍的確實(shí)閃爍了,PDF我會(huì)發(fā)到QQ群。

開發(fā)平臺(tái)與工具鏈

  • VSCode

  • GCC 交叉編譯工具鏈 + Make +OpenOCD

  • STM32CubeMX

所使用的庫(kù)和第三方組件

  • STM32 HAL

  • RT-Thread Nano

  • LVGL

1. 準(zhǔn)備工作

1.1 準(zhǔn)備第三方源代碼

準(zhǔn)備RTThread源碼與LVGL源碼

官方下載地址:

RT-Thread Nano

LVGL Git倉(cāng)庫(kù)

下載后進(jìn)行解壓,Leo醬的目錄組織方法是在工作區(qū)目錄(家目錄下新建的Workspace目錄,用于存放當(dāng)前各種工作區(qū))下新建一個(gè)ThirdParty目錄,用以存放各類第三方組件,然后將RT-Thread和LVGL源碼解壓到或克隆到該目錄下。

由此,便準(zhǔn)備好了第三方源碼。

1.2 生成STM32項(xiàng)目結(jié)構(gòu)

到此,我們開始對(duì)于項(xiàng)目的創(chuàng)建,需要注意的是,無論使用那種集成開發(fā)環(huán)境或者交叉工具鏈,一個(gè)項(xiàng)目最核心的永遠(yuǎn)是編譯相關(guān)的文件,其他的對(duì)于項(xiàng)目組織的方式由著具體開發(fā)環(huán)境而異,因此,在本教程中,Leo醬會(huì)注意強(qiáng)調(diào)這點(diǎn),無論是使用HAL庫(kù)還是標(biāo)準(zhǔn)庫(kù),用STM32CubeMX配置項(xiàng)目初始源碼還是手動(dòng)添加相關(guān)的硬件庫(kù)甚至使用寄存器開發(fā)都無所謂。核心在于思路。因此這一步,工作的實(shí)質(zhì)是生成一個(gè)能夠使用的支撐STM32基本運(yùn)行的源碼集合,并且用一種方式去組織這些文件。

首先打開,STM32CubeMX,新建一個(gè)項(xiàng)目,選擇對(duì)應(yīng)型號(hào)MCU,進(jìn)入到項(xiàng)目配置中。

Leo醬使用的是STM32F103RET6。

首先我們配置好調(diào)試為串口調(diào)試(因?yàn)槭褂玫氖荢WD),并且配置HAL庫(kù)的時(shí)鐘源為其他的定時(shí)器,至于哪一個(gè)定時(shí)器無所謂,看你工程中留著哪一個(gè)。反正別用系統(tǒng)滴答定時(shí)器(SysTick),因?yàn)镽T-Thread需要使用它來提供系統(tǒng)時(shí)基。


其他的方式就是配置屏幕相關(guān)GPIO,由于Leo醬使用的板子和LCD顯示屏決定需要使用PB4-PB9(推挽輸出)作為L(zhǎng)CD的硬件接口。另外,為了演示RT-Thread,我們使用一個(gè)GPIO來進(jìn)行LED的閃爍。在此,Leo醬配置了PA8作為L(zhǎng)ED的驅(qū)動(dòng)端口(推挽輸出)。

最后使能外部高速時(shí)鐘HSE輸入,設(shè)置HCLK主頻為72MHz(這一步看你自己)

最后,配置項(xiàng)目信息,首先需要在Code Generator選項(xiàng)卡中配置對(duì)于每一個(gè)外設(shè)單獨(dú)生成.c和.h文件。然后配置項(xiàng)目生成信息如下圖。


需要注意的點(diǎn)就是,把堆棧的大小設(shè)置的大一些,因?yàn)槲覀冃枰渲肔VGL使用c標(biāo)準(zhǔn)庫(kù)進(jìn)行動(dòng)態(tài)內(nèi)存管理。另外,工具鏈配置為Makefile,設(shè)置好項(xiàng)目名就直接點(diǎn)擊生成項(xiàng)目吧。

在生成項(xiàng)目之后,我們得到了一個(gè)目錄,其中的目錄結(jié)構(gòu)如下

其中Core目錄是項(xiàng)目程序的核心邏輯業(yè)務(wù)實(shí)現(xiàn)代碼所在的目錄,Drivers目錄是驅(qū)動(dòng)所在目錄,HAL庫(kù)和CMSIS支持被放在這里。如果您不滿這種目錄組織方式,那就自己改就好了,畢竟怎么組織是人定的。Leo醬覺得這樣組織其實(shí)也不錯(cuò),就直接用了。在Core目錄中存放自己的業(yè)務(wù)邏輯,把自己寫的板級(jí)支持包(BSP)也正好可以放在Drivers目錄中。

至于剩下的文件,.ioc為拓展名的文件還有一個(gè).mxproject文件是CubeMX工程文件,如果你以后不打算再用CubeMX 進(jìn)行其他的配置,刪了也無妨,Leo醬有精神潔癖并且也確實(shí)不打算后期繼續(xù)使用CubeMX進(jìn)行配置(畢竟只是一個(gè)教學(xué)用的工程),所以就刪了。

Makefile是make使用的自動(dòng)編譯腳本,我們直接用。

startup_stm32f103xe.s是匯編啟動(dòng)文件,是項(xiàng)目源碼。

最后的.ld文件是鏈接腳本,如果要配置堆棧大小可以從這里配置。其他的可能在匯編啟動(dòng)文件中配置,但是使用Makefile進(jìn)行編譯就是在這里配置。工程編譯要用。

1.3 編寫VSCode配置文件

用VSCode打開該目錄。

按下Ctrl+Shift+P,選擇打開工作區(qū)設(shè)置

配置Json文件如下:

用于啟動(dòng)代碼提示和語法檢查

選擇運(yùn)行菜單中的添加配置,添加啟動(dòng)配置(點(diǎn)擊配置任務(wù)后隨便選,反正得刪了,我們只需要一個(gè)launch.json文件罷了),文件如下:

上述代碼中,我們指定了一個(gè)Build任務(wù)用于調(diào)試前編譯,我們需要寫這個(gè)任務(wù)。

所以我們按Ctrl+Shift+P,選擇配置任務(wù)。(點(diǎn)擊配置任務(wù)后隨便選,反正得刪了,我們只需要一個(gè)tasks.json文件罷了)

任務(wù)代碼如下:

至此,我們就配置完了VSCode的調(diào)試編譯環(huán)境。我們完全可以按F5編譯運(yùn)行一下,會(huì)生成一個(gè)build目錄,里面就是各種目標(biāo)文件。

2.移植RT-Thread

2.1 源碼添加與裁剪

首先我們得想一下,我們的RT-Thread源碼怎么放。這你們自己決定,我只按照我的方式來講。Leo醬的話,會(huì)在項(xiàng)目頂級(jí)目錄新建一個(gè)目錄叫做System顧名思義就是用來存放系統(tǒng)相關(guān)的文件,CubeMX生成第三方組件時(shí)會(huì)統(tǒng)一放到一個(gè)叫做Middlewares(中間件)的目錄中,我的話,就直接放在系統(tǒng)中,畢竟硬件和業(yè)務(wù)之間也就是隔著一個(gè)系統(tǒng)層和驅(qū)動(dòng)層咯。

所以新建System目錄并將RT-Thread源碼放到這里面,并改名為rt-thread(默認(rèn)就是這個(gè)名,是就不用改了)。之后的目錄結(jié)構(gòu)如下

下一步就是裁剪,把沒用的給刪咯。首先rt-thread目錄下不包括目錄的所有文件都刪咯。然后把docs目錄也刪咯。把bsp子目錄下的所有目錄刪咯。把board.c 和 rtconfig.h留著。

libcpu目錄下一個(gè)arm一個(gè)risc-v。這是針對(duì)架構(gòu)的底層支持包。Leo醬使用的芯片架構(gòu)是ARM-Cortex M3所以其他的全刪咯。剩下的目錄結(jié)構(gòu)如下

那幾個(gè).S匯編文件是針對(duì)不同編譯器的。我們用的是gcc所以把剩下倆也刪了。然后把那個(gè)拓展名.S中的大寫S改成小寫s,因?yàn)镸akefile文件去編譯的時(shí)候只認(rèn)小寫的.s(這不是Make的鍋,是CubeMX自動(dòng)生成的Makefile就是這么寫的,你也可以該Makefile,但是需要改的匯編文件就這一個(gè),不如直接改它)。

改完就是這樣。


2.2 修改Makefile添加RT-Thread文件

在移植RT-Thread之前,我們需要先添加RT-Thread項(xiàng)目文件。我們使用Makefile進(jìn)行構(gòu)建,所以我們需要修改Makefile文件。

在C_SOURCES中添加.c文件 (components我們不用所以就不用添加)

在ASM_SOURCES中添加匯編文件

System/rt-thread/libcpu/arm/cortex-m3/context_gcc.s

在C_INCLUDES中添加頭文件包含路徑

2.3 修改源碼,進(jìn)行移植

對(duì)于使用HAL庫(kù)而言,一般的啟動(dòng)順序是在匯編完成,C語言運(yùn)行環(huán)境初始化后直接跳轉(zhuǎn)到main函數(shù)進(jìn)行執(zhí)行,如下圖

而在RT-Thread中main函數(shù)用以提供main線程的入口函數(shù),并且按照原本的啟動(dòng)次序,并無法執(zhí)行任何RT-Thread相關(guān)源碼,談何對(duì)于系統(tǒng)環(huán)境進(jìn)行初始化呢?

RT-Thread提供了另外一個(gè)入口函數(shù)entry進(jìn)行替代。我們可以來看一下這個(gè)函數(shù)。

在components.c中有對(duì)這個(gè)函數(shù)的定義。如下

可見,對(duì)于不同的編譯器,RT-Thread提供了不同的入口函數(shù),對(duì)于GNUC,我們只需要將入口函數(shù)替換或者添加到gcc參數(shù)中,一般替換吧,方便。

修改完啟動(dòng)入口,我們需要移植中斷服務(wù)函數(shù),系統(tǒng)需要使用中斷服務(wù)函數(shù)進(jìn)行系統(tǒng)調(diào)度等系統(tǒng)級(jí)過程。需要移植的中斷處理函數(shù)有三個(gè)分別是

  • HardFault_Handler 硬中斷服務(wù)函數(shù),RT-Thread 接管了這個(gè)用以打印系統(tǒng)信息。

  • PendSV_Handler PendSV中斷服務(wù)函數(shù),RT-Thread接管用以產(chǎn)生上下文切換

  • SysTick_Handler 系統(tǒng)滴答定時(shí)器中斷服務(wù)函數(shù),RT-Thread用來產(chǎn)生系統(tǒng)時(shí)基

這三個(gè)中斷處理函數(shù)在 Core/Src/stm32f1xx_it.c中有定義,需要注釋掉或者在定義前添加__weak標(biāo)識(shí),刪了也行,在此使用添加__weak標(biāo)識(shí),畢竟共存而不對(duì)抗,融合而不破壞是一種美學(xué)。至于前面entry替換main,因?yàn)閙ain也會(huì)被用到,而且改回去其實(shí)也很方便。當(dāng)然如果需要針對(duì)搭載系統(tǒng)和不搭載系統(tǒng)進(jìn)行同步開發(fā),建議添加編譯器選項(xiàng),這樣可以在make時(shí)通過指定而方便切換。

中斷處理結(jié)束后,其實(shí)系統(tǒng)就能夠跑起來了,但是現(xiàn)在有一個(gè)問題就是,我們來看一下這段代碼

這是main函數(shù)里對(duì)于硬件的初始化,其中涉及了HAL庫(kù)的初始化,系統(tǒng)時(shí)鐘的初始化,這放在系統(tǒng)環(huán)境建立后,屬實(shí)不合適也不應(yīng)該。這類初始化難道不應(yīng)該在系統(tǒng)環(huán)境建立前期進(jìn)行的么?所以我們應(yīng)該對(duì)這部分代碼進(jìn)行搬移。我們回過頭看一下entry函數(shù),這是替代了原本main的入口,物歸原主,我們理所當(dāng)然應(yīng)當(dāng)這么去想。

在entry函數(shù)中調(diào)用了rtthread_startup(),rtthread_startup函數(shù)代碼如下

我們可以看到,對(duì)于系統(tǒng)初始化的工作應(yīng)當(dāng)放在最前方,因?yàn)榇a第一段禁用了中斷,這是系統(tǒng)初始化中一個(gè)很重要的部分,如果我們?cè)谟布跏蓟瘯r(shí)啟用了中斷,那么這可能會(huì)是很BadBad的事情。所以,我們將原本初始化的那部分代碼移動(dòng)到這里或者我們?cè)趍ain.c中對(duì)其封裝為Hardware_Init()方法。如下:

我們接下來就只需要在RT-Thread入口函數(shù)對(duì)應(yīng)位置進(jìn)行調(diào)用即可(沿著這個(gè)思路你甚至可以通過重寫入口函數(shù)進(jìn)行初始化)

最后,我們?nèi)コ蛞谎踨tconfig.h,對(duì)于其中的系統(tǒng)組件啟用與否都通過宏在其中進(jìn)行定義。

在檢查過程中,Leo醬發(fā)現(xiàn)了一個(gè)問題,請(qǐng)看

系統(tǒng)沒有啟用內(nèi)存堆,這對(duì)于動(dòng)態(tài)生成線程來說根本就是澀澀監(jiān)獄級(jí)別的禁止。取消注釋,啟用它!

至此,系統(tǒng)移植OK。

2.4 測(cè)試并準(zhǔn)備移植LVGL

我們的測(cè)試通過創(chuàng)建兩個(gè)線程進(jìn)行,一個(gè)用于LED閃爍,一個(gè)用于LVGL的服務(wù)線程。

可以單獨(dú)創(chuàng)建.c和.h文件用來初始化各個(gè)組件,我這個(gè)教學(xué)的項(xiàng)目也可以,但沒必要。所以直接寫到了main.c中,以函數(shù)命名進(jìn)行區(qū)分。

代碼如下:

測(cè)試結(jié)果

3. 移植LVGL

3.1 添加并裁剪LVGL文件

在System目錄中新建一個(gè)目錄名為lvgl,在lvgl目錄中再新建一個(gè)lvgl目錄和一個(gè)drivers目錄,為了防止無意義的大量刪除,我們這次只復(fù)制src目錄到lvgl/lvgl中,將lvgl源碼目錄下examples/porting目錄中的所有.c和.h文件復(fù)制到drivers目錄中并且刪除其文件名里的template(不刪也行,看你自己)。將lvgl源碼目錄中的lv_conf_template.h和lvgl.h復(fù)制到新建的lvgl/lvgl目錄中并刪除template。完成后的目錄結(jié)構(gòu)如下

3.2 準(zhǔn)備顯示屏驅(qū)動(dòng)

這一塊自己寫,寫完以后自己放。我只以自己的作為演示。

在Drivers目錄中新建BSP目錄,并在BSP目錄中新建st7735目錄。將驅(qū)動(dòng)文件st7735.c 和 st7735.c放在里面,并且添加源文件和頭文件包含目錄到Makefile

而對(duì)于驅(qū)動(dòng)程序,應(yīng)當(dāng)提供如下接口(我直接給我的.h文件內(nèi)容)

其中 LCD_Init用于液晶屏初始化,LCD_SetPixel用于像素點(diǎn)設(shè)置,LCD_FillRegion用于區(qū)域填充。

其中LCD_SetPixel和LCD_FillRegion二者可以只實(shí)現(xiàn)其一,但必須得有一個(gè),LVGL需要調(diào)用它們進(jìn)行輸出,實(shí)現(xiàn)LCD_SetPixel比較靈活,而LCD_FillRegion的寫入速度會(huì)快。

3.3 修改Makefile文件添加LVGL代碼

先修改C_INCLUDES添加頭文件包含路徑,如下

然后我們添加所有的.c文件,由于里面的.c文件是真的多,所以Leo醬不得不寫一個(gè)Python腳本用于檢索目錄獲取所有的.c文件

Python腳本如下

該P(yáng)ython腳本將檢索所有當(dāng)前目錄下的文件和子目錄并且將.c文件以Makefile待添加的格式寫入到csourcelist.txt中。

生成后的源文件列表如下


3.4 移植LVGL

移植操作需要做的僅僅是實(shí)現(xiàn)驅(qū)動(dòng),配置心跳并且配置LVGL。

3.4.1 配置lv_conf.h

打開lv_conf.h

將最上面的 #if 0改為#if 1以啟用該文件

修改顏色深度

#define LV_COLOR_DEPTH 16

默認(rèn)為16(RGB565格式),Leo醬用的不需要改。

找到這一行

#define LV_MEM_SIZE (48U * 1024U)

修改提供給LVGL進(jìn)行內(nèi)存分配的空間,Leo醬設(shè)置為

#define LV_MEM_SIZE (8U * 1024U)

3.4.2 實(shí)現(xiàn)驅(qū)動(dòng)(僅實(shí)現(xiàn)顯示驅(qū)動(dòng))

打開 drivers目錄下的lv_port_disp.c和lv_port_disp.h,將最上面的 #if 0改為#if 1以啟用該文件。

修改頭文件包含,畢竟我們刪了template,所以,#include 中也得刪咯。另外,包含我們實(shí)現(xiàn)的LCD驅(qū)動(dòng)頭文件。并且修改lvgl.h路徑,如下:

找到lv_port_disp_init函數(shù),找到

這三個(gè)是三種緩沖區(qū)的實(shí)現(xiàn)模板,留一個(gè)就行。我留了第一個(gè)。并且把MY_DISP_HOR_RES 改為具體的硬件尺寸定義。

將驅(qū)動(dòng)程序結(jié)構(gòu)體的hor_res和ver_res也改為具體硬件尺寸定義。

在disp_init函數(shù)中調(diào)用LCD初始化程序

在disp_flush函數(shù)中調(diào)用繪制函數(shù),在此使用LCD_SetPixel

3.4.3 配置心跳

lvgl需要給定一個(gè)心跳來控制顯示效果的時(shí)間。所以我們通過一個(gè)定時(shí)器來進(jìn)行時(shí)間控制??梢酝ㄟ^RT-Thread軟件定時(shí)器,也可以綁定在其他的時(shí)基上,在這里我們直接使用HAL庫(kù)的時(shí)基中斷為L(zhǎng)VGL提供心跳。


至此,移植完畢。

3.5 LVGL測(cè)試

打開那個(gè)LVGL初始化線程

然后在LVGL_Entry函數(shù)中執(zhí)行初始化操作,代碼如下:

編譯運(yùn)行。

運(yùn)行結(jié)果:



Linux平臺(tái)下STM32移植RTThread+LVGL的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
涡阳县| 乳山市| 麟游县| 琼海市| 鲁甸县| 江安县| 宜阳县| 乌拉特中旗| 灵武市| 新龙县| 鸡西市| 平和县| 上林县| 瓦房店市| 克什克腾旗| 天台县| 石台县| 龙井市| 平陆县| 湘阴县| 汨罗市| 道真| 曲松县| 平武县| 贵南县| 北辰区| 南安市| 高青县| 永修县| 芜湖县| 吕梁市| 通江县| 将乐县| 韶山市| 襄汾县| 平乡县| 安泽县| 西丰县| 铁岭县| 大田县| 班戈县|