赞
踩
RT-Thread官网 官网文档 Rt-thread学习文档
RT-Thread官方bilibili视频号 GD32官网
教你动手移植RT-Thread到国产MCU 如何移植RT-Thread到GD32单片机上(非studio版)
东方青讲RT-Thread RT-Thread内核入门指南
RT-Thread Studio 教程
rtthread移植
野火rt-thread教程
RT-Thread-学习分析(详细版)huawei
RT-Thread-学习分析(详细版)csdn
RT-THREAD 自动初始化详解
RT-Thread启动流程详解(硬件初始化篇)
RT-Thread的各种硬件、线程初始化过程
STM32 RT-Thread 系统分析(1)- 启动文件
RT-Thread学习笔记 --(1)RT-Thread开发环境搭建
RT-Thread学习笔记 --(2)RT-Thread启动过程分析
RT-Thread学习笔记 --(3)RT-Thread自动初始化机制分析
RT-Thread学习笔记 --(4)RT-Thread多线程学习总结
RT-Thread学习笔记 --(5)RT-Thread线程间同步学习总结
RT-Thread学习笔记 --(6)RT-Thread线程间通信学习总结
RT-Thread学习笔记 --(7)RT-Thread中断管理学习总结
RT-Thread学习笔记 --(8)RT-Thread时钟管理学习总结
RT-Thread学习笔记 --(9)RT-Thread内存管理学习总结
RT-Thread INIT_BOARD_EXPORT无效或进入不了导出的函数
进入这个界面,下面蓝色部分请添加:–keep .o(.rti_fn.)
RT-Thread的自动初始化依赖宏开关:RT_USING_COMPONENTS_INIT,分为6个等级,可以查看rtdef.h文件
使用INIT_APP_EXPORT(led_init)宏,初始化函数就会被自动初始化,不用在其他地方显式调用 led_init() 。
/* board init routines will be called in board_init() function */
#define INIT_BOARD_EXPORT(fn) INIT_EXPORT(fn, "1")
/* pre/device/component/env/app init routines will be called in init_thread */
/* components pre-initialization (pure software initilization) */
#define INIT_PREV_EXPORT(fn) INIT_EXPORT(fn, "2")
/* device initialization */
#define INIT_DEVICE_EXPORT(fn) INIT_EXPORT(fn, "3")
/* components initialization (dfs, lwip, ...) */
#define INIT_COMPONENT_EXPORT(fn) INIT_EXPORT(fn, "4")
/* environment initialization (mount disk, ...) */
#define INIT_ENV_EXPORT(fn) INIT_EXPORT(fn, "5")
/* appliation initialization (rtgui application etc ...) */
#define INIT_APP_EXPORT(fn) INIT_EXPORT(fn, "6")
INIT_BOARD_EXPORT(key_gpio_init); /* 先执行 01 */
INIT_BOARD_EXPORT(drv_pm_hw_init); /* 02 */
INIT_BOARD_EXPORT(rt_hw_rtc_init); /* 03 */
- rtthread_startup() 函数是 RT-Thread 规定的统一启动入口。启动调度器之前,系统所创建的线程在执行 rt_thread_startup() 后并不会立马运行,它们会处于就绪状态等待系统调度。MDK 的扩展功能 S u b Sub Sub$ 和 S u p e r Super Super$。
- startup_stm32f103xe.s 开始-> components.c
根据宏跳转到对应函数,如MDK: int S u b Sub Sub$main(void) ->int rtthread_startup(void)
rtthread_startup:关闭中断 ->板级初始化 -> 打印版本信息-> 定时器初始化->调度器初始化 -> 信号初始化->创建初始化线程(main线程) -> 定时器线程初始化 -> 空闲线程初始化->启动调度器。
RT thread 设备驱动组件之USART设备
Rtthread之串口初始化流程分析
剖析RT-Thread中console与finsh组件实现(1)
剖析RT-Thread中console与finsh组件实现(2)
剖析RT-Thread中console与finsh组件实现(3)
动态方法:
rt_thread_create();
rt_thread_delete();
静态方法:
rt_thread_init();
rt_thread_detach();
真正开始运行多任务
rt_thread_startup(tid)
线程追寻函数原型:
静态: 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); 动态: 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);
系统自带的线程创建实例:
void rt_application_init(void) { rt_thread_t tid; #ifdef RT_USING_HEAP tid = rt_thread_create("main", main_thread_entry, RT_NULL, RT_MAIN_THREAD_STACK_SIZE, RT_MAIN_THREAD_PRIORITY, 20); RT_ASSERT(tid != RT_NULL); #else rt_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; #endif rt_thread_startup(tid); }
静态创建实例:
/* 变量分配4字节对齐 */ ALIGN(RT_ALIGN_SIZE) /* 静态线程的 线程堆栈*/ static rt_uint8_t led_stack[512]; /* 静态线程的 线程控制块 */ 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); }
动态创建实例:
static void dynamic_thread_entry(void* parameter);
/* 动态线程的 线程控制块指针 */
rt_thread_t led2_thread;
/* 创建动态线程 : 堆栈大小512 bytes ,优先级 21 ,时间片 2个系统滴答 */
led2_thread = rt_thread_create("led2", dynamic_thread_entry, RT_NULL, 512, 21,2);
if (led2_thread != RT_NULL)
rt_thread_startup(led2_thread);
官网给的实例:
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); /* 延时 100ms */ rt_thread_mdelay(100); } } } /* 线程 2 入口 */ void thread2_entry(void* parameter) { int count = 0; while (1) { rt_kprintf("Thread2 count:%d\n", ++count); /* 延时 50ms */ rt_thread_mdelay(50); } } /* 线程例程初始化 */ int thread_sample_init() { rt_thread_t thread2_ptr; rt_err_t result; /* 初始化线程 1 */ /* 线程的入口是 thread1_entry,参数是 RT_NULL * 线程栈是 thread1_stack * 优先级是 200,时间片是 10 个 OS Tick */ result = rt_thread_init(&thread1, "thread1", thread1_entry, RT_NULL, &thread1_stack[0], sizeof(thread1_stack), 200, 10); /* 启动线程 */ if (result == RT_EOK) rt_thread_startup(&thread1); /* 创建线程 2 */ /* 线程的入口是 thread2_entry, 参数是 RT_NULL * 栈空间是 512,优先级是 250,时间片是 25 个 OS Tick */ thread2_ptr = rt_thread_create("thread2", thread2_entry, RT_NULL, 512, 250, 25); /* 启动线程 */ if (thread2_ptr != RT_NULL) rt_thread_startup(thread2_ptr); return 0; }
SAL:(套接字抽象层)、 Socket Adapter Layer、Socket Abstraction Layer
rt-thread之网络设备与BSD套接字组件
rt-thread示例代码(TCP/UDP)
启用 BSD Socket 的方法是在 env 中输入 menuconfig,找到 SAL 组件,再选择使用 BSD Socket 接口。
各选项顺序:
RT-Thread Components —-> Network —-> Socket abstraction layer —-> Enable BSD socket operated by file system API
kconfig常用语法,入门必看
Kconfig 语法分析详解
config TMPFS_POSIX_ACL
bool “Tmpfs POSIX Access Control Lists”
depends on TMPFS
select GENERIC_ACL
help
POSIX Access Control Lists (ACLs) support permissions for users and groups beyond the owner/group/world scheme.
- config是关键字,表示一个配置选项的开始;紧跟着的TMPFS_POSIX_ACL是配置选项的名称,省略了前缀"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”是提示信息(在上面的配置界面中就是通过它来识别CONFIG_TMPFS_POSIX_ACL),在配置界面中上下移动光标选中它时,就可以通过按空格或回车键来设置CONFIG_ TMPFS_POSIX_ACL的值(即选择了哪个值就会把该值赋值给CONFIG_TMPFS_POSIX_ACL)
- depends on:表示依赖于XXX,“depends on TMPFS”表示只有当TMPFS配置选项被选中时,当前配置选项的提示信息才会出现,才能设置当前配置选项
- select:是反向依赖关系的意思,即当前配置选项被选中,则GENERIC_ACL就会被选中。
用于生成菜单名
menu "Floating point emulation"
config FPE_NWFPE
..............
config FPE_NWFPE_XP
.............
endmenu
choice条目将多个类似的配置选项组合在一起,供用户单选或多选,这不同于menu条目
choice prompt "soc x1000 codec type select" depends on SOC_X1000 config SND_ASOC_INGENIC_PHOENIX_ICDC tristate "Audio support for phoenix with internal codec" select SND_ASOC_DMA_V13 select SND_ASOC_JZ_AIC_I2S_V13 select SND_ASOC_JZ_ICDC_D3 #select SND_ASOC_JZ_PCM_V13 #select SND_ASOC_FIIO_PCM5242 config SND_ASOC_INGENIC_PHOENIX_SPDIF tristate "Audio support for phoenix with spdif" select SND_ASOC_DMA_V13 select SND_ASOC_JZ_AIC_SPDIF_V13 select SND_ASOC_JZ_SPDIF_V13 #select SND_ASOC_JZ_PCM_V13 endchoice
显示注释信息
menu “Floating point emulation”
comment “At least one emulation must be selected”
config FPE_NWFPE
...
config FPE_NWFPE_XP
endmenu
mainmenu "RT-Thread Configuration" config $BSP_DIR string option env="BSP_ROOT" default "." config $RTT_DIR string option 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_DIR string option env="PKGS_ROOT" default "packages" config $ENV_DIR string option 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_MAX int "The maximal size of kernel object name" range 2 32 default 8 help Each 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_SMP bool "Enable SMP(Symmetric multiprocessing)" default n help This option should be selected by machines which have an SMP- capable CPU. The only effect of this option is to make the SMP-related options available to the user for configuration. # 太长了,省略。。。 endmenu
config LCD_TRULY_TFT240240_2_E
tristate "SLCD TRULY TFT240240-2-E with control IC st7789s (240x240)"
depends on BACKLIGHT_CLASS_DEVICE
default n
1、config
//Kconfig中: config BSP_USING_WDT bool "Enable Watchdog Timer" select RT_USING_WDT default n config RT_CONSOLE_DEVICE_NAME string "the device name for console" default "uart1" config BSP_I2C1_SCL_PIN int "I2C1 scl pin number" range 1 176 default 116 //rtconfig.h中: #define BSP_USING_WDT #define RT_USING_WDT #define RT_CONSOLE_DEVICE_NAME "uart1" #define BSP_I2C1_SCL_PIN 116
2、menu
menu "Hardware Drivers Config"
config BSP_USING_COM2
bool "Enable COM2 (uart2 pin conflict with Ethernet and PWM)"
select BSP_USING_UART
select BSP_USING_UART2
default n
config BSP_USING_COM3
bool "Enable COM3 (uart3 pin conflict with Ethernet)"
select BSP_USING_UART3
default n
endmenu
3、if/endif
menu "Hardware Drivers Config"
menuconfig BSP_USING_CAN
bool "Enable CAN"
default n
select RT_USING_CAN
if BSP_USING_CAN
config BSP_USING_CAN1
bool "Enable CAN1"
default n
endif
endmenu
4、menuconfig
menu "Hardware Drivers Config" menuconfig BSP_USING_UART bool "Enable UART" default y select RT_USING_SERIAL if BSP_USING_UART config BSP_USING_UART1 bool "Enable UART1" default y config BSP_UART1_RX_USING_DMA bool "Enable UART1 RX DMA" depends on BSP_USING_UART1 && RT_SERIAL_USING_DMA default n endif endmenu
5、choice
menu "Hardware Drivers Config" menuconfig BSP_USING_ONCHIP_RTC bool "Enable RTC" select RT_USING_RTC select RT_USING_LIBC default n if BSP_USING_ONCHIP_RTC choice prompt "Select clock source" default BSP_RTC_USING_LSE config BSP_RTC_USING_LSE bool "RTC USING LSE" config BSP_RTC_USING_LSI bool "RTC USING LSI" endchoice endif endmenu
在env目录中运行env.exe或env.bat,右击标题栏->settings->Intergration->点击上半部分的register->save settings.
在bsp/stm32f407工程目录下右键->ConEmeu_here,进入当前目录的env控制台
拷贝/env/sample/Kconfig文件拷贝至工程目录,修改"RTT_ROOT"路径,才能使用menuconfig。
config BSP_DIR
string
option env="BSP_ROOT"
default "."
config RTT_DIR
string
option 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内容。
项目的配置保存在:.config文件中,而后根据.config内容重新生成rtconfig.h内容。
scons --genconfig #根据 rtconfig.h 逆向生成 .config
scons通过读取rtconfig.h文件配置成mdk5、mdk4、iar工程并编译。
进入bsp目录下对应工程目录下,删除原有的project.eww、project.uvproj、project.uvprojx三个文件,在当前目录中打开env,输入:
scons --target=mdk5 #根据rtconfig.h生成project.uvprojx工程文件
scons #采用自带gcc编译
官网软件包 https://github.com/RT-Thread-packages
工程目录打开env->menuconfig->RT-Thread online packages按空格键选中所需软件包
pkgs --update #更新软件包(需要安装git)
scons --targer=mdk5 #重新生成mdk5工程
(5)env设置
menuconifg -s
#进入Env config可配置自动更新软件包、自动生成工程
RT-Thread-国产MCU移植系列教程汇总
(1)视频版1(没成功)
高手版:如何移植RT-Thread到GD32单片机上(非studio版)
(2)文档版(成功)
GD32F405VG 移植RTT
手工向GD32F450移植RT-Thread内核
综合了上面两篇文章,框架用了第1个,调试始终卡在main线程的动态生成那里,考虑是椎的配置有问题,开始以为是大小的配置,后来在受第2篇文章启发,查看board.c中的rt_hw_board_init中对堆的初始化,决定不使用外部SDRAM,将rtconfig.h中的#define BSP_USING_SDRAM注释掉。
(或者是把Kconfig中的注掉,其实用snv生成后,也是转成rhconfig.h中的定义)
//Kconfig中关于使用SDRAM的定义注掉
config BSP_USING_SDRAM
bool "Using sdram"
default y
//board.c中关于堆初始化的两种方式选择(SDRAM、SRAM) void rt_hw_board_init() { /* NVIC Configuration */ #define NVIC_VTOR_MASK 0x3FFFFF80 #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x10000000 */ SCB->VTOR = (0x10000000 & NVIC_VTOR_MASK); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x08000000 */ SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK); #endif SystemClock_Config(); #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif #ifdef RT_USING_CONSOLE rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #endif #ifdef BSP_USING_SDRAM rt_system_heap_init((void *)EXT_SDRAM_BEGIN, (void *)EXT_SDRAM_END); //用SDRAM没成功 #else rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END); //用SRAM成功了 #endif }
#ifndef __BOARD_H__ #define __BOARD_H__ #include <gd32f4xx.h> #define GD32_FLASH_START_ADDRESS ((uint32_t)0x8000000) //自己加的 #define GD32_FLASH_SIZE (2048*1024) #define EXT_SDRAM_BEGIN (0xC0000000U) /* the begining address of external SDRAM */ #define EXT_SDRAM_END (EXT_SDRAM_BEGIN + (32U * 1024 * 1024)) /* the end address of external SDRAM */ // <o> Internal SRAM memory size[Kbytes] <8-64> // <i>Default: 64 #ifdef __ICCARM__ // Use *.icf ram symbal, to avoid hardcode. extern char __ICFEDIT_region_RAM_end__; #define GD32_SRAM_END &__ICFEDIT_region_RAM_end__ #else #define GD32_SRAM_SIZE 64 //128 //原来128,网上说大了有问题,就改成64------ #define GD32_SRAM_END (0x20000000 + GD32_SRAM_SIZE * 1024) #endif #ifdef __CC_ARM extern int Image$$RW_IRAM1$$ZI$$Limit; #define HEAP_BEGIN (&Image$$RW_IRAM1$$ZI$$Limit) #elif __ICCARM__ #pragma section="HEAP" #define HEAP_BEGIN (__segment_end("HEAP")) #else extern int __bss_end; #define HEAP_BEGIN (&__bss_end) #endif #define HEAP_END GD32_SRAM_END #endif
//components.c int rtthread_startup(void) { rt_hw_interrupt_disable(); rt_hw_board_init(); /* board level initialization 在这里进行堆初始化*/ rt_show_version(); /* show RT-Thread version */ rt_system_timer_init(); /* timer system initialization */ rt_system_scheduler_init(); /* scheduler system initialization */ #ifdef RT_USING_SIGNALS rt_system_signal_init(); /* signal system initialization */ #endif rt_application_init(); /* create init_thread */ rt_system_timer_thread_init(); /* timer thread initialization */ rt_thread_idle_init(); /* idle thread initialization */ rt_system_scheduler_start(); /* start scheduler */ return 0; /* never reach here */ }
(3)用bsp中的复制移植
参考这篇:教你动手移植RT-Thread到国产MCU
//board.h
#define GD32_SRAM_SIZE 192 //128
board.h中的sram为64M时,开lwip就会在出问题。
board.h中的sram为512M时,堆初始化会出问题,因为不连续。
void rt_system_heap_init(void *begin_addr, void *end_addr)
board.h中的sram为连续的128或192时,才能正常。
一般 rt-thread 发布的 bsp 库默认的 rt_kprintf 函数的输出设备是串口1,想要更改输出设备为串口1,以 stm32 为例步骤如下:
首先,打开 UART2 设备
其次,在 menuconfig 中 RT-Thread Kernel — Kernel Device Object — Using console for rt_kprintf 修改 the device name for console 的值为 uart2
最后,在文件 <stm32f1xx_hal_msp.c> 中加入串口2相关的时钟、引脚配置信息即可
基于STM32F429实现web服务器功能
RT-Thread进阶笔记之网络框架
RT-thread 项目实战–添加wifi和net双网卡
这个是没有添加drv_enet.c、synopsys_emac.c的报错:
修改/bsp/GD32450I/drivers/SConscript文件:使Kconfig中的配置与具体的驱动文件对应
# 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']
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; };
1 INIT_BOARD_EXPORT(fn) 非常早期的初始化,此时**调度器还未启动**
2 INIT_PREV_EXPORT(fn) 主要是用于纯软件的初始化、**没有太多依赖的函数**
3 INIT_DEVICE_EXPORT(fn) 外设驱动初始化相关,比如网卡设备
4 INIT_COMPONENT_EXPORT(fn) 组件初始化,比如文件系统或者 LWIP
5 INIT_ENV_EXPORT(fn) 系统环境初始化,比如挂载文件系统
6 INIT_APP_EXPORT(fn) 应用初始化,比如 GUI 应用
#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_INIT int 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); } #else const 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_INIT int 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); } #else const 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);
上面的移植出现问题,有两个部分,一个是使用sdram,而板子上没有sdram,另一个是sram的大小,太小lwip有问题,太大则超过了sram的连续部分,在初始化堆时报错。
//使用内存堆时,必须要在系统初始化的时候进行堆的初始化,这个函数会把参数 begin_addr,end_addr 区域的内存空间作为内存堆来使用:
void rt_system_heap_init(void* begin_addr, void* end_addr);
//在使用 memheap 堆内存时,必须要在系统初始化的时候进行堆内存的初始化
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
const char *name,
void *start_addr,
rt_uint32_t size)
//如果有多个不连续的 memheap 可以多次调用该函数将其初始化并加入 memheap_item 链表。
三个地方的设置要一致:gd32_rom.sct、gd32_rom.ld、rt_hw_board_init()中断向量设置。
gd32_rom.ld是魔术棒Linker当中自定义,默认是取的魔术棒Target对话框中rom、ram的设置。其生成的定义在xxx
rom起始设在0x800400,问题卡在:
void rt_mp_free(void *block)
level = rt_hw_interrupt_disable();
rom起始设在0x800000,问题卡在:(原因是中断向量表向后偏了)
void rt_system_scheduler_start(void)
rt_hw_context_switch_to((rt_uint32_t)&to_thread->sp);
KEIL工程boot跳转失败,死在rt_system_scheduler_start()问题的解决
//board.c中对中断向量偏移进行了改动
void rt_hw_board_init()
//SCB->VTOR = (0x08004000 & NVIC_VTOR_MASK);
SCB->VTOR = (0x08000000 & NVIC_VTOR_MASK);
基于STM32F4实现RT-Thread的串口OTA(Ymodem_ota方式)
RT-Thread在线升级(Ymodem_OTA)
【rt-thread官网】webnet介绍
【gitee】webnet参考文档
webnet使用指南(CGI)
rt-thread应用篇(03)—基于STM32F429实现web服务器功能
文件系统要求:
WebNet 软件包使用,需要文件系统的支持(FAT 文件系统,ROMFS 文件系统等,支持 RT-Thread 的设备虚拟文件系统),用于 WebNet 软件包中访问的静态页面的存储、上传下载文件的存储等功能。
解决struct timeval报错:
#include <sys/time.h>
默认网页的位置:
//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; }
官网fal介绍
fal的api介绍
DFS文件系统管理与devfs/elmfat示例
DFS( Device File System)框架:
没有开启fatfs:
- 初始化 DFS 组件。
- 注册具体类型的文件系统。
- 挂载文件系统
- 当文件系统不再使用,可以将它卸载。
//初始化 int dfs_init(void) //注册文件系统 int dfs_register(const struct dfs_filesystem_ops *ops); //挂载 int dfs_mount(const char *device_name, const char *path, const char *filesystemtype, unsigned long rwflag, const void *data); //格式化设备(device_name)为(fs_name)文件格式 int dfs_mkfs(const char *fs_name, const char *device_name) int dfs_file_open(struct dfs_fd *fd, const char *path, int flags) int open(const char *file, int flags, ...) //卸载 int dfs_unmount(const char *specialfile);
加入自动初始化
INIT_PREV_EXPORT(dfs_init);
初始化 DFS:
- 清除文件系统操作表
- 清除文件系统表
- 清除文件描述符表
- 初始化互斥量
- 设置当前工作目录为“/”
官网FAL的API
1、这个是在lwip之前初始化fal:
///..\rt-thread\components\net\lwip-2.0.2\src\arch\sys_arch.c(214) : void sys_init(void)
#include <fal.h>
void sys_init(void)
{
/* nothing on RT-Thread porting */
rt_kprintf("in sys_init: fal_init()----\r\n");
/*flash initial here for read to set ipaddr*/
fal_init(); // ppp-----
}
2、错误解决
(1)“expected an expression” 错误解决
USED static const struct fal_partition partition_table_def[] SECTION("FalPartTable") = FAL_PART_TABLE;
把其中一行注释,而应该删除,且上面那个换行符后面有空格也不行。
(2)dfs_mount(FS_PARTITION_NAME, “/webnet”, “lfs”, 0, 0)失败
主要是在:dfs_mount()中的dfs_file_open()失败,调试时感觉走的不对,该返回的也不返回。
这个是dfs的问题,将/components/dfs整个文件夹替换成可用的。
后来仔细对了下,是/filesystems/romfs/romfs.c中直接将dummy换成webnet了,感觉没从根本上解决,只是取了个巧:
RT_WEAK const struct romfs_dirent _root_dirent[] =
{
{ROMFS_DIRENT_DIR, "webnet", (rt_uint8_t *)_dummy, sizeof(_dummy) / sizeof(_dummy[0])},
//{ROMFS_DIRENT_FILE, "dummy.txt", _dummy_txt, sizeof(_dummy_txt)},
};
(3)rtthread4.1.1以上的虚拟文件系统中由于结构体调整,在dfs_file_open()中没有对data进行赋值,导致文件打开失败,修改如下:
int dfs_file_open(struct dfs_fd *fd, const char *path, int flags)
fd->flags = flags;
fd->data = fs; //fa->data没给值,加上 ppp----
3、打印分区表
void fal_show_part_table(void)
//fal_def.h
#define FAL_PRINTF rt_kprintf //printf
4、设备表和分区表
- 分区表名称不能重复
- 设备名称必须与设备表里定义设备的名称一致(.name参数)
- 分区表相对设备的起始地址
- 该分区表的大小,以字节为单位。
board.h中的定义也以字节为单位:
rtthread利用片上flash挂载littlefs文件系统并操作
基于RTT系统的LITTLEFS文件系统移植说明(STM32片内FLASH)
netutils应用笔记
TFTP:简单文件传输协议
netutils软件包中有TFTP小工具。TFTP (Trivial File Transfer Protocol),端口号为 69。在板卡上开启TFTP Server后,就可以在PC上使用TFTP Client软件将HTML网页文件上传到板卡的SPI FLASH中。
传输文件写出现错误,原因是创建tftpserver时的目录为"/",这个文件系统不可写,要改成“/webnet”。总之要根据自己创建的文件系统来决定。
static int _tftp_msh(int argc, char *argv[])
//server = tftp_server_create(path[0], port);
server = tftp_server_create("/webnet", port);
板子创建tftp服务端:
//finsh中输入
tftp -s
tftp工具软件选client:
RT-Thread IO设备管理模型
RT-Thread设备管理框架
RTThread IO设备和驱动学习
IO设备类型:
/* 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 */ };
设备结构体:
/* 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_OPS const 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; #endif void *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() //设置接收回调
rt_device_set_tx_complete() //设置发送回调
《rt-thread驱动框架分析》-i2c驱动
【rtthread设备】第六篇:i2c设备
lwip官方文档(重点)
【野火】LwIP应用开发实战指南—基于RT1052
LWIP学习笔记6——使用 NETCONN 接口编程
LWIP使用解析【网卡驱动 比较好】
LWIP使用经验—变态级(树状图比较好)
LwIP提供了三种编程接口,分别为 RAW/Callback API、Netconn API、Socket API。他们的易用性从左到右依次提高,而执行效率从左到右依次降低,用户可以根据实际情况,平衡利弊,选择合适的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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。