Nuttx系统启动流程

Nuttx系统启动流程

借用一位大神的图[天又亮了的博客http://blog.csdn.net/zhumaill/article/details/23261543]

__start--                                 #处理器执行的第一条指令
        |  
        v  
   stm32_clockconfig()------              #初始化时钟
                           |  
                           v  
                 rcc_reset()              #复位rcc
                 stm32_stdclockconfig()   #初始化标准时钟
                 rcc_enableperipherals()  #使能外设时钟
                           |  
        --------------------  
        |  
        v  
   stm32_fpuconfig()                      #配置fpu,shenzhou/nsh未调用
   stm32_lowsetup()                       #基本初始化串口,之后可以使用up_lowputc()
   stm32_gpioinit()                       #初始化gpio,只是调用stm32_gpioremap()设置重映射
   up_earlyserialinit()                   #初始化串口,之后可以使用up_putc()
   stm32_boardinitialize()--              #板级初始化
                           |  
                           v  
                 stm32_spiinitialize()    #初始化spi,只是调用stm32_configgpio()设置gpio
                 stm32_usbinitialize()    #初始化usb,只是调用stm32_configgpio()设置gpio
                 board_led_initialize()   #初始化led,只是调用stm32_configgpio()设置gpio
                           |  
        --------------------  
        |  
        v  
   os_start()---------------              #初始化操作系统
                           |  
                           v  
                 dq_init()                #初始化各种状态的任务列表(置为null)
                 g_pidhash[i]=            #初始化唯一可以确定的元素--进程ID
                 g_pidhash[PIDHASH(0)]=   #分配空闲任务的进程ID为0
                 g_idletcb=               #初始化空闲任务的任务控制块
                 sem_initialize()--       #初始化信号量
                                  |  
                                  v  
                       dq_init()          #将信号量队列置为null
                       sem_initholders()  #初始化持有者结构以支持优先级继承,shenzhou/nsh未调用
                                  |  
                           --------  
                           |  
                           v  
                 up_allocate_heap()       #分配用户模式的堆(设置堆的起点和大小)
                 kumm_initialize()        #初始化用户模式的堆
                 up_allocate_kheap()      #分配内核模式的堆,shenzhou/nsh未调用
                 kmm_initialize()         #初始化内核模式的堆,shenzhou/nsh未调用
                 task_initialize()        #初始化任务数据结构,shenzhou/nsh未调用
                 irq_initialize()         #将所有中断向量都指向同一个异常中断处理程序
                 wd_initialize()          #初始化看门狗数据结构
                 clock_initialize()       #初始化rtc
                 timer_initialize()       #配置POSIX定时器
                 sig_initialize()         #初始化信号
                 mq_initialize()          #初始化命名消息队列
                 pthread_initialize()     #初始化线程特定的数据,空函数
                 fs_initialize()---       #初始化文件系统
                                  |  
                                  v  
                       sem_init()         #初始化节点信号量为1
                       files_initialize() #初始化文件数组,空函数
                                  |  
                           --------  
                           |  
                           v  
                 net_initialize()--       #初始化网络
                                  |  
                                  v  
                       uip_initialize()   #初始化uIP层
                       net_initroute()    #初始化路由表,shenzhou/nsh未调用
                       netdev_seminit()   #初始化网络设备信号量
                       arptimer_init()    #初始化ARP定时器
                                  |  
                           --------  
                           |  
                           v  
                 up_initialize()---       #处理器特定的初始化
                                  |  
                                  v  
                       up_calibratedelay()#校准定时器
                       up_addregion()     #增加额外的内存段
                       up_irqinitialize() #设置中断优先级,关联硬件异常处理函数
                       up_pminitialize()  #初始化电源管理,shenzhou/nsh未调用
                       up_dmainitialize() #初始化DMA,shenzhou/nsh未调用
                       up_timerinit()     #初始化定时器中断
                       devnull_register() #注册/dev/null
                       devzero_register() #注册/dev/zero,shenzhou/nsh未调用
                       up_serialinit()    #注册串口控制台/dev/console和串口/dev/ttyS0
                       up_rnginitialize() #初始化并注册随机数生成器,shenzhou/nsh未调用
                       up_netinitialize() #初始化网络,是arch/arm/src/chip/stm32_eth.c中的
                       up_usbinitialize() #初始化usb驱动,shenzhou/nsh未调用
                       board_led_on()     #打开中断使能led,但很快会被其它地方的led操作改变状态
                                  |  
                           --------  
                           |  
                           v  
                 lib_initialize()         #初始化c库,空函数
                 group_allocate()         #分配空闲组
                 group_setupidlefiles()   #在空闲任务上创建stdout、stderr、stdin
                 group_initialize()       #完全初始化空闲组
                 os_bringup()------       #创建初始任务
                                  |  
                                  v  
                       KEKERNEL_THREAD()  #启动内核工作者线程
                       board_initialize() #最后一刻的板级初始化,shenzhou/nsh未调用
                       TASK_CREATE()      #启动默认应用程序
                                  |  
                           --------  
                           |  
                           v  
for up_idle()            #空闲任务循环
                           |  
        --------------------  
        |  
        v  
for(;;)                                #不应该到达这里

下面我就以FRDM-k64为主介绍一下nuttx的启动代码流程图,因为使用的是Nuttx7.18的代码可能和上面大神的有点区别。

_start()函数启动开始(在Kinetis_start.c)

kinetis_wddisable();//关闭看门狗
kinetis_clockconfig();//配置时钟
stm32_fpuconfig();//初始化FPU功能
kinetis_lowsetup();//芯片最初的一些初始化
#ifdef USE_EARLYSERIALINIT
  up_earlyserialinit();//系统早期的串口初始化
#endif
#ifdef CONFIG_BUILD_PROTECTED
  kinetis_userspace();//初始化用户空间
#endif
kinetis_boardinitialize();//初始化板上的所有资源
  /* Then start NuttX */
  os_start();//系统开始运行

  /* Shouldn't get here */
  for (; ; );//不会运行到这
os_start()函数解析,在Os_start.c文件中
    /*初始化RTOS数据,初始化任务链表*/
    dq_init(&g_readytorun);
    dq_init(&g_pendingtasks);
    dq_init(&g_waitingforsemaphore);
    //这里还初始化了系统运行的其他一些初始参数
    /* Initialize the IDLE task TCB 初始化任务块*******************************************/
    //在这是初始化一些信号量,内存分配等等系统运行必要参数,上面大神写的比较清楚,我主要看了下面两个函数
    up_initialize();//特定处理器的初始化
    os_bringup();//创建初始任务
up_initialize(void);在nuttx/arch/arm/src/common/Up_initialize.c中
  /* Calibrate the timing loop */

  up_calibratedelay();//校正时钟

  /* Colorize the interrupt stack */

  up_color_intstack();//初始化中断任务块

  /* Add any extra memory fragments to the memory manager */

  up_addregion();

  /* Initialize the interrupt subsystem */

  up_irqinitialize();//初始化中断表
  /*
  在这还有其他的一些初始化比如usb初始化、telnet初始化等等
  */

  //最后就是
    board_autoled_on(LED_IRQSENABLED);//初始化板载中断,有中断产生就点亮RGB
os_bringup();在nuttx/sched/init/Os_bringup.c中
  /* Start the page fill worker kernel thread that will resolve page faults.
   * This should always be the first thread started because it may have to
   * resolve page faults in other threads
   */
  os_pgworker();

  /* Start the worker thread that will serve as the device driver "bottom-
   * half" and will perform misc garbage clean-up.
   */

  os_workqueues();

  /* Once the operating system has been initialized, the system must be
   * started by spawning the user initialization thread of execution.  This
   * will be the first user-mode thread.
   */

  os_start_application();//开始应用程序初始化
os_start_application();在nuttx/sched/init/Os_bringup.c中
static inline void os_start_application(void)//inline 定义的是一个内联函数
{
#ifdef CONFIG_BOARD_INITTHREAD//如果定义了,机会创建一个线程来执行os_do_appstart();如果没有就是直接调用os_do_appstart();
  int pid;

  /* Do the board/application initialization on a separate thread of
   * execution.
   */

  pid = kernel_thread("AppBringUp", CONFIG_BOARD_INITTHREAD_PRIORITY,
                      CONFIG_BOARD_INITTHREAD_STACKSIZE,
                      (main_t)os_start_task, (FAR char * const *)NULL);
  ASSERT(pid > 0);

#else
  /* Do the board/application initialization on this thread of execution. */

  os_do_appstart();

#endif
}
os_do_appstart();在nuttx/sched/init/Os_bringup.c中
static inline void os_do_appstart(void)
{
  int pid;

#ifdef CONFIG_BOARD_INITIALIZE
  /* Perform any last-minute, board-specific initialization, if so
   * configured.
   */

  board_initialize();//板级初始化
#endif

  /* Start the application initialization task.  In a flat build, this is
   * entrypoint is given by the definitions, CONFIG_USER_ENTRYPOINT.  In
   * the protected build, however, we must get the address of the
   * entrypoint from the header at the beginning of the user-space blob.
   */

  sinfo("Starting init thread\n");

#ifdef CONFIG_BUILD_PROTECTED
  DEBUGASSERT(USERSPACE->us_entrypoint != NULL);
  pid = task_create("init", SCHED_PRIORITY_DEFAULT,
                    CONFIG_USERMAIN_STACKSIZE, USERSPACE->us_entrypoint,
                    (FAR char * const *)NULL);//创建任务,
#else
  pid = task_create("init", SCHED_PRIORITY_DEFAULT,
                    CONFIG_USERMAIN_STACKSIZE,
                    (main_t)CONFIG_USER_ENTRYPOINT,
                    (FAR char * const *)NULL);//创建任务,CONFIG_USER_ENTRYPOINT指的是NSH_MAIN(nsh_main)
#endif
  ASSERT(pid > 0);
}

最后执行up_idle()这个空闲任务,到这整个Nuttx启动就结束了。启动完后有一个可以通过串口进行调试的串口,类似ssh这种命令窗口,但是不知道为什么,只有dev和proc两个文件夹,难道是K64没有完整的移植好,还是我的使用有误。

在整个分析过程中有一部分还不是很清楚,比如任务调度器的运行原理,还是缺乏操作系统原理的知识。

希望正在学习的同学可以一起交流一些,同学习PX4才学习这个系统,如果有什么错误欢迎大家更正。同时也希望大神级的前辈指导一下。

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值