USB-SLAVE mstorage使用指南¶
1. 介绍¶
sifli USB控制器支持DEVICE、HOST等设备模式,其中DEVICE模式可支持CDC、MSTORAGE、HID、WINUSB等功能。本文主要说明USB作为MSTORAGE设备的使用流程:
工作模式:作为DEVICE的MSTORAGE设备时,在PC上以可读写U盘形式呈现
核心功能:PC可对U盘内文件进行增删改操作,拔出后修改会同步保留在HDK文件系统对应分区
2. USB配置¶
USB配置包括PINMUX引脚配置和menuconfig配置,需注意:
时钟需运行在60MHz
仅支持fatfs文件系统,暂不支持littlefs
2.1 PINMUX引脚配置¶
需将USB引脚配置为IO模式,代码如下:
#if defined(BSP_USING_USBD) || defined(BSP_USING_USBH)
HAL_PIN_Set_Analog(PAD_PA01, 1);
HAL_PIN_Set_Analog(PAD_PA03, 1);
#endif
特殊处理(563hdk):
563hdk的USB引脚与uart1引脚复用,而默认配置中uart1用于HCPU日志打印。若需正常使用USB,需修改如下配置:
关闭“Enable UART1”
开启“Enable UART4”和“Enable UART4 RX DMA”
将HCPU日志打印切换为uart4(配置项:“the device name for console -> uart4”)
相关配置截图:
3. USB功能代码流程¶
3.1 核心流程¶
插入检测: callback(app_usb_function(USB_CONTROL_ENABLED)) → usb_start() → enabled_usb() → USB 驱动 → PC 挂载
拔出检测: callback(app_usb_function(USB_CONTROL_DISABLED)) → usb_stop() → disabled_usb() → USB 驱动 → HDK 卸载 → HDK 重新挂载
3.2 关键接口实现¶
3.2.1 核心控制函数app_usb_function¶
void app_usb_function(void *on_off)
{
struct rt_device *usb_device;
uint8_t usb_stat = *(uint8_t *)on_off;
LOG_I("%s %d", __func__, usb_stat);
if (USB_CONTROL_ENABLED == usb_stat)
{
#ifdef BSP_PM_FREQ_SCALING
rt_pm_hw_device_start(); //关闭自动降频
#endif
usb_start();
}
if (USB_CONTROL_DISABLED == usb_stat)
{
usb_stop();
usb_ota_to_msg_app(); //上报OTA升级包事件
usb_to_msg_gui(NULL, 0, USB_GUI_MSG_ID); //上报USB事件ID
#ifdef BSP_PM_FREQ_SCALING
rt_pm_hw_device_stop(); //打开自动降频
#endif
}
}
3.2.2 插入 / 拔出检测方式¶
USB检测可以根据使用情况分为USB检测引脚进行识别与USB充电接口识别;
USB 检测引脚识别
//usb 检测引脚回调函数
static int irq_usb_service_callback(data_callback_arg_t *arg)
{
if (MSG_SERVICE_DATA_NTF_IND == arg->msg_id)
{
pin_common_msg_t pin_msg;
RT_ASSERT(arg != NULL);
RT_ASSERT(sizeof(pin_common_msg_t) == arg->data_len);
memcpy(&pin_msg, arg->data, arg->data_len);
if (pin_msg.id == INSERT_DETE_USB_PIN)
{
rt_usb_irq_pin_enable(0); //关闭中断
rt_thread_mdelay(200); //usb检测pin防抖延时
int read_pin = rt_pin_read(INSERT_DETE_USB_PIN);
if (read_pin == 1)
{
if (USB_CONTROL_DISABLED == usb_get_irq_state())
{
LOG_I("%s USB_CONTROL_PIN_IN", __func__);
usb_set_irq_state(USB_CONTROL_ENABLED);
app_usb_function(&usb_pin_state); //调用USB协议
}
}
else if (USB_CONTROL_ENABLED == usb_get_irq_state())
{
LOG_I("%s USB_CONTROL_PIN_OUT", __func__);
usb_set_irq_state(USB_CONTROL_DISABLED);
app_usb_function(&usb_pin_state);
}
rt_usb_irq_pin_enable(1);
}
}
.......
}
USB 充电接口识别
收到充电事件:调用app_usb_function(USB_CONTROL_ENABLED)
收到充电移除事件:调用app_usb_function(USB_CONTROL_DISABLED)
在USB使用时频率需要一直保持在60MHz运行,因此系统不能降频也不能进行睡眠,所以在检测到USB插入时候系统需要进入IDLE模式再开启USB使能进行USB协议检测,只有当USB协议检测成功后PC才能识别到当前U盘
3.2.3 USB 启动与停止¶
启动 USB(usb_start)
void usb_start(void)
{
usb_timer_start(); //开启定时器;500ms检测一次USB协议
if (!usb_flag)
{
rt_kprintf("%s rt_pm_request\n", __func__);
rt_pm_request(PM_SLEEP_MODE_IDLE); //系统进入IDLE模式
usb_flag = 1;
}
enabled_usb(); //使能USB协议
}
在拔出USB后需要对将加载到PC上的分区进行卸载后再重新再HDK上进行加载;
停止 USB(usb_stop)
void usb_stop(void)
{
udevice_t usb_device;
disabled_usb();
if (USB_IN == device_status_get(USB_CONNECT_STATUS)) //成功在PC上加载过分区
{
usb_unmount_fs(); //先卸载分区
usb_mount_fs(); //重新加载分区
}
if (usb_flag)
{
#ifdef RT_USING_PM
LOG_I("%s rt_pm_release", __func__);
rt_pm_release(PM_SLEEP_MODE_IDLE); //退出IDLE
#endif
usb_flag = 0;
}
device_status_set(USB_CONNECT_STATUS, USB_OUT); //设置USB模块状态
usb_device = rt_usbd_find_device(usb_dcd);
RT_ASSERT(usb_device);
usb_device->state = USB_STATE_NOTATTACHED; // 重置USB协议状态
}
使能 USB(enabled_usb)
static void enabled_usb(void)
{
struct rt_device *usb_device;
usb_device = rt_device_find("usb_reg");
if (usb_device)
rt_device_control(usb_device, RT_DEVICE_OFLAG_OPEN, NULL);
}
关闭 USB(disabled_usb)
static void disabled_usb(void)
{
struct rt_device *usb_device;
usb_device = rt_device_find("usb_reg");
if (usb_device)
rt_device_control(usb_device, RT_DEVICE_OFLAG_CLOSE, NULL);
}
3.2.4 USB 协议检测¶
通过定时器超时函数检测 USB 协议是否识别成功(5 秒内未识别则关闭 USB):
/**
功能:定时检测USB协议
使用:开了一个定时器去定时检测USB协议是否识别成功
*/
static udcd_t usb_dcd;
int app_usb_init(void)
{
usb_dcd = (udcd_t)rt_device_find("usbd");
RT_ASSERT(usb_dcd);
}
static uint8_t usb_handler(void)
{
static uint8_t usb_protocol_flag = 0;
uint8_t usb_intput;
udevice_t usb_device;
usb_device = rt_usbd_find_device(usb_dcd); //usb_dcd是一个全局变量的USB设备指针,在初始化时去find该设备并赋值给usb_dcd
RT_ASSERT(usb_device);
rt_kprintf("%s,state=%d\n", __func__, usb_device->state);
if (USB_STATE_CONFIGURED == usb_device->state) //USB协议识别成功
{
device_status_set(USB_CONNECT_STATUS, USB_IN); //设置USB 的状态
usb_protocol_flag = 0;
usb_to_msg_gui(NULL, 0, USB_GUI_MSG_ID); //上报USB识别成功的状态
usb_timer_stop(); //USB协议识别成功就关闭当前定时器
}
else //USB没有检测到协议
{
usb_protocol_flag ++;
if (10 == usb_protocol_flag) //5s内没有识别到协议
{
usb_stop(); //关闭USB模块
usb_timer_stop(); //关闭当前定时器
usb_protocol_flag = 0;
}
}
return 0;
}
3.2.5 USB 功耗控制(拔出后)¶
在USB拔出后为了节约功耗需要将USB功能禁用并pinmux配置为如下
void BSP_USB_Power_Down(void)
{
#if defined(BSP_USING_USBD) && defined(BSP_USING_USBH)
HAL_PIN_Set(PAD_PA01, GPIO_A1, PIN_PULLUP, 1);
HAL_PIN_Set(PAD_PA03, GPIO_A3, PIN_PULLUP, 1);
#endif
}
4. USB OTA升级¶
通过 USB 实现 OTA 升级(支持资源差分、代码差分、全量升级)。具体实现为在通过usb数据线在pc上挂载系统指定的分区后将需要升级的文件放入指定的文件夹中,在拔出USB后会直接检测指定的文件夹里是否含有文件,如果有就执行系统升级,并上报GUI进行界面显示。
使用USB作为OTA的流程为:拔出USB callback(app_usb_function(USB_CONTROL_DISABLED)) → usb_read_ota_dir(检测是否有OTA文件) → usb_to_msg_gui(向UI上报OTA事件) → usb_ota_all_file(执行升级)
4.1 升级目录与配置¶
####4.1.1 升级目录定义
/**
* @brief OTA check ID
*/
enum
{
USB_OTA_CHECK_ROOT = 0X01,
USB_OTA_CHECK_DYN = 0X02,
USB_OTA_CHECK_MUSIC = 0X04,
USB_OTA_CHECK_UDISK = 0X08,
USB_OTA_CHECK_MISC = 0X10,
USB_OTA_CHECK_HCPU = 0X20,
USB_OTA_MOVING_IDLE = 0XFF,
USB_OTA_MOVING_ING = 0xC0,
USB_OTA_MOVING_SUCC = 0x3F,
};
/**
* @brief OTA Upgrade Directory Contains resources and code
*/
#define USB_DIFF_RES_PATH "/udisk/diff_res"
#define USB_DIFF_CODE_PATH "/udisk/diff_code"
#define USB_DIFF_RES_ROOT_PATH "/udisk/diff_res/root" /**<root Resource upgrade directory */
#define USB_DIFF_RES_DYN_PATH "/udisk/diff_res/dyn" /**<dyn Resource upgrade directory */
#define USB_DIFF_RES_MUSIC_PATH "/udisk/diff_res/music" /**<music Resource upgrade directory */
#define USB_DIFF_RES_MISC_PATH "/udisk/diff_res/misc" /**<misc Resource upgrade directory */
#define USB_DIFF_RES_UDISK_PATH "/udisk/diff_res/udisk" /**<udisk Resource upgrade directory */
#define USB_DIFF_CODE_HCPU_PATH "/udisk/diff_code/hcpu" /**<hcpu code upgrade directory */
4.1.2 升级目录与 ID 映射¶
/**
* @brief Directory and corresponding ID for USB upgrade
*/
struct usb_diff_msg
{
char *path; /**升级文件的目录*/
char *dev_name; /**升级文件的device设备名*/
uint16_t id; /**check id*/
};
static struct usb_diff_msg usb_ota_msg[] =
{
{USB_DIFF_RES_ROOT_PATH, "root", USB_OTA_CHECK_ROOT},
{USB_DIFF_RES_DYN_PATH, "dyn", USB_OTA_CHECK_DYN},
{USB_DIFF_RES_MUSIC_PATH, "music", USB_OTA_CHECK_MUSIC},
{USB_DIFF_RES_UDISK_PATH, "udisk", USB_OTA_CHECK_UDISK},
{USB_DIFF_RES_MISC_PATH, "misc", USB_OTA_CHECK_MISC},
{USB_DIFF_CODE_HCPU_PATH, "code_pang", USB_OTA_CHECK_HCPU},
};
4.2 升级核心流程¶
OTA升级流程如下:
系统资源升级:发现有升级文件 → 使用读取文件系统的方式读取需要升级的文件 → 将读取的文件写入到相应的资源地址 → 写入kvdb标志用于开机检测 → 删除文件系统文件 → 重启
代码升级:发现有升级文件 → 使用读取文件系统的方式读取需要升级的文件 → 将读取的文件写入到emmc一段空白地址处 → 写入env标志位用于OTAmanager执行 → 写入kvdb标志用于开机检测 → 删除文件系统文件 → 重启
4.2.1 检测升级文件并上报¶
/**
功能:向UI发送消息接口
*/
void usb_ota_to_msg_app(void)
{
int ota_file_page_num = 0, file_len = 0, page_num = 0;
for (int i = 0; i < USB_OTAD_PATH_FILE_NUM; i ++)//遍历udisk上的所有文件夹
{
file_len = usb_read_ota_dir(usb_ota_msg[i].path, NULL); //读取指定目录是都有文件
page_num = file_len / USB_OTA_PACKAGE_SIZE; //计算升级的包数 512字节一包
if (file_len % USB_OTA_PACKAGE_SIZE) page_num++; //计算余数
ota_file_page_num += page_num; /*Calculate the total number of packages to upgrade*/
}
if (ota_file_page_num)
{
usb_to_msg_gui(NULL, ota_file_page_num, USB_GUI_OTA_ID);/*Send the total number of packages that need to be upgraded to the GUI*/
LOG_I("%s page num %d", __func__, ota_file_page_num);
usb_ota_all_file(usb_ota_msg, ota_file_page_num);/*Execute USB upgrade resources and code*/
}
}
4.2.2 执行全量升级(usb_ota_all_file)¶
/*
功能:ota所有文件
参数:ota_msg->所有的升级目录信息;ota_page_max:总包数(512一个包)
*/
void usb_ota_all_file(struct usb_diff_msg ota_msg[], uint32_t ota_page_max)
{
uint32_t bin_size = 0;
ota_page_count = 0;
usb_ota_write_flag(0x00); //将check id 全部设置为0
for (int i = 0; i < USB_OTAD_PATH_FILE_NUM; i ++)
{
LOG_I("%s,path=%s", __func__, ota_msg[i].path);
bin_size = usb_ota_file_transfer(ota_msg[i], ota_page_max); //执行单个文件的升级
}
usb_ota_write_flag(usb_ota_read_flag() >> 0x2); //写入升级完成的标志 00xx xxxx:(7,8位:00升级完成;11升级中)
usb_ota_jump(usb_ota_get_type(), bin_size); //重启跳转
}
/*
功能:ota文件搬移与标志位写如
参数:ota_msg:需要升级的文件信息;page_max:总包数(512一个包)
返回:如果有执行代码(HCPU)的升级就返回该文件大小,没有就返回0.
*/
/*Performing an upgrade of a single file*/
static uint32_t usb_ota_file_transfer(struct usb_diff_msg ota_msg, uint32_t page_max)
{
uint32_t size = 0, ota_hcpu_size = 0;
uint8_t usb_check = 0;
char file_name[USB_DEVICE_NAME_LEN] = {0};
memset(file_name, 0x00, USB_DEVICE_NAME_LEN);
usb_check = usb_ota_read_flag(); //获取check ID
size = usb_read_ota_dir(ota_msg.path, file_name);
if (size)
{
LOG_I("%s ota_msg.path=%s,name=%s", __func__, ota_msg.path, file_name);
usb_check |= USB_OTA_MOVING_ING;/*Upgrading*/
usb_ota_write_flag(usb_check);/*Write upgrade flag*/
if (RT_EOK == usb_ota_moving_file(ota_msg, file_name, page_max)) //进行文件的搬移
{
LOG_I("%s moving succ !!!", __func__);
usb_check |= ota_msg.id;/*file upgrad succ*/
usb_ota_write_flag(usb_check);/*Write upgrade flag*/
if (0 == strcmp(ota_msg.dev_name, "code_pang"))
{
usb_ota_set_type(USB_OTA_TYPE_HCPU);
ota_hcpu_size = size;
}
else usb_ota_set_type(USB_OTA_TYPE_RES);
}
else
{
LOG_I("%s moving fail !!!", __func__);
usb_check |= (!ota_msg.id);/*file upgrad fail*/
usb_ota_write_flag(usb_check);/*Write upgrade flag*/
}
}
else
{
usb_check |= ota_msg.id;
usb_ota_write_flag(usb_check);/*Write upgrade flag*/
}
return ota_hcpu_size;
}
4.2.4 重启跳转(usb_ota_jump)¶
/*
功能:跳转以重启
参数:flag:升级的类型;len:执行代码升级的文件大小
*/
void usb_ota_jump(uint32_t flag, uint32_t len)
{
if (flag == USB_OTA_TYPE_HCPU)
{
/*jump to ota manager code*/
LOG_I("%s,USB_OTA_CODE_HCPU drv_reboot,file_size=%d", __func__, len);
dfu_ctrl_env_t *env = dfu_ctrl_get_env();
env->prog.state = DFU_CTRL_USB_INSTALL; //写入OTA manager的标志
env->prog.FW_version = len; //HCPU 代码大小
dfu_ctrl_update_prog_info(env); //保存env
drv_reboot(); //重启
}
else if (flag == USB_OTA_TYPE_RES)
{
/*Just restart the resource file*/
LOG_I("%s,USB_OTA_RES drv_reboot", __func__);
drv_reboot();
}
}
4.2.5 开机检测升级结果¶
/**
* check ID:是由一个uint8_t的数以位作为每个文件的标志组成;
* check ID:uint8_t ID = 0x3f ; 1111 1111 :1-6位依次为文件 ROOT DYN MUSIC MISC UDISK HCPU的升级成功标志 1-升级成功 0-升级失败;7-8位 11-升级中;00升级完成,
* 在usb_ota_file_transfer()接口中没有升级此文件时候也会将该文件的标志置为1;因此0x3f是升级完成,在升级完成后会将check ID置为0xff。
*
*/
static void dfs_check_res_integrity(void)
{
uint8_t usb_ota_stater = 0;
usb_ota_stater = usb_ota_read_flag();
LOG_I("%s usb_ota_stater=%p", __func__, usb_ota_stater);
switch (usb_ota_stater)
{
case USB_OTA_MOVING_IDLE:
{
LOG_I("%s IDLE", __func__);
}
break;
case USB_OTA_MOVING_SUCC: //升级成功
{
LOG_I("%s Resource updated !", __func__);
usb_ota_write_flag(USB_OTA_MOVING_IDLE); //写入0xff
}
break;
default :
{
LOG_I("%s Upgrade failed, please upgrade again !", __func__);
usb_ota_to_msg_app(); //为其他值视为升级失败,就重新进入升级流程
}
break;
}
}
4.3 OTA Manager(代码升级专用)¶
仅当升级 HCPU 代码时进入,负责将 emmc 中的升级文件写入 APP 运行地址。(只升级资源就直接覆盖后重启即可)。
4.3.1 重置处理函数¶
uint8_t dfu_ctrl_reset_handler(void)
{
dfu_ctrl_env_t *env = dfu_ctrl_get_env();
RT_ASSERT(env->mode == DFU_CTRL_OTA_MODE);
uint16_t state = env->prog.state;
uint8_t status = DFU_ERR_GENERAL_ERR;
uint8_t is_jump = 0;
LOG_I("dfu_ctrl_reset_handler %d", state);
// dfu_ota_bootloader_ram_run_set(DFU_RAM_STATE_UPDATE_FAIL);
if (HAL_Get_backup(RTC_BAKCUP_OTA_FORCE_MODE) == 1)
{
HAL_Set_backup(RTC_BAKCUP_OTA_FORCE_MODE, 0);
dfu_flash_addr_reset(0);
dfu_ctrl_boot_to_user_fw();
}
...........
switch (state)
{
case DFU_CTRL_USB_INSTALL: //USB升级标志
{
#ifdef OTA_EMMC
env->callback(DFU_APP_RESET_IND, NULL); //打开UI
LOG_I("%s moving addr=%p,bin_size=%d\n", __func__, HCPU_FLASH_CODE_START_ADDR, env->prog.FW_version);
uint8_t dfu_emmc_code_upgrade(dfu_ctrl_env_t *env, uint32_t size);
uint8_t dfu_upgrade_result = dfu_emmc_code_upgrade(env, env->prog.FW_version);//进行code升级
switch (dfu_upgrade_result)
{
case DFU_USB_FIND_FAIL: //升级失败
{
LOG_I("%s find fail!\n", __func__);
env->prog.state = DFU_CTRL_IDLE; //写入标志位 回退之前的app,重启
env->prog.FW_version = 0;
dfu_ctrl_update_prog_info(env);
drv_reboot();
}
break;
case DFU_USB_FAIL: //在搬移过程中失败
{
LOG_I("%s fail!,env->prog.FW_version=%d\n", __func__, env->prog.FW_version);
if (env->prog.FW_version == 0) env->prog.FW_version = 1;
else if (env->prog.FW_version == 5) //重启超过5次就不在重启了
{
LOG_I("%s while(1)\n", __func__);
while (1) {;}
}
else env->prog.FW_version += 1;
dfu_ctrl_update_prog_info(env);
drv_reboot();
}
break;
}
#else
is_jump = 1;
#endif
}
break;
...........
return 0;
}
4.3.2 EMMC 代码升级实现¶
/**
* 功能:code升级
* 参数:env;size:文件大小
* 返回:升级结果
*/
uint8_t dfu_emmc_code_upgrade(dfu_ctrl_env_t *env, uint32_t size)
{
uint32_t page_num = size / DFU_EMMC_PAGE_MAX;
uint32_t emmc_offset = 0, nor_offset = 0, end_page_size = size % DFU_EMMC_PAGE_MAX;
if (end_page_size) page_num ++ ;
rt_device_t dev = rt_device_find("code_pang");
LOG_I("%s page_num=%d,dev=%p,name=%s", __func__, page_num, dev, dev->parent.name);
env->callback(DFU_APP_DL_END_AND_INSTALL_START_IND, NULL);
if (dev)
{
if (RT_EOK == rt_device_open(dev, RT_DEVICE_FLAG_RDWR))
{
int res = 0;
while (page_num --)
{
memset(code_buf, 0x00, DFU_EMMC_PAGE_MAX);
res = rt_device_read(dev, emmc_offset, (void *)code_buf, DFU_EMMC_PAGE_MAX / 512);//读取emmc里面的code
if (res > 0)
{
rt_flash_erase(HCPU_FLASH_CODE_START_ADDR + (nor_offset * DFU_EMMC_PAGE_MAX), DFU_EMMC_PAGE_MAX);//擦除nor
uint32_t wr_size = rt_flash_write(HCPU_FLASH_CODE_START_ADDR + (nor_offset * DFU_EMMC_PAGE_MAX), code_buf, DFU_EMMC_PAGE_MAX);//将代码写入nor上的app地址
if (wr_size != DFU_EMMC_PAGE_MAX)
{
LOG_I("%s write fail!,nor_offset=0x%x,ADDR=0x%x wr_size=%d", __func__, nor_offset, HCPU_FLASH_CODE_START_ADDR + (nor_offset * DFU_EMMC_PAGE_MAX), wr_size);
return DFU_USB_FAIL;
}
}
else
{
rt_device_close(dev);
LOG_I("%s read fail!,emmc_offset=0x%x,ADDR=0x%x res=%d", __func__, emmc_offset, HCPU_FLASH_CODE_START_ADDR, res);
return DFU_USB_FAIL;
}
emmc_offset += (DFU_EMMC_PAGE_MAX / 512);
nor_offset += 1;
dfu_install_progress_ind(nor_offset * DFU_EMMC_PAGE_MAX, size);//向UI发送进度
}
}
}
else
{
LOG_I("%s find code_pang fail!", __func__);
rt_device_close(dev);
return DFU_USB_FIND_FAIL;
}
LOG_I("%s emmc code moving sucss!", __func__);
env->callback(DFU_APP_INSTALL_COMPLETD_IND, NULL);
env->callback(DFU_APP_TO_USER, NULL);
env->prog.state = DFU_CTRL_IDLE;
env->prog.FW_state = DFU_CTRL_FW_INSTALLED;
env->prog.FW_version = 0;
env->is_force_update = 0;
dfu_ctrl_update_prog_info(env);//保存状态
dfu_ctrl_boot_to_user_fw();//重启
return DFU_USB_EOK;
}
4.4 USB OTA使用流程¶
插入USB,pc上正确识别到U盘。并且能正常打开里面的目录,目录如下:
#define USB_DIFF_RES_PATH "/udisk/diff_res"
#define USB_DIFF_CODE_PATH "/udisk/diff_code"
#define USB_DIFF_RES_ROOT_PATH "/udisk/diff_res/root" /**<root 图库 字体 等相关资源 */
#define USB_DIFF_RES_DYN_PATH "/udisk/diff_res/dyn" /**<dyn 资源升级目录 */
#define USB_DIFF_RES_MUSIC_PATH "/udisk/diff_res/music" /**<music 资源升级目录 */
#define USB_DIFF_RES_MISC_PATH "/udisk/diff_res/misc" /**<misc 资源升级目录 */
#define USB_DIFF_RES_UDISK_PATH "/udisk/diff_res/udisk" /**<udisk 资源升级目录 */
#define USB_DIFF_CODE_HCPU_PATH "/udisk/diff_code/hcpu" /**<hcpu 代码升级目录 hcpu已经包含了lcpu代码 */
将需要升级的文件放至对应的目录里面去
拔出 USB:自动检测并执行升级
仅资源升级:显示 copy 进度 → 完成后重启至主界面
含代码升级:copy 完成 → 重启至 OTA manager 安装 → 完成后重启至主界面
5. 常见报错¶
5.1 检测不到 USB 协议¶
检查 USB 时钟是否为 60MHz(在bsp_init.c或brv_io.c中确认)
在bf0_hal_pcd.c中
HAL_RCC_DisableModule(RCC_MOD_USBC);
检查是否有代码关闭 USB 模块(如
HAL_RCC_DisableModule(RCC_MOD_USBC);)确认 USB 引脚连接正确
5.2 PC 识别到 MSTORAGE 设备但无 U 盘¶
检查 USB 协议通信是否正常,可使用 wireshark 抓取 USB 协议包分析
确认 menuconfig 中分区配置正确(分区名或 DHARA 映射名)