从之前对总体结构的介绍,参考crazyflie2_nrf51822程序分析--总体结构
可以看出来程序运行的顺序是MBR->MBS->Bootloader->Firmware,MBR我们动不了,所以先分析下MBS都做了什么事情,main函数主要做的事情如下:
<span style="font-size:14px;">int main() __attribute__ ((noreturn)); int main() { press = press_none; /* Lock flash for MBR and MBS 锁住MBR and MBS */ NRF_MPU->PROTENSET0 = 0x00000001UL; NRF_MPU->PROTENSET1 = 0x80000000UL; //LED设置为输出模式 nrf_gpio_cfg_output(LED_PIN); nrf_gpio_pin_set(LED_PIN); //控制STM32的供电引脚拉低,禁止对stm32供电 nrf_gpio_cfg_output(PM_VCCEN_PIN); nrf_gpio_pin_clear(PM_VCCEN_PIN); //按键引脚配置为输入上拉 nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP); //选择晶振源:HFCLK,就是外部晶振 NRF_CLOCK->TASKS_HFCLKSTART = 1UL; while(!NRF_CLOCK->EVENTS_HFCLKSTARTED); // Start button timer 开启检测按键定时器,通过比较器判断按下的时间长短 NRF_TIMER0->PRESCALER = 7; // Prescaler of 16, result frequency is 1MHz NRF_TIMER0->BITMODE = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos; NRF_TIMER0->CC[0] = 1.5*SEC; // Launch bootloader long press timing NRF_TIMER0->EVENTS_COMPARE[0] = 0; NRF_TIMER0->CC[1] = 5*SEC; // Launch bootloader verylong press timing NRF_TIMER0->EVENTS_COMPARE[1] = 0; NRF_TIMER0->TASKS_CLEAR = 1; NRF_TIMER0->TASKS_START = 1; // Setup LED blinking timer开启灯闪烁定时器 NRF_TIMER1->PRESCALER = 7; //Prescaler of 16, result frequency is 1MHz NRF_TIMER1->BITMODE = TIMER_BITMODE_BITMODE_16Bit << TIMER_BITMODE_BITMODE_Pos; NRF_TIMER1->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk; // Calculate number of page before the bootloader计算页的个数 if ((*(uint32_t*)(BOOTLOADER_CONFIG)) > (FLASH_SIZE*PAGE_SIZE)) fault(); flashPages = (*(uint32_t*)(BOOTLOADER_CONFIG))/1024; if (nrf_gpio_pin_read(BUTTON_PIN) == 0) { press = press_short; } //判断按下按键的时间,按下时间越长,灯闪越快 while (nrf_gpio_pin_read(BUTTON_PIN) == 0) { // LED定时器 if (NRF_TIMER1->EVENTS_COMPARE[0]) { NRF_TIMER1->EVENTS_COMPARE[0] = 0; nrf_gpio_pin_toggle(LED_PIN); } // 1.5s长按定时器 if (NRF_TIMER0->EVENTS_COMPARE[0]) { NRF_TIMER0->EVENTS_COMPARE[0] = 0; blinking_timer(1*SEC); press = press_long; } // 5s长按定时器 if (NRF_TIMER0->EVENTS_COMPARE[1]) { NRF_TIMER0->EVENTS_COMPARE[1] = 0; blinking_timer(250*MS); NRF_TIMER0->TASKS_STOP = 1UL; press = press_verylong; } } // Saves the detected press in a retained register //保留按键按压状态在retain寄存器中,Bootloader中会获取GPREGRET来判断按键时间长短 NRF_POWER->GPREGRET &= ~(0x03UL << 1); NRF_POWER->GPREGRET |= 0x80 | ((press&0x03UL)<<1);</span> //通过判断按键按下时间长短,进入不同的模式 if (press != press_verylong) { if(verify_flash_flags()) { //fault(); copy_flash();//这里在做什么事情?需要进一步看code,论坛中有点对这块的解释,但是没明白这里真正的作用是什么?</span> } else { start_firmware();//这里是进入bootloader } } else { start_stm_dfu();//very long 按下会进入使得stm进入dfu } while(1); }大致就是在判断按键按压的时间长短,然后进入不同模式,但是对于上面红色部分flash的一些操作,不知道在做什么事情,论坛中有一些解释,但是还是不太懂,论坛链接如下:
https://forum.bitcraze.io/viewtopic.php?f=6&t=1640
顺便贴出解释的内容:
问题:Crazyflie bootloader sequence
Hi. I'm trying to analyze bootloader sequence.
I'm starting with mbs program.
In main function, the program detects button input command,
and if the button is not "very_long", it calls verify_flash_flags(), line 242 of mbs/main.c
In the function, it uses variable "flashFlags", which is a pointer for last flash page.
CopyFlashFlags_t *flashFlags = (void*)FLASH_BASE+((flashPages-1)*PAGE_SIZE);
Variable "flashPages" is caculated before, using bootloader address written in NRF_UICR_BASE+0x80
I stucked here, I can not find who write the flash page that "flashFlags" read.
It contains header; size of bootloader and softdevice; crcs; etc.
Please help me where the flash page is written.
arnaud回答:
Hi,
The bootloader is described in the wiki there: https://wiki.bitcraze.io/doc:crazyflie: ... r:protocol and is implemented in crazyflie2-nrf-bootloader.
The MBS you are looking at is not the main bootloader but it can flash the bootloader and the softdevice. The idea is that the bootloader is not able to write over itself and over the bluetooth softdevice (the bootloader depends of the softdevice). So the solution is to flash a new bootloader and a new softdevice in a pre-defined way: anywhere in the writable flash, with a correct CRC32 checksum and with the address in a well-known location. This way when the copter restart the MBS verifies the checksum and if it matches it flashes softdevice and bootloader. From the MBS point of view the data appear here like magic .
This design tries to avoid any possibility to brick the bootloader from the bootloader: in order to change the bootloader you must do it on purpose, not by mistake.
The real bootloader (the one that permits to load the flash from radio) is in this project: https://github.com/bitcraze/crazyflie2-nrf-bootloader