STM32H7第3章 ThreadX USBX协议栈移植到STM32H7
Posted Simon223
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32H7第3章 ThreadX USBX协议栈移植到STM32H7相关的知识,希望对你有一定的参考价值。
教程更新中:ThreadX USBX协议栈教程更新记录贴,前5章发布(2021-10-11) - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz!http://www.armbbs.cn/forum.php?mod=viewthread&tid=108546
第3章 ThreadX USBX协议栈移植到STM32H7
本章节为大家讲解USBX协议栈移植到STM32H7。
目录
3.2.7 第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.1 初学者重要提示
1、 本章使用的ST专门为STM32H7提供的软件包:http://www.armbbs.cn/forum.php?mod=viewthread&tid=108816
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驱动文件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步,添加工程路径
大家根据自己添加的源文件位置,添加相关路径即可:
3.2.4 第4步,禁止掉添加进来一些文件
之所以要禁止掉是因为这些文件要用到NetXDUO网络协议栈,或者大家不添加进来都是可以的。添加进来后再禁止的优势是添加时候可以全选添加。
禁止的方法是右击此文件去掉如下对钩即可:
3.2.5 第4步,配置GPIO和时钟
USB时钟配置在bsp.c文件的函数SystemClock_Config里面:
{
/*
USB工作需要48MHz的时钟,可以由PLL1Q,PLL3Q和HSI48提供
PLL1Q用于给SDMMC提供时钟
PLL3Q给LTDC提供时钟,也可以跟USB共用,不过得更USB设置相同的频率才可一起用。
HSI48可以供USB独享,就是精度不是很高。
*/
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
#if 0
/* PLL3-Q for USB Clock = 48M */
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInitStruct.PLL3.PLL3M = 5;
PeriphClkInitStruct.PLL3.PLL3N = 48;
PeriphClkInitStruct.PLL3.PLL3P = 2;
PeriphClkInitStruct.PLL3.PLL3Q = 5;
PeriphClkInitStruct.PLL3.PLL3R = 2;
PeriphClkInitStruct.PLL3.PLL3RGE = RCC_PLL3VCIRANGE_2;
PeriphClkInitStruct.PLL3.PLL3VCOSEL = RCC_PLL3VCOWIDE;
PeriphClkInitStruct.PLL3.PLL3FRACN = 0;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL3;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct)!= HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
#else
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USB;
PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_HSI48;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler(__FILE__, __LINE__);
}
HAL_PWREx_EnableUSBVoltageDetector();
#endif
}
USB的GPIO,NVIC初始化在demo_sd_usbx.c:
/* 配置USB GPIO, NVIC */
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG1_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* 使能USB FS时钟 */
__HAL_RCC_USB2_OTG_FS_CLK_ENABLE();
/* 在睡眠模式下禁用USB时钟 */
__HAL_RCC_USB2_OTG_FS_ULPI_CLK_SLEEP_DISABLE();
/* 配置USB FS中断 */
HAL_NVIC_SetPriority(OTG_FS_IRQn, 0x2, 0);
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
}
/* 初始化USB */
{
HAL_PWREx_EnableUSBVoltageDetector();
memset(&hpcd_USB_OTG_FS, 0x0, sizeof(PCD_HandleTypeDef));
hpcd_USB_OTG_FS.Instance = USB2_OTG_FS;
hpcd_USB_OTG_FS.Init.dev_endpoints = 8;
hpcd_USB_OTG_FS.Init.use_dedicated_ep1 = 0;
hpcd_USB_OTG_FS.Init.ep0_mps = 0x40;
hpcd_USB_OTG_FS.Init.low_power_enable = 0;
hpcd_USB_OTG_FS.Init.phy_itface = PCD_PHY_EMBEDDED;
hpcd_USB_OTG_FS.Init.Sof_enable = 0;
hpcd_USB_OTG_FS.Init.speed = PCD_SPEED_FULL;
hpcd_USB_OTG_FS.Init.vbus_sensing_enable = 0;
hpcd_USB_OTG_FS.Init.lpm_enable = 0;
/* 初始化USB */
HAL_PCD_Init(&hpcd_USB_OTG_FS);
/* 设置TX FIFO和RX FIFO */
HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 1024);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 64);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 1024);
/* 注册STM32到USBX协议栈并初始化 */
status = ux_dcd_stm32_initialize((ULONG)USB2_OTG_FS, (ULONG)&hpcd_USB_OTG_FS);
if (status != FX_SUCCESS)
{
return;
}
}
3.2.6 第5步,MPU配置
为了方便大家移植测试,我们这里直接关闭AXI SRAM的读Cache和写Cache(这样就跟使用STM32F1或者STM32F4系列里面的SRAM一样)。此配置是在bsp.c文件的MPU_Config函数里面实现:
/*
*********************************************************************************************************
* 函 数 名: MPU_Config
* 功能说明: 配置MPU
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable();
#if 0
/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#else
/* 当前是采用下面的配置 */
/* 配置AXI SRAM的MPU属性为NORMAL, NO Read allocate,NO Write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
#endif
/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x60000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
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
代码如下:
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
代码如下:
/**
* @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)
{
UINT status = 0U;
BSP_SD_ReadBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
//while(BSP_SD_GetCardState() != SD_TRANSFER_OK);
status = check_sd_status(0);
return (status);
}
用于实现SD模拟U盘的读取功能。
3.3.3 写入函数app_usb_device_thread_media_write
代码如下:
/**
* @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)
{
UINT status = 0U;
BSP_SD_WriteBlocks((uint32_t *) data_pointer, lba, number_blocks, 500);
//while(BSP_SD_GetCardState() != SD_TRANSFER_OK);
status = check_sd_status(0);
return (status);
}
用于实现SD模拟U盘的写入功能。
3.3.4 接口函数注册
接口函数的注册是在文件demo_sd_usbx.c里面:
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 实验例程
配套例子:
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
RTT打印:
3.6 总结
本章节就为大家讲解这么多,后面章节再为大家详细讲解USBX的玩法。
以上是关于STM32H7第3章 ThreadX USBX协议栈移植到STM32H7的主要内容,如果未能解决你的问题,请参考以下文章
STM32H7第4章 ThreadX USBX协议栈基础知识
STM32H7第5章 ThreadX USBX各种USB描述符简介
ThreadX NetXDUO网络协议栈移植到STM32H7