USB-SLAVE mstorage使用指南

USB介绍

sifli USB控制器目前支持DEVICE、HOST等设备。其中作为DEVICE时支持CDC、MSTORAGE、HID、WINUSB等相关功能。以下主要叙述USB作为MSTORAGE设备使用流程。 当前USB功能主要作为device的MSTORAGE设备使用,在PC上以可读写的U盘模式出现。PC上可以对该U盘里面的文件进行增加、删除、修改文件等操作,拔出U盘后并在HDK上的文件系统相应分区上保留对应的文件修改。

USB配置

USB的配置包括PINMUX与menuconfig的配置,其中时钟需要在60MHz的频率下运行,目前U盘模式只支持fatfs文件系统,暂时不支持littlefs文件系统。

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中存在USB引脚与uart1引脚进行了复用,由于在sifli默认的代码中uart1用来作为HCPU的log打印;因此需要想要正常使用USB需要将uart1进行关闭"Enable UART1",打开"Enable UART4";“Enable UART4 RX DMA”,同时将HCPU的log换为uart4打印;“the device name gor console -> (uart4)”,HCPU相关配置如下。

../_images/usb_uart_1.PNG ../_images/usb_uart_2.PNG

USB功能代码流程

代码整体流程分为:

1)检测到插入时;callback(app_usb_function(USB_CONTROL_ENABLED)) ==> usb_start() ==> enabled_usb() ==> USB驱动 ==> PC挂载

2)检测到拔出时;callback(app_usb_function(USB_CONTROL_DISABLED)) ==> usb_stop() ==> disabled_usb() ==> USB驱动 ==> HDK卸载 ==> HDK挂载

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
    }
}

USB检测可以根据使用情况分为USB检测引脚进行识别与USB充电接口识别;

1)使用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);
        }
    }
    .......
}

2)USB充电接口识别:

1、在收到充电事件ID时调用app_usb_function(USB_CONTROL_ENABLED);

2、在收到移除充电事件ID时调用app_usb_function(USB_CONTROL_DISABLED)

在USB使用时频率需要一直保持在60MHz运行,因此系统不能降频也不能进行睡眠,所以在检测到USB插入时候系统需要进入IDLE模式再开启USB使能进行USB协议检测,只有当USB协议检测成功后PC才能识别到当前U盘

void usb_start(void)
{
    usb_timer_start();                                  //开启定时器;500ms检测一次USB协议
    if (!usb_flag)
    {
        rt_kprintf("%s rt_pm_request

", __func__);
        rt_pm_request(PM_SLEEP_MODE_IDLE);              //系统进入IDLE模式
        usb_flag = 1;
    }
    enabled_usb();                                      //使能USB协议
}

在拔出USB后需要对将加载到PC上的分区进行卸载后再重新再HDK上进行加载;

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协议

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协议

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);
}

去检测是否有USB协议,当前服务函数为检测协议的定时器超时函数,用于检测USB的协议是否识别成功。再5S内没有识别到USB协议就证明插入的设备没有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

", __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;
}

在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
}

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(执行升级)

/**
 * @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           */

/**
 * @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},
};
/**
功能:向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*/
    }
}

在本次案例上主要展示在555平台flash为emmc模式。OTA细节流程为; 系统资源升级:发现有升级文件->使用读取文件系统的方式读取需要升级的文件->将读取的文件写入到相应的资源地址->写入kvdb标志用于开机检测->删除文件系统文件->重启 运行代码升级:发现有升级文件->使用读取文件系统的方式读取需要升级的文件->将读取的文件写入到emmc一段空白地址处->写入env标志位用于OTAmanager执行->写入kvdb标志用于开机检测->删除文件系统文件->重启 代码流程如下:

/*
    功能: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;
}
/*
    功能:跳转以重启
    参数: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();
    }
}

开机check检测

/**
 * 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;

    }
}

ota manager

此功能只会需要升级运行代码(HCPU代码)的时候才会进入,只是升级资源就直接覆盖后重启即可,在ota manager中需要将已经在指定的emmc地址段中读取数据后覆盖到APP运行地址中去。

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

", __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!

", __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

", __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)

", __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;
}
/**
 * 功能: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;
}

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代码   */

二、将需要升级的文件放至对应的目录里面去。

../_images/usb_ota_1.PNG ../_images/usb_ota_2.PNG

三、拔出USB检测到有升级的文件后,自动进入copy界面 如果只有资源文件升级则就是copy界面完成后就自动重启。

../_images/usb_ota_res_1.png ../_images/usb_ota_res_2.png

然后重启到主界面

../_images/usb_ota_master.png

如果有code升级文件,那就先copy界面后再重启到ota manager界面进行安装,安装完成后重启

../_images/usb_ota_code_1.png ../_images/usb_ota_code_2.png ../_images/usb_ota_code_3.png

然后重启到主界面

../_images/usb_ota_master.png

常见报错

检测不到USB协议

检查一些USB的时钟是否开启,如果开启了查看USB的时钟频率是否为60MHz。在bsp_init.c中或者brv_io.c检查,并且检查一下是否有位置关闭了USB功能模块。

在bf0_hal_pcd.c中
HAL_RCC_DisableModule(RCC_MOD_USBC);

同时检查一下相关的USB引脚是否正确连接。

PC上识别到了mstorage设备,但是没有对应的U盘。

检查一下USB的协议通信是否正常,使用wireshark工具抓一下USB协议包。