HC32F460+RTthread U盘使用详解

最近项目要求利用U盘进行在线升级,使用的是华大单片机跑的是RTthread,弄完后自己简单整理了下,希望对大家有所帮助。

一、准备工作

1.1硬件

华大HC32F460 demo评估板(方便连线调试使用)、某宝买的U盘一个(Fat32)

1.2软件

编译环境还是用了keil(5.29),操作系统用了RTthread(标准版:4.0.0.1)

RTthread下载链接(RTT各种版本可以在他们官网下载),RTthead移植到华大单片机这边就不详细说了,有兴趣可以直接上他们官网直接查看很全面的移植教程RTthread文档中心

二、移植步骤

2.1USB驱动移植

在使用U盘前我们首先需要实现USB驱动,华大官方其实在源码驱动库中已经实现了USB驱动并封装成USB lib库,我们只需要简单修改下对应引脚配置即可。

华大驱动库下载链接(华大最新的驱动库在官网下载,这边使用的是V2.2.0版本)
在这里插入图片描述
在这里插入图片描述
如图USB核心驱动代码,华大官方是以usb_lib形式提供的,我们可以直接整个拷贝到我们工程目录下面,如下图,usb_lib这里面内容基本不需要更改。
在这里插入图片描述
上面是usb驱动的准备工作把USB驱动库添加到我们工程,接下就是移植USB的主要步骤。
第一步:底层驱动的实现主要包括时钟和相关引脚的配置:
如果第一次使用可以直接拷贝官方驱动库目录下example中usb例子.C和.h文件,因为我们这次U盘数据读取采用的是USB 作为主机模式方式,所以直接用usb_host_msc下的源文件(usb_app_conf.h,usb_bsp.c,usb_bsp.h,usb_host_user.h,usb_host_user,c)把这些文件直接拷贝到我们工程中。
在这里插入图片描述
在这里插入图片描述
根据实际需要我们需要修改这几个文件。
usb_bsp.c
该文件就是usb驱动需要我们移植修改的主要文件,主要是初始化usb工作时钟和相关引脚,我这边重新定义成drv_usb.c了为保持工程其他驱动文件命名格式。这里移植的时候需要注意因为我们跑了rtthread,SysTick_Handler需要把该文件中的屏蔽掉,否则会跟RTT自带的重复定义,系统滴答时钟部分如果我们在RTT中已经定义也需要屏蔽,避免重复,时钟因为我们在跑rtt时board.c中已经初始化配置过,该文件中的我们也可以屏蔽掉,只需要在UsbClkIni中设置时钟源即可,详见下图。

/**
 *******************************************************************************
 ** \brief  Initilizes BSP configurations
 ** \param  None
 ** \retval None
 ******************************************************************************/
void hd_usb_bsp_init(usb_core_instance *pdev)
{
    stc_port_init_t stcPortInit;

//    /* clock config */
//    BSP_CLK_Init();
    UsbClkIni();   //USB时钟:48MHZ
    CLK_GetClockFreq(&stcClkFreq);
//    BSP_LED_Init();//指示灯
//    BSP_KEY_Init();//键盘扫描

//    /* SysTick configuration */
//    SysTick_Init(1000u);
//    NVIC_SetPriority (SysTick_IRQn, DDL_IRQ_PRIORITY_14);
//    
//    DDL_PrintfInit(BSP_PRINTF_DEVICE, BSP_PRINTF_BAUDRATE, BSP_PRINTF_PortInit);
//    DDL_Printf("USBFS start !!\n");

    /* port config */
    /* Disable digital function for DM DP */
    MEM_ZERO_STRUCT(stcPortInit);
    stcPortInit.enPinMode = Pin_Mode_Ana;
    PORT_Init(PortA, Pin11, &stcPortInit);
    PORT_Init(PortA, Pin12, &stcPortInit);
    PORT_SetFunc(PortA, Pin11, Func_UsbF, Disable);
    PORT_SetFunc(PortA, Pin12, Func_UsbF, Disable);
    PORT_SetFunc(PortB, Pin08, Func_UsbF, Disable);
    //使能USB
    PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USBFS, Enable);
}
/**
 ******************************************************************************
 ** \brief  Initialize the usb clock for the sample
 **
 ** \param  None
 **
 ** \return None
 ******************************************************************************/
static void UsbClkIni(void)
{
//    stc_clk_upll_cfg_t      stcUpllCfg;

//    stcUpllCfg.pllmDiv = 2u;
//    stcUpllCfg.plln = 84u;
//    stcUpllCfg.PllpDiv = 7u;//48M
//    stcUpllCfg.PllqDiv = 7u;
//    stcUpllCfg.PllrDiv = 7u;
//    CLK_UpllConfig(&stcUpllCfg);
//    CLK_UpllCmd(Enable);
//    /* Wait UPLL ready. */
//    while(Set != CLK_GetFlagStatus(ClkFlagUPLLRdy))
//    {
//        ;
//    }
   CLK_SetUsbClkSource(ClkUsbSrcMpllr);//设置USB时钟源
//    /* Set USB clock source */
//    CLK_SetUsbClkSource(ClkUsbSrcUpllp);
}

下面时board.c中时钟配置以及sysTick配置,RTT系统节拍为1ms。

/*==================================================================
* Function      :rt_hw_board_init
* Description   :板级初始化
* Input Para    :None
* Output Para   :None
* Return Value  :None
==================================================================*/
void rt_hw_board_init()
{
    stc_clk_freq_t stcClkFreq = {0};
    /*中断向量表*/
    SCB->VTOR = 0x00000000;
    /*开启fpu*/
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
    /*开启时钟*/
    ClockInit();
    /*SysTick设置*/
    CLK_GetClockFreq(&stcClkFreq);
    SysTick_Config( stcClkFreq.sysclkFreq / RT_TICK_PER_SECOND );
    PORT_DeInit();
    PORT_Unlock();M4_PORT->PCCR = 0xC000;PORT_Lock();
    /* 调用组件初始化函数 */
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
#ifdef RT_USING_CONSOLE    
    //指定控制台输出串口
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
    rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
#endif
}
/*==================================================================
* Function	    :ClockInit
* Description	:开启各总线时钟
* Input Para	:None
* Output Para	:None
* Return Value  :None
==================================================================*/
static void ClockInit(void)
{
    en_clk_sys_source_t     enSysClkSrc;
    stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;

    MEM_ZERO_STRUCT(enSysClkSrc);
    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv = ClkSysclkDiv1;   // Max 168MHz
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2;  // Max 84MHz
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;  // Max 168MHz
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;  // Max 42MHz
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;  // Max 60MHz
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;  // Max 42MHz
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;  // Max 84MHz
    CLK_SysClkConfig(&stcSysClkCfg);

    stcXtalCfg.enMode = ClkXtalModeOsc;       //外部高速晶振作为时钟源
    stcXtalCfg.enDrv = ClkXtalLowDrv;         //外部高速晶振驱动能力选择(8~16MHZ晶振)
    stcXtalCfg.enFastStartup = Enable;        //允许超高速驱动
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);                      //外部晶振使能

    /* MPLL config. */
    /*system clk = 168M*/
    /*MPLLP输出频率 =(输入时钟/MPLL输入时钟分频)*MPLL倍频系数/MPLLP输出分频比*/
    stcMpllCfg.pllmDiv = 1u;                  //MPLL分频系数
    stcMpllCfg.plln =42u;                     //MPLL倍频系数
    stcMpllCfg.PllpDiv = 2u;                  //MPLLP分频系数主要用于系统时钟
    stcMpllCfg.PllqDiv = 2u;
    stcMpllCfg.PllrDiv = 7u;
    CLK_SetPllSource(ClkPllSrcXTAL);          //选择外部XTAL为PLL源
    CLK_MpllConfig(&stcMpllCfg);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);             //读等待5个周期
    EFM_Lock();

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);
    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);

    stc_sram_config_t   stcSramCfg;
    MEM_ZERO_STRUCT(stcSramCfg);
    stcSramCfg.u8SramIdx = Sram12Idx | Sram3Idx | SramRetIdx;
    stcSramCfg.enSramRC = SramCycle2;
    stcSramCfg.enSramWC = SramCycle2;
    SRAM_Init(&stcSramCfg);
}

其中hd_usb_udelay和hd_usb_mdelay两个延时函数我们也需要根据实际情况配置,我这边通过获取系统时钟函数获取当前时钟进行计算延时。

/**
 *******************************************************************************
 ** \brief  This function provides delay time in micro sec
 ** \param  usec : Value of delay required in micro sec
 ** \retval None
 ******************************************************************************/
#define Fclk SystemCoreClock

void hd_usb_udelay(const uint32_t usec)
{
    __IO uint32_t i;

    uint32_t j = stcClkFreq.sysclkFreq / 1000000ul * usec;
    for(i = 0ul; i < j; i++)
    {
        ;
    }
}
#include <rtdevice.h>
/**
 *******************************************************************************
 ** \brief  This function provides delay time in milli sec
 ** \param  msec : Value of delay required in milli sec
 ** \retval None
 ******************************************************************************/
void hd_usb_mdelay (const uint32_t msec)
{
 //   SysTick_Delay(msec);
    hd_usb_udelay(msec*1000);
}

usb_host_user.c
该文件主要是usb作为主机模式时应用程序部分可以根据实际功能添加实现,我这边只修改了host_user_msc_app函数让U盘初始化成功后挂载文件系统即可(USB_HOST_USER_AppState = USH_USR_FS_IDLE)
在这里插入图片描述
至此,基于RTthread U盘使用,USB驱动部分大概完成。

2.2 FatFs移植

fatFs是专为小型嵌入式设备开发的一个兼容微软fat的文件系统,采用ANSI C编写,采用抽象的硬件I/O层以及提供持续的维护,因此具有良好的硬件无关性以及可移植性。

FatFs官方网址
RT-Thread将FatFs整合为一个RT-Thread组件,并置于DFS层之下。因此可以非常方便的在RT-Thread中使用FatFs。

在这里插入图片描述

在这里插入图片描述

我们可以直接在RTT组件下把以上两个源文件添加到我们工程,目前RTT组件中FatFS的版本是R0.12b,如果有需要新版本可以直接去官网下载。FatFS源码说明可以参考这片内容,虽然版本有所差异但是大致一样
FatFs文件系统访问硬件主要通过disk_initialize、disk_status、disk_read、disk_write、disk_ioctl这五个函数实现,而华大官方驱动库中已帮我们实现这五个函数在USB host模式下,所以我们RTT中使用USB驱动可以直接调用usb_host_msc_fatfs.c里的这五个函数,屏蔽dfs_elm.c中对应函数。
在这里插入图片描述
最后,通过dfs_register注册FatFS文件系统到DFS下,这样我们就可以在控制台直接命令操作文件和直接使用,为应用程序提供统一的 POSIX 文件和目录操作接口:read、write、poll/select 等,RTT虚拟文件系统详解DFS
在这里插入图片描述

三、测试

在host_user_ms_app,挂载usb设备文件系统,注意USB正常连接会周期执行该轮询函数,其中`dfs_mount(0, "/", "elm", 0, 0)`第一个参数我们可以设置成 0,让RTT使用特殊驱动方式调用USB驱动而不通过USB设备框架。在串口终端内可以直接命令操作U盘,当然我们也可以统一的 POSIX 文件和目录操作接口:read、write、poll/select 等操作文件。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛肉爆弹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值