你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】ThreadX USBX协议栈移植到STM32H7

[复制链接]
STMCU小助手 发布时间:2022-1-1 19:00
3.1   初学者重要提示
1、  本章使用的ST专门为STM32H7提供的软件包

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

3.2   USBX移植步骤
ThreadX USBX的移植步骤如下:

3.2.1      第1步,了解整体设计框架
为了方便大家移植,需要大家先对移植好的工程有个整体认识:

556edb9b3bb947f5b69aac84272def1d.png



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

  模拟U盘驱动文件ux_device_msc.c/.h和ux_device_descriptors.c/.h添加到自己的工程里面,路径不限。
配套例子是放在\User\usb文件。

  USB驱动文件stm32h7xx_hal_hcd.c,stm32h7xx_hal_pcd.c,stm32h7xx_hal_pcd_ex.c和stm32h7xx_ll_usb.c。
这个是STM32H7的HAL库自带的。

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

3.2.3      第3步,添加工程路径
大家根据自己添加的源文件位置,添加相关路径即可:

7d4292e15d424274b8e5aab1d6cd32a9.png




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

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

418a71e2dcbd48a199034bbf6765d9fc.png 4d161770a4734368b6881fe1ed982494.png


696837e6177b4f3caa286c6913cf4ea3.png f052ff2297b4462daa7186e7fc3b6ab8.png


0dadc8e05ea349beb4e04a737e86ed07.png


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

4db1e499f0f7422f9e522bf1e7bcecfe.png




3.2.5      第4步,配置GPIO和时钟
USB时钟配置在bsp.c文件的函数SystemClock_Config里面:

  1. {
  2.                 /*
  3.                 USB工作需要48MHz的时钟,可以由PLL1Q,PLL3Q和HSI48提供
  4.                         PLL1Q用于给SDMMC提供时钟
  5.                     PLL3Q给LTDC提供时钟,也可以跟USB共用,不过得更USB设置相同的频率才可一起用。
  6.                     HSI48可以供USB独享,就是精度不是很高。
  7.                 */
  8.                 RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  9. #if 0
  10.                 /* PLL3-Q for USB Clock = 48M */
  11.                 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
  12.                 PeriphClkInitStruct.PLL3.PLL3M = 5;
  13.                 PeriphClkInitStruct.PLL3.PLL3N = 48;
  14.                 PeriphClkInitStruct.PLL3.PLL3P = 2;
  15.                 PeriphClkInitStruct.PLL3.PLL3Q = 5;
  16.                 PeriphClkInitStruct.PLL3.PLL3R = 2;
  17.                 PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
  18.                 PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
  19.                 PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
  20.                 PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;
  21.                 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct)!= HAL_OK)
  22.                 {
  23.                         Error_Handler(__FILE__, __LINE__);
  24.                 }        
  25. #else
  26.                 PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
  27.                 PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
  28.                 if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  29.                 {
  30.                         Error_Handler(__FILE__, __LINE__);
  31.                 }
  32.               HAL_PWREx_EnableUSBVoltageDetector();
  33. #endif
  34.         }        
复制代码

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

  1. /* 配置USB GPIO, NVIC */
  2.     {
  3.         GPIO_InitTypeDef  GPIO_InitStruct = {0};

  4.         __HAL_RCC_GPIOA_CLK_ENABLE();

  5.         GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
  6.         GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  7.         GPIO_InitStruct.Pull = GPIO_NOPULL;
  8.         GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  9.         GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS;
  10.         HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  11.         /* 使能USB FS时钟 */
  12.         __HAL_RCC_USB2_OTG_FS_CLK_ENABLE();

  13.         /* 在睡眠模式下禁用USB时钟 */
  14.         __HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE();

  15.         /* 配置USB FS中断 */
  16.         HAL_NVIC_SetPriority(OTG_FS_IRQn, 0x2, 0);
  17.         HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
  18.     }

  19.     /* 初始化USB */
  20.     {
  21.         HAL_PWREx_EnableUSBVoltageDetector();

  22.         memset(&hpcd_USB_OTG_FS, 0x0, sizeof(PCD_HandleTypeDef));
  23.         hpcd_USB_OTG_FS.Instance = USB2_OTG_FS;
  24.         hpcd_USB_OTG_FS.Init.dev_endpoints = 8;
  25.         hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = 0;
  26.         hpcd_USB_OTG_FS.Init.ep0_mps = 0x40;
  27.         hpcd_USB_OTG_FS.Init.low_power_enable = 0;
  28.         hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
  29.         hpcd_USB_OTG_FS.Init.Sof_enable = 0;
  30.         hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
  31.         hpcd_USB_OTG_FS.Init.vbus_sensing_enable = 0;
  32.         hpcd_USB_OTG_FS.Init.lpm_enable = 0;

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

  35.         /* 设置TX FIFO和RX FIFO */
  36.         HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 1024);
  37.         HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 64);
  38.         HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 1024);

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

  41.         if (status != FX_SUCCESS)
  42.         {
  43.             return;
  44.         }

  45.     }
复制代码

3.2.6      第5步,MPU配置

为了方便大家移植测试,我们这里直接关闭AXI SRAM的读Cache和写Cache(这样就跟使用STM32F1或者STM32F4系列里面的SRAM一样)。此配置是在bsp.c文件的MPU_Config函数里面实现:

  1. /*
  2. *********************************************************************************************************
  3. *        函 数 名: MPU_Config
  4. *        功能说明: 配置MPU
  5. *        形    参: 无
  6. *        返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.         MPU_Region_InitTypeDef MPU_InitStruct;

  12.         /* 禁止 MPU */
  13.         HAL_MPU_Disable();

  14. #if 0
  15.            /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  16.         MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  17.         MPU_InitStruct.BaseAddress      = 0x24000000;
  18.         MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  19.         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  20.         MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  21.         MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  22.         MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  23.         MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  24.         MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  25.         MPU_InitStruct.SubRegionDisable = 0x00;
  26.         MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  27.         HAL_MPU_ConfigRegion(&MPU_InitStruct);

  28. #else
  29.      /* 当前是采用下面的配置 */
  30.         /* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */
  31.         MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  32.         MPU_InitStruct.BaseAddress      = 0x24000000;
  33.         MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  34.         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  35.         MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
  36.         MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
  37.         MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  38.         MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  39.         MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  40.         MPU_InitStruct.SubRegionDisable = 0x00;
  41.         MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  42.         HAL_MPU_ConfigRegion(&MPU_InitStruct);
  43. #endif
  44.         /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  45.         MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  46.         MPU_InitStruct.BaseAddress      = 0x60000000;
  47.         MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;        
  48.         MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  49.         MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  50.         MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;
  51.         MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  52.         MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  53.         MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  54.         MPU_InitStruct.SubRegionDisable = 0x00;
  55.         MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
  56.         
  57.         HAL_MPU_ConfigRegion(&MPU_InitStruct);

  58.         /*使能 MPU */
  59.         HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  60. }
复制代码

3.2.7      第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
代码如下:

  1. UINT  app_usb_device_thread_media_status(VOID *storage, ULONG lun, ULONG media_id, ULONG *media_status)
  2. {

  3.   /* The ATA drive never fails. This is just for app_usb_device only !!!! */
  4.   return (UX_SUCCESS);
  5. }
复制代码

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

3.3.2  读取函数app_usb_device_thread_media_read

代码如下:

  1. /**
  2.   * @brief  Function implementing app_usb_device_thread_media_read.
  3.   * @param  storage : Not used
  4.   * @param  lun: Logical unit number
  5.   * @param  lba: Logical block address
  6.   * @param  number_blocks: Blocks number
  7.   * @param  data_pointer: Data
  8.   * @param  media_status: Not used
  9.   * @retval Status (0 : OK / -1 : Error)
  10.   */
  11. UINT  app_usb_device_thread_media_read(VOID *storage, ULONG lun,
  12.                                        UCHAR *data_pointer,
  13.                                        ULONG number_blocks,
  14.                                        ULONG lba, ULONG *media_status)
  15. {
  16.     UINT status = 0U;

  17.     BSP_SD_ReadBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);                                                                        
  18.     //while(BSP_SD_GetCardState() != SD_TRANSFER_OK);
  19.     status = check_sd_status(0);   
  20.     return (status);
  21. }
复制代码

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

3.3.3  写入函数app_usb_device_thread_media_write
代码如下:

  1. /**
  2.   * @brief  Function implementing app_usb_device_thread_media_write.
  3.   * @param  storage : Not used
  4.   * @param  lun: Logical unit number
  5.   * @param  lba: Logical block address
  6.   * @param  number_blocks: Blocks number
  7.   * @param  data_pointer: Data
  8.   * @param  media_status: Not used
  9.   * @retval Status (0 : OK / -1 : Error)
  10.   */
  11. UINT  app_usb_device_thread_media_write(VOID *storage, ULONG lun,
  12.                                         UCHAR *data_pointer,
  13.                                         ULONG number_blocks,
  14.                                         ULONG lba, ULONG *media_status)
  15. {
  16.     UINT status = 0U;

  17.     BSP_SD_WriteBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
  18.     //while(BSP_SD_GetCardState() != SD_TRANSFER_OK);
  19.     status = check_sd_status(0);

  20.     return (status);
  21. }
复制代码

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

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

  1. storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_read  =  app_usb_device_thread_media_read;

  2. storage_parameter.ux_slave_class_storage_parameter_lun[0].ux_slave_class_storage_media_write  =  app_usb_device_thread_media_write;

  3. 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盘,效果如下:

a9cb882c39474dd9bd63b8c7e14cb451.png


注意使用的是MicroUSB接口:

f871e17a6a2d4c03a9413daf725670c4.png



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

41272c92c8c9483f9d5dc6a04cbf87b8.png



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

3.5   实验例程
配套例子:

V7-2401_ThreadX USBX Template

实验目的:

学习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方式查看。

实验操作:

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

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

74d954c9e7b649289184a7a4bd58d6e6.png




RTT打印:

cdcab0e093ed468a912923050806de22.png




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



收藏 评论0 发布时间:2022-1-1 19:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版