1. 升级FW之后,整个板子就清净了,清净到下载的应用程序都不执行了。blinky这样的应用程序下载之后就不再有console的输出。这个是肿么了?
大致是这个逻辑,通常的应用开发,在reset之后就跳转到代码启动地址。这个也是原生代码开发,如应用keil等开发通常会遇到的。但是在simplityStudio这样的独立生态开发,采用了另外的模式,就是首先搞一个bootloader,再由bootloader启动应用程序。这个就是本帖所遇到的问题。
先说解决方法,再demo中找到bootloader程序,然后选择一个适合自己的下载,这次选择的是bootloader UART,编译下载,
顺利解决问题,前面下载的blink可以正确运行的。
2. Bootloader是不是没有用?
基本上可以很确定的给出这个问题的答案,那就是非常有必要。
除非是使用8位机,只有8k的flash,执行简单玩具级别的功能,事实上现在的玩具逻辑也复杂起来了,那么用bootloader没什么效果。
一个良好的bootloader,就像计算机的bios一样,起到自检,硬件定义,简单内存管理等功能,通过开放的接口,在没有复杂代码和外部工具的情况下,执行设备和系统的调试和管理,通常还有自动升级软件的功能。
即使不是大的系统,也要用c语言搞一个自己的bootloader,这样在跨平台,在不同的芯片上开发的时候,都可以先弄bootloader,然后再加载其他应用程序。
如果,是开发一个需要升级的产品,那么,bootloader是绝对的需要。
3. Bootloader的实现。
Boot loader需要选择起始引导位置,本代码用的是uart,
如simplicity可以看到,用spi,i2c都可以,在有外部flash的情况下,还需要访问spi。推荐采用uart就足够的。
进入bootloader需要使用GPIO的button按键,定义函数如下,
bool gpio_enterBootloader(void)
{
bool pressed;
#if defined(CMU_HFBUSCLKEN0_GPIO)
// Enable GPIO clock
CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_GPIO;
#endif
#if defined(_CMU_CLKEN0_MASK)
// Enable GPIO clock
CMU->CLKEN0_SET = CMU_CLKEN0_GPIO;
#endif
// Since the button may have decoupling caps, they may not be charged
// after a power-on and could give a false positive result. To avoid
// this issue, drive the output as an output for a short time to charge
// them up as quickly as possible.
GPIO_PinModeSet(BSP_BTL_BUTTON_PORT,
BSP_BTL_BUTTON_PIN,
gpioModePushPull,
BTL_GPIO_ACTIVATION_POLARITY);
for (volatile int i = 0; i < 100; i++) {
// Do nothing
}
// Reconfigure as an input with pull(up|down) to read the button state
GPIO_PinModeSet(BSP_BTL_BUTTON_PORT,
BSP_BTL_BUTTON_PIN,
gpioModeInputPull,
BTL_GPIO_ACTIVATION_POLARITY);
// We have to delay again here so that if the button is depressed the
// cap has time to discharge again after being charged up by the above delay
for (volatile int i = 0; i < 500; i++) {
// Do nothing
}
pressed = GPIO_PinInGet(BSP_BTL_BUTTON_PORT, BSP_BTL_BUTTON_PIN)
!= BTL_GPIO_ACTIVATION_POLARITY;
// Disable GPIO pin
GPIO_PinModeSet(BSP_BTL_BUTTON_PORT,
BSP_BTL_BUTTON_PIN,
gpioModeDisabled,
BTL_GPIO_ACTIVATION_POLARITY);
#if defined(CMU_HFBUSCLKEN0_GPIO)
// Disable GPIO clock
CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_GPIO;
#endif
return pressed;
}
4. 应用的起始地址,在不同的产品系列如下,启动后访问0x0h,如果没有bootloader,那么在0x6000h的应用代码就无法访问到。
启动顺序如下,
进入页面,先按下btn0,然后rst就进入bootloader页面,这里啥也没显示,然后按照手册访问uart_dft.exe 就可以完成对应的功能,
整个过程比较完整,而且也在不停升级优化,更详细资料需要认真读代码。整个编译效率很高,小于2k。
5 整个代码包括uart初始化,gpio初始化,dft,crc和sha256加密等过程。完整核心代码供参考。
#include "config/btl_config.h"
#include "api/btl_interface.h"
#include "core/btl_core.h"
#include "core/btl_reset.h"
#include "core/btl_parse.h"
#include "core/btl_bootload.h"
#include "core/btl_upgrade.h"
#include "plugin/debug/btl_debug.h"
#ifdef BTL_PLUGIN_GPIO_ACTIVATION
#include "plugin/gpio/gpio-activation/btl_gpio_activation.h"
#endif
#ifdef BTL_PLUGIN_EZSP_GPIO_ACTIVATION
#include "plugin/gpio/ezsp-gpio-activation/btl_ezsp_gpio_activation.h"
#endif
#ifdef BOOTLOADER_SUPPORT_STORAGE
#include "plugin/storage/btl_storage.h"
#include "plugin/storage/bootloadinfo/btl_storage_bootloadinfo.h"
#endif
#ifdef BOOTLOADER_SUPPORT_COMMUNICATION
#include "plugin/communication/btl_communication.h"
#endif
#include "em_device.h"
#include "em_cmu.h"
#include "em_gpio.h"
#include "em_chip.h"
#if defined(__GNUC__)
#define ROM_END_SIZE 0
extern const size_t __rom_end__;
#elif defined(__ICCARM__)
#define ROM_END_SIZE 4
const size_t __rom_end__ @ "ROM_SIZE";
#endif
// --------------------------------
// Local function declarations
__STATIC_INLINE bool enterBootloader(void);
SL_NORETURN static void bootToApp(uint32_t);
#if defined(BOOTLOADER_WRITE_DISABLE)
__STATIC_INLINE void lockBootloaderArea(void)
{
// Disable write access to bootloader.
// Prevents application from touching the bootloader.
#if defined(_MSC_PAGELOCK0_MASK)
#if defined(CRYPTOACC_PRESENT)
CMU->CLKEN1_SET = CMU_CLKEN1_MSC;
#endif
for (uint32_t i = (BTL_FIRST_STAGE_BASE / FLASH_PAGE_SIZE);
i < ((BTL_MAIN_STAGE_MAX_SIZE + BTL_FIRST_STAGE_SIZE) / FLASH_PAGE_SIZE);
i++) {
MSC->PAGELOCK0_SET = (0x1 << i);
}
#if defined(CRYPTOACC_PRESENT)
CMU->CLKEN1_CLR = CMU_CLKEN1_MSC;
#endif
#elif defined(MSC_BOOTLOADERCTRL_BLWDIS)
MSC->BOOTLOADERCTRL |= MSC_BOOTLOADERCTRL_BLWDIS;
#else
// Do nothing
#endif
}
#endif
void HardFault_Handler(void)
{
BTL_DEBUG_PRINTLN("Fault ");
reset_resetWithReason(BOOTLOADER_RESET_REASON_FATAL);
}
// Main Bootloader implementation
int main(void)
{
int32_t ret = BOOTLOADER_ERROR_STORAGE_BOOTLOAD;
CHIP_Init();
// Enabling HFXO will add a hefty code size penalty (~1k)
// CMU_HFXOInit_TypeDef hfxoInit = CMU_HFXOINIT_DEFAULT;
// CMU_HFXOInit(&hfxoInit);
// CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFXO);
// CMU_OscillatorEnable(cmuOsc_HFRCO, false, false);
BTL_DEBUG_PRINTLN("BTL entry");
#if defined(EMU_CMD_EM01VSCALE2) && defined(EMU_STATUS_VSCALEBUSY)
// Device supports voltage scaling, and the bootloader may have been entered
// with a downscaled voltage. Scale voltage up to allow flash programming.
EMU->CMD = EMU_CMD_EM01VSCALE2;
while (EMU->STATUS & EMU_STATUS_VSCALEBUSY) {
// Do nothing
}
#endif
btl_init();
#ifdef BOOTLOADER_SUPPORT_STORAGE
if (!reset_resetCounterEnabled()) {
// Storage bootloaders might use part of the reason signature as a counter,
// so only invalidate the signature when the counter is not in use.
reset_invalidateResetReason();
}
#else
reset_invalidateResetReason();
#endif
#ifdef BOOTLOADER_SUPPORT_STORAGE
// If the bootloader supports storage, first attempt to apply an existing
// image from storage.
ret = storage_main();
if (ret == BOOTLOADER_OK) {
// Firmware upgrade from storage successful. Disable the reset counter
// and return to application
if (reset_resetCounterEnabled()) {
reset_disableResetCounter();
}
reset_resetWithReason(BOOTLOADER_RESET_REASON_GO);
} else {
if (!reset_resetCounterEnabled()) {
// Start counting the number of consecutive resets after the first reset
reset_enableResetCounter();
}
// Stop after three consecutive resets (the first one counts as 0)
if (reset_getResetCounter() >= 2) {
// If the system is not able to recover from a fault like BADAPP or
// BADIMAGE, wait in a busy loop to ease reflashing and debugging.
BTL_DEBUG_PRINTLN("Reset loop detected. Stopping...");
reset_disableResetCounter();
while (1) {
// Wait...
}
} else {
reset_incrementResetCounter();
}
// Wait a short while (approx. 500 ms) before continuing.
// This allows other operations to complete before the reset.
for (volatile int i = 800000; i > 0; i--) {
// Do nothing
}
}
#endif
#ifdef BOOTLOADER_SUPPORT_COMMUNICATION
communication_init();
ret = communication_start();
if (ret != BOOTLOADER_OK) {
reset_resetWithReason(BOOTLOADER_RESET_REASON_FATAL);
}
ret = communication_main();
BTL_DEBUG_PRINT("Protocol returned ");
BTL_DEBUG_PRINT_WORD_HEX(ret);
BTL_DEBUG_PRINT_LF();
communication_shutdown();
if ((ret == BOOTLOADER_OK)
|| (ret == BOOTLOADER_ERROR_COMMUNICATION_DONE)) {
reset_resetWithReason(BOOTLOADER_RESET_REASON_GO);
}
#endif // BOOTLOADER_SUPPORT_COMMUNICATION
// An error occurred in storage or communication, and a firmware upgrade
// was not performed
if (0
#ifdef BOOTLOADER_SUPPORT_COMMUNICATION
|| (ret == BOOTLOADER_ERROR_COMMUNICATION_IMAGE_ERROR)
|| (ret == BOOTLOADER_ERROR_COMMUNICATION_TIMEOUT)
#endif
#ifdef BOOTLOADER_SUPPORT_STORAGE
|| (ret == BOOTLOADER_ERROR_STORAGE_BOOTLOAD)
#endif
) {
reset_resetWithReason(BOOTLOADER_RESET_REASON_BADIMAGE);
} else {
reset_resetWithReason(BOOTLOADER_RESET_REASON_FATAL);
}
return 0;
}
#ifdef BOOTLOADER_SUPPORT_STORAGE
extern const BootloaderStorageFunctions_t storageFunctions;
#endif
const MainBootloaderTable_t mainStageTable = {
{
.type = BOOTLOADER_MAGIC_MAIN,
.layout = BOOTLOADER_HEADER_VERSION_MAIN,
.version = BOOTLOADER_VERSION_MAIN
},
// Bootloader size is the relative address of the end variable plus 4 for the
// CRC
.size = ((uint32_t)&__rom_end__) - BTL_MAIN_STAGE_BASE + ROM_END_SIZE + 4,
.startOfAppSpace = (BareBootTable_t *)(BTL_APPLICATION_BASE),
.endOfAppSpace = (void *)(BTL_APPLICATION_BASE + BTL_APP_SPACE_SIZE),
.capabilities = (0
#ifdef BOOTLOADER_ENFORCE_SIGNED_UPGRADE
| BOOTLOADER_CAPABILITY_ENFORCE_UPGRADE_SIGNATURE
#endif
#ifdef BOOTLOADER_ENFORCE_ENCRYPTED_UPGRADE
| BOOTLOADER_CAPABILITY_ENFORCE_UPGRADE_ENCRYPTION
#endif
#ifdef BOOTLOADER_ENFORCE_SECURE_BOOT
| BOOTLOADER_CAPABILITY_ENFORCE_SECURE_BOOT
#endif
#ifdef BOOTLOADER_SUPPORT_CERTIFICATES
| BOOTLOADER_CAPABILITY_ENFORCE_CERTIFICATE_SECURE_BOOT
#endif
#ifdef BOOTLOADER_ROLLBACK_PROTECTION
| BOOTLOADER_CAPABILITY_ROLLBACK_PROTECTION
#endif
| BOOTLOADER_CAPABILITY_BOOTLOADER_UPGRADE
| BOOTLOADER_CAPABILITY_EBL
| BOOTLOADER_CAPABILITY_EBL_SIGNATURE
#if !defined(BTL_PARSER_NO_SUPPORT_ENCRYPTION)
| BOOTLOADER_CAPABILITY_EBL_ENCRYPTION
#endif
#ifdef BOOTLOADER_SUPPORT_STORAGE
| BOOTLOADER_CAPABILITY_STORAGE
#endif
#ifdef BOOTLOADER_SUPPORT_COMMUNICATION
| BOOTLOADER_CAPABILITY_COMMUNICATION
#endif
),
.init = &btl_init,
.deinit = &btl_deinit,
.verifyApplication = &bootload_verifyApplication,
.initParser = &core_initParser,
.parseBuffer = &core_parseBuffer,
#ifdef BOOTLOADER_SUPPORT_STORAGE
.storage = &storageFunctions,
#else
.storage = NULL,
#endif
.parseImageInfo = core_parseImageInfo,
.parserContextSize = core_parserContextSize,
#ifdef BOOTLOADER_ROLLBACK_PROTECTION
.remainingApplicationUpgrades = &bootload_remainingApplicationUpgrades
#else
.remainingApplicationUpgrades = NULL
#endif
};
#if defined(BOOTLOADER_SUPPORT_CERTIFICATES)
const ApplicationCertificate_t sl_app_certificate = {
.structVersion = APPLICATION_CERTIFICATE_VERSION,
.flags = { 0U },
.key = { 0U },
.version = 0,
.signature = { 0U },
};
#endif
const ApplicationProperties_t sl_app_properties = {
.magic = APPLICATION_PROPERTIES_MAGIC,
.structVersion = APPLICATION_PROPERTIES_VERSION,
.signatureType = APPLICATION_SIGNATURE_NONE,
.signatureLocation = ((uint32_t)&__rom_end__) - BTL_MAIN_STAGE_BASE + ROM_END_SIZE,
.app = {
.type = APPLICATION_TYPE_BOOTLOADER,
.version = BOOTLOADER_VERSION_MAIN,
.capabilities = 0UL,
.productId = { 0U },
},
#if defined(BOOTLOADER_SUPPORT_CERTIFICATES)
// If certificate based boot chain is enabled, the bootloader binary will be provided with
// a certificate that does not contain any key.
// A valid certificate needs to be injected to the bootloader images using Simplicity Commander.
// Simplicity Commander will replace this certificate.
.cert = (ApplicationCertificate_t *)&sl_app_certificate,
#else
.cert = NULL,
#endif
.longTokenSectionAddress = NULL,
};
/**
* This function gets executed before ANYTHING got initialized.
* So, no using global variables here!
*/
void SystemInit2(void)
{
// Initialize debug before first debug print
BTL_DEBUG_INIT();
// Assumption: We should enter the app
volatile bool enterApp = true;
// Assumption: The app should be verified
volatile bool verifyApp = true;
// Check if we came from EM4. If any other bit than the EM4 bit it set, we
// can't know whether this was really an EM4 reset, and we need to do further
// checking.
#if defined(RMU_RSTCAUSE_EM4RST) && defined(APPLICATION_VERIFICATION_SKIP_EM4_RST)
if (RMU->RSTCAUSE == RMU_RSTCAUSE_EM4RST) {
// We came from EM4, app doesn't need to be verified
verifyApp = false;
} else if (enterBootloader()) {
// We want to enter the bootloader, app doesn't need to be verified
enterApp = false;
verifyApp = false;
}
#else
if (enterBootloader()) {
// We want to enter the bootloader, app doesn't need to be verified
enterApp = false;
verifyApp = false;
}
#endif
uint32_t startOfAppSpace = (uint32_t)mainStageTable.startOfAppSpace;
// Sanity check application program counter
uint32_t pc = *(uint32_t *)(startOfAppSpace + 4);
if (pc == 0xFFFFFFFF) {
// Sanity check failed; enter the bootloader
reset_setResetReason(BOOTLOADER_RESET_REASON_BADAPP);
enterApp = false;
verifyApp = false;
}
// App should be verified
if (verifyApp) {
// If app verification fails, enter bootloader instead
enterApp = bootload_verifyApplication(startOfAppSpace);
if (!enterApp) {
reset_setResetReason(BOOTLOADER_RESET_REASON_BADAPP);
}
}
#if defined(BOOTLOADER_ROLLBACK_PROTECTION)
// Clean the stored application versions if requested with a magic.
// The magic is only written when a bootloader upgrade is triggered.
bootload_removeStoredApplicationVersions();
if (enterApp) {
enterApp = bootload_storeApplicationVersion(startOfAppSpace);
}
#endif
if (enterApp) {
BTL_DEBUG_PRINTLN("Enter app");
BTL_DEBUG_PRINT_LF();
#if defined(BOOTLOADER_SUPPORT_STORAGE)
// Disable the reset counter if we're booting (back) into the application
if (reset_resetCounterEnabled()) {
reset_disableResetCounter();
}
#endif
#if defined(BOOTLOADER_WRITE_DISABLE)
lockBootloaderArea();
#endif
#if defined(BOOTLOADER_ENFORCE_SECURE_BOOT) && defined(APPLICATION_WRITE_DISABLE)
// The neccessary check of valid signature pointer for application at startOfAppSpace
// is already done in bootload_verifyApplication.
bootload_lockApplicationArea(startOfAppSpace, 0);
#endif
// Set vector table to application's table
SCB->VTOR = startOfAppSpace;
bootToApp(startOfAppSpace);
}
// Enter bootloader
}
/**
* Jump to app
*/
SL_NORETURN static void bootToApp(uint32_t startOfAppSpace)
{
(void)startOfAppSpace;
// Load SP and PC of application
__ASM("mov r0, %0 \n" // Load address of SP into R0
"ldr r1, [r0] \n" // Load SP into R1
"msr msp, r1 \n" // Set MSP
"msr psp, r1 \n" // Set PSP
"ldr r0, [r0, #4] \n" // Load PC into R0
"mov pc, r0 \n" // Set PC
:: "r" (startOfAppSpace) : "r0", "r1");
while (1) {
// Do nothing
}
}
/**
* Check whether we should enter the bootloader
*
* @return True if the bootloader should be entered
*/
__STATIC_INLINE bool enterBootloader(void)
{
// *INDENT-OFF*
#if defined(EMU_RSTCAUSE_SYSREQ)
if (EMU->RSTCAUSE & EMU_RSTCAUSE_SYSREQ) {
#else
if (RMU->RSTCAUSE & RMU_RSTCAUSE_SYSREQRST) {
#endif
// Check if we were asked to run the bootloader...
switch (reset_classifyReset()) {
case BOOTLOADER_RESET_REASON_BOOTLOAD:
case BOOTLOADER_RESET_REASON_FORCE:
case BOOTLOADER_RESET_REASON_UPGRADE:
case BOOTLOADER_RESET_REASON_BADAPP:
// Asked to go into bootload mode
return true;
default:
break;
}
}
// *INDENT-ON*
#ifdef BTL_PLUGIN_GPIO_ACTIVATION
if (gpio_enterBootloader()) {
// GPIO pin state signals bootloader entry
return true;
}
#endif
#ifdef BTL_PLUGIN_EZSP_GPIO_ACTIVATION
if (ezsp_gpio_enterBootloader()) {
// GPIO pin state signals bootloader entry
return true;
}
#endif
return false;
}
bool bootloader_enforceSecureBoot(void)
{
#ifdef BOOTLOADER_ENFORCE_SECURE_BOOT
return true;
#else
return false;
#endif
}
4. bootloader的主要作用,就是加载应用程序。本例中使用的gecko bootloader1.2版本相当的完整。
本帖最后由 北方 于 2022-1-14 10:55 编辑
bootload做的很不错,可以学习学习