PX4与Ardupilot的入门基础知识(第一章:架构与启动过程

				版权声明:本文为博主原创文章,未经博主允许不得转载。					https://blog.csdn.net/lixiaoweimashixiao/article/details/81545640				</div>
							            <div id="content_views" class="markdown_views">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h3 id="目录"><a name="t0"></a>目录</h3>

摘要

本节主要记录自己学px4的代码架构与Ardupilot代码架构对比文档,欢迎批评指正。



  (1)px4与apm固件的区别与联系
  (2)px4与apm每个文件夹的作用
  (3)px4与apm无人机的启动过程

  
  
  • 1
  • 2
  • 3


第一节:px4与apm的区别与联系



这里写图片描述
(1)pixhawk
pixhawk硬件
(2)APM
APM硬件
(3)px4—Firmware
这里写图片描述
(4)apm—Ardupilot
这里写图片描述



第二节:px4与apm每个文件夹的作用



(1)px4代码代码架构
1>整理目录
这里写图片描述


2>每个文件夹的作用
这里写图片描述


(2)apm代码代码架构
1>整理目录
这里写图片描述


2>每个文件夹的作用
这里写图片描述



第三节:px4与apm无人机的启动过程

这里只讲解Nuttx启动到ArduCopter多旋翼入口函数的过程,Bootloader到Nuttx的过程将在:Bootloader启动分析中讲解。
代码逻辑

1.px4固件启动过程




(1)Bootloader启动后,单片机的入口函数:stm32_start.c





需要思考的问题:这个启动过程是STM32F427还是STM32F103的入口,或者两个同时都有


//复位后的入口函数:This is the reset entry point.
void __start(void)
{
  const uint32_t *src;
  uint32_t *dest;

#ifdef CONFIG_ARMV7M_STACKCHECK
  /* Set the stack limit before we attempt to call any functions */

  __asm__ volatile ("sub r10, sp, %0" : : "r" (CONFIG_IDLETHREAD_STACKSIZE - 64) : );
#endif

  /* Configure the UART so that we can get debug output as soon as possible */

  stm32_clockconfig(); //初始化时钟
  stm32_fpuconfig();   //配置FPU(浮点运算)
  stm32_lowsetup();    //基本初始化串口,之后可以使用up_lowputc()
  stm32_gpioinit();    //初始化gpio,只是调用stm32_gpioremap()设置重映射
  showprogress('A');   //输出A

  /* Clear .bss.  We'll do this inline (vs. calling memset) just to be
   * certain that there are no issues with the state of global variables.
   */

  for (dest = _START_BSS; dest < _END_BSS; )
    {
      *dest++ = 0;
    }

  showprogress('B');

  /* Move the initialized data section from his temporary holding spot in
   * FLASH into the correct place in SRAM.  The correct place in SRAM is
   * give by _sdata and _edata.  The temporary location is in FLASH at the
   * end of all of the other read-only data (.text, .rodata) at _eronly.
   */

  for (src = _DATA_INIT, dest = _START_DATA; dest < _END_DATA; )
    {
      *dest++ = *src++;
    }

  showprogress('C');

#ifdef CONFIG_ARMV7M_ITMSYSLOG
  /* Perform ARMv7-M ITM SYSLOG initialization */

  itm_syslog_initialize();
#endif

  /* Perform early serial initialization */

#ifdef USE_EARLYSERIALINIT
  up_earlyserialinit(); //初始化串口,之后可以使用up_putc()
#endif
  showprogress('D');

  /* For the case of the separate user-/kernel-space build, perform whatever
   * platform specific initialization of the user memory is required.
   * Normally this just means initializing the user space .data and .bss
   * segments.
   */

#ifdef CONFIG_BUILD_PROTECTED
  stm32_userspace();
  showprogress('E');
#endif

  /* Initialize onboard resources */

  stm32_boardinitialize();  //stm32硬件板层配置初始化,完成,之后可以启动STM32的Nuttx操作系统
  showprogress('F');

  /* Then start NuttX */

  showprogress('\r');
  showprogress('\n');

#ifdef CONFIG_STACK_COLORATION
  /* Set the IDLE stack to the coloration value and jump into os_start() */

  go_os_start((FAR void *)&_ebss, CONFIG_IDLETHREAD_STACKSIZE);
#else
  /* Call os_start() */

  os_start();  //启动Nuttx操作系统

  /* Shoulnd't get here */

  for (; ; ); //进入死循环,这里是不是看到跟一般的FreeRTOS基本一样,就是配置硬件时钟,串口,IO等等,可以启动Nuttx操作系统,之后执行while死循环。
#endif
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92



(2)nuttx启动入口函数:void os_start(void)

这里写图片描述



/****************************************************************************
 * Name: os_start
 *
 * Description:
 *   This function is called to initialize the operating system and to spawn
 *   the user initialization thread of execution.  This is the initial entry
 *   point into NuttX
 *
 * Input Parameters:
 *   None
 *
 * Returned value:
 *   Does not return.
 *
 ****************************************************************************/
//这个函数被调用来初始化操作系统并生成执行的用户初始化线程。这是NuttX最初的切入点。
void os_start(void)
{
#ifdef CONFIG_SMP
  int cpu;
#else
# define cpu 0
#endif
  int i;

  sinfo("Entry\n");

  /* Boot up is complete */

  g_os_initstate = OSINIT_BOOT;

  /* Initialize RTOS Data ***************************************************/
  /* Initialize all task lists */

  dq_init(&g_readytorun); //初始化各种状态的任务列表(置为null)
  dq_init(&g_pendingtasks);
  dq_init(&g_waitingforsemaphore);
#ifndef CONFIG_DISABLE_SIGNALS
  dq_init(&g_waitingforsignal);
#endif
#ifndef CONFIG_DISABLE_MQUEUE
  dq_init(&g_waitingformqnotfull);
  dq_init(&g_waitingformqnotempty);
#endif
#ifdef CONFIG_PAGING
  dq_init(&g_waitingforfill);
#endif
  dq_init(&g_inactivetasks);
#if (defined(CONFIG_BUILD_PROTECTED) || defined(CONFIG_BUILD_KERNEL)) && \
     defined(CONFIG_MM_KERNEL_HEAP)
  sq_init(&g_delayed_kfree);
#endif
#ifndef CONFIG_BUILD_KERNEL
  sq_init(&g_delayed_kufree);
#endif

#ifdef CONFIG_SMP
  for (i = 0; i < CONFIG_SMP_NCPUS; i++)
    {
      dq_init(&g_assignedtasks[i]);
    }
#endif

  /* Initialize the logic that determine unique process IDs. */

  g_lastpid = 0;
  for (i = 0; i < CONFIG_MAX_TASKS; i++) //初始化唯一可以确定的元素--进程ID
    {
      g_pidhash[i].tcb = NULL;
      g_pidhash[i].pid = INVALID_PROCESS_ID;
    }

  /* Initialize the IDLE task TCB *******************************************/
//初始化空闲任务TCB
#ifdef CONFIG_SMP
  for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++, g_lastpid++)
#endif
    {
      FAR dq_queue_t *tasklist;
      int hashndx;

      /* Assign the process ID(s) of ZERO to the idle task(s) */

      hashndx                = PIDHASH(g_lastpid);
      g_pidhash[hashndx].tcb = &g_idletcb[cpu].cmn;
      g_pidhash[hashndx].pid = g_lastpid;

      /* Initialize a TCB for this thread of execution.  NOTE:  The default
       * value for most components of the g_idletcb are zero.  The entire
       * structure is set to zero.  Then only the (potentially) non-zero
       * elements are initialized. NOTE:  The idle task is the only task in
       * that has pid == 0 and sched_priority == 0.
       */

      memset((void *)&g_idletcb[cpu], 0, sizeof(struct task_tcb_s));
      g_idletcb[cpu].cmn.pid        = g_lastpid;
      g_idletcb[cpu].cmn.task_state = TSTATE_TASK_RUNNING;

      /* Set the entry point.  This is only for debug purposes.  NOTE: that
       * the start_t entry point is not saved.  That is acceptable, however,
       * becaue it can be used only for restarting a task: The IDLE task
       * cannot be restarted.
       */

#ifdef CONFIG_SMP
      if (cpu > 0)
        {
          g_idletcb[cpu].cmn.start      = os_idle_trampoline;
          g_idletcb[cpu].cmn.entry.main = os_idle_task;
        }
      else
#endif
        {
          g_idletcb[cpu].cmn.start      = (start_t)os_start;
          g_idletcb[cpu].cmn.entry.main = (main_t)os_start;
        }

      /* Set the task flags to indicate that this is a kernel thread and, if
       * configured for SMP, that this task is locked to this CPU.
       */

#ifdef CONFIG_SMP
      g_idletcb[cpu].cmn.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_NONCANCELABLE |
                                  TCB_FLAG_CPU_LOCKED);
      g_idletcb[cpu].cmn.cpu   = cpu;
#else
      g_idletcb[cpu].cmn.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_NONCANCELABLE);
#endif

#ifdef CONFIG_SMP
      /* Set the affinity mask to allow the thread to run on all CPUs.  No,
       * this IDLE thread can only run on its assigned CPU.  That is
       * enforced by the TCB_FLAG_CPU_LOCKED which overrides the affinity
       * mask.  This is essential because all tasks inherit the affinity
       * mask from their parent and, ultimately, the parent of all tasks is
       * the IDLE task.
       */

      g_idletcb[cpu].cmn.affinity = SCHED_ALL_CPUS;
#endif

#if CONFIG_TASK_NAME_SIZE > 0
      /* Set the IDLE task name */

#  ifdef CONFIG_SMP
      snprintf(g_idletcb[cpu].cmn.name, CONFIG_TASK_NAME_SIZE, "CPU%d IDLE", cpu);
#  else
      strncpy(g_idletcb[cpu].cmn.name, g_idlename, CONFIG_TASK_NAME_SIZE);
      g_idletcb[cpu].cmn.name[CONFIG_TASK_NAME_SIZE] = '\0';
#  endif
#endif

      /* Configure the task name in the argument list.  The IDLE task does
       * not really have an argument list, but this name is still useful
       * for things like the NSH PS command.
       *
       * In the kernel mode build, the arguments are saved on the task's
       * stack and there is no support that yet.
       */

#if CONFIG_TASK_NAME_SIZE > 0
      g_idleargv[cpu][0]  = g_idletcb[cpu].cmn.name;
#else
      g_idleargv[cpu][0]  = (FAR char *)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */
      g_idleargv[cpu][1]  = NULL;
      g_idletcb[cpu].argv = &g_idleargv[cpu][0];

      /* Then add the idle task's TCB to the head of the corrent ready to
       * run list.
       */

#ifdef CONFIG_SMP
      tasklist = TLIST_HEAD(TSTATE_TASK_RUNNING, cpu);
#else
      tasklist = TLIST_HEAD(TSTATE_TASK_RUNNING);
#endif
      dq_addfirst((FAR dq_entry_t *)&g_idletcb[cpu], tasklist);

      /* Initialize the processor-specific portion of the TCB */

      up_initial_state(&g_idletcb[cpu].cmn);
    }

  /* Task lists are initialized */

  g_os_initstate = OSINIT_TASKLISTS;

  /* Initialize RTOS facilities *********************************************/
  /* Initialize the semaphore facility.  This has to be done very early
   * because many subsystems depend upon fully functional semaphores.
   */

  sem_initialize();   //初始化信号量

#if defined(MM_KERNEL_USRHEAP_INIT) || defined(CONFIG_MM_KERNEL_HEAP) || \
    defined(CONFIG_MM_PGALLOC)
  /* Initialize the memory manager */

  {
    FAR void *heap_start;
    size_t heap_size;

#ifdef MM_KERNEL_USRHEAP_INIT
    /* Get the user-mode heap from the platform specific code and configure
     * the user-mode memory allocator.
     */

    up_allocate_heap(&heap_start, &heap_size); //分配用户模式的堆(设置堆的起点和大小)
    kumm_initialize(heap_start, heap_size); //初始化用户模式的堆
#endif

#ifdef CONFIG_MM_KERNEL_HEAP
    /* Get the kernel-mode heap from the platform specific code and configure
     * the kernel-mode memory allocator.
     */

    up_allocate_kheap(&heap_start, &heap_size);
    kmm_initialize(heap_start, heap_size);
#endif

#ifdef CONFIG_MM_PGALLOC
    /* If there is a page allocator in the configuration, then get the page
     * heap information from the platform-specific code and configure the
     * page allocator.
     */
    //如果在配置页面分配器,然后让页面堆信息从特定于平台的代码和配置页面分配器。
    up_allocate_pgheap(&heap_start, &heap_size); //分配用户模式的堆(设置堆的起点和大小)
    mm_pginitialize(heap_start, heap_size);      //初始化内核模式的堆
#endif
  }
#endif

  /* The memory manager is available */

  g_os_initstate = OSINIT_MEMORY;

#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
  /* Initialize tasking data structures */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (task_initialize != NULL)
#endif
    {
      task_initialize(); //初始化任务数据结构
    }
#endif

  /* Initialize the interrupt handling subsystem (if included) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (irq_initialize != NULL)
#endif
    {
      irq_initialize(); //初始化中断处理子系统(如果包含的话)
    }

  /* Initialize the watchdog facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (wd_initialize != NULL)
#endif
    {
      wd_initialize(); //初始化看门狗设施(如果包含在链接中)
    }

  /* Initialize the POSIX timer facility (if included in the link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (clock_initialize != NULL)
#endif
    {
      clock_initialize(); //初始化POSIX定时器工具(如果包含在链接中)
    }

#ifndef CONFIG_DISABLE_POSIX_TIMERS
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (timer_initialize != NULL)
#endif
    {
      timer_initialize(); //配置POSIX定时器
    }
#endif

#ifndef CONFIG_DISABLE_SIGNALS
  /* Initialize the signal facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (sig_initialize != NULL)
#endif
    {
      sig_initialize();//初始化信号设施(如果在链路中)
    }
#endif

#ifndef CONFIG_DISABLE_MQUEUE
  /* Initialize the named message queue facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (mq_initialize != NULL)
#endif
    {
      mq_initialize(); //初始化命名的消息队列设施(如果在链接中)
    } 
#endif

#ifndef CONFIG_DISABLE_PTHREAD
  /* Initialize the thread-specific data facility (if in link) */

#ifdef CONFIG_HAVE_WEAKFUNCTIONS
  if (pthread_initialize != NULL)
#endif
    {
      pthread_initialize(); //初始化线程特定的数据,空函数
    }
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0
  /* Initialize the file system (needed to support device drivers) */

  fs_initialize(); //初始化文件系统 
#endif

#ifdef CONFIG_NET
  /* Initialize the networking system.  Network initialization is
   * performed in two steps:  (1) net_setup() initializes static
   * configuration of the network support.  This must be done prior
   * to registering network drivers by up_initialize().  This step
   * cannot require upon any hardware-depending features such as
   * timers or interrupts.
   */

  net_setup(); //初始化网络
#endif

  /* The processor specific details of running the operating system
   * will be handled here.  Such things as setting up interrupt
   * service routines and starting the clock are some of the things
   * that are different for each  processor and hardware platform.
   */

  up_initialize(); //处理器特定的初始化

  /* Hardware resources are available */

  g_os_initstate = OSINIT_HARDWARE;

#ifdef CONFIG_NET
  /* Complete initialization the networking system now that interrupts
   * and timers have been configured by up_initialize().
   */

  net_initialize();
#endif

#ifdef CONFIG_MM_SHM
  /* Initialize shared memory support */

  shm_initialize();
#endif

  /* Initialize the C libraries.  This is done last because the libraries
   * may depend on the above.
   */

  lib_initialize();

  /* IDLE Group Initialization **********************************************/
  /* Announce that the CPU0 IDLE task has started */

  sched_note_start(&g_idletcb[0].cmn);

#ifdef CONFIG_SMP
  /* Initialize the IDLE group for the IDLE task of each CPU */

  for (cpu = 0; cpu < CONFIG_SMP_NCPUS; cpu++)
#endif
    {
#ifdef HAVE_TASK_GROUP
      /* Allocate the IDLE group */

      DEBUGVERIFY(group_allocate(&g_idletcb[cpu], g_idletcb[cpu].cmn.flags));
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
#ifdef CONFIG_SMP
      if (cpu > 0)
        {
          /* Clone stdout, stderr, stdin from the CPU0 IDLE task. */

          DEBUGVERIFY(group_setuptaskfiles(&g_idletcb[cpu]));
        }
      else
#endif
        {
          /* Create stdout, stderr, stdin on the CPU0 IDLE task.  These
           * will be inherited by all of the threads created by the CPU0
           * IDLE task.
           */

          DEBUGVERIFY(group_setupidlefiles(&g_idletcb[cpu]));
        }
#endif

#ifdef HAVE_TASK_GROUP
      /* Complete initialization of the IDLE group.  Suppress retention
       * of child status in the IDLE group.
       */

      DEBUGVERIFY(group_initialize(&g_idletcb[cpu]));
      g_idletcb[cpu].cmn.group->tg_flags = GROUP_FLAG_NOCLDWAIT;
#endif
    }

  /* Start SYSLOG ***********************************************************/
  /* Late initialization of the system logging device.  Some SYSLOG channel
   * must be initialized late in the initialization sequence because it may
   * depend on having IDLE task file structures setup.
   */

  syslog_initialize(SYSLOG_INIT_LATE);

#ifdef CONFIG_SMP
  /* Start all CPUs *********************************************************/

  /* A few basic sanity checks */

  DEBUGASSERT(this_cpu() == 0 && CONFIG_MAX_TASKS > CONFIG_SMP_NCPUS);

  /* Take the memory manager semaphore on this CPU so that it will not be
   * available on the other CPUs until we have finished initialization.
   */

  DEBUGVERIFY(kmm_trysemaphore());

  /* Then start the other CPUs */

  DEBUGVERIFY(os_smp_start());//然后启动其他cpus

#endif /* CONFIG_SMP */

  /* Bring Up the System ****************************************************/
  /* The OS is fully initialized and we are beginning multi-tasking */

  g_os_initstate = OSINIT_OSREADY;

  /* Create initial tasks and bring-up the system */

  DEBUGVERIFY(os_bringup()); //创建初始线程并提出系统

#ifdef CONFIG_SMP
  /* Let other threads have access to the memory manager */

  kmm_givesemaphore(); //让其他线程访问内存管理器

#endif /* CONFIG_SMP */

  /* The IDLE Loop **********************************************************/
  /* When control is return to this point, the system is idle. */

  sinfo("CPU0: Beginning Idle Loop\n");
  for (; ; )
    {
      /* Perform garbage collection (if it is not being done by the worker
       * thread).  This cleans-up memory de-allocations that were queued
       * because they could not be freed in that execution context (for
       * example, if the memory was freed from an interrupt handler).
       */

#ifndef CONFIG_SCHED_WORKQUEUE
      /* We must have exclusive access to the memory manager to do this
       * BUT the idle task cannot wait on a semaphore.  So we only do
       * the cleanup now if we can get the semaphore -- this should be
       * possible because if the IDLE thread is running, no other task is!
       *
       * WARNING: This logic could have undesirable side-effects if priority
       * inheritance is enabled.  Imaginee the possible issues if the
       * priority of the IDLE thread were to get boosted!  Moral: If you
       * use priority inheritance, then you should also enable the work
       * queue so that is done in a safer context.
       */

      if (sched_have_garbage() && kmm_trysemaphore() == 0)
        {
          sched_garbage_collection();
          kmm_givesemaphore();
        }
#endif

      /* Perform any processor-specific idle state operations */

      up_idle(); //执行任何处理器特定的空闲状态操作
    }
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495



(3)创建初始线程任务:os_bringup()
这里写图片描述




int os_bringup(void)
{
  /* Setup up the initial environment for the idle task.  At present, this
   * may consist of only the initial PATH variable.  The PATH variable is
   * (probably) not used by the IDLE task.  However, the environment
   * containing the PATH variable will be inherited by all of the threads
   * created by the IDLE task.
   */

//为空闲任务设置初始环境。目前,这可能只有初始路径变量。路径变量(可能)不被空闲任务使用。然而,包含路径变量,将所有的空闲任务创建线程继承的环境。
#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)setenv("PATH", CONFIG_PATH_INITIAL, 1);
#endif

  /* 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.
   */
 //启动将充当设备驱动程序“下半部分”的工作线程,并执行MISC垃圾清理
  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(); //这里是比较重要的函数

  /* We an save a few bytes by discarding the IDLE thread's environment. */

#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)clearenv();
#endif

  return OK;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42



(4)创建初始线程任务:os_start_application()
这里写图片描述




static inline void os_start_application(void)
{
#ifdef CONFIG_BOARD_INITTHREAD
  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
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

//分析下这个函数:kernel_thread()

int kernel_thread(FAR const char *name, int priority,
                  int stack_size, main_t entry, FAR char *const argv[])
{
  return thread_create(name, TCB_FLAG_TTYPE_KERNEL, priority, stack_size,
                       entry, argv);
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
static int thread_create(FAR const char *name, uint8_t ttype, int priority,
                         int stack_size, main_t entry,
                         FAR char * const argv[])
{
  FAR struct task_tcb_s *tcb;
  pid_t pid;
  int errcode;
  int ret;

  /* Allocate a TCB for the new task. */

  tcb = (FAR struct task_tcb_s *)kmm_zalloc(sizeof(struct task_tcb_s));
  if (!tcb)
    {
      serr("ERROR: Failed to allocate TCB\n");
      errcode = ENOMEM;
      goto errout;
    }

  /* Allocate a new task group with privileges appropriate for the parent
   * thread type.
   */

#ifdef HAVE_TASK_GROUP
  ret = group_allocate(tcb, ttype);
  if (ret < 0)
    {
      errcode = -ret;
      goto errout_with_tcb;
    }
#endif

#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
#if 0 /* No... there are side effects */
  /* Associate file descriptors with the new task.  Exclude kernel threads;
   * kernel threads do not have file or socket descriptors.  They must use
   * SYSLOG for output and the low-level psock interfaces for network I/O.
   */

  if (ttype != TCB_FLAG_TTYPE_KERNEL)
#endif
    {
      ret = group_setuptaskfiles(tcb);
      if (ret < OK)
        {
          errcode = -ret;
          goto errout_with_tcb;
        }
    }
#endif

  /* Allocate the stack for the TCB */

  ret = up_create_stack((FAR struct tcb_s *)tcb, stack_size, ttype);
  if (ret < OK)
    {
      errcode = -ret;
      goto errout_with_tcb;
    }

  /* Initialize the task control block */

  ret = task_schedsetup(tcb, priority, task_start, entry, ttype);
  if (ret < OK)
    {
      errcode = -ret;
      goto errout_with_tcb;
    }

  /* Setup to pass parameters to the new task */

  (void)task_argsetup(tcb, name, argv);

  /* Now we have enough in place that we can join the group */

#ifdef HAVE_TASK_GROUP
  ret = group_initialize(tcb);
  if (ret < 0)
    {
      errcode = -ret;
      goto errout_with_tcb;
    }
#endif

  /* Get the assigned pid before we start the task */

  pid = (int)tcb->cmn.pid;

  /* Activate the task */

  ret = task_activate((FAR struct tcb_s *)tcb);
  if (ret < OK)
    {
      errcode = get_errno();

      /* The TCB was added to the active task list by task_schedsetup() */

      dq_rem((FAR dq_entry_t *)tcb, (FAR dq_queue_t *)&g_inactivetasks);
      goto errout_with_tcb;
    }

  return pid;

errout_with_tcb:
  sched_releasetcb((FAR struct tcb_s *)tcb, ttype);

errout:
  set_errno(errcode);
  return ERROR;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111



(5)创建初始线程任务:os_start_task()
这里写图片描述




#ifdef CONFIG_BOARD_INITTHREAD
static int os_start_task(int argc, FAR char **argv)
{
  /* Do the board/application initialization and exit */

  os_do_appstart(); //核心任务,这个将会调用FMU和IO的APP函数入口
  return OK;
}
#endif
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
#if defined(CONFIG_INIT_ENTRYPOINT)
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);
#endif
  ASSERT(pid > 0);
}
#elif defined(CONFIG_INIT_FILEPATH)
static inline void os_do_appstart(void)
{
  int ret;

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

  board_initialize();
#endif

  /* Start the application initialization program from a program in a
   * mounted file system.  Presumably the file system was mounted as part
   * of the board_initialize() operation.
   */

  sinfo("Starting init task: %s\n", CONFIG_USER_INITPATH);

  ret = exec(CONFIG_USER_INITPATH, NULL, CONFIG_INIT_SYMTAB,
             CONFIG_INIT_NEXPORTS);
  ASSERT(ret >= 0);
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58



(6)核心接口CONFIG_USER_ENTRYPOINT
这里写图片描述




CONFIG_USER_ENTRYPOINT="nsh_main"
  
  
  • 1

//所在的目录
这里写图片描述

CONFIG_USER_ENTRYPOINT="user_start"
  
  
  • 1

//所在的目录
这里写图片描述



到这里需要分两路去研究,一路是STM32F427的nsh_main()函数,另外一路是user_start()




(7)核心接口nsh_main()函数




int nsh_main(int argc, char *argv[])
#endif
{
  int exitval = 0;
  int ret;

  /* Call all C++ static constructors */

#if defined(CONFIG_EXAMPLES_NSH_CXXINITIALIZE)
  up_cxxinitialize(); //调用C++静态构造函数
#endif

  /* Make sure that we are using our symbol table */

#if defined(CONFIG_LIBC_EXECFUNCS) && defined(CONFIG_EXECFUNCS_SYMTAB)
  exec_setsymtab(CONFIG_EXECFUNCS_SYMTAB, 0); //外部函数缺少定义
#endif

  /* Register the BINFS file system */

#if defined(CONFIG_FS_BINFS) && (CONFIG_BUILTIN)
  ret = builtin_initialize();
  if (ret < 0)
    {
     fprintf(stderr, "ERROR: builtin_initialize failed: %d\n", ret);
     exitval = 1;
   }
#endif

  /* Initialize the NSH library */

  nsh_initialize(); //初始化NSH库

  /* If the Telnet console is selected as a front-end, then start the
   * Telnet daemon UNLESS network initialization is deferred via
   * CONFIG_NSH_NETLOCAL.  In that case, the telnet daemon must be
   * started manually with the telnetd command after the network has
   * been initialized
   */

#if defined(CONFIG_NSH_TELNET) && !defined(CONFIG_NSH_NETLOCAL)
  ret = nsh_telnetstart(ADDR_FAMILY);
  if (ret < 0)
    {
     /* The daemon is NOT running.  Report the error then fail...
      * either with the serial console up or just exiting.
      */

     fprintf(stderr, "ERROR: Failed to start TELNET daemon: %d\n", ret);
     exitval = 1;
   }
#endif

  /* If the serial console front end is selected, then run it on this thread */

#ifdef CONFIG_NSH_CONSOLE
  ret = nsh_consolemain(0, NULL); //重要的函数

  /* nsh_consolemain() should not return.  So if we get here, something
   * is wrong.
   */

#if CONFIG_NFILE_DESCRIPTORS > 0
  fprintf(stderr, "ERROR: nsh_consolemain() returned: %d\n", ret);
#else
  printf("ERROR: nsh_consolemain() returned: %d\n", ret);
#endif

  exitval = 1;
#endif

  return exitval;
}

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

(1)int nsh_consolemain(int argc, char *argv[])

int nsh_consolemain(int argc, char *argv[])
{
  FAR struct console_stdio_s *pstate = nsh_newconsole();
  int ret;

  DEBUGASSERT(pstate != NULL);

#ifdef CONFIG_NSH_ROMFSETC
  /* Execute the start-up script */

  (void)nsh_initscript(&pstate->cn_vtbl); //执行脚本初始化

#ifndef CONFIG_NSH_DISABLESCRIPT
  /* Reset the option flags */

  pstate->cn_vtbl.np.np_flags = NSH_NP_SET_OPTIONS_INIT;
#endif
#endif

#ifdef CONFIG_NSH_USBDEV_TRACE
  /* Initialize any USB tracing options that were requested */

  usbtrace_enable(TRACE_BITSET);
#endif

  /* Execute the session */

  ret = nsh_session(pstate); //与用户交互的终端命令,我们用还是那个危机连接飞控时,可以与飞控交互的串口命令

  /* Exit upon return */

  nsh_exit(&pstate->cn_vtbl, ret);
  return ret;
}

#endif /* !HAVE_USB_CONSOLE && !HAVE_USB_KEYBOARD */

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37


到这里是PX4的关键点,很多人想了解px4或者apm怎么创建任务的,整个程序是怎么运转的,就得仔细分析这里



(2) (void)nsh_initscript(&pstate->cn_vtbl);

int nsh_initscript(FAR struct nsh_vtbl_s *vtbl)
{
  static bool initialized;
  bool already;
  int ret = OK;

  /* Atomic test and set of the initialized flag */

  sched_lock();  //任务调度上锁
  already     = initialized;
  initialized = true;
  sched_unlock(); //任务调度解锁

  /* If we have not already executed the init script, then do so now */
//如果我们还没有执行init脚本,那么现在就执行它。
  if (!already)
    {
      ret = nsh_script(vtbl, "init", NSH_INITPATH); //解析脚本,这里很重要,理解这个就可以知道px4是如何运转的
    }

  return ret;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

(3)ret = nsh_script(vtbl, “init”, NSH_INITPATH); //解析脚本
这里写图片描述



到这里我们需要分析目录”init.d/rcS”,也就是rcS文件,看下面的文档就是rcS


#!nsh     #shell脚本默认开头格式
# Un comment and use set +e to ignore and set -e to enable 'exit on error control'
set +e    #这里有个错误,报错但是继续执行下面的脚本
# Un comment the line below to help debug scripts by printing a trace of the script commands
#set -x #显示脚本运行是的冗余输出,在set命令之后执行的每一条命令以及加载命令行中的任何参数都会显示出来,每一行都会加上加号(+),提示它是跟踪输出的标识。
# PX4FMU startup script.
#
# NOTE: environment variable references:
#    If the dollar sign ('$') is followed by a left bracket ('{') then the
#    variable name is terminated with the right bracket character ('}').
#    Otherwise, the variable name goes to the end of the argument.
#
#
# NOTE: COMMENT LINES ARE REMOVED BEFORE STORED IN ROMFS.
#
# 串口映射 FMUv2/3/4:
# UART mapping on FMUv2/3/4:
#
# UART1         /dev/ttyS0      IO debug
# USART2        /dev/ttyS1      TELEM1 (flow control)
# USART3        /dev/ttyS2      TELEM2 (flow control)
# UART4
# UART7                         CONSOLE
# UART8                         SERIAL4
#
#
# UART mapping on FMUv5:这个是FMUV5的串口
#
# UART1         /dev/ttyS0      GPS
# USART2        /dev/ttyS1      TELEM1 (flow control)
# USART3        /dev/ttyS2      TELEM2 (flow control)
# UART4         /dev/ttyS3      ?
# USART6        /dev/ttyS4      TELEM3 (flow control)
# UART7         /dev/ttyS5      ?
# UART8         /dev/ttyS6      CONSOLE

#
# Mount the procfs.挂载procfs(进程文件系统,包含一个伪文件系统(启动时动态生成的文件系统),用于通过内核访问进程信息。)
#
mount -t procfs /proc  #挂载文件系统

#
# Start CDC/ACM serial driver  # 启动usb/串口驱动 (sercon)
#
sercon

# print full system version打印系统版本
ver all

#
# Default to auto-start mode.无人机的模式默认是自动模式
#
set MODE autostart  #设置默认模式

set TUNE_ERR ML<<CP4CP4CP4CP4CP4
set LOG_FILE /fs/microsd/bootlog.txt  #设置LOG文件

#
# Try to mount the microSD card.尝试挂载SD卡
#
# REBOOTWORK this needs to start after the flight control loop这需要在飞行控制回路之后开始。
if mount -t vfat /dev/mmcsd0 /fs/microsd
then
    echo "[i] microSD mounted: /fs/microsd"
    if hardfault_log check
    then
        tone_alarm error #警报声音应用
        if hardfault_log commit
        then
            hardfault_log reset
            tone_alarm stop
        fi
    else
        # Start playing the startup tune开始播放启动曲调
        tone_alarm start
    fi
else
    tone_alarm MBAGP
    if mkfatfs /dev/mmcsd0
    then
        if mount -t vfat /dev/mmcsd0 /fs/microsd
        then
            echo "INFO  [init] MicroSD card formatted"
        else
            echo "ERROR [init] Format failed"
            tone_alarm MNBG
            set LOG_FILE /dev/null
        fi
    else
        set LOG_FILE /dev/null
    fi
fi

#
# Look for an init script on the microSD card.在MICROSD卡上查找init脚本
# Disable autostart if the script found.如果找到脚本,请禁用自动启动。
#
set FRC /fs/microsd/etc/rc.txt
if [ -f $FRC ]
then
    echo "INFO  [init] Executing script: ${FRC}"
    sh $FRC
    set MODE custom
fi
unset FRC

if [ $MODE == autostart ]
then

    #
    # Start the ORB (first app to start) uorb消息总线启动(第一个需要启动的应用)
    #
    uorb start#开始uorb

    #
    # Load parameters加载参数
    #
    # mtd 连接板载e2rom的应用
    set PARAM_FILE /fs/microsd/params
    if mtd start
    then
        set PARAM_FILE /fs/mtd_params
    fi

    param select $PARAM_FILE
    if param load
    then
    else
        if param reset
        then
        fi
    fi

    #
    # Start system state indicator
    ## 启动系统状态指示器
    if rgbled start
    then
    else
        if blinkm start
        then
            blinkm systemstate
        fi
    fi

    # FMUv5 may have both PWM I2C RGB LED support
    # FMUv5 同时支持 PWM、I2C,RGB LED
    rgbled_pwm start

    #
    # Set AUTOCNF flag to use it in AUTOSTART scripts
    # 设置 AUTOCNF 参数用于 AUTOSTART 脚本
    if param compare SYS_AUTOCONFIG 1
    then
        # Wipe out params except RC* and total flight time
        param reset_nostart RC* LND_FLIGHT_T_*
        set AUTOCNF yes
    else
        set AUTOCNF no

        #
        # Release 1.4.0 transitional support:
        # set to old default if unconfigured.
        # this preserves the previous behaviour
        #
        if param compare BAT_N_CELLS 0
        then
            param set BAT_N_CELLS 3
        fi
    fi

    #
    # Set default values
    #设置默认参数
    set VEHICLE_TYPE none
    set MIXER none
    set MIXER_AUX none
    set OUTPUT_MODE none
    set PWM_OUT none
    set PWM_RATE p:PWM_RATE
    set PWM_DISARMED p:PWM_DISARMED
    set PWM_MIN p:PWM_MIN
    set PWM_MAX p:PWM_MAX
    set PWM_AUX_OUT none
    set PWM_AUX_RATE none
    set PWM_ACHDIS none
    set PWM_AUX_DISARMED p:PWM_AUX_DISARMED
    set PWM_AUX_MIN p:PWM_AUX_MIN
    set PWM_AUX_MAX p:PWM_AUX_MAX
    set FAILSAFE_AUX none
    set MK_MODE none
    set FMU_MODE pwm
    set AUX_MODE pwm
    set FMU_ARGS ""
    set MAVLINK_F default
    set MAVLINK_COMPANION_DEVICE /dev/ttyS2
    set MAV_TYPE none
    set FAILSAFE none
    set USE_IO no
    set LOGGER_BUF 16

    if ver hwcmp PX4FMU_V4
    then
        param set SYS_FMU_TASK 1
    fi

    if ver hwcmp PX4FMU_V4PRO
    then
        param set SYS_FMU_TASK 1
    fi

    if ver hwcmp PX4FMU_V5
    then
        param set SYS_FMU_TASK 1
        set MAVLINK_COMPANION_DEVICE /dev/ttyS3

        set LOGGER_BUF 64
        param set SDLOG_MODE 2
    fi

    if ver hwcmp CRAZYFLIE
    then
        if param compare SYS_AUTOSTART 0
        then
            param set SYS_AUTOSTART 4900
            set AUTOCNF yes
        fi
    fi

    if ver hwcmp AEROFC_V1
    then
        if param compare SYS_AUTOSTART 0
        then
            set AUTOCNF yes
        fi

        # We don't allow changing AUTOSTART as it doesn't work in
        # other configurations
        param set SYS_AUTOSTART 4070
    fi

    if ver hwcmp NXPHLITE_V3
    then
        param set SYS_FMU_TASK 1
        set MAVLINK_COMPANION_DEVICE /dev/ttyS4
    fi

    #
    # Set USE_IO flag
    #
    if param compare SYS_USE_IO 1
    then
        set USE_IO yes
    fi

    if param compare SYS_FMU_TASK 1
    then
        set FMU_ARGS "-t"
    fi

    #
    # Set parameters and env variables for selected AUTOSTART
    #
    if param compare SYS_AUTOSTART 0
    then
    else
        sh /etc/init.d/rc.autostart
    fi
    unset MODE

    #
    # If mount (gimbal) control is enabled and output mode is AUX, set the aux
    # mixer to mount (override the airframe-specific MIXER_AUX setting)
    #
    if param compare MNT_MODE_IN -1
    then
    else
        if param compare MNT_MODE_OUT 0
        then
            set MIXER_AUX mount
        fi
    fi

    #
    # Override parameters from user configuration file
    #
    set FCONFIG /fs/microsd/etc/config.txt
    if [ -f $FCONFIG ]
    then
        echo "Custom: ${FCONFIG}"
        sh $FCONFIG
    fi
    unset FCONFIG

    #
    # If autoconfig parameter was set, reset it and save parameters
    #
    if [ $AUTOCNF == yes ]
    then
        # Disable safety switch by default on Pixracer
        if ver hwcmp PX4FMU_V4
        then
            param set CBRK_IO_SAFETY 22027
        fi
        param set SYS_AUTOCONFIG 0
    fi
    unset AUTOCNF

    set IO_PRESENT no

    if [ $USE_IO == yes ]
    then
        #
        # Check if PX4IO present and update firmware if needed
        # 检查PX4IO固件是否需要更新
        if [ -f /etc/extras/px4io-v2.bin ]
        then
            set IO_FILE /etc/extras/px4io-v2.bin

            if px4io checkcrc ${IO_FILE}
            then
                echo "[init] PX4IO CRC OK" >> $LOG_FILE

                set IO_PRESENT yes
            else
                tone_alarm MLL32CP8MB

                if px4io start
                then
                    # try to safe px4 io so motor outputs dont go crazy
                    if px4io safety_on
                    then
                        # success! no-op
                    else
                        # px4io did not respond to the safety command
                        px4io stop
                    fi
                fi

                if px4io forceupdate 14662 ${IO_FILE}
                then
                    usleep 10000
                    if px4io checkcrc ${IO_FILE}
                    then
                        echo "PX4IO CRC OK after updating" >> $LOG_FILE
                        tone_alarm MLL8CDE

                        set IO_PRESENT yes
                    else
                        echo "PX4IO update failed" >> $LOG_FILE
                        tone_alarm ${TUNE_ERR}
                    fi
                else
                    echo "PX4IO update failed" >> $LOG_FILE
                    tone_alarm ${TUNE_ERR}
                fi
            fi
        fi
        unset IO_FILE

        if [ $IO_PRESENT == no ]
        then
            echo "PX4IO not found" >> $LOG_FILE
            tone_alarm ${TUNE_ERR}
        fi
    fi

    #
    # Set default output if not set
    #
    if [ $OUTPUT_MODE == none ]
    then
        if [ $USE_IO == yes ]
        then
            set OUTPUT_MODE io
        else
            set OUTPUT_MODE fmu
        fi
    fi

    if [ $OUTPUT_MODE == io -a $IO_PRESENT != yes ]
    then
        # Need IO for output but it not present, disable output
        set OUTPUT_MODE none
    fi

    if [ $OUTPUT_MODE == tap_esc ]
    then
        set FMU_MODE rcin
    fi
#dataman地图航迹点管理
    set DATAMAN_OPT ""
    if ver hwcmp AEROFC_V1
    then
        set DATAMAN_OPT -i
    fi
    if ver hwcmp AEROCORE2
    then
        set DATAMAN_OPT "-f /fs/mtd_dataman"
    fi
    # waypoint storage
    # REBOOTWORK this needs to start in parallel
    if dataman start $DATAMAN_OPT
    then
    fi
    unset DATAMAN_OPT

    #
    # Sensors System (start before Commander so Preflight checks are properly run)
    # commander Needs to be this early for in-air-restarts
    #传感器系统(在commander启动前启动以确保检测是否正常运行)
    if param compare SYS_HITL 1
    then
        set OUTPUT_MODE hil
        sensors start -h
        commander start --hil
    else
        if ver hwcmp PX4_SAME70XPLAINED_V1
        then
            gps start -d /dev/ttyS2
        else
            gps start
        fi
        sh /etc/init.d/rc.sensors# 启动rc.sensors
        commander start #中心控制程序
    fi

    send_event start
    load_mon start

    #
    # Check if UAVCAN is enabled, default to it for ESCs
    #检查UAVCAN是否使能,默认是ESC
    if param greater UAVCAN_ENABLE 2
    then
        set OUTPUT_MODE uavcan_esc
    fi

    # Sensors on the PWM interface bank
    if param compare SENS_EN_LL40LS 1
    then
        # clear pins 5 and 6
        set FMU_MODE pwm4
        set AUX_MODE pwm4
    fi
    if param greater TRIG_MODE 0
    then
        # We ONLY support trigger on pins 5 and 6 when simultanously using AUX for actuator output
        if param compare TRIG_PINS 56
        then
            # clear pins 5 and 6
            set FMU_MODE pwm4
            set AUX_MODE pwm4
        else
            set FMU_MODE none
            set AUX_MODE none
        fi
        camera_trigger start

        param set CAM_FBACK_MODE 1
        camera_feedback start
    fi

    # If OUTPUT_MODE == none then something is wrong with setup and we shouldn't try to enable output
    if [ $OUTPUT_MODE != none ]
    then
        if [ $OUTPUT_MODE == uavcan_esc ]
        then
            if param compare UAVCAN_ENABLE 0
            then
                echo "OVERRIDING UAVCAN_ENABLE = 3" >> $LOG_FILE
                param set UAVCAN_ENABLE 3
            fi
        fi

        if [ $OUTPUT_MODE == io -o $OUTPUT_MODE == uavcan_esc ]
        then
            if px4io start
            then
                sh /etc/init.d/rc.io    #rc.io启动
            else
                echo "PX4IO start failed" >> $LOG_FILE
                tone_alarm $TUNE_ERR
            fi
        fi

        if [ $OUTPUT_MODE == fmu ]
        then
            if fmu mode_$FMU_MODE $FMU_ARGS
            then
            else
                echo "FMU start failed" >> $LOG_FILE
                tone_alarm $TUNE_ERR
            fi
        fi

        if [ $OUTPUT_MODE == mkblctrl ]
        then
            set MKBLCTRL_ARG ""
            if [ $MKBLCTRL_MODE == x ]
            then
                set MKBLCTRL_ARG "-mkmode x"
            fi
            if [ $MKBLCTRL_MODE == + ]
            then
                set MKBLCTRL_ARG "-mkmode +"
            fi

            if mkblctrl $MKBLCTRL_ARG
            then
            else
                echo "MK start failed" >> $LOG_FILE
                tone_alarm $TUNE_ERR
            fi
            unset MKBLCTRL_ARG
        fi
        unset MK_MODE

        if [ $OUTPUT_MODE == hil ]
        then
            if pwm_out_sim mode_pwm16
            then
            else
                tone_alarm $TUNE_ERR
            fi
        fi

        #
        # Start IO or FMU for RC PPM input if needed开启IO或者FMU为RCPPM输入需要
        #
        if [ $IO_PRESENT == yes ]
        then
            if [ $OUTPUT_MODE != io ]
            then
                if px4io start #开启px4io
                then
                    sh /etc/init.d/rc.io
                else
                    echo "PX4IO start failed" >> $LOG_FILE
                    tone_alarm $TUNE_ERR
                fi
            fi
        else
            if [ $OUTPUT_MODE != fmu ]
            then
                if fmu mode_${FMU_MODE} $FMU_ARGS
                then
                else
                    echo "FMU mode_${FMU_MODE} start failed" >> $LOG_FILE
                    tone_alarm $TUNE_ERR
                fi
            fi
        fi
    fi

    if [ $MAVLINK_F == default ]
    then
        # Normal mode, use baudrate 57600 (default) and data rate 1000 bytes/s
        set MAVLINK_F "-r 1200 -f"

        # Avoid using ttyS1 for MAVLink on FMUv4
        if ver hwcmp PX4FMU_V4
        then
            set MAVLINK_F "-r 1200 -d /dev/ttyS1"
            # Start MAVLink on Wifi (ESP8266 port)
            mavlink start -r 20000 -b 921600 -d /dev/ttyS0
        fi

        if ver hwcmp AEROFC_V1
        then
            set MAVLINK_F "-r 1200 -d /dev/ttyS3"
        fi

        if ver hwcmp CRAZYFLIE
        then
            # Avoid using either of the two available serials
            set MAVLINK_F none
        fi
    fi

    if [ "x$MAVLINK_F" == xnone ]
    then
    else
        mavlink start ${MAVLINK_F}
    fi
    unset MAVLINK_F

    #
    # MAVLink onboard / TELEM2
    #
    # XXX We need a better way for runtime eval of shell variables,
    # but this works for now
    if param compare SYS_COMPANION 10
    then
        frsky_telemetry start -d ${MAVLINK_COMPANION_DEVICE}
    fi
    if param compare SYS_COMPANION 20
    then
        syslink start
        mavlink start -d /dev/bridge0 -b 57600 -m osd -r 40000
    fi
    if param compare SYS_COMPANION 921600
    then
        if ver hwcmp AEROFC_V1
        then
            if protocol_splitter start ${MAVLINK_COMPANION_DEVICE}
            then
                mavlink start -d /dev/mavlink -b 921600 -m onboard -r 5000 -x
                micrortps_client start -d /dev/rtps -b 921600 -l -1 -s 2000
            else
                 mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 921600 -m onboard -r 80000 -x -f
            fi
        else
            mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 921600 -m onboard -r 80000 -x -f
        fi
    fi
    if param compare SYS_COMPANION 57600
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 57600 -m onboard -r 5000 -x -f
    fi
    if param compare SYS_COMPANION 460800
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 460800 -m onboard -r 5000 -x -f
    fi
    if param compare SYS_COMPANION 157600
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 57600 -m osd -r 1000
    fi
    if param compare SYS_COMPANION 257600
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 57600 -m magic -r 5000 -x -f
    fi
    if param compare SYS_COMPANION 319200
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 19200 -r 1000 -f
    fi
    if param compare SYS_COMPANION 338400
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 38400 -r 1000 -f
    fi
    if param compare SYS_COMPANION 357600
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 57600 -r 1000 -f
    fi
    if param compare SYS_COMPANION 3115200
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 115200 -r 1000 -f
    fi
    if param compare SYS_COMPANION 419200
    then
        iridiumsbd start -d /dev/ttyS2
        mavlink start -d /dev/iridium -b 19200 -m iridium -r 10
    fi
    if param compare SYS_COMPANION 1921600
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 921600 -r 20000
    fi
    if param compare SYS_COMPANION 1500000
    then
        mavlink start -d ${MAVLINK_COMPANION_DEVICE} -b 1500000 -m onboard -r 10000 -x -f
    fi

    unset MAVLINK_COMPANION_DEVICE

    #
    # Starting stuff according to UAVCAN_ENABLE value
    #
    if param greater UAVCAN_ENABLE 0
    then
        if uavcan start
        then
            set LOGGER_BUF 6
            uavcan start fw
        else
            tone_alarm ${TUNE_ERR}
        fi
    fi

    if ver hwcmp PX4FMU_V4
    then
        frsky_telemetry start -d /dev/ttyS6
    fi

    if ver hwcmp MINDPX_V2
    then
        frsky_telemetry start -d /dev/ttyS6
    fi

    if ver hwcmp PX4FMU_V2
    then
        # Check for flow sensor - as it is a background task, launch it last
        px4flow start &
    fi

    if ver hwcmp PX4FMU_V4
    then
        # Check for flow sensor - as it is a background task, launch it last
        px4flow start &
    fi

    if ver hwcmp PX4FMU_V4PRO
    then
        # Check for flow sensor - as it is a background task, launch it last
        px4flow start &
    fi

    if ver hwcmp MINDPX_V2
    then
        px4flow start &
    fi

    if ver hwcmp AEROFC_V1
    then
        # don't start mavlink ttyACM0 on aerofc_v1
    else
        # Start MAVLink
        mavlink start -r 800000 -d /dev/ttyACM0 -m config -x
    fi

    #
    # Logging
    #
    if param compare SYS_LOGGER 0
    then
        sdlog2 start -r 100 -a -b 9 -t
    else
        set LOGGER_ARGS ""

        if param compare SDLOG_MODE 1
        then
            set LOGGER_ARGS "-e"
        fi

        if param compare SDLOG_MODE 2
        then
            set LOGGER_ARGS "-f"
        fi

        if ver hwcmp AEROFC_V1
        then
            set LOGGER_ARGS "-m mavlink"
        fi

        logger start -b ${LOGGER_BUF} -t ${LOGGER_ARGS}

        unset LOGGER_BUF
        unset LOGGER_ARGS
    fi

    #
    # Fixed wing setup
    #
    if [ $VEHICLE_TYPE == fw ]
    then
        if [ $MIXER == none ]
        then
            # Set default mixer for fixed wing if not defined
            set MIXER AERT
        fi

        if [ $MAV_TYPE == none ]
        then
            # Use MAV_TYPE = 1 (fixed wing) if not defined
            set MAV_TYPE 1
        fi

        param set MAV_TYPE ${MAV_TYPE}

        # Load mixer and configure outputs
        sh /etc/init.d/rc.interface

        # Start standard fixedwing apps
        sh /etc/init.d/rc.fw_apps
    fi

    #
    # Multicopters setup
    #
    if [ $VEHICLE_TYPE == mc ]
    then
        if [ $MIXER == none ]
        then
            echo "Mixer undefined"
        fi

        if [ $MAV_TYPE == none ]
        then
            # Use mixer to detect vehicle type
            if [ $MIXER == quad_x -o $MIXER == quad_+ ]
            then
                set MAV_TYPE 2
            fi
            if [ $MIXER == quad_w -o $MIXER == quad_dc ]
            then
                set MAV_TYPE 2
            fi
            if [ $MIXER == quad_h ]
            then
                set MAV_TYPE 2
            fi
            if [ $MIXER == tri_y_yaw- -o $MIXER == tri_y_yaw+ ]
            then
                set MAV_TYPE 15
            fi
            if [ $MIXER == hexa_x -o $MIXER == hexa_+ ]
            then
                set MAV_TYPE 13
            fi
            if [ $MIXER == hexa_cox ]
            then
                set MAV_TYPE 13
            fi
            if [ $MIXER == octo_x -o $MIXER == octo_+ ]
            then
                set MAV_TYPE 14
            fi
            if [ $MIXER == octo_cox -o $MIXER == octo_cox_w ]
            then
                set MAV_TYPE 14
            fi
            if [ $MIXER == coax ]
            then
                set MAV_TYPE 3
            fi
        fi

        # Still no MAV_TYPE found
        if [ $MAV_TYPE == none ]
        then
            echo "Unknown MAV_TYPE"
            param set MAV_TYPE 2
        else
            param set MAV_TYPE ${MAV_TYPE}
        fi

        # Load mixer and configure outputs
        sh /etc/init.d/rc.interface

        # Start standard multicopter apps
        sh /etc/init.d/rc.mc_apps
    fi

    #
    # VTOL setup
    #
    if [ $VEHICLE_TYPE == vtol ]
    then
        if [ $MIXER == none ]
        then
            echo "VTOL mixer undefined"
        fi

        if [ $MAV_TYPE == none ]
        then
            # Use mixer to detect vehicle type
            if [ $MIXER == caipirinha_vtol ]
            then
                set MAV_TYPE 19
            fi
            if [ $MIXER == firefly6 ]
            then
                set MAV_TYPE 21
            fi
            if [ $MIXER == quad_x_pusher_vtol ]
            then
                set MAV_TYPE 22
            fi
        fi

        # Still no MAV_TYPE found
        if [ $MAV_TYPE == none ]
        then
            echo "Unknown MAV_TYPE"
            param set MAV_TYPE 19
        else
            param set MAV_TYPE ${MAV_TYPE}
        fi

        # Load mixer and configure outputs
        sh /etc/init.d/rc.interface

        # Start standard vtol apps
        sh /etc/init.d/rc.vtol_apps
    fi

    #
    # UGV setup
    #
    if [ $VEHICLE_TYPE == ugv ]
    then
        if [ $MIXER == none ]
        then
            # Set default mixer for UGV if not defined
            set MIXER ugv_generic
        fi

        if [ $MAV_TYPE == none ]
        then
            # Use MAV_TYPE = 10 (UGV) if not defined
            set MAV_TYPE 10
        fi

        param set MAV_TYPE ${MAV_TYPE}

        # Load mixer and configure outputs
        sh /etc/init.d/rc.interface

        # Start standard UGV apps
        sh /etc/init.d/rc.ugv_apps
    fi

    #
    # For snapdragon, we need a passthrough mode
    # Do not run any mavlink instances since we need the serial port for
    # communication with Snapdragon.
    #
    if [ $VEHICLE_TYPE == passthrough ]
    then
        mavlink stop-all
        commander stop

        # Stop multicopter attitude controller if it is running, the controls come
        # from Snapdragon.
        if mc_att_control stop
        then
        fi

        # Start snapdragon interface on serial port.
        if ver hwcmp PX4FMU_V2
        then
            # On Pixfalcon use the standard telemetry port (Telem 1).
            snapdragon_rc_pwm start -d /dev/ttyS1
            px4io start
        fi

        if ver hwcmp PX4FMU_V4
        then
            # On Pixracer use Telem 2 port (TL2).
            snapdragon_rc_pwm start -d /dev/ttyS2
            fmu mode_pwm4 $FMU_ARGS
        fi

        pwm failsafe -c 1234 -p 900
        pwm disarmed -c 1234 -p 900

        # Arm straightaway.
        pwm arm
        # Use 400 Hz PWM on all channels.
        pwm rate -a -r 400
    fi

    unset MIXER
    unset MAV_TYPE
    unset OUTPUT_MODE

    #
    # Start the navigator
    #
    navigator start

    #
    # Generic setup (autostart ID not found)
    #
    if [ $VEHICLE_TYPE == none ]
    then
        echo "No autostart ID found"
        ekf2 start
    fi

    # Start any custom addons
    set FEXTRAS /fs/microsd/etc/extras.txt
    if [ -f $FEXTRAS ]
    then
        echo "Addons script: ${FEXTRAS}"
        sh $FEXTRAS
    fi
    unset FEXTRAS

    if ver hwcmp CRAZYFLIE
    then
        # CF2 shouldn't have an sd card
    else

        if ver hwcmp AEROCORE2
        then
            # AEROCORE2 shouldn't have an sd card
        else

            # Run no SD alarm
            if [ $LOG_FILE == /dev/null ]
            then
                # Play SOS
                tone_alarm error
            fi

        fi

    fi

    #
    # Check if we should start a thermal calibration
    # TODO move further up and don't start unnecessary services if we are calibrating
    #
    set TEMP_CALIB_ARGS ""
    if param compare SYS_CAL_GYRO 1
    then
        set TEMP_CALIB_ARGS "${TEMP_CALIB_ARGS} -g"
        param set SYS_CAL_GYRO 0
    fi
    if param compare SYS_CAL_ACCEL 1
    then
        set TEMP_CALIB_ARGS "${TEMP_CALIB_ARGS} -a"
        param set SYS_CAL_ACCEL 0
    fi
    if param compare SYS_CAL_BARO 1
    then
        set TEMP_CALIB_ARGS "${TEMP_CALIB_ARGS} -b"
        param set SYS_CAL_BARO 0
    fi
    if [ "x$TEMP_CALIB_ARGS" != "x" ]
    then
        send_event temperature_calibration ${TEMP_CALIB_ARGS}
    fi
    unset TEMP_CALIB_ARGS

    # vmount to control mounts such as gimbals, disabled by default.
    if param compare MNT_MODE_IN -1
    then
    else
        if vmount start
        then
        fi
    fi

# End of autostart
fi

# There is no further script processing, so we can free some RAM
# XXX potentially unset all script variables.
unset TUNE_ERR

# Boot is complete, inform MAVLink app(s) that the system is now fully up and running
mavlink boot_complete

  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797
  • 798
  • 799
  • 800
  • 801
  • 802
  • 803
  • 804
  • 805
  • 806
  • 807
  • 808
  • 809
  • 810
  • 811
  • 812
  • 813
  • 814
  • 815
  • 816
  • 817
  • 818
  • 819
  • 820
  • 821
  • 822
  • 823
  • 824
  • 825
  • 826
  • 827
  • 828
  • 829
  • 830
  • 831
  • 832
  • 833
  • 834
  • 835
  • 836
  • 837
  • 838
  • 839
  • 840
  • 841
  • 842
  • 843
  • 844
  • 845
  • 846
  • 847
  • 848
  • 849
  • 850
  • 851
  • 852
  • 853
  • 854
  • 855
  • 856
  • 857
  • 858
  • 859
  • 860
  • 861
  • 862
  • 863
  • 864
  • 865
  • 866
  • 867
  • 868
  • 869
  • 870
  • 871
  • 872
  • 873
  • 874
  • 875
  • 876
  • 877
  • 878
  • 879
  • 880
  • 881
  • 882
  • 883
  • 884
  • 885
  • 886
  • 887
  • 888
  • 889
  • 890
  • 891
  • 892
  • 893
  • 894
  • 895
  • 896
  • 897
  • 898
  • 899
  • 900
  • 901
  • 902
  • 903
  • 904
  • 905
  • 906
  • 907
  • 908
  • 909
  • 910
  • 911
  • 912
  • 913
  • 914
  • 915
  • 916
  • 917
  • 918
  • 919
  • 920
  • 921
  • 922
  • 923
  • 924
  • 925
  • 926
  • 927
  • 928
  • 929
  • 930
  • 931
  • 932
  • 933
  • 934
  • 935
  • 936
  • 937
  • 938
  • 939
  • 940
  • 941
  • 942
  • 943
  • 944
  • 945
  • 946
  • 947
  • 948
  • 949
  • 950
  • 951
  • 952
  • 953
  • 954
  • 955
  • 956
  • 957
  • 958
  • 959
  • 960
  • 961
  • 962
  • 963
  • 964
  • 965
  • 966
  • 967
  • 968
  • 969
  • 970
  • 971
  • 972
  • 973
  • 974
  • 975
  • 976
  • 977
  • 978
  • 979
  • 980
  • 981
  • 982
  • 983
  • 984
  • 985
  • 986
  • 987
  • 988
  • 989
  • 990
  • 991
  • 992
  • 993
  • 994
  • 995
  • 996
  • 997
  • 998
  • 999
  • 1000
  • 1001
  • 1002
  • 1003
  • 1004
  • 1005
  • 1006
  • 1007
  • 1008
  • 1009
  • 1010
  • 1011
  • 1012
  • 1013
  • 1014
  • 1015
  • 1016
  • 1017
  • 1018
  • 1019
  • 1020
  • 1021
  • 1022
  • 1023
  • 1024
  • 1025
  • 1026
  • 1027
  • 1028
  • 1029
  • 1030
  • 1031
  • 1032
  • 1033
  • 1034
  • 1035
  • 1036
  • 1037
  • 1038
  • 1039
  • 1040
  • 1041
  • 1042
  • 1043
  • 1044



int nsh_script(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
               FAR const char *path)
{
  FAR char *fullpath;
  FAR FILE *savestream;
  FAR char *buffer;
  FAR char *pret;
  int ret = ERROR;

  /* The path to the script may be relative to the current working directory */

  fullpath = nsh_getfullpath(vtbl, path);
  if (!fullpath)
    {
      return ERROR;
    }

  /* Get a reference to the common input buffer */

  buffer = nsh_linebuffer(vtbl);
  if (buffer)
    {
      /* Save the parent stream in case of nested script processing */

      savestream = vtbl->np.np_stream;

      /* Open the file containing the script */

      vtbl->np.np_stream = fopen(fullpath, "r");
      if (!vtbl->np.np_stream)
        {
          nsh_output(vtbl, g_fmtcmdfailed, cmd, "fopen", NSH_ERRNO);

          /* Free the allocated path */

          nsh_freefullpath(fullpath);

          /* Restore the parent script stream */

          vtbl->np.np_stream = savestream;
          return ERROR;
        }

      /* Loop, processing each command line in the script file (or
       * until an error occurs)
       */

      do
        {
          /* Flush any output generated by the previous line */

          fflush(stdout);

#ifndef CONFIG_NSH_DISABLE_LOOPS
          /* Get the current file position.  This is used to control
           * looping.  If a loop begins in the next line, then this file
           * offset will be needed to locate the top of the loop in the
           * script file.  Note that ftell will return -1 on failure.
           */

          vtbl->np.np_foffs = ftell(vtbl->np.np_stream);
          vtbl->np.np_loffs = 0;

          if (vtbl->np.np_foffs < 0)
            {
              nsh_output(vtbl, g_fmtcmdfailed, "loop", "ftell", NSH_ERRNO);
            }
#endif

          /* Now read the next line from the script file */

          pret = fgets(buffer, CONFIG_NSH_LINELEN, vtbl->np.np_stream);
          if (pret)
            {
              /* Parse process the command.  NOTE:  this is recursive...
               * we got to cmd_sh via a call to nsh_parse.  So some
               * considerable amount of stack may be used.
               */

              if ((vtbl->np.np_flags & NSH_PFLAG_SILENT) == 0)
                {
                  nsh_output(vtbl,"%s", buffer);
                }

              ret = nsh_parse(vtbl, buffer);
            }
        }
      while (pret && (ret == OK || (vtbl->np.np_flags & NSH_PFLAG_IGNORE)));

      /* Close the script file */

      fclose(vtbl->np.np_stream);

      /* Restore the parent script stream */

      vtbl->np.np_stream = savestream;
    }

  /* Free the allocated path */

  nsh_freefullpath(fullpath);
  return ret;
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104



(8)核心接口user_start()函数




//所在的目录
这里写图片描述


可以看出IO只是FMU的一个核心模块。所以FMU与IO怎么启动的过程是我们需要核心研究的




int user_start(int argc, char *argv[])
{
    /* configure the first 8 PWM outputs (i.e. all of them) */
    up_pwm_servo_init(0xff); //配置8路PWM输出

#if defined(CONFIG_HAVE_CXX) && defined(CONFIG_HAVE_CXXINITIALIZE)

    /* run C++ ctors before we go any further */

    up_cxxinitialize(); //运行C++库

#   if defined(CONFIG_EXAMPLES_NSH_CXXINITIALIZE)
#       error CONFIG_EXAMPLES_NSH_CXXINITIALIZE Must not be defined! Use CONFIG_HAVE_CXX and CONFIG_HAVE_CXXINITIALIZE.
#   endif

#else
#  error platform is dependent on c++ both CONFIG_HAVE_CXX and CONFIG_HAVE_CXXINITIALIZE must be defined.
#endif

    /* reset all to zero */
    memset(&system_state, 0, sizeof(system_state));//复位系统存储

    /* configure the high-resolution time/callout interface */
    hrt_init(); //配置高速时钟

    /* calculate our fw CRC so FMU can decide if we need to update */
    calculate_fw_crc(); //计算我用的crc时钟,判断fmu是否更新

    /*
     * Poll at 1ms intervals for received bytes that have not triggered
     * a DMA event.对于未触发的接收字节,以1ms间隔进行轮询
     */
#ifdef CONFIG_ARCH_DMA
    hrt_call_every(&serial_dma_call, 1000, 1000, (hrt_callout)stm32_serial_dma_poll, NULL);
#endif

    /* print some startup info */
    syslog(LOG_INFO, "\nPX4IO: starting\n");

    /* default all the LEDs to off while we start */
    LED_AMBER(false); //关闭所有的灯
    LED_BLUE(false);
    LED_SAFETY(false);
#ifdef GPIO_LED4
    LED_RING(false);
#endif

    /* turn on servo power (if supported) */
#ifdef POWER_SERVO
    POWER_SERVO(true); //打开servo电源
#endif

    /* turn off S.Bus out (if supported) */
#ifdef ENABLE_SBUS_OUT
    ENABLE_SBUS_OUT(false); //关闭SBUS
#endif

    /* start the safety switch handler */
    safety_init(); //启动安全开关处理器

    /* initialise the control inputs */
    controls_init(); //初始化控制输入

    /* set up the ADC */
    adc_init(); //初始化ADC

    /* start the FMU interface */
    interface_init();//串口初始化

    /* add a performance counter for mixing */
    perf_counter_t mixer_perf = perf_alloc(PC_ELAPSED, "mix"); //添加用于混合的性能计数器

    /* add a performance counter for controls */
    perf_counter_t controls_perf = perf_alloc(PC_ELAPSED, "controls");//为控件添加性能计数器

    /* and one for measuring the loop rate */
    perf_counter_t loop_perf = perf_alloc(PC_INTERVAL, "loop"); //一种测量环路速率的方法

    struct mallinfo minfo = mallinfo();
    r_page_status[PX4IO_P_STATUS_FREEMEM] = minfo.mxordblk;
    syslog(LOG_INFO, "MEM: free %u, largest %u\n", minfo.mxordblk, minfo.fordblks);

    /* initialize PWM limit lib */
    pwm_limit_init(&pwm_limit); //初始化PWM限制

    /*
     *    P O L I C E    L I G H T S
     *
     * Not enough memory, lock down.
     *
     * We might need to allocate mixers later, and this will
     * ensure that a developer doing a change will notice
     * that he just burned the remaining RAM with static
     * allocations. We don't want him to be able to
     * get past that point. This needs to be clearly
     * documented in the dev guide.
     *
     */
    if (minfo.mxordblk < 600) 
    {

        syslog(LOG_ERR, "ERR: not enough MEM");
        bool phase = false;

        while (true) 
        {

            if (phase) 
            {
                LED_AMBER(true);
                LED_BLUE(false);

            } else 
            {
                LED_AMBER(false);
                LED_BLUE(true);
            }

            up_udelay(250000);

            phase = !phase;
        }
    }

    /* Start the failsafe led init */
    failsafe_led_init();//启动故障安全LED初始化

    /*
     * Run everything in a tight loop.把每件事都搞得一团糟
     */

    uint64_t last_debug_time = 0;
    uint64_t last_heartbeat_time = 0;
    uint64_t last_loop_time = 0;

    for (;;) 
    {
        dt = (hrt_absolute_time() - last_loop_time) / 1000000.0f;
        last_loop_time = hrt_absolute_time();

        if (dt < 0.0001f) 
        {
            dt = 0.0001f;

        } else if (dt > 0.02f) 
        {
            dt = 0.02f;
        }

        /* track the rate at which the loop is running */
        perf_count(loop_perf);//计算循环运行时间

        /* kick the mixer */
        perf_begin(mixer_perf);
        mixer_tick();
        perf_end(mixer_perf);

        /* kick the control inputs */
        perf_begin(controls_perf);
        controls_tick();
        perf_end(controls_perf);

        /* some boards such as Pixhawk 2.1 made
           the unfortunate choice to combine the blue led channel with
           the IMU heater. We need a software hack to fix the hardware hack
           by allowing to disable the LED / heater.
         */
        if (r_page_setup[PX4IO_P_SETUP_THERMAL] == PX4IO_THERMAL_IGNORE) {
            /*
              blink blue LED at 4Hz in normal operation. When in
              override blink 4x faster so the user can clearly see
              that override is happening. This helps when
              pre-flight testing the override system
             */
            uint32_t heartbeat_period_us = 250 * 1000UL;

            if (r_status_flags & PX4IO_P_STATUS_FLAGS_OVERRIDE) {
                heartbeat_period_us /= 4;
            }

            if ((hrt_absolute_time() - last_heartbeat_time) > heartbeat_period_us) {
                last_heartbeat_time = hrt_absolute_time();
                heartbeat_blink();
            }

        } else if (r_page_setup[PX4IO_P_SETUP_THERMAL] < PX4IO_THERMAL_FULL) {
            /* switch resistive heater off */
            LED_BLUE(false);

        } else {
            /* switch resistive heater hard on */
            LED_BLUE(true);
        }

        update_mem_usage();

        ring_blink();

        check_reboot();

        /* check for debug activity (default: none) */
        show_debug_messages();

        /* post debug state at ~1Hz - this is via an auxiliary serial port
         * DEFAULTS TO OFF!
         */
        if (hrt_absolute_time() - last_debug_time > (1000 * 1000)) {

            isr_debug(1, "d:%u s=0x%x a=0x%x f=0x%x m=%u",
                  (unsigned)r_page_setup[PX4IO_P_SETUP_SET_DEBUG],
                  (unsigned)r_status_flags,
                  (unsigned)r_setup_arming,
                  (unsigned)r_setup_features,
                  (unsigned)mallinfo().mxordblk);
            last_debug_time = hrt_absolute_time();
        }
    }
}


  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222


可以看出px4所有的任务都是以任务函数执行,都在那个rcs里面,然而apm的不是这样
PX4的运行过程就先说到这里,后面会继续研究每个函数的作用,这里只是大致梳理一下过程。与APM形成比较




2.APM固件启动过程




(1)void __start(void)


void __start(void)
{
  const uint32_t *src;
  uint32_t *dest;

#ifdef CONFIG_ARMV7M_STACKCHECK
  /* Set the stack limit before we attempt to call any functions */

  __asm__ volatile ("sub r10, sp, %0" : : "r" (CONFIG_IDLETHREAD_STACKSIZE - 64) : );
#endif

  /* Configure the uart so that we can get debug output as soon as possible */

  stm32_clockconfig();//初始化时钟
  stm32_fpuconfig();  //配置FMU
  stm32_lowsetup();   //初始化基本串口
  stm32_gpioinit();   //配置IO
  showprogress('A');

  /* Clear .bss.  We'll do this inline (vs. calling memset) just to be
   * certain that there are no issues with the state of global variables.
   */

  for (dest = &_sbss; dest < &_ebss; )
    {
      *dest++ = 0;
    }

  showprogress('B');

  /* Move the intialized data section from his temporary holding spot in
   * FLASH into the correct place in SRAM.  The correct place in SRAM is
   * give by _sdata and _edata.  The temporary location is in FLASH at the
   * end of all of the other read-only data (.text, .rodata) at _eronly.
   */

  for (src = &_eronly, dest = &_sdata; dest < &_edata; )
    {
      *dest++ = *s
				版权声明:本文为博主原创文章,未经博主允许不得转载。					https://blog.csdn.net/lixiaoweimashixiao/article/details/81545640				</div>
							            <div id="content_views" class="markdown_views">
						<!-- flowchart 箭头图标 勿删 -->
						<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg>
						<h3 id="目录"><a name="t0"></a>目录</h3>

猜你喜欢

转载自blog.csdn.net/qq_43445076/article/details/88915550