第一个正式版本刚发出去做板,现在有空可以来好好看看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
2,所以我们只用到抢占优先级,下一步是重点的函数:
//Launch the system task that will initialize and start everything systemLaunch();
/* 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());
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等任务,这些任务基本上都是需要关心的,之后将会在适当的时候一一讲述实现的过程。