前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【STM32F407】第3章 ThreadX USBX协议栈移植到STM32F407

【STM32F407】第3章 ThreadX USBX协议栈移植到STM32F407

作者头像
Simon223
发布2021-10-20 16:23:36
7920
发布2021-10-20 16:23:36
举报

教程更新中:http://www.armbbs.cn/forum.php?mod=viewthread&tid=108546

第3章 ThreadX USBX协议栈移植到STM32F407

本章节为大家讲解USBX协议栈移植到STM32F407。

3.1 初学者重要提示

3.2 USBX移植步骤

3.3 USBX的模拟U盘移植接口文件ux_device_msc.c。

3.4 使用的MicroUSB接口并注意跳线帽设置

3.5 实验例程

3.6 总结

3.1 初学者重要提示

1、 本章使用的ST专门为STM32F4提供的软件包:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=108636 .

2、 本章配套例子使用SD卡模拟一个U盘,使用的MicroUSB接口。

3.2 USBX移植步骤

ThreadX USBX的移植步骤如下:

3.2.1 第1步,了解整体设计框架

为了方便大家移植,需要大家先对移植好的工程有个整体认识:

3.2.2 第2步,添加USBX和USB驱动到工程

这里我们在FileX教程做的模板例子基础上添加USBX文件和USB驱动文件,大家可以直接从本章教程提供的例子里面复制。

  • 模拟U盘驱动文件ux_device_msc.c/.h和ux_device_descriptors.c/.h添加到自己的工程里面,路径不限。

配套例子是放在\User\usb文件。

  • USB驱动文件stm32f4xx_hal_hcd.c,stm32f4xx_hal_pcd.c,stm32f4xx_hal_pcd_ex.c和stm32f4xx_ll_usb.c。

这个是STM32F4的HAL库自带的。

  • USBX相关源文件。

大家可以将所有相关文件都复制到自己的工程里面,配套例子是放在\USBX。

3.2.3 第3步,添加工程路径

大家根据自己添加的源文件位置,添加相关路径即可:

3.2.4 第4步,禁止掉添加进来一些文件

之所以要禁止掉是因为这些文件要用到NetXDUO网络协议栈,或者大家不添加进来都是可以的。添加进来后再禁止的优势是添加时候可以全选添加。

禁止的方法是右击此文件去掉如下对钩即可:

3.2.5 第4步,配置GPIO和时钟

USB时钟配置在bsp.c文件的函数SystemClock_Config里面:

代码语言:javascript
复制
    /* 芯片内部的LDO稳压器输出的电压范围,选用的PWR_REGULATOR_VOLTAGE_SCALE1 */
    __HAL_RCC_PWR_CLK_ENABLE();
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /* 使能HSE,并选择HSE作为PLL时钟源 */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 25;
    RCC_OscInitStruct.PLL.PLLN = 336;
    RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
    RCC_OscInitStruct.PLL.PLLQ = 7;  这个分频很重要,分频出48MHz
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler(__FILE__, __LINE__);
    }

USB的GPIO,NVIC初始化在demo_sd_usbx.c:

代码语言:javascript
复制
    /* 配置USB GPIO, NVIC */
    {
        GPIO_InitTypeDef  GPIO_InitStruct = {0};

        __HAL_RCC_GPIOA_CLK_ENABLE();

        GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_11;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
        

        /* 使能USB FS时钟 */
        __HAL_RCC_USB_OTG_FS_CLK_ENABLE();

        
        /* 配置USB FS中断 */
        HAL_NVIC_SetPriority(OTG_FS_IRQn, 0, 0); 
        HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
    }

    /* 初始化USB */
    {
        memset(&hpcd_USB_OTG_FS, 0x0, sizeof(PCD_HandleTypeDef));
      hpcd_USB_OTG_FS.Instance = USB_OTG_FS;
      hpcd_USB_OTG_FS.Init.dev_endpoints = 4;
      hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
      hpcd_USB_OTG_FS.Init.dma_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
      hpcd_USB_OTG_FS.Init.Sof_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.low_power_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.lpm_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.vbus_sensing_enable = DISABLE;
      hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = DISABLE;

        /* 初始化USB  */
        HAL_PCD_Init(&hpcd_USB_OTG_FS);

        /* 设置TX FIFO和RX FIFO */
        HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 128);
        HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 64);
        HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 128);

        /* 注册STM32到USBX协议栈并初始化 */
        status =  ux_dcd_stm32_initialize((ULONG)USB_OTG_FS, (ULONG)&hpcd_USB_OTG_FS);

        if (status != FX_SUCCESS)
        {
            return;
        }
        
    }

3.2.6 第7步,添加应用代码(USB中断,打开U盘和关闭U盘)

USB操作专门整理到了文件demo_sd_usbx.c。主要三部分,打开U盘,关闭U盘和USB中断服务程序。这三个函数基本是通用的,大家直接复制粘贴使用即可

特别注意USB中断服务程序别忘了添加。

3.3 USBX的模拟U盘移植接口文件ux_device_msc.c说明

这里将USBX的底层接口文件ux_device_msc.c的实现为大家简单做个说明。

3.3.1 状态函数app_usb_device_thread_media_status

代码如下:

代码语言:javascript
复制
UINT  app_usb_device_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
{

  /* The ATA drive never fails. This is just for app_usb_device only !!!! */
  return (UX_SUCCESS);
}

此函数主要用于获取SD卡模拟U盘的状态。

3.3.2 读取函数app_usb_device_thread_media_read

代码如下:

代码语言:javascript
复制
/**
  * @brief  Function implementing app_usb_device_thread_media_read.
  * @param  storage : Not used
  * @param  lun: Logical unit number
  * @param  lba: Logical block address
  * @param  number_blocks: Blocks number
  * @param  data_pointer: Data
  * @param  media_status: Not used
  * @retval Status (0 : OK / -1 : Error)
  */
UINT  app_usb_device_thread_media_read(VOID *storage, ULONG lun,
                                       UCHAR *data_pointer,
                                       ULONG number_blocks,
                                       ULONG lba, ULONG *media_status)
{
#if 0
    UINT status = 0U;

    BSP_SD_ReadBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);                                    
    status = check_sd_status(0);    
    return (status);

#else
    UINT status;
    if(check_sd_status(0) != BSP_ERROR_NONE)
    {
        
    }
    
    status = BSP_SD_ReadBlocks_DMA((uint32_t*)data_pointer, lba, number_blocks);

    if (status == BSP_ERROR_NONE)
    {
        if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) == TX_SUCCESS)
        {
            status = FX_SUCCESS;
        }
        else
        {
            status =  FX_BUFFER_ERROR;
        }
    }

    return status;
#endif
}

用于实现SD模拟U盘的读取功能。

3.3.3 写入函数app_usb_device_thread_media_write

代码如下:

代码语言:javascript
复制
/**
  * @brief  Function implementing app_usb_device_thread_media_write.
  * @param  storage : Not used
  * @param  lun: Logical unit number
  * @param  lba: Logical block address
  * @param  number_blocks: Blocks number
  * @param  data_pointer: Data
  * @param  media_status: Not used
  * @retval Status (0 : OK / -1 : Error)
  */
UINT  app_usb_device_thread_media_write(VOID *storage, ULONG lun,
                                        UCHAR *data_pointer,
                                        ULONG number_blocks,
                                        ULONG lba, ULONG *media_status)
{
#if 0
    UINT status = 0U;

    BSP_SD_WriteBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
    status = check_sd_status(0);
    
    return (status);

#else
    UINT status;
    
    if(check_sd_status(0) != BSP_ERROR_NONE)
    {
        
    }

    status = BSP_SD_ReadBlocks_DMA((uint32_t*)data_pointer, lba, number_blocks);

    if (status == BSP_ERROR_NONE)
    {
        if(tx_semaphore_get(&transfer_semaphore, DEFAULT_TIMEOUT) == TX_SUCCESS)
        {
            status = FX_SUCCESS;
        }
        else
        {
            status =  FX_BUFFER_ERROR;
        }
    }

#endif

    return status;
}

用于实现SD模拟U盘的写入功能。

3.3.4 接口函数注册

接口函数的注册是在文件demo_sd_usbx.c里面:

代码语言:javascript
复制
storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read  =  app_usb_device_thread_media_read;

storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write  =  app_usb_device_thread_media_write; 

storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_status =  app_usb_device_thread_media_status;

3.4 使用的MicroUSB接口并注意跳线帽设置

本周教程移植的例子使用内部RAM模拟了一个U盘,效果如下:

注意使用的是MicroUSB接口:

注意板子左下角跳线帽的设置:

这里是用于选择CAN1 TX使用PB9或者PA12引脚,CAN1 RX使用PB8或者PA11引脚。大家这里可以什么都不接,或者CAN1 TX通过跳线帽短接PA12,CAN1 RX通过跳线帽短接PA11。切记不可以短接到PA12和PA11引脚上,USB要使用这两个引脚。

3.5 实验例程

配套例子:

V6-2401_ThreadX USBX Template

实验目的:

  1. 学习USBX模板,通过SD来模拟U盘。

实验内容:

1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况

========================================================

CPU利用率 = 0.89%

任务执行时间 = 0.586484645s

空闲执行时间 = 85.504470575s

中断执行时间 = 0.173225395s

系统总执行时间 = 86.264180615s

=======================================================

任务优先级 任务栈大小 当前使用栈 最大栈使用 任务名

Prio StackSize CurStack MaxStack Taskname

2 4092 303 459 App Task Start

5 4092 167 167 App Msp Pro

4 4092 167 167 App Task UserIF

5 4092 167 167 App Task COM

0 1020 191 191 System Timer Thread

串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。

App Task Start任务 :启动任务,这里用作BSP驱动包处理。

App Task MspPro任务 :消息处理。

App Task UserIF任务 :按键消息处理。

App Task COM任务 :这里用作LED闪烁。

System Timer Thread任务:系统定时器任务

2、(1) 凡是用到printf函数的全部通过函数App_Printf实现。

(2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

3、默认上电是通过串口打印信息,如果使用RTT打印信息

(1) MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

#define Enable_RTTViewer 1

(2) Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。

实验操作:

  1. 测试前务必将SD卡插入到开发板左上角的卡座中。
  2. 支持以下6个功能,用户通过电脑端串口软件发送数字1-6给开发板即可
  3. printf("1 - 显示根目录下的文件列表\r\n");
  4. printf("2 - 创建一个新文件armfly.txt\r\n");
  5. printf("3 - 读armfly.txt文件的内容\r\n");
  6. printf("4 - 创建目录\r\n");
  7. printf("5 - 删除文件和目录\r\n");
  8. printf("6 - 读写文件速度测试\r\n");
  9. printf("a - 打开SD卡模拟U盘\r\n");
  10. printf("b - 关闭SD卡模拟U盘\r\n");

串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

RTT打印:

3.6 总结

本章节就为大家讲解这么多,后面章节再为大家详细讲解USBX的玩法。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-10-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 第3章 ThreadX USBX协议栈移植到STM32F407
    • 3.1 初学者重要提示
      • 3.2 USBX移植步骤
        • 3.2.1 第1步,了解整体设计框架
        • 3.2.2 第2步,添加USBX和USB驱动到工程
        • 3.2.3 第3步,添加工程路径
        • 3.2.4 第4步,禁止掉添加进来一些文件
        • 3.2.5 第4步,配置GPIO和时钟
        • 3.2.6 第7步,添加应用代码(USB中断,打开U盘和关闭U盘)
      • 3.3 USBX的模拟U盘移植接口文件ux_device_msc.c说明
        • 3.3.1 状态函数app_usb_device_thread_media_status
        • 3.3.2 读取函数app_usb_device_thread_media_read
        • 3.3.3 写入函数app_usb_device_thread_media_write
        • 3.3.4 接口函数注册
      • 3.4 使用的MicroUSB接口并注意跳线帽设置
        • 3.5 实验例程
          • 3.6 总结
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档