RT-Thread学习
一、入門
RT-Thread官網(wǎng) 官網(wǎng)文檔 Rt-thread學(xué)習(xí)文檔
RT-Thread官方bilibili視頻號(hào) GD32官網(wǎng)
教你動(dòng)手移植RT-Thread到國(guó)產(chǎn)MCU 如何移植RT-Thread到GD32單片機(jī)上(非studio版)
東方青講RT-Thread RT-Thread內(nèi)核入門指南
RT-Thread Studio 教程
rtthread移植
野火rt-thread教程
RT-Thread-學(xué)習(xí)分析(詳細(xì)版)huawei
RT-Thread-學(xué)習(xí)分析(詳細(xì)版)csdn
二、啟動(dòng)流程
RT-THREAD 自動(dòng)初始化詳解
RT-Thread啟動(dòng)流程詳解(硬件初始化篇)
RT-Thread的各種硬件、線程初始化過(guò)程
STM32 RT-Thread 系統(tǒng)分析(1)- 啟動(dòng)文件
RT-Thread學(xué)習(xí)筆記 --(1)RT-Thread開發(fā)環(huán)境搭建
RT-Thread學(xué)習(xí)筆記 --(2)RT-Thread啟動(dòng)過(guò)程分析
RT-Thread學(xué)習(xí)筆記 --(3)RT-Thread自動(dòng)初始化機(jī)制分析
RT-Thread學(xué)習(xí)筆記 --(4)RT-Thread多線程學(xué)習(xí)總結(jié)
RT-Thread學(xué)習(xí)筆記 --(5)RT-Thread線程間同步學(xué)習(xí)總結(jié)
RT-Thread學(xué)習(xí)筆記 --(6)RT-Thread線程間通信學(xué)習(xí)總結(jié)
RT-Thread學(xué)習(xí)筆記 --(7)RT-Thread中斷管理學(xué)習(xí)總結(jié)
RT-Thread學(xué)習(xí)筆記 --(8)RT-Thread時(shí)鐘管理學(xué)習(xí)總結(jié)
RT-Thread學(xué)習(xí)筆記 --(9)RT-Thread內(nèi)存管理學(xué)習(xí)總結(jié)
RT-Thread INIT_BOARD_EXPORT無(wú)效或進(jìn)入不了導(dǎo)出的函數(shù)
進(jìn)入這個(gè)界面,下面藍(lán)色部分請(qǐng)?zhí)砑?#xff1a;–keep .o(.rti_fn.)
RT-Thread的自動(dòng)初始化依賴宏開關(guān):RT_USING_COMPONENTS_INIT,分為6個(gè)等級(jí),可以查看rtdef.h文件
使用INIT_APP_EXPORT(led_init)宏,初始化函數(shù)就會(huì)被自動(dòng)初始化,不用在其他地方顯式調(diào)用 led_init() 。
- rtthread_startup() 函數(shù)是 RT-Thread 規(guī)定的統(tǒng)一啟動(dòng)入口。啟動(dòng)調(diào)度器之前,系統(tǒng)所創(chuàng)建的線程在執(zhí)行 rt_thread_startup() 后并不會(huì)立馬運(yùn)行,它們會(huì)處于就緒狀態(tài)等待系統(tǒng)調(diào)度。MDK 的擴(kuò)展功能 SubSubSub$ 和 SuperSuperSuper$。
- startup_stm32f103xe.s 開始-> components.c
根據(jù)宏跳轉(zhuǎn)到對(duì)應(yīng)函數(shù),如MDK: int SubSubSub$main(void) ->int rtthread_startup(void)
rtthread_startup:關(guān)閉中斷 ->板級(jí)初始化 -> 打印版本信息-> 定時(shí)器初始化->調(diào)度器初始化 -> 信號(hào)初始化->創(chuàng)建初始化線程(main線程) -> 定時(shí)器線程初始化 -> 空閑線程初始化->啟動(dòng)調(diào)度器。
三、串口相關(guān)
RT thread 設(shè)備驅(qū)動(dòng)組件之USART設(shè)備
Rtthread之串口初始化流程分析
rtthread串口接收不定長(zhǎng)數(shù)據(jù)
四、finsh相關(guān)
剖析RT-Thread中console與finsh組件實(shí)現(xiàn)(1)
剖析RT-Thread中console與finsh組件實(shí)現(xiàn)(2)
剖析RT-Thread中console與finsh組件實(shí)現(xiàn)(3)
五、線程
5.1 線程使用
動(dòng)態(tài)方法:rt_thread_create();rt_thread_delete(); 靜態(tài)方法:rt_thread_init();rt_thread_detach();真正開始運(yùn)行多任務(wù) rt_thread_startup(tid)線程追尋函數(shù)原型:
靜態(tài): rt_err_t rt_thread_init(struct rt_thread *thread,const char *name,void (*entry)(void *parameter),void *parameter,void *stack_start,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick); 動(dòng)態(tài): rt_thread_t rt_thread_create(const char *name,void (*entry)(void *parameter),void *parameter,rt_uint32_t stack_size,rt_uint8_t priority,rt_uint32_t tick);系統(tǒng)自帶的線程創(chuàng)建實(shí)例:
void rt_application_init(void) {rt_thread_t tid; #ifdef RT_USING_HEAPtid = rt_thread_create("main", main_thread_entry, RT_NULL,RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20);RT_ASSERT(tid != RT_NULL); #elsert_err_t result;tid = &main_thread;result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL,main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20);RT_ASSERT(result == RT_EOK);/* if not define RT_USING_HEAP, using to eliminate the warning */(void)result; #endifrt_thread_startup(tid); }靜態(tài)創(chuàng)建實(shí)例:
/* 變量分配4字節(jié)對(duì)齊 */ ALIGN(RT_ALIGN_SIZE) /* 靜態(tài)線程的 線程堆棧*/ static rt_uint8_t led_stack[512]; /* 靜態(tài)線程的 線程控制塊 */ static struct rt_thread led_thread;static void led_thread_entry(void *parameter) {while(1){rt_thread_delay(RT_TICK_PER_SECOND / 2);} ]rt_err_t result;result = rt_thread_init(&led_thread, "led", led_thread_entry, RT_NULL,(rt_uint8_t *)&led_stack[0], sizeof(led_stack), 2, 5); if(result==RT_EOK) {rt_thread_startup(&main_thread); }動(dòng)態(tài)創(chuàng)建實(shí)例:
static void dynamic_thread_entry(void* parameter);/* 動(dòng)態(tài)線程的 線程控制塊指針 */ rt_thread_t led2_thread; /* 創(chuàng)建動(dòng)態(tài)線程 : 堆棧大小512 bytes ,優(yōu)先級(jí) 21 ,時(shí)間片 2個(gè)系統(tǒng)滴答 */ led2_thread = rt_thread_create("led2", dynamic_thread_entry, RT_NULL, 512, 21,2); if (led2_thread != RT_NULL)rt_thread_startup(led2_thread);官網(wǎng)給的實(shí)例:
static struct rt_thread thread1; static rt_uint8_t thread1_stack[512];/* 線程 1 入口 */ void thread1_entry(void* parameter) {int i;while (1){for (i = 0; i < 10; i ++){rt_kprintf("%d\n", i);/* 延時(shí) 100ms */rt_thread_mdelay(100);}} }/* 線程 2 入口 */ void thread2_entry(void* parameter) {int count = 0;while (1){rt_kprintf("Thread2 count:%d\n", ++count);/* 延時(shí) 50ms */rt_thread_mdelay(50);} }/* 線程例程初始化 */ int thread_sample_init() {rt_thread_t thread2_ptr;rt_err_t result;/* 初始化線程 1 *//* 線程的入口是 thread1_entry,參數(shù)是 RT_NULL* 線程棧是 thread1_stack* 優(yōu)先級(jí)是 200,時(shí)間片是 10 個(gè) OS Tick*/result = rt_thread_init(&thread1,"thread1",thread1_entry, RT_NULL,&thread1_stack[0], sizeof(thread1_stack),200, 10);/* 啟動(dòng)線程 */if (result == RT_EOK) rt_thread_startup(&thread1);/* 創(chuàng)建線程 2 *//* 線程的入口是 thread2_entry, 參數(shù)是 RT_NULL* 棧空間是 512,優(yōu)先級(jí)是 250,時(shí)間片是 25 個(gè) OS Tick*/thread2_ptr = rt_thread_create("thread2",thread2_entry, RT_NULL,512, 250, 25);/* 啟動(dòng)線程 */if (thread2_ptr != RT_NULL) rt_thread_startup(thread2_ptr);return 0; }5.2 線程同步
5.2.1 信號(hào)量
信號(hào)量使用
六、網(wǎng)絡(luò)通信
SAL:(套接字抽象層)、 Socket Adapter Layer、Socket Abstraction Layer
rt-thread之網(wǎng)絡(luò)設(shè)備與BSD套接字組件
rt-thread示例代碼(TCP/UDP)
七、Kconfig語(yǔ)法
kconfig常用語(yǔ)法,入門必看
Kconfig 語(yǔ)法分析詳解
7.1 config條目
config TMPFS_POSIX_ACLbool “Tmpfs POSIX Access Control Lists”depends on TMPFSselect GENERIC_ACLhelpPOSIX Access Control Lists (ACLs) support permissions for users and groups beyond the owner/group/world scheme.- config是關(guān)鍵字,表示一個(gè)配置選項(xiàng)的開始;緊跟著的TMPFS_POSIX_ACL是配置選項(xiàng)的名稱,省略了前綴"CONFIG_"
- bool表示變量類型,即"CONFIG_ TMPFS_POSIX_ACL "的類型,有5種類型:bool、tristate、string、hex和int,其中tristate和string是基本的類型
bool變量的值: y和n
tristate變量的值:y、n和m
string變量的值: 字符串 - bool之后的字符串“Tmpfs POSIX Access Control Lists”是提示信息(在上面的配置界面中就是通過(guò)它來(lái)識(shí)別CONFIG_TMPFS_POSIX_ACL),在配置界面中上下移動(dòng)光標(biāo)選中它時(shí),就可以通過(guò)按空格或回車鍵來(lái)設(shè)置CONFIG_ TMPFS_POSIX_ACL的值(即選擇了哪個(gè)值就會(huì)把該值賦值給CONFIG_TMPFS_POSIX_ACL)
- depends on:表示依賴于XXX,“depends on TMPFS”表示只有當(dāng)TMPFS配置選項(xiàng)被選中時(shí),當(dāng)前配置選項(xiàng)的提示信息才會(huì)出現(xiàn),才能設(shè)置當(dāng)前配置選項(xiàng)
- select:是反向依賴關(guān)系的意思,即當(dāng)前配置選項(xiàng)被選中,則GENERIC_ACL就會(huì)被選中。
7.2 menu
用于生成菜單名
menu "Floating point emulation"config FPE_NWFPE..............config FPE_NWFPE_XP............. endmenu7.3 choice條目
choice條目將多個(gè)類似的配置選項(xiàng)組合在一起,供用戶單選或多選,這不同于menu條目
choiceprompt "soc x1000 codec type select"depends on SOC_X1000 config SND_ASOC_INGENIC_PHOENIX_ICDCtristate "Audio support for phoenix with internal codec"select SND_ASOC_DMA_V13select SND_ASOC_JZ_AIC_I2S_V13select SND_ASOC_JZ_ICDC_D3#select SND_ASOC_JZ_PCM_V13#select SND_ASOC_FIIO_PCM5242config SND_ASOC_INGENIC_PHOENIX_SPDIFtristate "Audio support for phoenix with spdif"select SND_ASOC_DMA_V13select SND_ASOC_JZ_AIC_SPDIF_V13select SND_ASOC_JZ_SPDIF_V13#select SND_ASOC_JZ_PCM_V13endchoice7.4 comment條目
顯示注釋信息
menu “Floating point emulation” comment “At least one emulation must be selected” config FPE_NWFPE ... config FPE_NWFPE_XP endmenu7.5 rt-thread中的Kconfig示例
mainmenu "RT-Thread Configuration"config $BSP_DIRstringoption env="BSP_ROOT"default "."config $RTT_DIRstringoption env="RTT_ROOT"default "../../rt-thread"# you can change the RTT_ROOT default "../.." to your rtthread_root, # example : default "F:/git_repositories/rt-thread"config $PKGS_DIRstringoption env="PKGS_ROOT"default "packages"config $ENV_DIRstringoption env="ENV_ROOT"default "/"source "$RTT_DIR/Kconfig" source "$PKGS_DIR/Kconfig" source "$BSP_DIR/../../drivers/Kconfig" source "$BSP_DIR/../../libraries/Kconfig" menu "RT-Thread Kernel"config RT_NAME_MAXint "The maximal size of kernel object name"range 2 32default 8helpEach kernel object, such as thread, timer, semaphore etc, has a name,the RT_NAME_MAX is the maximal size of this object name.config RT_USING_SMPbool "Enable SMP(Symmetric multiprocessing)"default nhelpThis option should be selected by machines which have an SMP-capable CPU.The only effect of this option is to make the SMP-relatedoptions available to the user for configuration.# 太長(zhǎng)了,省略。。。endmenu config LCD_TRULY_TFT240240_2_E tristate "SLCD TRULY TFT240240-2-E with control IC st7789s (240x240)"depends on BACKLIGHT_CLASS_DEVICEdefault n7.6 使用對(duì)照
1、config
//Kconfig中: config BSP_USING_WDTbool "Enable Watchdog Timer"select RT_USING_WDTdefault nconfig RT_CONSOLE_DEVICE_NAMEstring "the device name for console"default "uart1"config BSP_I2C1_SCL_PINint "I2C1 scl pin number"range 1 176default 116//rtconfig.h中: #define BSP_USING_WDT #define RT_USING_WDT#define RT_CONSOLE_DEVICE_NAME "uart1" #define BSP_I2C1_SCL_PIN 1162、menu
menu "Hardware Drivers Config"config BSP_USING_COM2bool "Enable COM2 (uart2 pin conflict with Ethernet and PWM)"select BSP_USING_UARTselect BSP_USING_UART2default nconfig BSP_USING_COM3bool "Enable COM3 (uart3 pin conflict with Ethernet)"select BSP_USING_UART3default n endmenu3、if/endif
menu "Hardware Drivers Config"menuconfig BSP_USING_CANbool "Enable CAN"default nselect RT_USING_CANif BSP_USING_CANconfig BSP_USING_CAN1bool "Enable CAN1"default nendif endmenu4、menuconfig
menu "Hardware Drivers Config"menuconfig BSP_USING_UARTbool "Enable UART"default yselect RT_USING_SERIALif BSP_USING_UARTconfig BSP_USING_UART1bool "Enable UART1"default yconfig BSP_UART1_RX_USING_DMAbool "Enable UART1 RX DMA"depends on BSP_USING_UART1 && RT_SERIAL_USING_DMAdefault nendif endmenu5、choice
menu "Hardware Drivers Config"menuconfig BSP_USING_ONCHIP_RTCbool "Enable RTC"select RT_USING_RTCselect RT_USING_LIBCdefault nif BSP_USING_ONCHIP_RTCchoiceprompt "Select clock source"default BSP_RTC_USING_LSEconfig BSP_RTC_USING_LSEbool "RTC USING LSE"config BSP_RTC_USING_LSIbool "RTC USING LSI"endchoiceendif endmenu8. env配置
Env官方文檔
Env工程配置
8.1 環(huán)境配置
在env目錄中運(yùn)行env.exe或env.bat,右擊標(biāo)題欄->settings->Intergration->點(diǎn)擊上半部分的register->save settings.
在bsp/stm32f407工程目錄下右鍵->ConEmeu_here,進(jìn)入當(dāng)前目錄的env控制臺(tái)
8.2 env配置項(xiàng)目(menuconfig)
拷貝/env/sample/Kconfig文件拷貝至工程目錄,修改"RTT_ROOT"路徑,才能使用menuconfig。
config BSP_DIRstringoption env="BSP_ROOT"default "."config RTT_DIRstringoption env="RTT_ROOT"default "./rt-thread"# you can change the RTT_ROOT default "rt-thread" # example : default "F:/git_repositories/rt-thread" # default: "../../"工程目錄打開env,輸入menuconfig(>rtthread3.0),最終配置修改rtconfig.h內(nèi)容。
項(xiàng)目的配置保存在:.config文件中,而后根據(jù).config內(nèi)容重新生成rtconfig.h內(nèi)容。
8.3 生成mdk5工程(scons)
scons通過(guò)讀取rtconfig.h文件配置成mdk5、mdk4、iar工程并編譯。
進(jìn)入bsp目錄下對(duì)應(yīng)工程目錄下,刪除原有的project.eww、project.uvproj、project.uvprojx三個(gè)文件,在當(dāng)前目錄中打開env,輸入:
8.4 軟件包管理(pkgs)
官網(wǎng)軟件包 https://github.com/RT-Thread-packages
工程目錄打開env->menuconfig->RT-Thread online packages按空格鍵選中所需軟件包
(5)env設(shè)置
menuconifg -s #進(jìn)入Env config可配置自動(dòng)更新軟件包、自動(dòng)生成工程9. 工程實(shí)踐
9.1 GD32450IIH6上移植
RT-Thread-國(guó)產(chǎn)MCU移植系列教程匯總
(1)視頻版1(沒成功)
高手版:如何移植RT-Thread到GD32單片機(jī)上(非studio版)
- (1)復(fù)制/rtthread/bsp目錄下一個(gè)相近工程。
- (2)修改gd32_rom.sct中的內(nèi)存和flash的大小。
- (3)修改template.uvprojx中的工程名和芯片型號(hào)等。
- (4)替換/Library下的CMSIS、GD32F4xx_standard_peripheral、GD32F4xx_usb_driver,并修改/Libraries目錄下的SConscript文件,將其中的目錄進(jìn)行替換、CPPDEFINES、.c文件、啟動(dòng)文件等。
- (5)修改/drivers下的驅(qū)動(dòng),并修改board.h中的GD32_SRAM_SIZE改成實(shí)際大小(KB)
- (6)修改工程目錄下的Kconfig文件,
- (7)menuconfig修改系統(tǒng)配置,并用scons --targer=mdk5生成mdk工程。
- (8)編譯修改錯(cuò)誤。
(2)文檔版(成功)
GD32F405VG 移植RTT
手工向GD32F450移植RT-Thread內(nèi)核
綜合了上面兩篇文章,框架用了第1個(gè),調(diào)試始終卡在main線程的動(dòng)態(tài)生成那里,考慮是椎的配置有問(wèn)題,開始以為是大小的配置,后來(lái)在受第2篇文章啟發(fā),查看board.c中的rt_hw_board_init中對(duì)堆的初始化,決定不使用外部SDRAM,將rtconfig.h中的#define BSP_USING_SDRAM注釋掉。
(或者是把Kconfig中的注掉,其實(shí)用snv生成后,也是轉(zhuǎn)成rhconfig.h中的定義)
(3)用bsp中的復(fù)制移植
參考這篇:教你動(dòng)手移植RT-Thread到國(guó)產(chǎn)MCU
board.h中的sram為64M時(shí),開lwip就會(huì)在出問(wèn)題。
board.h中的sram為512M時(shí),堆初始化會(huì)出問(wèn)題,因?yàn)椴贿B續(xù)。
board.h中的sram為連續(xù)的128或192時(shí),才能正常。
9.2 更改kprintf()串口輸出
一般 rt-thread 發(fā)布的 bsp 庫(kù)默認(rèn)的 rt_kprintf 函數(shù)的輸出設(shè)備是串口1,想要更改輸出設(shè)備為串口1,以 stm32 為例步驟如下:
首先,打開 UART2 設(shè)備
其次,在 menuconfig 中 RT-Thread Kernel — Kernel Device Object — Using console for rt_kprintf 修改 the device name for console 的值為 uart2
最后,在文件 <stm32f1xx_hal_msp.c> 中加入串口2相關(guān)的時(shí)鐘、引腳配置信息即可
9.3 添加網(wǎng)絡(luò)
基于STM32F429實(shí)現(xiàn)web服務(wù)器功能
RT-Thread進(jìn)階筆記之網(wǎng)絡(luò)框架
RT-thread 項(xiàng)目實(shí)戰(zhàn)–添加wifi和net雙網(wǎng)卡
這個(gè)是沒有添加drv_enet.c、synopsys_emac.c的報(bào)錯(cuò):
9.3.1 添加網(wǎng)絡(luò)驅(qū)動(dòng)文件
修改/bsp/GD32450I/drivers/SConscript文件:使Kconfig中的配置與具體的驅(qū)動(dòng)文件對(duì)應(yīng)
# add uart drivers. if GetDepend('RT_USING_SERIAL'):src += ['drv_usart.c']# add sdram drivers. if GetDepend('BSP_USING_SDRAM'):src += ['drv_exmc_sdram.c']# add eth drivers. if GetDepend('BSP_USING_ETH'):src += ['drv_enet.c']# add eth drivers. if GetDepend('BSP_USING_ETH'):src += ['synopsys_emac.c']9.3.2 mac結(jié)構(gòu)體
eth_device:
struct eth_device {/* inherit from rt_device */struct rt_device parent;/* network interface for lwip */struct netif *netif;struct rt_semaphore tx_ack;rt_uint16_t flags;rt_uint8_t link_changed;rt_uint8_t link_status;/* eth device interface */struct pbuf* (*eth_rx)(rt_device_t dev);rt_err_t (*eth_tx)(rt_device_t dev, struct pbuf* p); };gd32_emac:
struct gd32_emac {/* inherit from Ethernet device */struct eth_device parent;rt_uint8_t phy_mode;/* interface address info. */rt_uint8_t dev_addr[MAX_ADDR_LEN]; /* hw address */struct rt_synopsys_eth * ETHERNET_MAC;IRQn_Type ETHER_MAC_IRQ;EMAC_DMADESCTypeDef *DMATxDescToSet;EMAC_DMADESCTypeDef *DMARxDescToGet;#pragma pack(4)EMAC_DMADESCTypeDef DMARxDscrTab[EMAC_RXBUFNB]; #pragma pack(4)EMAC_DMADESCTypeDef DMATxDscrTab[EMAC_TXBUFNB]; #pragma pack(4)rt_uint8_t Rx_Buff[EMAC_RXBUFNB][EMAC_MAX_PACKET_SIZE]; #pragma pack(4)rt_uint8_t Tx_Buff[EMAC_TXBUFNB][EMAC_MAX_PACKET_SIZE];struct rt_semaphore tx_buf_free; };9.4 硬件初始化
RT-Thread 自動(dòng)初始化詳解
1 INIT_BOARD_EXPORT(fn) 非常早期的初始化,此時(shí)**調(diào)度器還未啟動(dòng)** 2 INIT_PREV_EXPORT(fn) 主要是用于純軟件的初始化、**沒有太多依賴的函數(shù)** 3 INIT_DEVICE_EXPORT(fn) 外設(shè)驅(qū)動(dòng)初始化相關(guān),比如網(wǎng)卡設(shè)備 4 INIT_COMPONENT_EXPORT(fn) 組件初始化,比如文件系統(tǒng)或者 LWIP 5 INIT_ENV_EXPORT(fn) 系統(tǒng)環(huán)境初始化,比如掛載文件系統(tǒng) 6 INIT_APP_EXPORT(fn) 應(yīng)用初始化,比如 GUI 應(yīng)用 #define INIT_EXPORT(fn, level) RT_USED const init_fn_t __rt_init_##fn SECTION(".rti_fn."level) = fn /* board init routines will be called in board_init() function */ #define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1") //commponents.c #ifdef RT_USING_COMPONENTS_INIT /** Components Initialization will initialize some driver and components as following* order:* rti_start --> 0* BOARD_EXPORT --> 1* rti_board_end --> 1.end** DEVICE_EXPORT --> 2* COMPONENT_EXPORT --> 3* FS_EXPORT --> 4* ENV_EXPORT --> 5* APP_EXPORT --> 6** rti_end --> 6.end** These automatically initializaiton, the driver or component initial function must* be defined with:* INIT_BOARD_EXPORT(fn);* INIT_DEVICE_EXPORT(fn);* ...* INIT_APP_EXPORT(fn);* etc.*/ static int rti_start(void) {return 0; } INIT_EXPORT(rti_start, "0");static int rti_board_start(void) {return 0; } INIT_EXPORT(rti_board_start, "0.end");static int rti_board_end(void) {return 0; } INIT_EXPORT(rti_board_end, "1.end");static int rti_end(void) {return 0; } INIT_EXPORT(rti_end, "6.end");/*** RT-Thread Components Initialization for board*/ void rt_components_board_init(void) { #if RT_DEBUG_INITint result;const struct rt_init_desc *desc;for (desc = &__rt_init_desc_rti_board_start; desc < &__rt_init_desc_rti_board_end; desc ++){rt_kprintf("initialize %s", desc->fn_name);result = desc->fn();rt_kprintf(":%d done\n", result);} #elseconst init_fn_t *fn_ptr;for (fn_ptr = &__rt_init_rti_board_start; fn_ptr < &__rt_init_rti_board_end; fn_ptr++){(*fn_ptr)();} #endif }/*** RT-Thread Components Initialization*/ void rt_components_init(void) { #if RT_DEBUG_INITint result;const struct rt_init_desc *desc;rt_kprintf("do components intialization.\n");for (desc = &__rt_init_desc_rti_board_end; desc < &__rt_init_desc_rti_end; desc ++){rt_kprintf("initialize %s", desc->fn_name);result = desc->fn();rt_kprintf(":%d done\n", result);} #elseconst init_fn_t *fn_ptr;for (fn_ptr = &__rt_init_rti_board_end; fn_ptr < &__rt_init_rti_end; fn_ptr ++){(*fn_ptr)();} #endif } int rt_hw_usart_init(void) {struct stm32_uart *uart;struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT;uart = &uart1;config.baud_rate = BAUD_RATE_115200;serial1.ops = &stm32_uart_ops;serial1.config = config;MX_USART_UART_Init(&uart->huart);/* register UART1 device */rt_hw_serial_register(&serial1, "uart1",RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,uart);return 0; } INIT_BOARD_EXPORT(rt_hw_usart_init); int rt_hw_pin_init(void) {int result;result = rt_device_pin_register("pin", &_stm32_pin_ops, RT_NULL);return result; } INIT_BOARD_EXPORT(rt_hw_pin_init);9.5 堆的初始化
上面的移植出現(xiàn)問(wèn)題,有兩個(gè)部分,一個(gè)是使用sdram,而板子上沒有sdram,另一個(gè)是sram的大小,太小lwip有問(wèn)題,太大則超過(guò)了sram的連續(xù)部分,在初始化堆時(shí)報(bào)錯(cuò)。
//使用內(nèi)存堆時(shí),必須要在系統(tǒng)初始化的時(shí)候進(jìn)行堆的初始化,這個(gè)函數(shù)會(huì)把參數(shù) begin_addr,end_addr 區(qū)域的內(nèi)存空間作為內(nèi)存堆來(lái)使用: void rt_system_heap_init(void* begin_addr, void* end_addr); //在使用 memheap 堆內(nèi)存時(shí),必須要在系統(tǒng)初始化的時(shí)候進(jìn)行堆內(nèi)存的初始化 rt_err_t rt_memheap_init(struct rt_memheap *memheap,const char *name,void *start_addr,rt_uint32_t size) //如果有多個(gè)不連續(xù)的 memheap 可以多次調(diào)用該函數(shù)將其初始化并加入 memheap_item 鏈表。9.6 關(guān)于程序的起始地址
9.6.1 設(shè)置一致性
三個(gè)地方的設(shè)置要一致:gd32_rom.sct、gd32_rom.ld、rt_hw_board_init()中斷向量設(shè)置。
gd32_rom.ld是魔術(shù)棒Linker當(dāng)中自定義,默認(rèn)是取的魔術(shù)棒Target對(duì)話框中rom、ram的設(shè)置。其生成的定義在xxx
9.6.2 實(shí)際經(jīng)歷
rom起始設(shè)在0x800400,問(wèn)題卡在:
void rt_mp_free(void *block)level = rt_hw_interrupt_disable();rom起始設(shè)在0x800000,問(wèn)題卡在:(原因是中斷向量表向后偏了)
void rt_system_scheduler_start(void)rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);KEIL工程boot跳轉(zhuǎn)失敗,死在rt_system_scheduler_start()問(wèn)題的解決
//board.c中對(duì)中斷向量偏移進(jìn)行了改動(dòng) void rt_hw_board_init()//SCB->VTOR = (0x08004000 & NVIC_VTOR_MASK);SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);10. bootloader實(shí)現(xiàn)OTA在線升級(jí)
基于STM32F4實(shí)現(xiàn)RT-Thread的串口OTA(Ymodem_ota方式)
RT-Thread在線升級(jí)(Ymodem_OTA)
11. webnet應(yīng)用
【rt-thread官網(wǎng)】webnet介紹
【gitee】webnet參考文檔
webnet使用指南(CGI)
rt-thread應(yīng)用篇(03)—基于STM32F429實(shí)現(xiàn)web服務(wù)器功能
文件系統(tǒng)要求:
WebNet 軟件包使用,需要文件系統(tǒng)的支持(FAT 文件系統(tǒng),ROMFS 文件系統(tǒng)等,支持 RT-Thread 的設(shè)備虛擬文件系統(tǒng)),用于 WebNet 軟件包中訪問(wèn)的靜態(tài)頁(yè)面的存儲(chǔ)、上傳下載文件的存儲(chǔ)等功能。
解決struct timeval報(bào)錯(cuò):
默認(rèn)網(wǎng)頁(yè)的位置:
//wn_sample.c static void asp_var_version(struct webnet_session* session) {RT_ASSERT(session != RT_NULL);static const char *version = "<html><body><font size=\"+2\">RT-Thread %d.%d.%d</font><br><br>""<a href=\"javascript:history.go(-1);\">Go back to root</a></html></body>";webnet_session_printf(session, version, RT_VERSION_MAJOR, RT_VERSION_MINOR, RT_VERSION_PATCH); //RT_VERSION, RT_SUBVERSION, RT_REVISION } int webnet_module_cgi(struct webnet_session* session, int event) {if (event == WEBNET_EVENT_INIT){/* set default cgi path */if (_cgi_root[0] == '\0'){strcpy(_cgi_root, "/cgi-bin/");}}else if (event == WEBNET_EVENT_URI_PHYSICAL){struct webnet_request* request;char *cgi_path = RT_NULL;RT_ASSERT(session != RT_NULL);request = session->request;RT_ASSERT(request != RT_NULL);/* check whether a cgi request */cgi_path = strstr(request->path, _cgi_root);if (cgi_path != RT_NULL){char* cgi_name;rt_uint32_t index;//judge contain ".cgi"-------自己加的--------char* lastname = cgi_path + strlen(cgi_path)-4; if(strncasecmp(lastname,".cgi",4) == 0){int len = strlen(cgi_path);cgi_path[len-4] = '\0';}//----------end-----------------------------cgi_name = cgi_path + strlen(_cgi_root);for (index = 0; index < _cgi_count; index ++){if ((strlen(cgi_name) == strlen(_cgi_items[index].name))&& strncasecmp(cgi_name, _cgi_items[index].name, strlen(_cgi_items[index].name)) == 0){/* found it */_cgi_items[index].handler(session);return WEBNET_MODULE_FINISHED;}}/* set 404 not found error */request->result_code = 404;}}return WEBNET_MODULE_CONTINUE; }12. 文件系統(tǒng)
官網(wǎng)fal介紹
fal的api介紹
DFS文件系統(tǒng)管理與devfs/elmfat示例
DFS( Device File System)框架:
沒有開啟fatfs:
12.1 虛擬文件系統(tǒng)使用步驟:
- 初始化 DFS 組件。
- 注冊(cè)具體類型的文件系統(tǒng)。
- 掛載文件系統(tǒng)
- 當(dāng)文件系統(tǒng)不再使用,可以將它卸載。
12.2 初始化
加入自動(dòng)初始化
INIT_PREV_EXPORT(dfs_init);初始化 DFS:
- 清除文件系統(tǒng)操作表
- 清除文件系統(tǒng)表
- 清除文件描述符表
- 初始化互斥量
- 設(shè)置當(dāng)前工作目錄為“/”
13.3 fal
官網(wǎng)FAL的API
1、這個(gè)是在lwip之前初始化fal:
2、錯(cuò)誤解決
(1)“expected an expression” 錯(cuò)誤解決
把其中一行注釋,而應(yīng)該刪除,且上面那個(gè)換行符后面有空格也不行。
(2)dfs_mount(FS_PARTITION_NAME, “/webnet”, “l(fā)fs”, 0, 0)失敗
主要是在:dfs_mount()中的dfs_file_open()失敗,調(diào)試時(shí)感覺走的不對(duì),該返回的也不返回。
這個(gè)是dfs的問(wèn)題,將/components/dfs整個(gè)文件夾替換成可用的。
后來(lái)仔細(xì)對(duì)了下,是/filesystems/romfs/romfs.c中直接將dummy換成webnet了,感覺沒從根本上解決,只是取了個(gè)巧:
(3)rtthread4.1.1以上的虛擬文件系統(tǒng)中由于結(jié)構(gòu)體調(diào)整,在dfs_file_open()中沒有對(duì)data進(jìn)行賦值,導(dǎo)致文件打開失敗,修改如下:
int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)fd->flags = flags; fd->data = fs; //fa->data沒給值,加上 ppp----3、打印分區(qū)表
void fal_show_part_table(void) //fal_def.h #define FAL_PRINTF rt_kprintf //printf4、設(shè)備表和分區(qū)表
- 分區(qū)表名稱不能重復(fù)
- 設(shè)備名稱必須與設(shè)備表里定義設(shè)備的名稱一致(.name參數(shù))
- 分區(qū)表相對(duì)設(shè)備的起始地址
- 該分區(qū)表的大小,以字節(jié)為單位。
board.h中的定義也以字節(jié)為單位:
13.4 littlefs(lfs)
rtthread利用片上flash掛載littlefs文件系統(tǒng)并操作
基于RTT系統(tǒng)的LITTLEFS文件系統(tǒng)移植說(shuō)明(STM32片內(nèi)FLASH)
13. TFTP
netutils應(yīng)用筆記
TFTP:簡(jiǎn)單文件傳輸協(xié)議
netutils軟件包中有TFTP小工具。TFTP (Trivial File Transfer Protocol),端口號(hào)為 69。在板卡上開啟TFTP Server后,就可以在PC上使用TFTP Client軟件將HTML網(wǎng)頁(yè)文件上傳到板卡的SPI FLASH中。
傳輸文件寫出現(xiàn)錯(cuò)誤,原因是創(chuàng)建tftpserver時(shí)的目錄為"/",這個(gè)文件系統(tǒng)不可寫,要改成“/webnet”??傊鶕?jù)自己創(chuàng)建的文件系統(tǒng)來(lái)決定。
static int _tftp_msh(int argc, char *argv[])//server = tftp_server_create(path[0], port);server = tftp_server_create("/webnet", port);板子創(chuàng)建tftp服務(wù)端:
//finsh中輸入 tftp -stftp工具軟件選client:
14. 設(shè)備管理
RT-Thread IO設(shè)備管理模型
RT-Thread設(shè)備管理框架
RTThread IO設(shè)備和驅(qū)動(dòng)學(xué)習(xí)
IO設(shè)備類型:
/* include/rtdef.h */ enum rt_device_class_type {RT_Device_Class_Char = 0, /**< character device */RT_Device_Class_Block, /**< block device */RT_Device_Class_NetIf, /**< net interface */RT_Device_Class_MTD, /**< memory device */RT_Device_Class_CAN, /**< CAN device */RT_Device_Class_RTC, /**< RTC device */RT_Device_Class_Sound, /**< Sound device */RT_Device_Class_Graphic, /**< Graphic device */RT_Device_Class_I2CBUS, /**< I2C bus device */RT_Device_Class_USBDevice, /**< USB slave device */RT_Device_Class_USBHost, /**< USB host bus */RT_Device_Class_SPIBUS, /**< SPI bus device */RT_Device_Class_SPIDevice, /**< SPI device */RT_Device_Class_SDIO, /**< SDIO bus device */RT_Device_Class_PM, /**< PM pseudo device */RT_Device_Class_Pipe, /**< Pipe device */RT_Device_Class_Portal, /**< Portal device */RT_Device_Class_Timer, /**< Timer device */RT_Device_Class_Miscellaneous, /**< Miscellaneous device */RT_Device_Class_Sensor, /**< Sensor device */RT_Device_Class_Touch, /**< Touch device */RT_Device_Class_Unknown /**< unknown device */ };設(shè)備結(jié)構(gòu)體:
/* include/rtdef.h */ struct rt_device {struct rt_object parent; /**< inherit from rt_object */enum rt_device_class_type type; /**< device type */rt_uint16_t flag; /**< device flag */rt_uint16_t open_flag; /**< device open flag */rt_uint8_t ref_count; /**< reference count */rt_uint8_t device_id; /**< 0 - 255 *//* device call back */rt_err_t (*rx_indicate)(rt_device_t dev, rt_size_t size);rt_err_t (*tx_complete)(rt_device_t dev, void *buffer);#ifdef RT_USING_DEVICE_OPSconst struct rt_device_ops *ops; #else/* common device interface */rt_err_t (*init) (rt_device_t dev);rt_err_t (*open) (rt_device_t dev, rt_uint16_t oflag);rt_err_t (*close) (rt_device_t dev);rt_size_t (*read) (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);rt_size_t (*write) (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);rt_err_t (*control)(rt_device_t dev, int cmd, void *args); #endif#if defined(RT_USING_POSIX)const struct dfs_file_ops *fops;struct rt_wqueue wait_queue; #endifvoid *user_data; /**< device private data */ }; rt_device_create() rt_device_destroy() rt_device_register() rt_device_find() rt_device_init() rt_device_open() rt_device_close() rt_device_control() rt_device_read() rt_device_write() rt_device_set_rx_indicate() //設(shè)置接收回調(diào) rt_device_set_tx_complete() //設(shè)置發(fā)送回調(diào)15. lwip
lwip官方文檔(重點(diǎn))
【野火】LwIP應(yīng)用開發(fā)實(shí)戰(zhàn)指南—基于RT1052
LWIP學(xué)習(xí)筆記6——使用 NETCONN 接口編程
LWIP使用解析【網(wǎng)卡驅(qū)動(dòng) 比較好】
LWIP使用經(jīng)驗(yàn)—變態(tài)級(jí)(樹狀圖比較好)
LwIP提供了三種編程接口,分別為 RAW/Callback API、Netconn API、Socket API。他們的易用性從左到右依次提高,而執(zhí)行效率從左到右依次降低,用戶可以根據(jù)實(shí)際情況,平衡利弊,選擇合適的API進(jìn)行網(wǎng)絡(luò)應(yīng)用程序的開發(fā)。
啟動(dòng)時(shí)序(圖不錯(cuò)):
15.1 api
RAW:
err_t raw_bind (struct raw_pcb *pcb, const ip_addr_t *ipaddr) void raw_bind_netif (struct raw_pcb *pcb, const struct netif *netif) err_t raw_connect (struct raw_pcb *pcb, const ip_addr_t *ipaddr) void raw_disconnect (struct raw_pcb *pcb) void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr) err_t raw_sendto_if_src (struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, struct netif *netif, const ip_addr_t *src_ip) err_t raw_send (struct raw_pcb *pcb, struct pbuf *p) void raw_remove (struct raw_pcb *pcb)TCP:
//connect---- tcp_new() tcp_bind() tcp_listen() and tcp_listen_with_backlog() tcp_accept() tcp_connect() //send---- tcp_write() tcp_output() tcp_sent() //recv---- tcp_recv() tcp_recved() void tcp_backlog_delayed (struct tcp_pcb *pcb) void tcp_backlog_accepted (struct tcp_pcb *pcb) err_t tcp_close (struct tcp_pcb *pcb) err_t tcp_shutdown (struct tcp_pcb *pcb, int shut_rx, int shut_tx) void tcp_abort (struct tcp_pcb *pcb) err_t tcp_bind (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) void tcp_bind_netif (struct tcp_pcb *pcb, const struct netif *netif) struct tcp_pcb * tcp_listen_with_backlog (struct tcp_pcb *pcb, u8_t backlog) struct tcp_pcb * tcp_listen_with_backlog_and_err (struct tcp_pcb *pcb, u8_t backlog, err_t *err) void tcp_recved (struct tcp_pcb *pcb, u16_t len) err_t tcp_connect (struct tcp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port, tcp_connected_fn connected) struct tcp_pcb * tcp_new (void) struct tcp_pcb * tcp_new_ip_type (u8_t type) void tcp_arg (struct tcp_pcb *pcb, void *arg) void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv) void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent) void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err) void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept) void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) err_t tcp_write (struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) err_t tcp_output (struct tcp_pcb *pcb)UDP:
err_t udp_send (struct udp_pcb *pcb, struct pbuf *p) err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port) err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) err_t udp_sendto_if_src (struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif, const ip_addr_t *src_ip) err_t udp_bind (struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) void udp_bind_netif (struct udp_pcb *pcb, const struct netif *netif) err_t udp_connect (struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) void udp_disconnect (struct udp_pcb *pcb) void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) void udp_remove (struct udp_pcb *pcb) struct udp_pcb * udp_new (void) struct udp_pcb * udp_new_ip_type (u8_t type)總結(jié)
以上是生活随笔為你收集整理的RT-Thread学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 论网卡数据是如何从驱动到桥接/ip层(N
- 下一篇: 玩转华为ENSP模拟器系列 | 配置Do