本文主要讲述了基于MDK与AliOS Things的第一个应用程序——串口输出“hello world”,能够做为AliOS Things入门的第一个里程碑,打开AliOS Things(如下简称AOS)知识的大门。
相比GCC+makefile文件方式,基于IDE(MDK\IAR…)的好处在于,不须要关心makefile的编译规则等,经过IDE工具创建好工程后,点击“编译(make)”按键,IDE会自动经过内嵌的编译器工具链(MDK-armcc、IAR-icc…)、连接脚本文件(.sct)等完成可执行目标文件的输出(.hex、.bin、.elf…),并可结合JLink\STLink等工具实如今线仿真与调试。ios
PS:本文代码基于AliOS Things rel_2.1.0版本web
本文主要内容涉及了AliOS Things内核启动过程、main入口与应用层代码入口、helloworld应用示例等。AliOS Things的MDK开发环境的搭建能够参考另外一篇文章《基于STM32L4与MDK搭建AliOS Things2.1.0开发环境》编程
在嵌入式系统(MCU)中,启动文件(好比startup_stm32l476xx.s)是芯片上电最早运行的一段程序,是整个系统软件很是关键的部分,若是启动文件出现错误,则整个系统就跑不起来。
app
MCU上电后,启动文件会自动进行一些MCU芯片底层的初始化,构建程序运行必要的环境,包括:svg
一般,芯片原厂都提供了MDK对应内核芯片(好比ST STM32L4xx…)启动文件,启动文件由汇编程序编写,通常命名为startup_xxx.s,xxx为支持的芯片型号,好比startup_stm32l476xx.s。
基于MDK,通常默认都是使用芯片原厂提供的启动文件,并不须要涉及启动文件的修改。
函数
经过“2.1 MCU的启动过程”完成了MCU从系统上电开始运行到系统进入应用程序主代码(main函数)的准备工做。接下来即是RTOS内核启动。
下文配合AliOS Things 2.1.0中的stm32l476rg-nucleo示例进行说明。
工具
AOS的main()函数主要完成如下工做:ui
使用aos_heap_set进行堆区域起始地址、长度的设置spa
调用stm32_soc_init,初始化系统时钟(system clock)、OS无依赖的硬件HAL初始化(好比GPIO、DMA…).net
使用aos_init函数(实际上是对于krhino_init函数的封装)进行内核的初始化
建立一个sys_init的系统任务,在sys_init任务中会调用应用层代码application_start()函数
sys_init中进一步调用stm32_soc_peripheral_init,初始化应用层使用到的usart、iic等外设,这些外设使用了内核提供相关服务。
AOS内核启动流程:
从AOS实际代码看看:
main()函数所处的位置位于platform\mcu\stm32l4xx_cube\aos\aos.c文件中。
static void sys_init(void) { // 应用使用到的标准外设(USART\IIC..)初始化,好比helloworld示例应用中使用的串口USART,放在这里,主要是由于USART使用了内核相关服务 stm32_soc_peripheral_init(); #ifdef BOOTLOADER main(); #else hw_start_hal(); board_init(); var_init(); #ifdef AOS_COMP_CPLUSPLUS cpp_init(); #endif #if defined (AOS_OTA_RECOVERY_TYPE) sys_clear_ota_flag(); #endif // 完成各个组件的初始化以及进入应用程序 aos_components_init(&kinit); #ifndef AOS_BINS // 跳转到应用层代码入口函数 application_start(kinit.argc, kinit.argv); /* jump to app/example entry */ #endif #endif } static void sys_start(void) { // 堆的起始地址和长度初始化,该函数位于soc_impl.c中 aos_heap_set(); // 系统时钟(system clock)初始化、HAL初始化(好比GPIO、DMA...) stm32_soc_init(); // 内核初始化 // 1.内存初始化、内核对象初始化 // 2.新建默认任务(定时器任务、空闲任务、工做队列等) aos_init(); //创建aos-init任务,任务入口为sys_init,aos_start()执行后,内核调度sys_init,并调用应用层入口 //krhino_task_dyn_create(&g_aos_init, "aos-init", 0, AOS_DEFAULT_APP_PRI, 0, AOS_START_STACK, (task_entry_t)sys_init, 1); krhino_task_create(&demo_task_obj, "aos-init", 0,AOS_DEFAULT_APP_PRI, 0, demo_task_buf, AOS_START_STACK, (task_entry_t)sys_init, 1); aos_start(); } int main(void) { sys_start(); return 0; }
extern unsigned int Image$$RW_IRAM1$$ZI$$Limit; //comes from component board, may different to each other as hardware resource extern size_t g_iram1_start; extern size_t g_iram1_total_size; k_mm_region_t g_mm_region[1]; int g_region_num = 1; void aos_heap_set(void) { // 在.sct连接文件中指定的地址 g_mm_region[0].start = (uint8_t*)&Image$$RW_IRAM1$$ZI$$Limit; // 长度=RAM区的尾地址-bss段的结束地址-偏移地址 g_mm_region[0].len = (g_iram1_start + g_iram1_total_size - (size_t)&Image$$RW_IRAM1$$ZI$$Limit); }
void stm32_soc_init(void) { HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/RHINO_CONFIG_TICKS_PER_SECOND); MX_GPIO_Init(); MX_DMA_Init(); } void stm32_soc_peripheral_init(void) { /*default uart init*/ stduart_init(); hal_i2c_init(&brd_i2c1_dev); } static void stduart_init(void) { uart_0.port = 0; uart_0.config.baud_rate = 115200; uart_0.config.data_width = DATA_WIDTH_8BIT; uart_0.config.flow_control = FLOW_CONTROL_DISABLED; uart_0.config.mode = MODE_TX_RX; uart_0.config.parity = NO_PARITY; uart_0.config.stop_bits = STOP_BITS_1; hal_uart_init(&uart_0); }
AliOS Things rel_2.1.0提供sys_init(任务)\application_start()接口,做为应用层代码的入口。应用层参考代码放在app\example目录下,在application_start()函数中实现应用代码,如3章节 Hello Word示例应用。
int application_start(int argc, char *argv[])
AliOS Things的hello world应用程序放在alios-things\app\example\helloworld\helloworld.c
int application_start(int argc, char *argv[]) { int count = 0; printf("nano entry here!\r\n"); while(1) { // 串口输出hello world printf("hello world! count %d \r\n", count++); // 闪烁LED board_drv_led_ctrl(count & 0x01); // 挂起1s aos_msleep(1000); }; }
经过Jlink等下载到STM32硬件板子上,并运行,实际效果以下: