标签:方式 creat virtual proc 指针 list 链接器 gnu void
实时内核的实现包括:对象管理、线程管理及调度器、线程间通信管理、时钟管理及内存管理等等,内核最小的资源占用情况是 3KB ROM,1.2KB RAM。
1 IMPORT __main 2 LDR R0, =SystemInit 3 BLX R0 4 LDR R0, =__main 5 BX R0 6 ENDP
我们使用了 MDK 的扩展功能 $Sub$$ 和$Super$$ 。可以给 main 添加 $Sub$$ 的前缀符号作为一个新功能函数 $Sub$$main ,这个 $Sub$$main 可以先调用一些要补充在 main 之前的功能函数(这里添加 RT-Thread 系统初始化功能),再调用 $Super$$main
转到 main() 函数执行,这样可以让用户不用去管 main() 之前的系统初始化操作。
T-Thread 支持多种平台和多种编译器,而 rtthread_startup() 函数是 RT-Thread 规定的统一入口点,所以 $Sub$$main 函数只需调用rtthread_startup() 函数即可;
在 components.c 的代码中找到rtthread_startup() 函数,我们看到 RT-Thread 的启动流程如下图所示:
1 /* components.c 中定义的这段代码*/ 2 /* re-define main function */ 3 int $Sub$$main(void) 4 { 5 rt_hw_interrupt_disable(); 6 rtthread_startup(); 7 return 0; 8 }
1 int rtthread_startup(void) 2 { 3 rt_hw_interrupt_disable(); 4 5 /* board level initialization 6 * NOTE: please initialize heap inside board initialization. 7 */ 8 rt_hw_board_init(); 9 10 /* show RT-Thread version */ 11 rt_show_version(); 12 13 /* timer system initialization */ 14 rt_system_timer_init(); 15 16 /* scheduler system initialization */ 17 rt_system_scheduler_init(); 18 19 #ifdef RT_USING_SIGNALS 20 /* signal system initialization */ 21 rt_system_signal_init(); 22 #endif 23 24 /* create init_thread */ 25 rt_application_init(); 26 27 /* timer thread initialization */ 28 rt_system_timer_thread_init(); 29 30 /* idle thread initialization */ 31 rt_thread_idle_init(); 32 33 /* start scheduler */ 34 rt_system_scheduler_start(); 35 36 /* never reach here */ 37 return 0; 38 }
1 /* the system main thread */ 2 void main_thread_entry(void *parameter) 3 { 4 extern int main(void); 5 extern int $Super$$main(void); 6 7 /* RT-Thread components initialization */ 8 rt_components_init(); 9 10 /* invoke system main function */ 11 #if defined(__CC_ARM) || defined(__CLANG_ARM) 12 $Super$$main(); /* for ARMCC. */ 13 #elif defined(__ICCARM__) || defined(__GNUC__) 14 main(); 15 #endif 16 } 17 18 void rt_application_init(void) 19 { 20 rt_thread_t tid; 21 22 #ifdef RT_USING_HEAP 23 tid = rt_thread_create("main", main_thread_entry, RT_NULL, 24 1024*100, 0, 20); 25 RT_ASSERT(tid != RT_NULL);
1 int main(void) 2 { 3 /* user app entry */ 4 return 0; 5 }
程序运行之前,需要有文件实体被烧录到 STM32 的 Flash 中,一般是 bin 或者 hex 文件,该被烧录文件称为可执行映像文件。如图下图中左图所示,是可执行映像文件烧录到 STM32 后的内存分布,它包含 RO 段和 RW 段两个部分:其中 RO 段中保存了 Code、RO-data 的数据,RW 段保存了 RW-data 的数据,由于 ZI-data 都是 0,所以未包含在映像文件中。
1 int stm32_hw_usart_init(void) 2 { 3 struct stm32_uart *uart; 4 struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; 5 6 #ifdef RT_USING_UART1 7 uart = &uart1; 8 uart->UartHandle.Instance = USART1; 9 10 serial1.ops = &stm32_uart_ops; 11 serial1.config = config; 12 13 /* register UART1 device */ 14 rt_hw_serial_register(&serial1, 15 "uart1", 16 RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX, 17 uart); 18 #endif /* RT_USING_UART1 */ 19 ...... 20 ...... 21 } 22 INIT_BOARD_EXPORT(stm32_hw_usart_init);
代码最后的 INIT_BOARD_EXPORT(stm32_hw_usart_init) 表示使用自动初始化功能,按照这种方式,stm32_hw_usart_init() 函数就会被系统自动调用
系统启动流程图中,有两个函数:rt_components_board_init() 与 rt_components_init(),其后的带底色方框内部的函数表示被自动初始化的函数
1 static rt_uint8_t main_stack[2048]; 2 struct rt_thread main_thread; 3 4 void rt_application_init(void) 5 { 6 rt_thread_t tid; 7 8 #ifdef RT_USING_HEAP 9 /* 10 * 线程名:main 11 * 线程入口:main_thread_entry 12 * 参数:RT_NULL 13 * 站空间大小:1024*100 14 * 优先级:0 15 * 时间片:20个OS Tick 16 */ 17 tid = rt_thread_create("main", main_thread_entry, RT_NULL, //动态线程 18 1024*100, 0, 20); 19 RT_ASSERT(tid != RT_NULL); 20 #else 21 rt_err_t result; 22 23 tid = &main_thread; 24 /* 25 * 静态线程对象:main_thread 26 * 线程名:main 27 * 线程入口:main_thread_entry 28 * 参数:RT_NULL 29 * 线程起始地址:main_stack 30 * 线程堆栈大小:sizeof(main_stack) 31 * 优先级:RT_MAIN_THREAD_PRIORITY 32 * 时间片:20个OS Tick 33 */ 34 result = rt_thread_init(tid, "main", main_thread_entry, RT_NULL, //静态线程 35 main_stack, sizeof(main_stack), RT_MAIN_THREAD_PRIORITY, 20); 36 RT_ASSERT(result == RT_EOK); 37 38 /* if not define RT_USING_HEAP, using to eliminate the warning */ 39 (void)result; 40 #endif 41 42 rt_thread_startup(tid); //启动线程 43 }
rt_object 派生出来的有:线程对象、内存池对象、定时器对象、设备对象和 IPC对象(IPC:Inter-Process Communication,进程间通信。在 RT-Thread 实时操作系统中,IPC 对象的作用是进行线程间同步与通信);由 IPC 对象派生出信号量、互斥量、事件、邮箱与消息队列、信号等对象。
1 /** 2 * Base structure of Kernel object 3 */ 4 struct rt_object 5 { 6 char name[RT_NAME_MAX]; /**< name of kernel object 内核对象名称*/ 7 rt_uint8_t type; /**< type of kernel object 内核对象类型*/ 8 rt_uint8_t flag; /**< flag of kernel object 内核对象的参数*/ 9 10 #ifdef RT_USING_MODULE 11 void *module_id; /**< id of application module 内核对象模型id*/ 12 #endif 13 rt_list_t list; /**< list node of kernel object 内核对象管理链表*/ 14 }; 15 typedef struct rt_object *rt_object_t; /**< Type for kernel objects. */
enum rt_object_class_type { RT_Object_Class_Thread = 0, /**< The object is a thread. 线程类型*/ RT_Object_Class_Semaphore, /**< The object is a semaphore. 信号量类型*/ RT_Object_Class_Mutex, /**< The object is a mutex. 互斥量类型*/ RT_Object_Class_Event, /**< The object is a event. 时间类型*/ RT_Object_Class_MailBox, /**< The object is a mail box. 邮箱类型*/ RT_Object_Class_MessageQueue, /**< The object is a message queue. 消息队列类型*/ RT_Object_Class_MemHeap, /**< The object is a memory heap 内存堆类型*/ RT_Object_Class_MemPool, /**< The object is a memory pool. 内存池类型*/ RT_Object_Class_Device, /**< The object is a device 设备类型*/ RT_Object_Class_Timer, /**< The object is a timer. 定时器类型*/ RT_Object_Class_Module, /**< The object is a module. 模块*/ RT_Object_Class_Unknown, /**< The object is unknown. 未知类型*/ RT_Object_Class_Static = 0x80 /**< The object is a static object. 静态类型*/ };
如果是静态对象,那么对象类型的最高位将是 1(是RT_Object_Class_Static 与其他对象类型的与操作),否则就是动态对象,系统最多能够容纳的对象类别数目是 127 个。
/** * The information of the kernel object */ struct rt_object_information { enum rt_object_class_type type; /**< object class type */ rt_list_t object_list; /**< object list */ rt_size_t object_size; /**< object size */ };
一类对象由一个 rt_object_information 结构体来管理,每一个这类对象的具体实例都通过链表的形式挂接在 object_list 上。而这一类对象的内存块尺寸由 object_size 标识出来
void rt_object_init(struct rt_object *object, //需要初始化的对象指针,它必须指向具体的对象内存块,而不能是空指针或野指针 enum rt_object_class_type type, //对象的类型,必须是 rt_object_class_type 枚举类型中列出的除RT_Object_Class_Static 以外的类型 const char *name) //对象的名字。每个对象可以设置一个名字,这个名字的最大长度由 RT_NAME_MAX指定
/** * This function will detach a static object from object system, * and the memory of static object is not freed. * * @param object the specified object to be detached. */ void rt_object_detach(rt_object_t object)
/** * This function will allocate an object from object system * * @param type the type of object * @param name the object name. In system, the object‘s name must be unique. * * @return object */ rt_object_t rt_object_allocate(enum rt_object_class_type type, const char *name)
/** * This function will delete an object and release object memory. * * @param object the specified object to be deleted. */ void rt_object_delete(rt_object_t object)
/** * This function will judge the object is system object or not. * Normally, the system object is a static object and the type * of object set to RT_Object_Class_Static. * * @param object the specified object to be judged. * * @return RT_TRUE if a system object, RT_FALSE for others. */ rt_bool_t rt_object_is_systemobject(rt_object_t object)
在 RT-Thread 操作系统中,一个系统对象也就是一个静态对象,对象类型标识上 RT_Object_Class_Static 位置位。通常使用 rt_object_init() 方式初始化的对象都是系统对象。
/* RT-Thread 内核部分 */ #define RT_NAME_MAX 8 // 表示内核对象的名称的最大长度,若代码中对象名称的最大长度大于宏定义的长度,*多余的部分将被截掉。 #define RT_ALIGN_SIZE 4 // 字节对齐时设定对齐的字节个数。常使用 ALIGN(RT_ALIGN_SIZE) 进行字节对齐。 #define RT_THREAD_PRIORITY_32 #define RT_THREAD_PRIORITY_MAX 32 // 定义系统线程优先级数;通常用 RT_THREAD_PRIORITY_MAX-1 定义空闲线程的优先级 #define RT_TICK_PER_SECOND 1000 // 定义时钟节拍,为 1000 时表示 1000 个 tick 每秒,一个 tick 为 10ms #define RT_USING_OVERFLOW_CHECK // 检查栈是否溢出,未定义则关闭 #define RT_USING_HOOK // 定义该宏使用 HOOK #define RT_IDEL_HOOK_LIST_SIZE 4 // 定义HOOK链表大小 #define IDLE_THREAD_STACK_SIZE 1024 // 定义线程栈大小 #define RT_DEBUG // 定义该宏开启 debug 模式,未定义则关闭 /* 线程间同步与通信部分,该部分会使用到的对象有信号量、互斥量、事件、邮箱、消息队列、信号等。 */ #define RT_USING_SEMAPHORE // 定义该宏可开启信号量的使用,未定义则关闭 #define RT_USING_MUTEX // 定义该宏可开启互斥量的使用,未定义则关闭 #define RT_USING_EVENT // 定义该宏可开启事件集的使用,未定义则关闭 #define RT_USING_MAILBOX // 定义该宏可开启邮箱的使用,未定义则关闭 #define RT_USING_MESSAGEQUEUE // 定义该宏可开启消息队列的使用,未定义则关闭 /* 内存管理部分 */ #define RT_USING_MEMPOOL // 开启静态内存池的使用 #define RT_USING_MEMHEAP // 定义该宏可开启两个或以上内存堆拼接的使用,未定义则关闭 #define RT_USING_SMALL_MEM // 开启小内存管理算法 #define RT_USING_HEAP // 开启堆的使用 /* 内核设备对象 */ #define RT_USING_DEVICE // 表示开启了系统设备的使用 #define RT_USING_CONSOLE // 定义该宏可开启系统控制台设备的使用,未定义则关闭 #define RT_CONSOLEBUF_SIZE 128 // 定义控制台设备的缓冲区大小 #define RT_CONSOLE_DEVICE_NAME "uart1" // 控制台设备的名称 /* 自动初始化方式 */ #define RT_USING_COMPONENTS_INIT // 定义该宏开启自动初始化机制,未定义则关闭 /* Command shell */ #define RT_USING_FINSH // 定义该宏可开启系统 FinSH 调试工具的使用,未定义则关闭 #define FINSH_THREAD_NAME "tshell" // 开启系统 FinSH 时:将该线程名称定义为 tshell #define FINSH_USING_HISTORY // 开启系统 FinSH 时:使用历史命令 #define FINSH_HISTORY_LINES 5 // 开启系统 FinSH 时:对历史命令行数的定义 #define FINSH_USING_SYMTAB // 开启系统 FinSH 时:定义该宏开启使用 Tab 键,未定义则关闭 #define FINSH_USING_DESCRIPTION // 开启系统 FinSH 时:定义该宏使用描述,未定义则关闭 #define FINSH_THREAD_PRIORITY 20 // 开启系统 FinSH 时:定义该线程的优先级 #define FINSH_THREAD_STACK_SIZE 2048 // 开启系统 FinSH 时:定义该线程的栈大小 #define FINSH_CMD_SIZE 80 // 开启系统 FinSH 时:定义命令字符长度 /* Device virtual file system */ #define RT_USING_DFS // 使用DFS文件系统 #define DFS_USING_WORKDIR // 使用工作目录 #define DFS_FILESYSTEMS_MAX 4 // 文件系统 #define DFS_FILESYSTEM_TYPES_MAX 4 // 文件系统类型 #define DFS_FD_MAX 8 // DF容器大小 #define RT_USING_DFS_ELMFAT // 使用elmfat文件系统
rt_inline,定义如下,static 关键字的作用是令函数只能在当前的文件中使用;inline 表示内联,用static 修饰后在调用函数时会建议编译器进行内联展开。
#define rt_inline static __inline
RT_USED,定义如下,该宏的作用是向编译器说明这段代码有用,即使函数中没有调用也要保留编译。例如 RT-Thread 自动初始化功能使用了自定义的段,使用 RT_USED 会将自定义的代码段保留。
#define RT_USED __attribute__((used))
#define RT_UNUSED __attribute__((unused))
RT_WEAK,定义如下,常用于定义函数,编译器在链接函数时会优先链接没有该关键字前缀的函数,如果找不到则再链接由 weak 修饰的函数
#define RT_WEAK __weak
ALIGN(n),定义如下,作用是在给某对象分配地址空间时,将其存放的地址按照 n 字节对齐,这里 n 可取 2 的幂次方。字节对齐的作用不仅是便于 CPU 快速访问,同时合理的利用字节对齐可以有效地节省存储空间。
#define ALIGN(n) __attribute__((aligned(n)))
RT_ALIGN(size,align),定义如下,作用是将 size 提升为 align 定义的整数的倍数,例如,RT_ALIGN(13,4) 将返回 16。
#define RT_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1))
标签:方式 creat virtual proc 指针 list 链接器 gnu void
原文地址:https://www.cnblogs.com/icefree/p/10804126.html