这篇文章给大家介绍如何分析RT-Thread中的$Sub$main函数,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
int rtthread_startup(void) { rt_hw_interrupt_disable(); /* board level initialization * NOTE: please initialize heap inside board initialization. */ rt_hw_board_init(); /* 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(); #ifdef RT_USING_SMP rt_hw_spin_lock(&_cpus_lock); #endif /*RT_USING_SMP*/ /* start scheduler */ rt_system_scheduler_start(); /* never reach here */ return 0; }
rtthread_startup函数又分了是一个子函数:
1、关全局中断
2、板级初始化rt_hw_board_init,在/bsp/stm32f10x/drivers/board.c中。
/** * This function will initial STM32 board. */ void rt_hw_board_init(void) { /* NVIC Configuration */ NVIC_Configuration(); /* Configure the SysTick */ SysTick_Config( SystemCoreClock / RT_TICK_PER_SECOND ); #if STM32_EXT_SRAM EXT_SRAM_Configuration(); #endif rt_hw_usart_init(); rt_console_set_device(RT_CONSOLE_DEVICE_NAME); #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif }
又分成了好几个小程序。
第一个函数NVIC__Configuration设置嵌套向量中断控制器,也在/bsp/stm32f10x/drivers/board.c里。这里先不做操作,后面会用到这个函数的同名静态函数来初始化各个外设的中断控制器。
/******************************************************************************* * Function Name : NVIC_Configuration * Description : Configures Vector Table base location. * Input : None * Output : None * Return : None *******************************************************************************/ void NVIC_Configuration(void) { #ifdef VECT_TAB_RAM /* Set the Vector Table base location at 0x20000000 */ NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); #else /* VECT_TAB_FLASH */ /* Set the Vector Table base location at 0x08000000 */ NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0); #endif
第二个函数SysTick_Config设置了系统滴答计数器。系统滴答计数器负责唤醒rtt的线程调度器,也就是操作系统的“心跳”。
第三个函数rt_hw_usart_init负责初始化串口外设,可以初始化串口1到4。这个函数定义在/bsp/stm32f10x/drivers/usart.c中。这个函数引用了同文件里的静态函数NVIC__Configuration,与board.c里的函数同名,但是含参。这个函数负责设置串口中断的初始化。
void rt_hw_usart_init(void) { struct stm32_uart* uart; struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; RCC_Configuration(); GPIO_Configuration(); #if defined(RT_USING_UART1) uart = &uart1; config.baud_rate = BAUD_RATE_115200; serial1.ops = &stm32_uart_ops; serial1.config = config; NVIC_Configuration(uart); /* register UART1 device */ rt_hw_serial_register(&serial1, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART1 */ #if defined(RT_USING_UART2) uart = &uart2; config.baud_rate = BAUD_RATE_115200; serial2.ops = &stm32_uart_ops; serial2.config = config; NVIC_Configuration(uart); /* register UART2 device */ rt_hw_serial_register(&serial2, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART2 */ #if defined(RT_USING_UART3) uart = &uart3; config.baud_rate = BAUD_RATE_115200; serial3.ops = &stm32_uart_ops; serial3.config = config; NVIC_Configuration(uart); /* register UART3 device */ rt_hw_serial_register(&serial3, "uart3", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART3 */ #if defined(RT_USING_UART4) uart = &uart4; config.baud_rate = BAUD_RATE_115200; serial4.ops = &stm32_uart_ops; serial4.config = config; NVIC_Configuration(uart); /* register UART4 device */ rt_hw_serial_register(&serial4, "uart4", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_DMA_RX, uart); #endif /* RT_USING_UART4 */ }
static void NVIC_Configuration(struct stm32_uart* uart) { NVIC_InitTypeDef NVIC_InitStructure; /* Enable the USART1 Interrupt */ NVIC_InitStructure.NVIC_IRQChannel = uart->irq; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); }
第四个函数rt_console_set_device定义在/bsp/stm32f10x/drivers/board.c里。有说明,可以看出是控制台的设置函数。
/** * This function will set a device as console device. * After set a device to console, all output of rt_kprintf will be * redirected to this new device. * * @param name the name of new console device * * @return the old console device handler */ rt_device_t rt_console_set_device(const char *name) { rt_device_t new, old; /* save old device */ old = _console_device; /* find new console device */ new = rt_device_find(name); if (new != RT_NULL) { if (_console_device != RT_NULL) { /* close old console device */ rt_device_close(_console_device); } /* set new console device */ rt_device_open(new, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_STREAM); _console_device = new; } return old; }
第五个函数rt_components_board_init定义在/bsp/stm32f10x/drivers/components.c里。负责初始化板级组件。
/** * 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 }
3、rt_show_version,打印版本信息。
4、rt_system_timer_init,初始化系统时钟,应该是日期什么的。
5、rt_system_scheduler_init,初始化线程调度器。这个以后详细学习。
6、rt_application_init,初始化应用线程,也就是主线程。定义在/bsp/stm32f10x/drivers/components.c里。负责创建或初始化主线程,然后启动主线程。
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); }
系统主线程的定义也在这个文件里。而$Super$$main函数就在这里面了。
/* the system main thread */ void main_thread_entry(void *parameter) { extern int main(void); extern int $Super$$main(void); /* RT-Thread components initialization */ rt_components_init(); #ifdef RT_USING_SMP rt_hw_secondary_cpu_up(); #endif /* invoke system main function */ #if defined(__CC_ARM) || defined(__CLANG_ARM) $Super$$main(); /* for ARMCC. */ #elif defined(__ICCARM__) || defined(__GNUC__) main(); #endif }
关于如何分析RT-Thread中的$Sub$main函数就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。
原创文章,作者:306829225,如若转载,请注明出处:https://blog.ytso.com/222914.html