crazyflie2.0_crazyflie-firmware_总体程序概括

第一个正式版本刚发出去做板,现在有空可以来好好看看STM32F405这边到底做了哪些事情,今天先看到整体程序的架构,crazyflie用的是FreeRTOS,程序中大部分会用到创建任务和队列传递数据的过程,网上有中文版的FreeRTOS资料,看一遍基本明白创建任务及其队列实现的机制,今天我们先看下main这边主要做了什么事情,习惯用SourceInsight浏览代码。

首先从main函数开始:

int main() 
{
  //Initialize the platform.
  platformInit();

  //Launch the system task that will initialize and start everything
  systemLaunch();

  //Start the FreeRTOS scheduler
  vTaskStartScheduler();

  //TODO: Move to platform launch failed
  ledInit();
  ledSet(0, 1);
  ledSet(1, 1);

  //Should never reach this point!
  while(1);

  return 0;
}
1,platformInit();函数我们继续往下看:

//Low level init: Clock and Interrupt controller
  nvicInit();


void nvicInit(void)
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
}
而nvicInit();只是审定了中断优先级组的参数,这里主要是设置始终和中断控制器的优先级组为Group4,也就是说没有子优先级或者叫做副优先级,只有抢占优先级。具体的理解,可以参考如下对优先级的深刻理解:

http://bbs.ednchina.com/BLOG_ARTICLE_3000747.HTM

STM32有43个channel的settable的中断源;AIRC(Application Interrupt and Reset Register)寄存器中有用于指定优先级的4 bits。这4个bits用于分配preemption优先级和sub优先级,在STM32的固件库中定义如下
/* Preemption Priority Group -------------------------------------------------*/
#define NVIC_PriorityGroup_0          ((u32)0x700) /* 0 bits for pre-emption priority
                                                      4 bits for subpriority */
#define NVIC_PriorityGroup_1          ((u32)0x600) /* 1 bits for pre-emption priority
                                                      3 bits for subpriority */
#define NVIC_PriorityGroup_2          ((u32)0x500) /* 2 bits for pre-emption priority
                                                      2 bits for subpriority */
#define NVIC_PriorityGroup_3          ((u32)0x400) /* 3 bits for pre-emption priority
                                                      1 bits for subpriority */
#define NVIC_PriorityGroup_4          ((u32)0x300) /* 4 bits for pre-emption priority
                                                      0 bits for subpriority */
形象化的理解是:
你是上帝,
造了43个人,这么多人要分社会阶级和社会阶层了;
因为“阶级”的词性比较重;"阶层"比较中性,
所以preemption优先级->阶级;每个阶级内部,有一些阶层,sub优先级->阶层;

如果按照NVIC_PriorityGroup_4这么分,就分为了16个阶级(1个阶层就是1个preemption优先级),0个阶层;高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和15级嵌套。
每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级8”,则
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8; // 指定抢占式优先级别1,可取0-15

另外,在同一阶级内部,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系)
还有,如果他们两个同时想做事,因为没有阶层,那么就根据Vector table中的物理排序,让排名靠前的人去做;

又有1个人SPI1_IRQChannel,设定如下
NVIC_InitStructure.NVIC_IRQChannel = SPI1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别1,可取0-15

SPI1_IRQChannel的阶级高,EXTI0_IRQChannel做事的时候可以打断(嵌套)。

如果按照NVIC_PriorityGroup_3这么分,就分为了8个阶级(1个阶级是1个preemption优先级),每个阶级内有2个阶层(sub优先级);高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和7级嵌套。

每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;一个人叫EXTI0_IRQChannel,你指定他进入“阶级3”,则:
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别1,可取0-7
还需要指定他的阶层:
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0,可取0-1

另有1个人叫EXTI9_5_IRQChannel,他的阶级和阶层设定如下
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 指定抢占式优先级别0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1

那么这两个人是同一阶级的兄弟,一个人在做事的时候,另外一个人不能打断他;(preemption优先级别相同的中断源之间没有嵌套关系)
如果他们两个同时想做事,因为前者的阶层高,所以前者优先。

还有一个人叫USART1_IRQChannel,他的阶级和阶层设定如下
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 指定抢占式优先级别0,可取0-7
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1
USART1_IRQChannel的优先级最高,当前面两个人做事的时候,他都可以打断(嵌套)。
以下的类推。

2,所以我们只用到抢占优先级,下一步是重点的函数:

  //Launch the system task that will initialize and start everything
  systemLaunch();

systemLaunch里面仅仅做了一件事情,创建任务systemTask,所有的事情就是从这个任务开始了。

/* Public functions */
void systemLaunch(void)
{
  xTaskCreate(systemTask, (const signed char * const)SYSTEM_TASK_NAME,
              SYSTEM_TASK_STACKSIZE, NULL,
              SYSTEM_TASK_PRI, NULL);

}
在访问到systemTask看函数内部到底做了什么事情:

/* Private functions implementation */

void systemTask(void *arg)
{
  bool pass = true;
  
  ledInit();
  ledSet(CHG_LED, 1);

  uartInit();
  //Init the high-levels modules
  systemInit();

#ifndef USE_RADIOLINK_CRTP
#ifdef UART_OUTPUT_TRACE_DATA
  //debugInitTrace();
#endif
#ifdef ENABLE_UART
//  uartInit();
#endif
#endif //ndef USE_RADIOLINK_CRTP

  commInit();

  DEBUG_PRINT("----------------------------\n");
  DEBUG_PRINT("Crazyflie is up and running!\n");
  DEBUG_PRINT("Build %s:%s (%s) %s\n", V_SLOCAL_REVISION,
              V_SREVISION, V_STAG, (V_MODIFIED)?"MODIFIED":"CLEAN");
  DEBUG_PRINT("I am 0x%X%X%X and I have %dKB of flash!\n",
              *((int*)(MCU_ID_ADDRESS+8)), *((int*)(MCU_ID_ADDRESS+4)),
              *((int*)(MCU_ID_ADDRESS+0)), *((short*)(MCU_FLASH_SIZE_ADDRESS)));

  commanderInit();
  stabilizerInit();
  expbrdInit();
  memInit();
  
  //Test the modules
  pass &= systemTest();
  pass &= configblockTest();
  pass &= commTest();
  pass &= commanderTest();
  pass &= stabilizerTest();
  pass &= expbrdTest();
  pass &= memTest();
  
  //Start the firmware
  if(pass)
  {
    systemStart();
    ledseqRun(SYS_LED, seq_alive);
    ledseqRun(LINK_LED, seq_testPassed);
  }
  else
  {
    if (systemTest())
    {
      while(1)
      {
        ledseqRun(SYS_LED, seq_testPassed); //Red passed == not passed!
        vTaskDelay(M2T(2000));
      }
    }
    else
    {
      ledInit();
      ledSet(SYS_LED, true);
    }
  }
  DEBUG_PRINT("Free heap: %d bytes\n", xPortGetFreeHeapSize());
  
  workerLoop();
  
  //Should never reach this point!
  while(1)
    vTaskDelay(portMAX_DELAY);
}
我们发现做了对各个硬件的初始化:

ledInit();

uartInit();

systemInit();

commInit();

commanderInit();
stabilizerInit();
expbrdInit();
memInit();

以及发送到crazyflie PC client的debug信息,这里的信息显示在console选项卡下面:

  DEBUG_PRINT("----------------------------\n");
  DEBUG_PRINT("Crazyflie is up and running!\n");
  DEBUG_PRINT("Build %s:%s (%s) %s\n", V_SLOCAL_REVISION,
              V_SREVISION, V_STAG, (V_MODIFIED)?"MODIFIED":"CLEAN");
  DEBUG_PRINT("I am 0x%X%X%X and I have %dKB of flash!\n",
              *((int*)(MCU_ID_ADDRESS+8)), *((int*)(MCU_ID_ADDRESS+4)),
              *((int*)(MCU_ID_ADDRESS+0)), *((short*)(MCU_FLASH_SIZE_ADDRESS)));

以及对硬件的自测:

//Test the modules
  pass &= systemTest();
  pass &= configblockTest();
  pass &= commTest();
  pass &= commanderTest();
  pass &= stabilizerTest();
  pass &= expbrdTest();
  pass &= memTest();

最后自测通过之后,调用systemStart();函数一起一些LED的闪烁控制指示系统一切正常可以开始用手柄控制飞行了。

//Start the firmware
  if(pass)
  {
    systemStart();//启动飞行器
    ledseqRun(SYS_LED, seq_alive);//正常运行灯的状态
    ledseqRun(LINK_LED, seq_testPassed);//
  }
  else
  {
    if (systemTest())//自测失败,指示不同的灯闪烁
    {
      while(1)
      {
        ledseqRun(SYS_LED, seq_testPassed); //Red passed == not passed!
        vTaskDelay(M2T(2000));
      }
    }
    else
    {
      ledInit();
      ledSet(SYS_LED, true);
    }
  }
  DEBUG_PRINT("Free heap: %d bytes\n", xPortGetFreeHeapSize());

后面还有一个workerLoop();函数,没有看懂是在做什么,以后再研究,先Mark下。

3,main函数之后会调用任务调度程序:

//Start the FreeRTOS scheduler
  vTaskStartScheduler();

4,我们发现到现在我们只是创建了一个任务,还需要调度嘛?其实在systemTask任务对其他硬件初始化期间,创建了很多其他的任务,我们可以再SourceInsight下搜索下:

Adc_f103.c (drivers\src):  xTaskCreate(adcTask, (const signed char * const)"ADC",
Crtp.c (modules\src):  xTaskCreate(crtpTxTask, (const signed char * const)CRTP_TX_TASK_NAME,
Crtp.c (modules\src):  xTaskCreate(crtpRxTask, (const signed char * const)CRTP_RX_TASK_NAME,
Eskylink.c (hal\src):  xTaskCreate(eskylinkTask, (const signed char * const)ESKYLINK_TASK_NAME,
Info.c (modules\src):  xTaskCreate(infoTask, (const signed char * const)"Info",
Log.c (modules\src):  xTaskCreate(logTask, (const signed char * const)LOG_TASK_NAME,
Mem.c (modules\src):  xTaskCreate(memTask, (const signed char * const)MEM_TASK_NAME,
Nrf24link.c (hal\src):  xTaskCreate(nrf24linkTask, (const signed char * const)NRF24LINK_TASK_NAME,
Param.c (modules\src):	xTaskCreate(paramTask, (const signed char * const)PARAM_TASK_NAME,
Pidctrl.c (modules\src):  xTaskCreate(pidCrtlTask, (const signed char * const)"PIDCrtl",
Pm_f103.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Pm_f405.c (hal\src):  xTaskCreate(pmTask, (const signed char * const)PM_TASK_NAME,
Stabilizer.c (modules\src):  xTaskCreate(stabilizerTask, (const signed char * const)STABILIZER_TASK_NAME,
Syslink.c (hal\src):  if (xTaskCreate(syslinkTask, (const signed char * const)SYSLINK_TASK_NAME,
System.c (modules\src):  xTaskCreate(systemTask, (const signed char * const)SYSTEM_TASK_NAME,
Task.h (lib\freertos\include): * Type by which tasks are referenced.  For example, a call to xTaskCreate
Task.h (lib\freertos\include): portBASE_TYPE xTaskCreate(
Task.h (lib\freertos\include): * xTaskCreate() can only be used to create a task that has unrestricted
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, &ucParameterToPass, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * \defgroup xTaskCreate xTaskCreate
Task.h (lib\freertos\include):#define xTaskCreate( pvTaskCode, pcName, usStackDepth, pvParameters, uxPriority, pxCreatedTask ) xTaskGenericCreate( ( pvTaskCode ), ( pcName ), ( usStackDepth ), ( pvParameters ), ( uxPriority ), ( pxCreatedTask ), ( NULL ), ( NULL ) )
Task.h (lib\freertos\include): * for each of the normal xTaskCreate() parameters (see the xTaskCreate() API
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, &xHandle );
Task.h (lib\freertos\include): * At least one task should be created via a call to xTaskCreate ()
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include):	 xTaskCreate( vTaskCode, "NAME", STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
Task.h (lib\freertos\include): * xTaskCreate() and xTaskCreateRestricted() macros.
Tasks.c (lib\freertos):		xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), &xIdleTaskHandle );
Tasks.c (lib\freertos):		xReturn = xTaskCreate( prvIdleTask, ( signed char * ) "IDLE", tskIDLE_STACK_SIZE, ( void * ) NULL, ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), NULL );
Timers.c (lib\freertos):			xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, &xTimerTaskHandle );
Timers.c (lib\freertos):			xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "Tmr Svc", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY ) | portPRIVILEGE_BIT, NULL);
Usblink.c (hal\src):  xTaskCreate(usblinkTask, (const signed char * const)USBLINK_TASK_NAME,
从上面看到:

adcTask,crtpTxTask,crtpRxTask,eskylinkTask,infoTask,logTask,memTask,paramTask,pmTask,stabilizerTask,syslinkTask,systemTask,prvIdleTask,prvTimerTask和usblinkTask等任务,这些任务基本上都是需要关心的,之后将会在适当的时候一一讲述实现的过程。




你可能感兴趣的:(crazyflie2.0_crazyflie-firmware_总体程序概括)