fix(usb): enter the bootloader after USB update confirm without key 4

Keep the NVM sector out of the application image and arm a backup register that survives reset, so confirm stays in flash mode even when round key 4 is not held.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-09-26 12:42:29 +08:00
parent 968f8ae1ec
commit fa5aa85bee
5 changed files with 62 additions and 18 deletions

View File

@ -180,12 +180,14 @@ int main(void)
TM1617_GPIO_Init();
/* ????????????????????? App??
* ???????????? KEY_MAIN_A ????? USB ????????
* ??????????? KEY_NULL ???? App????<EFBFBD><EFBFBD>??????????????? Boot ?????? */
/* 按住圆键 4(KEY_MAIN_A),或 App 确认了 USB 更新,都停在烧录。
* USB 更新有两处标志:Flash 里的 UsbMode,以及复位后仍在的备份寄存器。
* 没按键且两处都没有标志才跳进 App。 */
wk_delay_ms(50);
TM1617KeyValue = TM1617_ScanFkey();
if (TM1617KeyValue != KEY_MAIN_A && !Boot_NvmUsbUpdateRequested())
if (TM1617KeyValue != KEY_MAIN_A &&
!Boot_NvmUsbUpdateRequested() &&
!drv_nvm_usb_boot_armed())
{
JumpToApplication();
}
@ -222,11 +224,14 @@ int main(void)
LCD_ALIGN_CENTER, WHITE, BLACK, 0, 24);
}
}
/* 画面出来后再清标志。擦写与 Boot 同在 Flash Bank1,期间关掉中断 */
if (Boot_NvmUsbUpdateRequested())
/* 画面出来后再清标志,避免还没进烧录就被下一次复位跳回 App。
* 擦写与 Boot 同在 Flash Bank1,期间关掉中断。 */
if (Boot_NvmUsbUpdateRequested() || drv_nvm_usb_boot_armed())
{
__disable_irq();
if (Boot_NvmUsbUpdateRequested())
Boot_NvmClearUsbUpdate();
drv_nvm_clear_usb_boot_arm();
__enable_irq();
}

View File

@ -62,8 +62,12 @@ void UI_UsbModeConfirm_Process(DisplayTaskMessage_Type msg)
case GUI_CONFIRM:
nvm = drv_nvm_param_ptr();
nvm->param.UsbMode = NVM_USB_UPDATE;
__disable_irq();
/* 先记备份寄存器,再写 Flash。系统复位不清 BPR,
* Boot 不按圆键 4 也会留下烧录。关中断放在保存之后,
* 避免日志互斥在关中断后永远等不到超时。 */
drv_nvm_arm_usb_boot();
drv_nvm_save_to_flash();
__disable_irq();
nvic_system_reset();
break;
default:

View File

@ -11,21 +11,22 @@
#ifndef FLASH_BASE
#define FLASH_BASE 0x08000000UL
#endif
#ifndef SECTOR_SIZE
#define NVM_SECTOR_SZ 1024UL
#else
#define NVM_SECTOR_SZ ((uint32_t)SECTOR_SIZE)
#endif
#define fwname "BRS08L\x00"
#define fwdata __DATE__
#define fwtime __TIME__
/* AT32F403A 扇区为 2KB。参数仍写在 256KB 末尾倒数第 2 个 1KB,
* 擦除必须对齐到扇区起点,否则 0->1(MIDI->更新)写不进去。 */
/* 参数固定在 0x0803FC00(256KB 末尾倒数第 2 个 1KB)。
* 地址不能跟 SECTOR_SIZE 走:App 与 Boot 对该宏不一致时,Boot 会读错,
* USB 更新标志对不上。AT32F403A 扇区是 2KB,擦除必须对齐扇区起点,
* 否则 0->1(MIDI->更新)写不进去。应用程序链接范围必须停在该扇区之前。 */
#define NVM_FLASH_SECTOR 2048UL
#define INNER_FLASH_SAVE_ADDRESS (FLASH_BASE + 0x00040000UL - NVM_SECTOR_SZ)
#define INNER_FLASH_SAVE_ADDRESS (FLASH_BASE + 0x00040000UL - 1024UL)
#define INNER_FLASH_SECTOR_ADDRESS (INNER_FLASH_SAVE_ADDRESS & ~(NVM_FLASH_SECTOR - 1UL))
/* 备份寄存器在系统复位后仍保留。确认 USB 更新时先写下这个值,
* Boot 即使没读到 Flash 里的 UsbMode,不按圆键 4 也会停在烧录模式。 */
#define NVM_USB_BOOT_MAGIC 0xB007u
#pragma pack(push, 1)
@ -89,4 +90,36 @@ void drv_nvm_load_default_calibration_static_value(NvmParam_Type * pData, uint8_
uint8_t drv_nvm_get_param_value_by_id (uint8_t nvmId);
#include "at32f403a_407_bpr.h"
#include "at32f403a_407_crm.h"
#include "at32f403a_407_pwc.h"
static inline void drv_nvm_bpr_open(void)
{
crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
pwc_battery_powered_domain_access(TRUE);
while (PWC->ctrl_bit.bpwen == FALSE)
{
}
}
static inline void drv_nvm_arm_usb_boot(void)
{
drv_nvm_bpr_open();
BPR->dt1 = NVM_USB_BOOT_MAGIC;
}
static inline uint8_t drv_nvm_usb_boot_armed(void)
{
drv_nvm_bpr_open();
return ((BPR->dt1 & 0xFFFFu) == NVM_USB_BOOT_MAGIC) ? 1u : 0u;
}
static inline void drv_nvm_clear_usb_boot_arm(void)
{
drv_nvm_bpr_open();
BPR->dt1 = 0;
}
#endif // _DRV_NVM_H_

View File

@ -5,7 +5,8 @@
define symbol __ICFEDIT_intvec_start__ = 0x08008000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08008000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
/* 0x0803F800-0x0803FFFF 是 NVM 扇区,留给 UsbMode。代码放进来会被参数擦除毁掉。 */
define symbol __ICFEDIT_region_ROM_end__ = 0x0803F7FF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
/* AT32F403ARCT7: 96KB SRAM (0x20000000-0x20017FFF). Do NOT use 224KB. */
define symbol __ICFEDIT_region_RAM_end__ = 0x20017FFF;

View File

@ -5,7 +5,8 @@
define symbol __ICFEDIT_intvec_start__ = 0x08008000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x08000000;
define symbol __ICFEDIT_region_ROM_end__ = 0x0803FFFF;
/* 0x0803F800-0x0803FFFF 是 NVM 扇区,留给 UsbMode。 */
define symbol __ICFEDIT_region_ROM_end__ = 0x0803F7FF;
define symbol __ICFEDIT_region_RAM_start__ = 0x20000000;
define symbol __ICFEDIT_region_RAM_end__ = 0x20037FFF;
define symbol __ICFEDIT_boot_start__ = 0x08000000;