该int rtthread_startup(void)函数完成了系统启动前的所有初始化动作,包括必要的硬件初始化、堆栈初始化,系统相关组件初始化、用户应用程序初始化,然后启动调度机制。
int rtthread_startup(void)
{
rt_hw_interrupt_disable();
/* board level initalization
* NOTE: please initialize heap inside board initialization.
*/
rt_hw_board_init();//初始化开发板硬件平台如LED,串口等
/* show RT-Thread version打印版本信息 */
rt_show_version();
/* timer system initialization */
rt_system_timer_init();
/* scheduler system initialization */
rt_system_scheduler_init();
#ifdef RT_USING_SIGNALS
/* signal system initialization */
rt_system_signal_init();
#endif
/* create init_thread */
rt_application_init();
/* timer thread initialization */
rt_system_timer_thread_init();/*初始化软件定时器*/
/* idle thread initialization */
rt_thread_idle_init(); /*初始化空线程*/
/* start scheduler */
rt_system_scheduler_start();
/* never reach here */
return 0;
}
#endif
1、 rt_hw_board_init()
完成中断向量表设置、系统滴答时钟设置,为系统提供串口初始化,将系统输入输出终端绑定到这个串口,后续系统运行信息就会从串口打印出来。
(void*)STM32_EXT_SRAM_END);内存管理设置好以后,应用程序就可以使用 rt_malloc、 rt_realloc、 re_free 等函数了。
2、 rt_application_init()
这个函数是为用户准备的,用户可以在这个函数里创建自己的应用线程。
什么是线程?
从系统的角度看,线程是竞争系统资源的最小运行单元。 RT-Thread 是一个支持多线程的操作系统。通俗的讲,即把一个大问题分解成多个相对简单、比较容易解决的小问题,小问题逐个被解决了,大问题也就随之解决了。同样,在设计一个较为复杂的应用程序时,也通常把一个大型任务分解成多个小任务,然后通过运行这些小任务,最终达到完成大任务的目的。叫做线程
static void led1_thread_entry(void* parameter)
{
while (1)
{
GPIO_SetBits(GPIOB,GPIO_Pin_8);
rt_thread_delay(500);
//rt_kprintf("led1_thread running,LED1_ON\r\n");
GPIO_ResetBits(GPIOB,GPIO_Pin_8);
rt_thread_delay(500);
//rt_kprintf("led1_thread running,LED1_OFF\r\n");
}
上面即是一个典型的线程代码结构—无限死循环
其中线程控制块 rt_thread 结构体具体内容如下:
struct rt_thread
{
/* rt object */
char name[RT_NAME_MAX]; /**< the name of thread */
rt_uint8_t type; /**< type of object */
rt_uint8_t flags; /**< thread's flags */
#ifdef RT_USING_MODULE
void *module_id; /**< id of application module */
#endif
rt_list_t list; /**< the object list */
rt_list_t tlist; /**< the thread list */
/* stack point and entry */
void *sp; /**< stack point */
void *entry; /**< entry */
void *parameter; /**< parameter */
void *stack_addr; /**< stack address */
rt_uint32_t stack_size; /**< stack size */
/* error code */
rt_err_t error; /**< error code */
rt_uint8_t stat; /**< thread status */
/* priority */
rt_uint8_t current_priority; /**< current priority */
rt_uint8_t init_priority; /**< initialized priority */
#if RT_THREAD_PRIORITY_MAX > 32
rt_uint8_t number;
rt_uint8_t high_mask;
#endif
rt_uint32_t number_mask;
#if defined(RT_USING_EVENT)
/* thread event */
rt_uint32_t event_set;
rt_uint8_t event_info;
#endif
#if defined(RT_USING_SIGNALS)
rt_sigset_t sig_pending; /**< the pending signals */
rt_sigset_t sig_mask; /**< the mask bits of signal */
void *sig_ret; /**< the return stack pointer from signal */
rt_sighandler_t *sig_vectors; /**< vectors of signal handler */
void *si_list; /**< the signal infor list */
#endif
rt_ubase_t init_tick; /**< thread's initialized tick */
rt_ubase_t remaining_tick; /**< remaining tick */
struct rt_timer thread_timer; /**< built-in thread timer */
void (*cleanup)(struct rt_thread *tid); /**< cleanup function when thread exit */
rt_uint32_t user_data; /**< private user data beyond this thread */
};
typedef struct rt_thread *rt_thread_t;
RT-Thread 中的线程分为静态线程—线程堆栈由编译器静态分配,使用 rt_thread_init()函数创建和动态线程—线程堆栈由系统动态分配,使用 rt_thread_create()函数创建。
使用静态线程时,必须先定义静态的线程控制块,并且定义好堆栈空间,然后调用rt_thread_init()来完成线程的初始化工作。采用这种方式,线程控制块和堆栈占用的内存会放在 RW/ZI 段,这段空间在编译时就已经确定,它不是可以动态分配的,所以不能被释放,而只能使用 rt_thread_detach()函数将该线程控制块从对象管理器中脱离。
使用动态定义方式 rt_thread_create()时, RT-Thread 会动态申请线程控制块和堆栈空间。在编译时,编译器是不会感知到这段空间的,只有在程序运行时, RT-Thread 才会从系统堆中申请分配这段内存空间,当不需要使用该线程时,调rt_thread_delete()函数就会将这段申请的内存空间重新释放到内存堆中。
静态定义方式会占用 RW/ZI 空间,但是不需要动态分配内存,运行时效率较高,实时性较好。动态方式不会占用额外的 RW/ZI 空间,占用空间小,但是运行时需要动态分配内存,效率没有静态方式高。