用户工具

站点工具


icore3_arm_hal_20

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
icore3_arm_hal_20 [2020/04/17 17:17]
fmj 创建
icore3_arm_hal_20 [2022/03/18 15:08] (当前版本)
sean
行 2: 行 2:
 |技术支持电话|**0379-69926675-801** ​ ||| |技术支持电话|**0379-69926675-801** ​ |||
 |技术支持邮件|Gingko@vip.163.com ​ ||| |技术支持邮件|Gingko@vip.163.com ​ |||
-|技术论坛|http://​www.eeschool.org ​ ||| 
 ^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^ ^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^
 |  V1.0  |  2020-04-17 ​ |  gingko ​ |  初次建立 ​ | |  V1.0  |  2020-04-17 ​ |  gingko ​ |  初次建立 ​ |
行 21: 行 20:
 {{ :​icore3:​icore3_cube_20_3.png?​direct | }} {{ :​icore3:​icore3_cube_20_3.png?​direct | }}
 4. 配置调试引脚 4. 配置调试引脚
-{{ :icore3:icore3_cube_19_4.png?direct | }}+{{ :icore3:icore3_cube_20_4.png?direct | }}
 5. 将LED对应的3个引脚(PI5,PI6,PI7)设置为GPIO_Output 5. 将LED对应的3个引脚(PI5,PI6,PI7)设置为GPIO_Output
 {{ :​icore3:​icore3_cube_20_5.png?​direct | }} {{ :​icore3:​icore3_cube_20_5.png?​direct | }}
行 63: 行 62:
 \\ \\
  
-===== 实验十USB_HID实验——双向数据传输 ​=====+===== 实验十:USBH_MSC实验——读/​写U盘(大容量存储器) ​=====
  
 ==== 一、 实验目的与意义 ==== ==== 一、 实验目的与意义 ====
 +  - 了解STM32 USB HOST结构。
 +  - 了解STM32 USB HOST特征。
 +  - 掌握STM32 HAL库中USBH_MSC的配置方法。
 +  - 掌握USBH_MSC 使用方法。
 +  - 掌握Keil MDK集成开发环境使用方法。
  
-  - 了解STM32 USB SLAVE结构。 
-  - 了解STM32 USB SLAVE特征。 
-  - 掌握USB SLAVE HID的使用方法。 
-  - 掌握STM32 HAL库中USB_HID属性的配置方法 
-  - 掌握KEIL MDK 集成开发环境使用方法。 
 ==== 二、 实验设备及平台 ==== ==== 二、 实验设备及平台 ====
  
行 81: 行 80:
   - 装有WIN XP(及更高版本)系统的计算机。   - 装有WIN XP(及更高版本)系统的计算机。
 ==== 三、 实验原理 ==== ==== 三、 实验原理 ====
-=== 1、USB_HID设备简介 ​=== +=== 1、USBH_MSC及USB大容量存储设备 === 
-  * USB HIDHuman Interface Device的缩写,由其名称可以了解HID设备是直接与人交互设备例如键盘、鼠标与游戏杆等。不过HID设备并不一定要有人接口,只要符合HID类别规范的设备都是HID设备。 +  * MSC一种计算机和移动设备之间传输协议它允许一个通用串行总线(USB)设备来访问主机的计算设备,使两者之间进行文件传输。 
-  * 交换的数据存储在称为报表(report)的结构内,设备的固件必须支持HID报表的格式。主在控制与中断传输中传送与要求报表,来传送与接收数据。报表格式非常有弹性可以处理任何类别的数据。 +  * USB大容量存储设备类(The USB mass storage device class)是一种计算和移动设备之间的传输协议它允许一个通用串行总线(USB)设备访问主机计算设备使两者之间进行文件传输 
-  * 设备除了HID接口之外,它可能同时还包含有其他的USB接口。例如影像显示设备可能使用HID接口来做亮度,对比,与更新率控制而使用传统的影 像接口来传送显示的数据。USB扩音器可以使用时传输来播放语音,同时使HID接口来控制音量,震荡,与低音等。HID接口通常比传统控制接口来得便宜。 +=== 2、USB_MSC HOST ===  ​ 
-  Wndows操作系统最先支持的HID设备。在windows98以及后的版本中内置有HID设备的程序,用程序可以直接使用这些驱动程序设备通信。 +  * USB MSC设备固件(firmware)或者硬(hardware)必须要实现下面这些功能: 
-  在设计一个USB接口的计算机设备时,如果HID类型的设备可以满足需要,可以将其设计为HID类型设备这样可以省去比较复杂USB驱动程序的编写直接利用Windows操作系统对标准HID类型USB设备支持+    * 检测和响应通用的USB Request和USB总线上的事件。 
 +    检测和响应自USB设备的关于信息或者作的USB Mass Storage Request。 
 +    * 检测和响,从USB Transfer中获得的SCSI Command。这些业界标准的命令,​是用获得状态信息,控制设备操作,向存储介质块中读取(read block)和写入(write block)数据的。 
 +    设备如果向存储介质中创建/​读取/​写入文件/​文件夹那么就涉及到文件系统,还要实现文件系统。嵌入式系统中常见文件系统有FAT16或FAT32。
  
-=== 2HID主要能力 === +=== 3USB MSC Device ​== 
-  * 交换数据储存在称为报表(Report)结构内,设备的固件必须支持HID报表的格式主机通过控制和中断传输中的传送和请求报表来传送和接收数据报表格式非常灵活。 +  * 我们所关注U盘,就是所谓MSC设备大容量存储设备。 
-  * 每一笔事务可以携带小量或中量的数据。低速设备每一笔事务最大是8B全速设备每一笔事务最大64B,高速设备每一笔事务最大是1024B一个报表可以使用多笔事务。 +  * U盘功能,就是数据存储而对应的数据传输,用的是USB中的Bulk Transfer 
-  * 设备可以未预期时间传送信息给主机例如键盘按键或是鼠标移动。所以主机会定时轮询设备以取得最新数据。 +=== 4、USB MSC相关协议 === 
-  * HID设备最大传输速度有限制。主机可以保证低速中断端点每10ms内最多1笔事务秒最多是800B。保证全速端点每lms笔事务,每一秒最多是64000B保证高速端点每125us三笔事务,每一秒最多是24.576MB。 +  * USB MSC Bulk-Only (BBB) Transport 
-  * HID设备没有保证的传输速率。果设备是设置在10ms的时距事务之间时间可等于或小于10ms。除非设备设置在全速时在每个帧传输数据,或是在高速时在每个微帧传输数据。这是最快的轮询速率所以端点可以保证正确的带宽可供使用。 +  * 如上所述Bulk-onlyUSB设备端,此处的U盘和USB Host端,即普通PC,之间信息交换的协议Bulk Only Transport,也被简称为BOT。 
-  HID设备除了传送数据给主机外它也会从主机接收数据。只要能够符合HID类别规范的设备都可以是HID设备。 +  * USB MSC USB Attached SCSI Protocol (UASP) 
-  设备除了HID接口之外它可能同时还包含有他的USB接口。例如影像显示设备可能使HID接口来做亮比度软件控制而使用传统影像接口来传送要显示数据。USB扩音器可以使用实时传输来播放语音,同时使用HID接口来控制音量、低音等 +  * “Attached”顾名思义,是附某个上面的,此处即附在SCSI协议上面的,即SCSI协议补充部分。 
-  * HID类别设备的规范文件主要是以下两份: +  * UASP规范,定义了关于如何在USB 2.0和USB 3.0中,UAS的传输标准是如何实现的,并且给出了些范例和些推荐的做法 
-    * Device Class Definition for Human interface Devices +{{ :​icore3:​icore3_arm_hal_20_1.png?direct |}} 
-    * HID Usabe Tables +  * 如上图我们U盘实现,主要就是数据的读写而Device和Host之间的数据通信主要两种: 
-=== 3、实现原理 ​== +    CBI:主要用于Floppy设备,所以新的设备很少用此协议 
-{{ :​icore3:​icore3_arm_hal_19_1.png?​direct |}} +    BOT:Bulk-Only Transport,也称BBB(Bulk/​Bulk/​Bulk)而对于BOT/​BBB来说,对提高USB总线利率,提高了USB速后,就是UASP协议故此处称UASP为BOT增强版协议。 
-{{ :icore3:icore3_arm_hal_19_2.png?direct |}} +=== 5USBH_MSC验介绍 === 
- +  * 硬件框架图: 
-  * iCore3中使用的STM32F407IGTx芯片带有USB高速物理层,通过外USB3300设备芯片实现USB_HID设备物理层搭建。 +{{ :icore3:icore3_arm_hal_20_2.png?direct&​600 ​|}} 
-  * USB HID设备无需驱动程序,Windows系统自带HID类的驱动程序。通过移植ST官方提供的代码来实现iCore3USB_HID双向数据传输点击测试软件灯控按钮来控制iCore3上的LED灯的亮灭实现上位机下位机传输数据并解析相应命令。按下iCore3的ARM-KEY按钮测试软显示ARM-KEY状态实现了下位机向上位机的数据传输+  * USBH_MSC实验是STM32F407的USB接实现iCore3作为主机对U盘(即USB大容量存储器)实现读/写操作并通过串口打印到电脑上并显示的实验。 
 +  * 实验内容: 
 +    * 通过cube MX库提供的代码来实现STM32对U盘或者读卡器等大容量USB存储设备读写操作本实验是向存储设备中新建一个名为test.txt文件文件中写入数据,待写入成功后,读出文件的内容并通过终端显示出来
  
 ==== 四、 实验程序 ==== ==== 四、 实验程序 ====
行 112: 行 116:
 int main(void)  ​ int main(void)  ​
 {  ​ {  ​
-  /* USER CODE BEGIN 1 */  ​ 
-  int i;  ​ 
-  unsigned char buffer[64];  ​ 
-  unsigned char send_buffer[64];  ​ 
-  static int counter;  ​ 
-  RTC_DateTypeDef sDate;  ​ 
-  RTC_TimeTypeDef sTime;  ​ 
-  /* USER CODE END 1 */  ​ 
   HAL_Init();  ​   HAL_Init();  ​
   SystemClock_Config();  ​   SystemClock_Config();  ​
-  /* Initialize all configured peripherals */  ​ 
   MX_GPIO_Init();  ​   MX_GPIO_Init();  ​
-  ​MX_RTC_Init();   +  ​MX_UART4_Init();   
-  ​MX_USB_DEVICE_Init();   +  ​MX_FATFS_Init();   
-  ​/* USER CODE BEGIN WHILE */  +  ​MX_USB_HOST_Init(); ​  
 +  uart4.printf("​\x0c"​);​ 
 +  uart4.printf("​\033[1;​32;​40m"​); ​   
 +  uart4.printf("​\r\nHello,​ I am iCore3.\r\n"​); ​     ​
   while (1)  ​   while (1)  ​
   {  ​   {  ​
-    ​/* USER CODE END WHILE */   +    ​MX_USB_HOST_Process();   
-        if(systick.second_flag == 1){   +    ​LED_RED_ON;  ​
-            systick.second_flag = 0;   +
-            ​if(hUsbDeviceHS.dev_state == USBD_STATE_CONFIGURED){ ​  +
-                if(counter ++ % 2){   +
-                    HAL_RTC_GetTime(&​hrtc,​ &sTime, RTC_FORMAT_BIN);  ​ +
-                    HAL_RTC_GetDate(&​hrtc,​ &sDate, RTC_FORMAT_BIN); ​  +
-                    memset(send_buffer,​0,​64);​  +
-                    sprintf((char *)send_buffer,"​time:​%02d:​%02d:​%02d ​ %02d-%02d-%02d",​sTime.Hours,​sTime.Minutes,​sTime.Seconds,​sDate.Year,​sDate.Month,​sDate.Date);​ +
-                    USBD_HID_SendReport(&​hUsbDeviceHS,​send_buffer,​64); ​  +
-                }else{ ​  +
-                    memset(send_buffer,​0,​64); ​  +
-                    if(ARM_KEY_STATE == KEY_DOWN) ​  +
-                        sprintf((char *)send_buffer,"​key:​KEY PRESS"​); ​  +
-                    else   +
-                        sprintf((char *)send_buffer,"​key:"​); ​  +
-                    USBD_HID_SendReport(&​hUsbDeviceHS,​send_buffer,​64);​  +
-                }          +
-            }          +
-        }   +
-        //​接收命令处理 +
-        if(usb_receive_flag == 1){   +
-            usb_receive_flag = 0;   +
-            memcpy(buffer,​usb_receive_buffer,​usb_receive_counter); ​  +
-            memset(usb_receive_buffer,​0,​usb_receive_counter); ​  +
-            for(i = 0;i < 64;​i++){ ​  +
-                buffer[i] = tolower(buffer[i]); ​  +
-            }   +
-            command_process(buffer); ​  +
-        }        ​+
   }  ​   }  ​
-  +
 </​code>​ </​code>​
-  * 主函数的while循环中通过定时器定时向主机发送时间数据。再过USB处理函数机发送过来的据进接收处理并送入处理函数进行处理实现相应功能。 +  * 对于USB机,需要调用一个重要函数MX_USB_HOST_Process该函数用于实现USB主机通信的核心状态机处理,该函数必须在里面,被循环调用,而且调用频率得比较快才(越快越好)以便及时处理各种事务。注意,MX_USB_HOST_Process函数仅在U盘识别阶段需要频繁反复调用,但是当U盘被识别后,剩下操作(U盘读写),都可以由USB中断处理。 
-=== 2. 时钟函数 ===+=== 2. 用户处理函数 ===
 <code c> <code c>
-void HAL_SYSTICK_Callback(void)  ​+static ​void USBH_UserProcess  ​(USBH_HandleTypeDef *phost, uint8_t id)  ​
 {  ​ {  ​
-    ​//​中断时间1ms, ​ +    ​int i,​j;  ​ 
-static int counter = 0;   +    static ​FRESULT res;   
- +    unsigned char write_buffer[512]; ​  
-    if((counter ​++ % 250) == 0){   +    unsigned char read_buffer[512]; ​  
-        ​systick.second_flag = 1     +    unsigned ​int counter;   
 +  switch(id) ​  
 +  {   
 +  case HOST_USER_SELECT_CONFIGURATION: ​  
 +  break;  
 +  case HOST_USER_DISCONNECTION: ​  
 +  Appli_state ​APPLICATION_DISCONNECT;   
 +  ​break; ​  
 +  case HOST_USER_CLASS_ACTIVE:​  
 +//​f_mount ​  
 +    res = f_mount(&​fatfs,"​0:",​1);  ​ 
 +    if(res != RES_OK){ ​  
 +        USBH_UsrLog("​\r\nf_mount error!"​); ​  
 +        return; ​  
 +    }else{ ​  
 +        USBH_UsrLog("​\r\nf_mount successful!"​); ​  
 +    }      
 +    //​f_open ​  
 +    for(i = 0; i < 512 ; i ++)write_buffer[i] ​i % 256;   
 +    res f_open(&​file,"​0:/​test.txt",​FA_READ | FA_WRITE | FA_OPEN_ALWAYS); ​  
 +    if(res != RES_OK){   
 +        ​USBH_UsrLog("​f_open error!"​)  
 +        return; ​  
 +    }else{ ​  
 +        USBH_UsrLog("​f_open successful!"​);  ​
     }  ​     }  ​
-+    ​//​f_lseek ​  
- +    ​res ​f_lseek(&file,0)  
-</code> +    if(res !RES_OK){   
-  * 通过时钟函数计时,定时向主机发送数据 +        ​USBH_UsrLog("​f_lseek error!"​);     
-=== 3. usb驱动文件修改 ===  +        ​return; ​       
-  * 因为hal库中的驱动没有对hid设备接收函数的处理,需要修改usbd_hid.c文件。主要是添加USBD_HID_DataOut函数,增加对从主机发送的数据接收功能。 +    }else{   
-<code c> +        ​USBH_UsrLog("​f_lseek successful!"​);  ​
-static uint8_t ​ USBD_HID_DataOut ​(USBD_HandleTypeDef *pdev   +
-                              uint8_t epnum  +
-  +
-    if(epnum == HID_EPOUT_ADDR){   +
-        ​usb_receive_counter = USBD_GetRxCount(pdev,epnum);   +
-        ​if(pdev->​dev_state == USBD_STATE_CONFIGURED){   +
-            ​usb_receive_flag = 1;   +
-  USBD_LL_PrepareReceive(pdev,​HID_EPOUT_ADDR,​usb_receive_buffer,​HID_EPOUT_SIZE);   +
-        }  +
     }  ​     }  ​
-  return ​USBD_OK;   +    //​f_write ​  
-+    res = f_write(&​file,​write_buffer,​512,&​counter); ​  
 +    if(res != RES_OK || counter != 512){   
 +        USBH_UsrLog("​f_write error!"​); ​  
 +        return; ​       
 +    }else{ ​  
 +        USBH_UsrLog("​f_write successful!"​); ​  
 +    } //​f_lseek ​  
 +    res = f_lseek(&​file,​0); ​  
 +    if(res != RES_OK){ ​  
 +        USBH_UsrLog("​f_lseek error!"​); ​  
 +        return; ​  
 +    }else{ ​  
 +        USBH_UsrLog("​f_lseek successful!"​); ​  
 +    }  
 +//​f_read ​  
 +    res = f_read(&​file,​read_buffer,​512,&​counter); ​  ​ 
 +    if(res != RES_OK || counter != 512){   
 +return; ​    
 +  }else{ ​  
 +        ​USBH_UsrLog("​f_read successful!"​); ​  
 +    ​  
 +    f_close(&​file); ​  
 +    USBH_UsrLog("​read data:"​); ​  
 +    for(i = 0;i < 32;​i++){ ​  
 +        for(j = 0; j < 16; j ++)   
 +            USBH_UsrLog("​%02X ",​read_buffer[i*16+j]); ​  
 +    }   
 +    memset(read_buffer,​0,​sizeof(read_buffer)); ​  
 +  break; ​  
 +  case HOST_USER_CONNECTION: ​  
 +  Appli_state = APPLICATION_START; ​  
 +  break; ​  
 +  default: ​  
 +  break; ​  
 +  }   
 +}  ​
  
 </​code>​ </​code>​
-  * 修改USBD_HID_Init函数,增加USBD_LL_OpenEP函数语句与USBD_LL_PrepareReceive函数语句保证相应功能初始化+ 
 +=== 3. 打印函数 ​===  
 +  * USBH自带打印输出但是需要向串口4打印输出需要修改相应的打印输出参数在打印调试输出之前需要打开USBH_DEBUG。打开方式参照iCore3_CubeMX教程二十_USBH_MSC或在usbh_conf.h中将宏定义USBH_DEBUG_LEVEL改为
 <code c> <code c>
-/* Open Ep Out */   +  ​#define USBH_DEBUG_LEVEL ​     1U 
-    USBD_LL_OpenEP(pdev,​ HID_EPOUT_ADDR,​ USBD_EP_TYPE_INTR,​ HID_EPOUT_SIZE); ​  ​ +
-    /* Prepare Out endpoint to receive next packet */   +
-    USBD_LL_PrepareReceive(pdev,​ HID_EPOUT_ADDR,​ usb_receive_buffer,​ HID_EPOUT_SIZE); ​+
 </​code>​ </​code>​
-  * 在usbd_hid.h中添加对EPOUT参数地址与大小的定义+  * 打开USBH_DEBUG后,需将打印信息输出到串口4,即将打印信息修改为
 <code c> <code c>
-#define HID_EPOUT_ADDR ​                             0x01   +#if (USBH_DEBUG_LEVEL > 0U)   
-#​define ​HID_EPOUT_SIZE ​                             0x40  +#​define  ​USBH_UsrLog(...)   uart4.printf(__VA_ARGS__);​\ ​  
-</​code>​ +                            uart4.printf("​\r\n"​);  ​ 
-  * 利用上位机hid.exe与iCore3通讯,HID设备的描述符需要进行修改,以便可以与上位机软件进行通讯。主要是对usbd_desc.c 设备描述符与usbd_hid.c配置描述符进行修改。这些描述符决定了HID设备的类型与定义,上位机需要根据这些描述符发出相应的指令控制。直接将程序中的usbd_hid.c文件替换为例程文件的usbd_hid.c。在usbd_desc.c中需要修改USBD_HS_DeviceDesc中的相应描述配置,将宏定义中的一些参数进行修改,即可实现hid描述符的修改。 +#else   
-<code c> +#​define ​USBH_UsrLog(...) do {} while (0)   
-#define USBD_VID ​    ​0x483 ​  +#endif   
-#​define ​USBD_LANGID_STRING ​    ​1033 ​  +   
-#define USBD_MANUFACTURER_STRING ​    "​Gingko" ​  +#if (USBH_DEBUG_LEVEL > 1U)   
-#define USBD_PID_HS ​    ​0x5720 ​  +   
-#​define ​USBD_PRODUCT_STRING_HS ​    "iCore3 in HS mode" ​  +#​define ​ ​USBH_ErrLog(...) do { \   
-#​define ​USBD_SERIALNUMBER_STRING_HS ​    "​00000000001A" ​  +                            uart4.printf("ERROR: ​") ; \   
-#​define ​USBD_CONFIGURATION_STRING_HS ​    "HID Config" ​  +                            uart4.printf(__VA_ARGS__);​ \   
-#define USBD_INTERFACE_STRING_HS ​    "HID Interface" ​  +#​define ​USBH_ErrLog(...) do {} while (0)   
-#define USB_SIZ_BOS_DESC ​           0x0C +#​endif ​    
 +#if (USBH_DEBUG_LEVEL > 2U)   
 +#​define ​ ​USBH_DbgLog(...) ​  do { \   
 +                            uart4.printf("DEBUG : ") ; \   
 +                            ​uart4.printf(__VA_ARGS__);​ \   
 +                            uart4.printf("\r\n"); \   
 +} while (0)   
 +#else   
 </​code>​ </​code>​
 +  * 即可正常向串口4打印调试信息。
 +
 ==== 五、 实验步骤 ==== ==== 五、 实验步骤 ====
   - 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连);   - 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连);
-  - 跳线帽插在USBOTG; +  - 跳线帽插在USB_UART; 
-  - 把iCore3(USB_OTG)通过Micro USB线与计算机相连,为iCore3供电; +  - 把iCore3(USB_UART)通过Micro USB线与计算机相连,为iCore3供电; 
-  - 打开Keil MDK开发环境,并打开本实验工程; +  - 把USB_OTG通过Micor USB线与U盘或者读卡器相连,向此存储设备写入文件; 
-  - 烧写程序到iCore3; +  - 打开Keil MDK 开发环境,并打开本实验工程; 
-  - 也可以进入Debug模式,单步运行或设置断点验证程序逻辑; +  - 打开PuTTY串口中断(注:PuTTY使用方法见附录); 
-  - 打开usb_hid.exe进行验证+  - 烧写程序到iCore3; 
 +  - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。
  
 ==== 六、 实验现象 ==== ==== 六、 实验现象 ====
-  * 点击测试软件的LED控制按钮iCore3上的LED灯的颜色状态将发生变化,点击校准时间,将用电脑系统的时间校准iCore3的部RTC按下iCore3上的ARM-KEY,​按键状态栏将显示按键的状态(如下图示)。 +  * 打开串口终端可以显示操作过程操作完成后可以通过电脑查看U盘是否操作成功,成功后U盘新建一个test.txt文件。 
-{{ :icore3:icore3_arm_hal_19_3.png?direct |}}+{{ :​icore3:​icore3_arm_hal_20_3.png?​direct |}} 
 + 
 +**附录:** 
 +**PuTTY使用方法:** 
 +  * 1、iCore3供电后打开计算机——属性——设备管理器——端口,查看iCore3所占用的COM口; 
 +{{ :icore3:icore3_arm_hal_20_4.png?direct |}} 
 +  * 2、打开PuTTY; 
 +{{ :​icore3:​icore3_arm_hal_20_5.png?​direct |}} 
 +  * 3、烧写程序验证 
  
icore3_arm_hal_20.1587115040.txt.gz · 最后更改: 2020/04/17 17:17 由 fmj