用户工具

站点工具


icore3_arm_hal_21

差别

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

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
icore3_arm_hal_21 [2020/04/18 17:30]
fmj
icore3_arm_hal_21 [2022/03/18 15:10] (当前版本)
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-18 ​ |  gingko ​ |  初次建立 ​ | |  V1.0  |  2020-04-18 ​ |  gingko ​ |  初次建立 ​ |
行 10: 行 9:
 \\ \\
 \\ \\
 +
  
 ===== STM32CubeMX教程二十一——虚拟串口 ===== ===== STM32CubeMX教程二十一——虚拟串口 =====
行 89: 行 89:
 === 2、USB_CDC ===  ​ === 2、USB_CDC ===  ​
   * USB2.0标准下定义了很多子类,有音频类,CDC类,HID,打印,大容量存储类,HUB,智能卡等等,这些在usb.org官网上有具体的定义,这里主要介绍通信类CDC。CDC(Communication Device Class)类是USB2.0标准下的一个子类,定义了通信相关设备的抽象集合。   * USB2.0标准下定义了很多子类,有音频类,CDC类,HID,打印,大容量存储类,HUB,智能卡等等,这些在usb.org官网上有具体的定义,这里主要介绍通信类CDC。CDC(Communication Device Class)类是USB2.0标准下的一个子类,定义了通信相关设备的抽象集合。
-USB的CDC类是USB通信设备类(Communication Device Class)的简称。CDC类是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通信设备)使用的USB子类。根据CDC类所针对通信设备的不同,CDC类又被分成以下不同的模型:USB传统纯电话业务(POTS)模型,USBISDN模型和USB网络模型,其中USB传统纯电话业务模型又可分为直线控制模型(Direct Line Control Model)、抽象模型、电话模型。虚拟串口就属于USB传统纯电话业务模型下的抽象控制模型。 +  * USB的CDC类是USB通信设备类(Communication Device Class)的简称。CDC类是USB组织定义的一类专门给各种通信设备(电信通信设备和中速网络通信设备)使用的USB子类。根据CDC类所针对通信设备的不同,CDC类又被分成以下不同的模型:USB传统纯电话业务(POTS)模型,USBISDN模型和USB网络模型,其中USB传统纯电话业务模型又可分为直线控制模型(Direct Line Control Model)、抽象模型、电话模型。虚拟串口就属于USB传统纯电话业务模型下的抽象控制模型。 
-USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信。其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的。之所以会有虚拟串口操作,主要是我们通常使用PC作为Host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口,这样一来,可以方便PC端软件通过操作串口的方式来与其进行通信,但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB操作。需要注意的是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率、驱动访问USB外设有效速率(两边)以及外部环境对通信本身造成的干扰率等因素组成。 +  ​* ​USB CDC类的通信部分主要包含三部分:枚举过程、虚拟串口操作和数据通信。其中虚拟串口操作部分并不一定强制需要,因为若跳过这些虚拟串口的操作,实际上USB依然是可以通信的。之所以会有虚拟串口操作,主要是我们通常使用PC作为Host端,在PC端使用一个串口工具来与其进行通信,PC端的对应驱动将其虚拟成一个普通串口,这样一来,可以方便PC端软件通过操作串口的方式来与其进行通信,但实际上,Host端与Device端物理上是通过USB总线来进行通信的,与串口没有关系,这一虚拟化过程,起决定性作用的是对应驱动,包含如何将每一条具体的虚拟串口操作对应到实际上的USB操作。需要注意的是,Host端与Device端的USB通信速率并不受所谓的串口波特率影响,它就是标准的USB2.0全速(12Mbps)速度,实际速率取决于总线的实际使用率、驱动访问USB外设有效速率(两边)以及外部环境对通信本身造成的干扰率等因素组成。 
-CDC类软件框架 +  ​* ​CDC类软件框架 
- +{{ :​icore3:​icore3_arm_hal_21_1.png?​direct |}} 
- +  * 如上图黄色USB Device Core部分为USB设备库文件,​属于中间件,​它为USB协议栈的核心源文件一般不需要修改: 
-=== 3、USB MSC Device == +  * USB Device Core,​Log/​debug为打印/​调试开; 
-  * 我们关注的U盘就是所谓的MSC设备,大容量存储设备。 +  * core为USB设备核心;​ 
-  * U盘的功能,就是数据存储。而对应的数据传输,用的是USB中的Bulk Transfer。 +  * USB request中定义了枚举过程中各种标准请求的理; 
-=== 4、USB MSC相的协议 === +  * I/O request为底层针对USB通信接口封装。 
-  * USB MSC Bulk-Only (BBB) Transport +  * 黄色USB Device Class部分为USB类文件也属于中间件,​USB设备库目前ST DEMO中支持类有HID, Customer HID, CDC, MSC, DFU, Audio, ST提供了这些类源码框架其他Class或者是复合设备需要自己根据实际需求情况进行扩展或制。果用户需求只是需要一个标准类,比CDC通信,那么最好就使用代码不需要任何修改就可以实现这个CDC类通信的功能。 
-  * 如上所述,Bulk-only是USB设备端,此的U盘和USB Host端,即普PC,之间息交换协议。Bulk Only Transport,也被简称为BOT。 +  * 蓝色USB Device HAL Driver为HAL库部分,是对USB外设接口封装属于底层驱动,不需要修改,它分为PCDLL Driver,PCD处于LL Driver之上。 
-  * USB MSC USB Attached SCSI Protocol (UASP) +  * 洋红色USB Device Configuration为USB配置封装,位于USB底层HAL层驱动与中间件USB协议栈之间,一方面向上层(USB设备库)提供各操作调接口,另一方面,向底层USB驱动提供各种回调接口。正是由它的存在,使得USB协议栈(USB设备库)与底层硬件完全分离从而使USB设备库具有更加兼容有STM32的通用性。USB Device Configuration为开放给用户的源文件,用户可根据自己某些特殊需要进行修改也可以使默认的源文件,假如没有任何特殊要求的话,我们使用默认即可。 
-  * “Attached”顾名思义是附在某个上面的此处即附在SCSI协议上面的,即SCSI协议补充部分。 +  Application为应用层USB Device Class有可能将自己应该的操作接口封装在一个操作数据结构中,由应用具体实现这些操作在系统初始化时,由应用将已经定义好的操作接口注册到应的USB类中比如usbd_cdc_if, 就这样,使得用层应用代码与属于中间件层的USB协议栈分离。同时USB协议栈会将一些字符串描述符放到APP中,当USB初始化时将这些已经定义好字符串通过指针初始化到USB协议栈中,以便后续需要时获取。 
-  * UASP规范,义了关于何在USB 2.0和USB 3.0中,UAS的传输标准何实现的,并且给出了一些范例和一些推荐的法。 +  * USB_CDC类详细内容可参考《USB_CDC类入门培训》。 
-{{ :​icore3:​icore3_arm_hal_20_1.png?​direct |}} +=== 3USBD_VCP实验介绍 == 
-  * 如上图,我们U盘实现的功能,主要就数据读写而DeviceHost之间的数据通信主要有两: +  * USBH_VCP实验是用STM32F407的USB接口通过STM32_HAL库生成的代码达到iCore3上的USB接口实现虚拟串口的功能。 
-    * CBI:主要用于Floppy设备,所以设备都很少此协议 +=== 4、实验内容: ​=== 
-    BOT:Bulk-Only Transport也称BBB(Bulk/​Bulk/​Bulk),而于BOT/BBB,对其提高USB总线利用率提高了USB速度后,就是对应的UASP协议,故此处称UASP为BOT的增强版的协议。 +  * 通过移植STM32_HAL库提供的代码来实现STM32虚拟串口功能,然后就可以像操作串口一样操作USB,本实验实现终端发送数据,STM32将接收到数据直接返回给终端,验证发送和接收。 
-=== 5USBH_MSC实验介绍 ​=== +{{ :​icore3:​icore3_arm_hal_21_2.png?​direct |}}
-  * 硬件框架图: +
-{{ :​icore3:​icore3_arm_hal_20_2.png?​direct&​600 |}} +
-  * USBH_MSC实验是用STM32F407的USB接口实现iCore3作为主机对U盘(即USB大容量存储器)实现读/写操作并通过串口打印到电脑上并显示实验。 +
-  ​* ​实验内容: +
-    * 通过cube MX库提供的代码来实现STM32对U盘或者读卡器等大容量USB存储设备的读写操作,本实验是向存储设备中新建一个名为test.txt的文件,并向文件中写入数据,待写入成功后,读出文件内容,并通过终端显示出来。 +
 ==== 四、 实验程序 ==== ==== 四、 实验程序 ====
  
行 123: 行 117:
   SystemClock_Config();  ​   SystemClock_Config();  ​
   MX_GPIO_Init();  ​   MX_GPIO_Init();  ​
-  ​MX_UART4_Init();   +  ​MX_USB_DEVICE_Init();   
-  ​MX_FATFS_Init();   +  ​LED_GREEN_ON;   
-  ​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)  ​
   {  ​   {  ​
-    MX_USB_HOST_Process(); ​  + 
-    LED_RED_ON; ​ +
   }  ​   }  ​
  
 </​code>​ </​code>​
-  * 对于USB机,需调用一个重要函数MX_USB_HOST_Process该函数用于实现USB主机通信的核心状态机处理,该函数必须主函数里面,被循环调用而且调用频率得比较快才行(越快越好),以便及时处理各种事务。注意,MX_USB_HOST_Process函数仅U盘识别阶段,需要频繁反复调用,但是当U盘被识别后,剩下的操作(U盘读写),都可以由USB断处理。 +  * 主程序主打开了LED_GREEN,在while循环中并没有写任何内容接受发送处理文件主要usb_cdc_if.c中。 
-=== 2. 用户处理函数 ===+=== 2. 接受回调函数: ===
 <code c> <code c>
-static ​void USBH_UserProcess  ​(USBH_HandleTypeDef ​*phostuint8_t id)  ​+static ​int8_t CDC_Receive_HS(uint8_tBufuint32_t *Len)  ​
 {  ​ {  ​
-    int i,j;   +  ​/* USER CODE BEGIN 11 */   
-    static FRESULT res;   +  ​USBD_CDC_SetRxBuffer(&hUsbDeviceHS, &Buf[0]);   
-    unsigned char write_buffer[512]; ​  +  ​USBD_CDC_ReceivePacket(&hUsbDeviceHS);   
-    unsigned char read_buffer[512]; ​  +   CDC_Transmit_HS(Buf,(uint16_t)(*Len));   
-    unsigned int counter; ​  +  return (USBD_OK);   
-  switch(id) ​  +  ​/USER CODE END 11 */  
-  {   +
-  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);   +
-    ​if(res != RES_OK){ ​  +
-        USBH_UsrLog("​f_lseek error!"​); ​    +
-        return; ​       +
-    }else{ ​  +
-        USBH_UsrLog("​f_lseek successful!"​); ​  +
-    }   +
-    //​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>​
- +=== 3. 发送函数 === 
-=== 3. 打印函数 ===  +
-  * USBH自带打印输出,但是需要向串口4打印输出,需要修改相应的打印输出参数。在打印调试输出之前需要打开USBH_DEBUG。打开方式参照iCore3_CubeMX教程二十_USBH_MSC或在usbh_conf.h中将宏定义USBH_DEBUG_LEVEL改为+
 <code c> <code c>
-  #define USBH_DEBUG_LEVEL ​     1U  + uint8_t CDC_Transmit_HS(uint8_tBuf, uint16_t Len)   
-</​code>​ +  
-  ​* ​打开USBH_DEBUG后,需将打印信息输出到串口4,即将打印信息修改为 +  uint8_t result = USBD_OK;   
-<code c> +  ​/* USER CODE BEGIN 12 */   
-#if (USBH_DEBUG_LEVEL > 0U)   +  ​USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceHS.pClassData; ​  
-#​define ​ USBH_UsrLog(...) ​  ​uart4.printf(__VA_ARGS__);  +  if (hcdc->TxState != 0)  
-                            ​uart4.printf("​\r\n"​); ​  +    ​return USBD_BUSY; ​  
-#else   +  ​  
-#define USBH_UsrLog(...) do {} while (0)   +  ​USBD_CDC_SetTxBuffer(&​hUsbDeviceHS,​ Buf, Len);   
-#​endif ​  +  ​result = USBD_CDC_TransmitPacket(&​hUsbDeviceHS)  
-   +  ​/* USER CODE END 12 */   
-#if (USBH_DEBUG_LEVEL ​1U)   +  ​return result;   
-   +}  ​
-#​define ​ USBH_ErrLog(...) do { \   +
-                            ​uart4.printf("​ERROR:​ ") ; \   +
-                            uart4.printf(__VA_ARGS__);   +
-#define USBH_ErrLog(...) do {} while (0)   +
-#​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打印试信息 +  * CDC_Transmit_HS是发送函数,指定数据首地址和字节长度,数据就会发送到串口,底层是USB库实现的。CDC_Receive_HS是接收到收据后的回函数,数据是收到一帧后才调用的CDC_Receive_HS,所以每次的字节长度不一定相同,传入的两个参数是数据缓存首地址和数据长度。这里简单的将接收到的数据原样返回,实现数据回环,只需要在CDC_Receive_HS函数添加一行调用CDC_Transmit_HS函数即可
 ==== 五、 实验步骤 ==== ==== 五、 实验步骤 ====
   - 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连);   - 把仿真器与iCore3的SWD调试口相连(直接相连或者通过转接器相连);
   - 将跳线帽插在USB_UART;   - 将跳线帽插在USB_UART;
-  - 把iCore3(USB_UART)通过Micro USB线与计算机相连,为iCore3供电; +  - 把iCore3通过Micro USB线与计算机相连,为iCore3供电;
-  - 把USB_OTG通过Micor USB线与U盘或者读卡器相连,向此存储设备写入文件+
   - 打开Keil MDK 开发环境,并打开本实验工程;   - 打开Keil MDK 开发环境,并打开本实验工程;
-  - 打开PuTTY串口中断(注:PuTTY使用方法见附录); 
   - 烧写程序到iCore3上;   - 烧写程序到iCore3上;
 +  - 打开Commix串口终端(注:Commix使用方法见附录);
   - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。   - 也可以进入Debug 模式,单步运行或设置断点验证程序逻辑。
  
 ==== 六、 实验现象 ==== ==== 六、 实验现象 ====
-  * 打开串口终端可以显示操作过程操作完成后可以通过电脑查看U盘是否操作成功,成功后U盘内新建一个test.txt文件。 +  * 终端发送“HelloI’M iCore3.”,STM32将接收到的消息又直接返回给终端,现象如下: 
-{{ :icore3:icore3_arm_hal_20_3.png?direct |}}+{{ :icore3:icore3_arm_hal_21_3.png?direct |}} 
 + 
 + 
 + 
  
 **附录:** **附录:**
-**PuTTY使用方法:** +  ​* 1、驱动安装:打开本实验文件夹中的驱动文件夹双击VCP_V1.4.0_Setup.exe,​开始安装虚拟串驱动。按照顺序安装即可。 
-  ​* 1、iCore3供电后,打开计算机——属性——设备管理器——端口查看iCore3所占用的COM +{{ :icore3:icore3_arm_hal_21_4.png?direct |}} 
-{{ :icore3:icore3_arm_hal_20_4.png?direct |}} +  * 2、安装完成后并下载程序设备上将会显示相应的端口 
-  * 2、打开PuTTY; +{{ :icore3:icore3_arm_hal_21_5.png?direct |}} 
-{{ :icore3:icore3_arm_hal_20_5.png?direct |}} +
-  * 3、烧写程序验证+
  
  
icore3_arm_hal_21.1587202240.txt.gz · 最后更改: 2020/04/18 17:30 由 fmj