色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

RT-Thread學習筆記(入門篇/內核篇/開發環境篇/外設驅動篇/使用篇)

RTThread物聯網操作系統 ? 來源:RTThread物聯網操作系統 ? 作者:出出啊 ? 2022-05-17 16:22 ? 次閱讀

前言

接觸 rt-thread 已有半年,混論壇也5個半月了,期間遇到過各種奇奇怪怪的棘手問題,有過尷尬,也自信曾經提供過比較妙的應對方案。所以產生了將一些典型的使用技巧匯總分享出來的想法,遂有此篇。

入門篇

Q1. 剛下載SDK 啥也沒干,編譯沒錯,為啥程序跑不起來?

如果使用 keil + env 環境,下載源碼后的第一件事就是menuconfig
如果使用 RT-Studio ,創建項目后的第一件事就是打開 Settings
把其中所有配置頁面所有配置項全瀏覽一遍,取消掉所有不相干的配置,最后只留一個內核。

先保證最小系統跑起來,用點燈程序驗證最小系統運行正常。然后再添加自己需要用到的功能和底層外設等等。

Q2. 剛下載的 SDK 啥也沒干,編譯沒錯,為啥程序跑起來 hard fault on thread

同上

Q3. 剛下載的 SDK 啥也沒干,編譯為啥報錯了?

同上

內核篇

Q1. RT_NAME_MAX 定義多少合適

原則上越少越省內存,以內核對象 100 個為例,一個對象名占用 8 字節,總共是 800 字節。但是考慮到struct rt_object結構體定義,后面跟了兩個 rt_uint8_t 型變量。

RT_NAME_MAX 可以定義成 2n+ 2

Q2. RT_DEBUG

如非必要,不要開啟內核調試。除非,你真的想學習內核,或者調試內核的問題。

Q3. 線程棧大小定義多少合適?

這個問題和應用有很大關系,如果僅僅是一個最小內核系統,除了 idle 線程,沒有使用其它中斷和應用,256 也將將夠。如果添加了應用代碼,還有中斷和消息機制。建議 1024 起步。

Q4. 怎么快速計算 GET_PIN 返回的編號?

我們知道,芯片的 GPIO 分組往往是從 PA 開始,往后依次是 PB PC PD PE ... PZ。往往的,每組端口或者是 16bit 或者是 8bit (分別對應 16 個 IO 和 8 個 IO)。下面給出GET_PIN的簡化公式:

16bit 是(X - A) * 16 + n

A10 就是 10.
C9 就是 2*16+9=41.
H1 就是 7*16+1=113.

8bit 是(X - A) * 8 + n

這個公式別忘啊,別忘了!

Q5. 硬定時器、軟定時器、硬件定時器,傻傻分不清楚

rt-thread 內核定義了軟件定時器,和硬件定時器不同,硬件定時器需要占用一個定時器外設,還有各種比較、捕獲等功能。軟件定時器僅僅是簡單的設定一個時間,時間 timeout 的時候執行我們設定的回調函數。

rt-thread 定義的軟件定時器還細分兩種,“硬定時器” “軟定時器”,前一種是在 SysTick 中斷中執行回調函數的,多數用于線程內置定時器,應用層也可以用,但是要時刻謹記它的回調函數是在中斷中執行的。

后一種,是在一個線程中運行的,應用層對定時精度要求不是很高的可以用這種,但是也要注意“定義定時器和執行定時器回調函數的線程是兩個不同的線程!”

Q6. 消息隊列池申請多少內存合適?

1rt_err_trt_mq_init(rt_mq_tmq,constchar*name,void*msgpool,
2rt_size_tmsg_size,rt_size_tpool_size,rt_uint8_tflag);
3rt_mq_trt_mq_create(constchar*name,rt_size_tmsg_size,rt_size_tmax_msgs,rt_uint8_tflag)

如果使用rt_mq_create創建消息隊列,消息隊列池自動根據消息體大小msg_size和消息隊列最多容納的消息數量max_msgs計算。

但如果使用rt_mq_init初始化消息隊列,消息隊列池的內存msgpool需要用戶提供,這個時候,需要注意消息池內存大小pool_size。根據下面的公式計算得出:

(RT_ALIGN(msg_size, RT_ALIGN_SIZE) + sizeof(struct rt_mq_message*)) * max_msgs

其中,msg_size是消息體大小,max_msgs是消息隊列中最多消息容量。

Q7. 使用消息隊列注意

雖然rt_mq_sendrt_mq_send_waitrt_mq_urgentrt_mq_recv幾個 api 有 size 參數,但是請嚴格按照rt_mq_initrt_mq_create中的 msg_size 參數值傳遞相等的實參值。千萬不要隨意改變 size 參數的數值

換種說法,別用消息隊列直接發變長數據。

Q8. INIT_xxx_EXPORT 宏詳解

當初接觸 rt-thread 第一個讓我感觸的地方就是,main 函數里沒有初始化配置,上來直接就是一個單獨的線程。而,其它線程都通過 INIT_APP_EXPORT 自動啟動了。

rt-thread 一共定義了 6 個啟動階段,

 1/*boardinitroutineswillbecalledinboard_init()function*/
 2#defineINIT_BOARD_EXPORT(fn)INIT_EXPORT(fn,"1")
 3
 4/*pre/device/component/env/appinitroutineswillbecalledininit_thread*/
 5/*componentspre-initialization(puresoftwareinitilization)*/
 6#defineINIT_PREV_EXPORT(fn)INIT_EXPORT(fn,"2")
 7/*deviceinitialization*/
 8#defineINIT_DEVICE_EXPORT(fn)INIT_EXPORT(fn,"3")
 9/*componentsinitialization(dfs,lwip,...)*/
10#defineINIT_COMPONENT_EXPORT(fn)INIT_EXPORT(fn,"4")
11/*environmentinitialization(mountdisk,...)*/
12#defineINIT_ENV_EXPORT(fn)INIT_EXPORT(fn,"5")
13/*appliationinitialization(rtguiapplicationetc...)*/
14#defineINIT_APP_EXPORT(fn)INIT_EXPORT(fn,"6")

其中, INIT_BOARD_EXPORT 運行在任務調度器啟動前,也是唯一任務調度器運行前被執行的。這里是外設初始化配置階段。

其余幾個階段都是任務調度器啟動以后,由 main 線程(標準版,如果使用了 main 線程)負責執行。

這些階段并不是完全固定,有些是可以調整的,例如,我曾經把 lcd 的初始化從 DEVICE 提前到 BOARD ,而把 emwin 的初始化放到 PREV 。還在 ENV 階段初始化了一些消息隊列等等。

大部分情況下,以上幾個階段可以完成所有定義的初始化工作。但是,也難免出現沖突的可能。

例如,github #5194 上的這個 pr。里面還提供了很多反應這個問題的鏈接。以及很多人提出的解決方案。

個人認為,啟動順序在同一級的,而且之間有依賴/互斥關系的兩個部分。這種情況,應要求開發者自己注意調整代碼執行順序,把兩個部分初始化過程寫到同一個函數里,由開發者自己維護依賴關系。

Q9. 怎么通過 rt_thread_suspend rt_thread_resume 掛起喚醒某線程

盡量不要這么做,在 rt-thread 里,一個線程進入 suspend 態有兩種情況,一種是時間片耗盡自動讓出 cpu;一種是等待資源阻塞讓出 cpu。兩個線程之間并沒有完整透明的了解對方當前狀態的途徑。

假如某線程 A 想顯式掛起線程 B,但是,A 并不知道 B 當前是運行中讓出 cpu,還是等待資源中已經處于掛起狀態,還是資源可用正在從掛起態被喚醒過程中。所以,不明就里地掛起其它線程的做法是危險的。

筆者唯一能想到的,就是 B 線程執行任務比較多,自己不會主動出讓 cpu。而且,它的線程優先級比較低,某高優先級線程 A 在某種條件下使得 B 掛起。但是這樣線程 B 勢必會影響到 idle 線程。

其實,這種場景,完全可以使用線程間同步機制實現,線程 B 通過發信號給 A 而掛起自己;線程 A 再通過另外一個信號喚醒線程 B。

曾經以為自己能找到直接使用這倆 api 的方式,有一天,突然想到 rt-thread 的 ipc 都是針對性的,因信號量掛起的,不可能因為郵箱被喚醒。因為時間片耗盡掛起的線程也別想著會被什么資源喚醒。掛起和喚醒具有唯一性。

Q10. list_thread 或 ps 查看線程狀態不對?

1、error 列的線程錯誤沒有多少參考價值,0 是正常,-2 表示超時,執行一個rt_thread_mdelay就變 -2 了。但并不表示有錯誤。目前還沒有看到賦值有其它錯誤值的代碼。

2、status 列代表當前線程狀態。但是呢,因為 list_thread 或 ps 兩條命令是在 tshell 線程執行的,所以 tshell 線程肯定是 running ;idle 線程不可能被掛起,肯定顯示的是 ready;其它線程可能會出現 ready,但是多數時候是 suspend。但是這并不表示其它線程一直是 suspend 不被調度了。

Q11. 定時器可以執行長時間操作?

如上所說,rt-thread 中有三種定時器,每種定時器有各自的特點
硬件定時器:回調函數在中斷里,不建議直接執行長時間操作。
硬定時器:同樣也是在中斷執行回調函數,不建議直接執行長時間操作。
軟定時器:由定時器線程執行調用回調函數的軟定時器,是具有執行長時間操作的理論基礎的。定時器線程同樣是一個線程,它也有自己的線程棧,優先級等。如果某些操作是獨立的,把它們放到某特定線程里和在定時器線程運行是沒區別的。

但是,目前定時器線程處理軟定時器的方式不適合執行長時間操作。需要進行修改后才能做到。具體修改方法見 rt-thread 系統優化系列(三) 之 軟定時器的定時漂移誤差分析

注意:定時器線程的優先級需要根據需要進行調整;若有多個軟定時器,回調函數執行都比較長,必然存在某回調被延遲執行的可能性,這個是無法避免的。

Q12. "Function[xxx] shall not be used in ISR" 錯誤是怎么回事兒?

以及類似的錯誤 "Function[xxx] shall not be used before scheduler start"
詳見rt-thread 那些你必須知道的幾類 api

開發環境篇

Q1. 改變 env 或者 RT studio 下載源

rt studio 內置了 env 環境,studio 可能也是借助 env 實現下載更新組件的。有些第三方組件的主倉庫在 github 上,這樣就難為了很多小伙伴,經常因為訪問不了 github 而出現下載更新失敗。其實官方提供了鏡像下載的方式,鏡像倉庫在 gitee 上,我們需要切換 env 下載方式為鏡像下載。見此文章RT-Studio 切換鏡像服務器下載

0191b576-d50a-11ec-bce3-dac502259ad0.png

文章中RTT_逍遙大佬提供了個命令menuconfig -s,這個命令也可以,查看 menuconfig 的幫助信息可以得到詳細說明。

Q2. 生成 MDK5 項目,配置變了怎么辦?

當執行scons --target=mdk5的時候,scons 從當前目錄下的 "template.uvprojx" 文件為模版生成 "project.uvprojx" 項目配置文件。

我們修改項目配置,啟用了 "Use MicroLIB" "Browse Information" "GNU extensions" 等等之后,重新生成可能導致之前的修改丟失,可以通過修改 "template.uvprojx" 文件

1"0""1"
2"0""1"
3"0""1"

還比如,有人問,“用Scons 生成keil工程時, 如何導入sct文件?”

打開 "template.uvprojx" 文件找到 “ScatterFile” 的位置,修改里面的文件路徑及文件名就可以了。

.oardlinker_scriptslink.sct

其它可類比。

Q3. 修改 scons 使用的編譯器

找到 rtconfig.py 文件,一般和 rtconfig.h 文件同目錄,文件開頭有幾個變量

1#toolchainsoptions
2ARCH='arm'
3CPU='cortex-m4'
4CROSS_TOOL='gcc'

分別定義了,cpu 核架構,版本,以及使用的交叉編譯工具鏈平臺。目前支持 gcc keil iar 三種平臺。

接下來,針對每一種平臺,使用不同的交叉編譯工具鏈及其安裝路徑

最后是每種交叉編譯工具鏈編譯選項。

通過修改CROSS_TOOL='gcc'的定義可以修改編譯器。

Q4. env 下的兩種界面配置姿勢

他人都說 studio 好,我卻獨衷心 env。
以前只知道 menuconfig,從此還有一個
scons --pyconfig

論壇 mysterywolf 大佬發現的這個命令,像撿到一個寶,不習慣 menuconfig 的童鞋,喜歡 studio 配置可以點點點的童鞋,你們可以回來繼續使用 env 啦!

01b432f4-d50a-11ec-bce3-dac502259ad0.jpg

修改完,點 SAVE -》關閉。

還支持搜索跳轉,點 Jump to...,彈出界面里輸入搜索內容,Search。

020ee960-d50a-11ec-bce3-dac502259ad0.png

選項里可以直接配置,或者雙擊跳回原菜單位置。

比 studio 或 menuconfig 里的功能一點兒不少,還更方便操作啦。

Q5. menuconfig 找不到需要的在線包怎么辦?

執行pkgs --upgrade命令,注意!不是pkgs --update
前一條命令用于更新 env 自帶的 RT-Thread online packages 包列表信息。后者用于下載、更新、刪除選擇的包。

Q6. RT-Studio 怎么修改編譯選項?

在 env 環境下,每個 bsp 根目錄下都有個 rtconfig.py 文件,里面是各種開發環境下交差編譯工具鏈配置(上文有提及過)。
修改了 rtconfig.py 文件后,使用 scons 編譯直接使用的修改后的配置;使用 keil 開發需要執行
scons --target=mdk5,把新修改同步更新到 keil 項目配置文件里。

如果使用 RT-Studio 呢?

1、修改 RT-Studio 里的編譯配置,需要按照 eclipse 的方式來。右鍵項目》》屬性》》C/C++ 構建》》設置》》工具設置,在這里可以修改的有 c 編譯器選項、c++ 編譯器選項、鏈接器選項,blablabla 眼花繚亂的不一定能改對,小心謹慎,多加練習吧。

2、使用scons --target=eclipse,更新 RT-Studio 項目配置文件。需要注意的是,執行這個命令前先關掉 RT-Studio ,然后打開 env 切換到項目目錄下,刪掉 ".cproject" 項目文件,最后修改 rtconfig.py 文件后執行scons --target=eclipse

Q7. 添加第三方 lib 及其搜索路徑

添加 lib 和路徑也需要在 rtconfig.py 文件里修改,修改 LFLAGS 變量,增加庫-lxxx。修改 LPATH 添加庫搜索路徑。

修改 rtconfig.py 之后按照上一小節的操作步驟刷新一下 IDE 工程文件。

還有一些 lib 是跟隨軟件包組件添加的,修改軟件包目錄下的 Scronscript 文件,

1pathlib=[cwdlib+'/Lib']
2
3group=DefineGroup('STemWin2RTT',src,depend=[''],CPPPATH=path,LIBS=['STemWin532_CM4_OS_Keil_ot'],LIBPATH=pathlib)

pathlib用于添加 lib 文件路徑。

“DefineGroup” 定義組時,增加兩個參數LIBS=['STemWin532_CM4_OS_Keil_ot'], LIBPATH = pathlib分別指定庫名稱和庫路徑。

Q8. 添加頭文件包含路徑

因為 rt-thread 源碼默認是 scons 自動化開發環境。源碼中有大量的 Scronscript 腳本文件,這些文件控制著源碼文件是否參與編譯,增加哪些頭文件搜索路徑
src += ['xxxx.c']添加源碼文件。

path += [cwd + '/ports']添加頭文件路徑。

外設驅動篇

Q1. USB Host 不識別 U 盤等設備

詳見rt-thread STM32F4 usbhost 調試筆記

這里還有另外兩位大佬提供的修改方案,可以都嘗試一下。或者集眾家之長,前一段時間我按照兩位大佬的也修改了一下,感覺都是可以兼容的,暫未發現問題。

PS: STM32 系列的芯片,可能要求 USBHOST 時鐘頻率是 48MHz ,這個要注意。

Q2. NAND Flash 驅動

gitee有完整代碼

Q3. 移植 yaffs2 文件系統

配合上面的 nand flash 驅動使用。
gitee有完整代碼

使用篇

Q1. 串口通訊數據被分多次接收了,怎么辦?

首先說明,串口是一種流設備,無協議接口。它收到一個字節給你一個字節,收到兩個字節給你兩個字節。如果你的數據是整齊的 16 個字節,而且想每收 16 個字節串口驅動給你個信號,這就難為人了。還有一種情況是,前后兩次不同的數據被拼接在一起了。

這個時候,需要我們在應用層進行處理。或者是定長包,或者定義包頭包尾,包長度等等。下面給出我在論壇上多次分享過的代碼,這個是帶包頭包尾的,在這個基礎上可以修改成其它各種形式包協議的。

  1rt_uint8_t*recvbuf=RT_NULL;
  2staticstructserial_configureuart_conf=RT_SERIAL_CONFIG_USER;
  3rt_uint8_t*datbuf=RT_NULL;
  4rt_size_trcv_off=0,recv_sz=1024,tmp=0;
  5rt_size_tdat_off=0,dat_len=0,i;
  6rt_tick_t_speed_ctrl=0;
  7
  8recvbuf=rt_malloc(128);
  9rt_memset(recvbuf,0,128);
 10datbuf=rt_malloc(32);
 11rt_memset(datbuf,0,32);
 12
 13busif_speed_ctrl=rt_tick_get();
 14
 15rt_sem_init(&rx_sem,"bifrx",0,0);
 16dev_busif=rt_device_find("uart1");
 17if(dev_busif==RT_NULL)
 18{
 19rt_kprintf("Cannotfinddevice:%s
","uart1");
 20return;
 21}
 22if(rt_device_open(dev_busif,RT_DEVICE_OFLAG_RDWR|RT_DEVICE_FLAG_INT_RX|
 23RT_DEVICE_FLAG_STREAM)==RT_EOK)
 24{
 25rt_device_set_rx_indicate(dev_busif,busif_rx_ind);
 26}
 27
 28while(1){
 29rt_sem_take(&rx_sem,RT_WAITING_FOREVER);
 30recv_sz=rt_device_read(dev_busif,-1,&recvbuf[rcv_off],128-rcv_off);
 31if(recv_sz>0){
 32rt_kprintf("data:%d
",recv_sz);
 33if(rcv_off==0){
 34i=0;
 35while((recvbuf[i]!=0x1A)&&(i//findheader
 36if(i==0){
 37rcv_off=recv_sz;
 38}elseif(i 39rcv_off=recv_sz-i;
 40rt_memcpy(recvbuf,&recvbuf[i],recv_sz-i);
 41}else{//noheader
 42rcv_off=0;
 43continue;
 44}
 45}else{
 46rcv_off+=recv_sz;
 47}
 48if(rcv_off2){//datanotenough
 49continue;
 50}
 51dat_len=recvbuf[1];
 52if(dat_len>16){//errorlength
 53rcv_off=0;
 54dat_len=0;
 55continue;
 56}
 57if(rcv_off>=(dat_len+3)){//lenenough
 58floatval=0;
 59AdcValadc_val;
 60
 61if(recvbuf[9+2]!=0x1B){//findtailererror
 62dat_len=0;
 63rcv_off=0;
 64continue;
 65}
 66tmp=rcv_off-(dat_len+3);
 67_speed_ctrl=rt_tick_get();
 68if(/*busif_busy>0||*/(_speed_ctrl-busif_speed_ctrl100)){
 69busif_busy--;
 70if(tmp>0){
 71rt_memcpy(recvbuf,&recvbuf[dat_len+3],tmp);
 72rcv_off=tmp;
 73}else{
 74rcv_off=0;
 75}
 76dat_len=0;
 77continue;
 78}
 79switch(recvbuf[2]){//mapfunctiontypeid
 80case1:
 81adc_val.type=FUNC_DCV;
 82break;
 83case2:
 84adc_val.type=FUNC_DCI;
 85break;
 86default://unsupporttypeid
 87if(tmp>0){
 88rt_memcpy(recvbuf,&recvbuf[dat_len+3],tmp);
 89rcv_off=tmp;
 90}else{
 91rcv_off=0;
 92}
 93dat_len=0;
 94rt_kprintf("errortype:%d
",adc_val.type);
 95continue;
 96break;
 97}
 98rt_memcpy(datbuf,recvbuf+4,7);//changestr2float
 99datbuf[7]=0;
100rt_kprintf("%s
",datbuf);//數據域,可以是字符串,可以是十六進制數據
101//其它數據處理
102....
103//preparenextpackage準備下一包
104if(tmp>0){
105rt_memcpy(recvbuf,&recvbuf[dat_len+3],tmp);
106rcv_off=tmp;
107}else{
108rcv_off=0;
109}
110dat_len=0;
111}
112}
113}

項目代碼,神明保佑,別被老板看到

Q2. 線程間傳輸不定長數據

有兩種消息機制可以傳輸數據,郵箱和消息隊列。以下是一些使用建議:

  • 郵箱傳輸的是定長 32bit 數據,或者是一個整型值,或者是一個地址;

  • 消息隊列的可伸縮性更強,而且有隊列,消息體大小由用戶決定,但是,一經初始化,消息體大小也是固定長度的了。

1、對于某些不同類型數據,每種數據長度固定,而且各種類型數據長度差別不是很多的情況,我們可以使用聯合體代替結構體。這樣消息體的長度也是固定的,以最長長度為準。

2、用郵箱傳遞內存地址,這樣不限定數據長度,但是要求每一次郵箱必須被接收方接收。發送方申請內存,接收方釋放內存。如果出現郵箱發送失敗,由發送方釋放內存。

3、用消息隊列傳遞內存地址,比郵箱的優勢就在于它能緩存多個地址,降低發送失敗的風險。

4、pipe 管道或 ringbuffer。pipe 內部數據結構也是 ringbuffer。雖然可以讀寫任意長度數據,但是,這樣又將數據變成流了。需要讀取方根據事先約定的協議進行解析拆分。還有個缺陷是它沒有消息機制,寫方需要單獨發消息通知接收方,或者,接收方死等這個數據。鑒于這種方式必須用鎖,不適合中斷和線程之間的數據傳輸。

Q3. 插上 U 盤怎么通知應用程序?

gitee有完整代碼,主要修改在 hub.c 和 udisk.c 兩個文件

Q4. 怎么優雅的掛載多種存儲設備?

內存、片上 flash 、片外 spi flash、sd 卡、U盤... 各式各樣的的設備,掛載的文件系統也可能不一而足。怎么優雅的把多種設備掛載到文件系統就是個需要考慮的問題了。

1、掛載 rom 根文件系統,同時創建其它可讀寫文件系統掛載點。

2、其它設備分別掛載到 rom 文件系統的掛載點上。

Q5. rom 文件系統

rt-thread 源碼目錄下 “components/dfs/filesystems/romfs” 有個 romfs.c 文件,是 rom 文件系統配置模板文件,拷貝它到你的應用目錄下,修改_root_dirent定義。可以創建只讀文件。

1RT_WEAKconststructromfs_dirent_root_dirent[]=
2{
3{ROMFS_DIRENT_DIR,"dummy",(rt_uint8_t*)_dummy,sizeof(_dummy)/sizeof(_dummy[0])},
4{ROMFS_DIRENT_FILE,"dummy.txt",_dummy_txt,sizeof(_dummy_txt)},
5};

或者,只有目錄

1RT_WEAKconststructromfs_dirent_root_dirent[]=
2{
3{ROMFS_DIRENT_DIR,"mnt",RT_NULL,0},
4{ROMFS_DIRENT_DIR,"usr",RT_NULL,0},
5{ROMFS_DIRENT_DIR,"var",RT_NULL,0},
6};

有了只讀文件系統,可以很方便擴展掛載很多其它文件系統。

Q6. 絲滑掛載設備

嵌入式里很多存儲設備是焊接到電路板上的存儲芯片。如果我們有在存儲芯片上掛載文件系統的需求,出廠生產必須有方式對存儲設備進行格式化。為此,可能難倒一大批流水線工人。可以使用下面的流程進行掛載。

 1result=dfs_mount(mtd_dev->parent.parent.name,"/usr","yaffs",0,0);
 2if(result==RT_EOK)
 3{
 4rt_kprintf("MountYAFFS2onNANDsuccessfully
");
 5}
 6else
 7{
 8result=dfs_mkfs("yaffs",mtd_dev->parent.parent.name);
 9if(result==RT_EOK)
10{
11result=dfs_mount(mtd_dev->parent.parent.name,"/usr","yaffs",0,0);
12}
13else
14{
15rt_kprintf("MountYAFFS2onNANDfailed
");
16return-RT_ERROR;
17}
18rt_kprintf("MountYAFFS2onNANDsuccessfully
");
19}

掛載失敗,直接格式化,有些比較暴力,但是不需要人工格式化存儲設備了。

Q7. 如何自動掛載文件系統

兩種方式:一種是通過配置,啟用 RT_USING_DFS_MNTTABLE 。這種方式需要使用者自己實現一個結構體數組const struct dfs_mount_tbl mount_table[]

另一種就是自己寫代碼掛載不同設備。我喜歡這一種,因為這樣我可以使用上一小節提到的設計。

Q8. assertion failed at function:rt_xxxxx

問題是我沒調用rt_xxxxx函數啊?!

這種問題分兩種:
一種是,確定這個函數在運行中正常調用的,例如:(tid != RT_NULL) assertion failed at function:rt_applilcation_init,可以確定的是rt_applilcation_init函數運作于線程調度器啟動前,這個時候肯定不會是多線程非法寫了內存引起的。可以確定是因為rt_thread_create函數調用返回了空指針。那么,問題來了,堆初始化成功了嗎?內存有多大?

另外一種是,沒有調用那個函數的地方,但是提示這個函數參數檢測出錯。這種情況大概率是 PC 指針飛了。走到了不應該走到的位置。

定位問題方法請見下節。

Q9. hard fault on thread: xxx

考慮了很久,要不要把這個加進來。出現這個錯誤提示的可能性太多了。從現象上看也分兩類,一類比較確定的,程序走到這個位置必然出現;一類不太確定,每次運行可能現象不一樣。

  • 環境搭建問題,系統移植有缺陷引起的。

  • 線程棧太小,線程棧爆棧。

  • 數組越界、野指針、函數參數傳參錯誤...

  • 邏輯性錯誤,內存釋放后還有可能被使用。多發生在外設的接收緩存上。

但是,上面這些只是扯淡,并不能定位到錯誤位置。定位問題是個方法論范疇的概念。每個人都應該有自己熟悉的一套做法,我的想法請見rt-thread 工具講解系列(二) 之 如何排查系統 bug

Q10. 怎么定義變量到指定內存位置?

非 gcc 版

  • 定義一個宏


	
 1#ifndef__MEMORY_AT
 2#if(defined(__CC_ARM))
 3#define__MEMORY_AT(x)__attribute__((at(x)))
 4#elif(defined(__ARMCC_VERSION)&&(__ARMCC_VERSION>=6010050))
 5#define__MEMORY_AT__(x)__attribute__((section(".ARM.__AT_"#x)))
 6#define__MEMORY_AT(x)__MEMORY_AT__(x)
 7#else
 8#define__MEMORY_AT(x)
 9#warningPositionmemorycontaining__MEMORY_ATmacroatabsoluteaddress!
10#endif
11#endif

  • 使用uint8_t blended_address_buffer[480*272*2] __MEMORY_AT(0xC0000000);

gcc 版

  • 修改鏈接文件

 1/*ProgramEntry,settomarkitas"used"andavoidgc*/
 2MEMORY
 3{
 4CODE(rx):ORIGIN=0x08000000,LENGTH=1024k/*1024KBflash*/
 5RAM1(rw):ORIGIN=0x20000000,LENGTH=192k/*192Ksram*/
 6RAM2(rw):ORIGIN=0x10000000,LENGTH=64k/*64Ksram*/
 7SDRAM(rw):ORIGIN=0xC0000000,LENGTH=8092k/*1024KBsdram*/
 8}
 9
10SECTIONS
11{
12.../*忽略其它內容*/
13
14.sdram:
15{
16KEEP(*(.sdram_section))
17}>SDRAM
18}

  • 定義一個宏

1#ifndef__MEMORY_AT
2#define__MEMORY_AT(x)__attribute__((section(".#x")))
3#endif

  • 使用uint8_t blended_address_buffer[480*272*2] __MEMORY_AT(sdram_section);

gcc 版本是把變量分配到某 section ,距離地址還有查一點兒。當多個變量放到同一個 section 的時候,它們的順序就不保證了。這種情況只能多定義一些 section。

Q11. 結構體字節對齊

 1__packedstruct__packed_struct{
 2...
 3};
 4struct__attribute__((packed))__packed_struct{
 5...
 6};
 7struct__packed_struct{
 8...
 9}__attribute__((packed));
10
11#pragmapack(push,n)
12struct__packed_struct{
13...
14};
15#pragmapack(pop)
keil 里可以這么寫,其它開發環境下有差異。gcc 不支持__packed的寫法
最后的寫法,可以指定按照 n 個字節對齊,n 是一個具體是常數,常用的有 1 2 4 8 ...

Q12. unaligned access 是怎么出現的?

據我所知,當取指令的時候要求比較嚴格,編譯器也往往把指令做了對齊處理。如果出現非對齊訪問,多半是 pc 指針異常了。

還有一種情況,有人說 ARMv7-M 架構設計的時候,0xC0000000-0xDFFFFFFF 這個地址段默認要求必須 4字節(數據總線寬度)對齊訪問。如果這片內存有個壓縮的結構體變量,對此變量讀寫也可能出現 unaligned access 錯誤。解決方法如下:

1、修改 MPU 讓這個區域變成正常儲存器

1/*ConfiguretheMPUattributesasWTforSRAM*/
2LL_MPU_ConfigRegion(LL_MPU_REGION_NUMBER1,0x00,0xC0000000UL,
3LL_MPU_REGION_SIZE_16MB|LL_MPU_REGION_FULL_ACCESS|LL_MPU_ACCESS_NOT_BUFFERABLE|
4LL_MPU_ACCESS_NOT_CACHEABLE|LL_MPU_ACCESS_NOT_SHAREABLE|LL_MPU_TEX_LEVEL1|
5LL_MPU_INSTRUCTION_ACCESS_DISABLE);

2、映射 SDRAM 到別的地址.(0x60000000, 如果你外掛 NOR Flash,這個方法行不通)

1RCC->APB2ENR|=RCC_APB2ENR_SYSCFGEN;
2SYSCFG->MEMRMP|=SYSCFG_MEMRMP_SWP_FMC_0;

3、取消未對齊訪問檢測

編譯器添加–no_unaligned_access編譯選項。
有人介紹這個選項的時候說“強制編譯對齊”或者“禁用未對齊訪問支持”,個人認為這種說法不正確,因為,結構體還是按照咱們的想法按照字節對齊的,只是在訪問這個數據的時候換了種方式,不用4字節(數據總線寬度)對齊的方式訪問了。添加這個選項,恰恰是支持了未對齊數據訪問。

支持未對齊數據訪問的基于 ARM 體系結構的處理器,包括:

  • 基于 ARMv6 體系結構的所有處理器

  • 基于 ARMv7-A 和 ARMv7-R 體系結構的處理器。

不支持未對齊數據訪問的基于 ARM 體系結構的處理器,包括:

  • 基于 ARMv6 以前版本的體系結構的所有處理器

  • 基于 ARMv7-M 體系結構的處理器。

Q13. STM32F767 怎么使用 PersimmonUI?

不止 STM32F767,可以使用 PersimmonUI 芯片可以很多,詳情見獨立文章STM32F767 使用 PersimmonUI 及其它芯片使用可行性分析

結束語

本人能力有限,文中難免有錯誤,或者方法錯誤。望各位同仁不吝賜教。
拜謝拜謝

此寶典不定期更新,希望有朝一日能破萬條。

原文標題:RT-Thread 使用寶典(持續更新中)

文章出處:【微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 內核
    +關注

    關注

    3

    文章

    1376

    瀏覽量

    40319
  • 開發環境
    +關注

    關注

    1

    文章

    226

    瀏覽量

    16647
  • RT-Thread
    +關注

    關注

    31

    文章

    1294

    瀏覽量

    40231

原文標題:RT-Thread 使用寶典(持續更新中)

文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    RT-Thread記錄(一、版本開發環境及配合CubeMX)

    RT-Thread 學習記錄的第一文章,RT-Thread記錄(一、RT-Thread 版本、RT-T
    的頭像 發表于 06-20 00:28 ?5271次閱讀
    <b class='flag-5'>RT-Thread</b>記錄(一、版本<b class='flag-5'>開發</b><b class='flag-5'>環境</b>及配合CubeMX)

    STM32L051上使用RT-Thread (五、完結

    應用-在STM32L051上使用RT-Thread 第五,也是本次應用的完結
    的頭像 發表于 06-29 10:34 ?4015次閱讀
    STM32L051上使用<b class='flag-5'>RT-Thread</b> (五、完結<b class='flag-5'>篇</b>)

    RT-Thread驅動開發指南進階-動手驅動先楫未適配的外設LCD

    經過上一的《《RT-Thread設備驅動開發指南》基礎--以先楫bsp的hwtimer設備為例》闡述,可以大致了解到
    的頭像 發表于 02-25 11:04 ?2636次閱讀
    <b class='flag-5'>RT-Thread</b><b class='flag-5'>驅動</b><b class='flag-5'>開發</b>指南進階<b class='flag-5'>篇</b>-動手<b class='flag-5'>驅動</b>先楫未適配的<b class='flag-5'>外設</b>LCD

    單片機學習入門篇)pdf

    單片機學習入門篇)
    發表于 10-10 10:26

    PCB設計技巧之入門篇

    PCB設計技巧之入門篇
    發表于 08-05 21:44

    單片機 (入門篇

    單片機 (入門篇
    發表于 08-20 16:42

    單片機(入門篇

    單片機(入門篇
    發表于 04-01 15:22

    CSR8670開發板--菜鳥入門篇

    CSR8670開發板--菜鳥入門篇
    發表于 09-30 08:45

    電子工程師自學速成 入門篇

    、毫伏表、示波器、頻率計和掃頻儀等內容。  《電子工程師自學速成入門篇》具有基礎起點低、內容由淺入深、語言通俗易懂、結構安排符合學習認知規律的特點。《電子工程師自學速成入門篇》適合作為電子工程師
    發表于 11-09 12:50

    機器學習入門篇:一個完整的機器學習項目

    機器學習項目入門篇:一個完整的機器學習項目
    發表于 05-11 14:47

    RK3399(內核入門篇)通過sysfs清楚了解設備的系統狀況

    RK3399平臺開發系列講解(內核入門篇)1.1、通過sysfs清楚了解設備的系統狀況 sys目錄
    發表于 12-16 08:00

    單片機(入門篇

    單片機(入門篇
    發表于 03-21 20:51 ?330次下載

    電子工程師自學速成 - 入門篇

    電子工程師自學速成 - 入門篇電子工程師自學速成 - 入門篇電子工程師自學速成 - 入門篇電子工程師自學速成 - 入門篇電子工程師自學速成 - 入門
    發表于 05-10 15:48 ?0次下載

    攝像機基礎培訓——入門篇

    攝像機基礎培訓——入門篇
    發表于 01-04 22:03 ?0次下載

    RT-Thread設備驅動開發指南》基礎--以先楫bsp的hwtimer設備為例

    一、概述(一)RT-Thread設備驅動RT-Thread設備驅動開發指南》書籍是RT-thread
    的頭像 發表于 02-24 08:16 ?1714次閱讀
    《<b class='flag-5'>RT-Thread</b>設備<b class='flag-5'>驅動</b><b class='flag-5'>開發</b>指南》基礎<b class='flag-5'>篇</b>--以先楫bsp的hwtimer設備為例
    主站蜘蛛池模板: 国产色精品久久人妻无码| 阿娇和冠希13分钟在线观看| 人妻中文字幕无码系列| 绝对诱惑在线试听| 久久国产亚洲电影天堂| 娇小萝被两个黑人用半米长| 国产免费69成人精品视频| 二级毛片免费观看全程| yw193龙物免费官网在线| 99久久精品费精品蜜臀AV| 中文字幕不卡一区二区三区| 亚洲天堂一区二区三区| 亚洲 天堂 欧美 日韩 国产| 午夜熟女插插XX免费视频| 色婷婷五月综合久久中文字幕| 欧美精品AV精品一区视频| 两个人在线观看的视频720| 亚洲国产精品无码中文字幕| 婷婷综合久久狠狠色| 色尼姑久久超碰在线| 日本理伦片午夜理伦片| 欧美色图天堂网| 欧美色图一区二区三区| 免费女性裸身照无遮挡网站| 蜜桃臀无码内射一区二区三区| 绝对诱惑在线试听| 麻豆国产99在线中文| 麻豆精品国产剧情观看| 好吊妞国产欧美日韩视频| 国产精品欧美一区二区在线看| 儿子好妈妈的HD3中字抢劫| 不用播放器的黄| 不卡人妻无码AV中文系列APP| yellow在线中文| 被免费网站在线视频| 成人在线视频网站| 福利一区国产| 国产精品人妻一区免费看8C0M| 国产毛片女人18水多| 果冻传媒完整免费网站在线观看| 国内精品久久久久久西瓜色吧 |