cubeIDE开发, stm32的USB从设备串口驱动设计
创始人
2024-03-27 01:32:09

一、USB_OTG简介

        USB_OTG(OTG,ON THE GO)是一款双角色设备(DRD) 控制器,同时支持从机(USB DEVICE)功能和主机(USB HOST)功能。在主机模式下,OTG 支持全速(OTG_FS,12 Mb/s)和低速(OTG_LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。主机模式下需要的唯一外部设备是提供VBUS的电荷泵。在驱动实现层面,USB OTG是USB Device和USB Host 的基础。在实际使用,USB OTG是USB Device和USB Host 的底层驱动。

        stm32芯片的通常USB物理接口管理两个引脚:

            DP/DM:内置上下拉,由控制器来设置不同类型的需求

        OTG实现时,额外配置ID引脚:
            ID:检测插入的线是B端还是A端,用于区分A类和B类设备,

        USB Host 模式下,需加配置Vbus引脚:
            Vbus:内置检测器,用于测试UBUS的有效性

        额外地需要支持SOF和NOF时,需要加配置SOF和NOF引脚。

        例如本文采用的STM32L496VGT3芯片,其配置支持到的引脚如下:

USB协议栈的层次划分

    一个Host可能有一个或者多个Device
    一个Device可能有一个或者多个Interface
    一个Interface可能有一个或者多个Endpoint

        Host(主机)连的是Device(设备),这一层是走物理连接的,也就是信号线实际连接两台设备。

        Device(设备)下可能有多个Interfece(接口),从这开始是逻辑概念,一个Interface,就是一个独立的功能接口,每个Interface模拟一个设备功能,比如集成了键盘和鼠标的USB设备,里面就是两个interface,一个是键盘,另一个是鼠标。Interface之间通常是隔离的,互相不干扰。
        每个Interface(接口)下面有一个或者多个Endpoint(端点),这也是逻辑概念,例如控制信号端口、数据信号端口等。端点是USB设备通信的基本单位,所有通信几乎都是从端点发起的。

二、创建工程及USB_Device配置

        本博文基于STM32L496VGTX3芯片实现,参考本专栏的博文:

cubeIDE开发, stm32的OLED点亮及字符显示设计(基于SPI通信)_py_free的博客-CSDN博客_stm32 hal spi oled

        基于该工程的(.ioc)文件创建了新工程stm32L496VGTx_USB,并移植了相关源码,实现了lpusart通信以及lcd显示字体。

        现打开工程的(.ioc)配置文件,进入cubeMX配置界面,开启USB_OTG_FS的USB Device功能,参数保持默认配置。

        确保USB_OTG_FS的中断功能已经开启。

         开启USB_OTG_FS的USB Device选项后,Middleware栏目可以去配置USB_Device信息,本文MCU作为USB_Device与笔记本电脑USB_HOST相连接,实现串口通信收发数据,因此选择通信类型虚拟串口功能,如下图所示,参数保持默认。

         设备描述符按默认设置:

         由于USB驱动引入了中间件代码,并比较复杂,需要更多缓存支持,现进入工程配置页面,调整min heap size和min stack size为合适的值,防止因数值较少而出现无法编译、编译异常、运行错误等情况出现。

         点击保存输出生成代码,关于USB_Device驱动相关代码如下,其中usb_cdc_if.h/c源码是用户可修改源文件:

 三、USB_Device驱动实现设计

        【1】在usb_cdc_if.h中,添加USB相关全局变量(接收缓存数组、最大长度、接收标记及长度)

/* USER CODE BEGIN INCLUDE */
#define USB_REC_LEN   256//定义USB串口最大接收字节数
extern uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.末字节为换行符
extern uint16_t USB_RX_STA;//接收状态标记(接收到的有效字节数量)
/* USER CODE END INCLUDE */

        【2】在usb_cdc_if.h中,添加USB打印输出函数USB_printf声明

/* USER CODE BEGIN EXPORTED_VARIABLES */
void USB_printf(const char *format,  ...);//USB模拟串口的打印函数
/* USER CODE END EXPORTED_VARIABLES */

        【3】在usb_cdc_if.c中,调整USB接收函数

static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{/* USER CODE BEGIN 6 *///新增代码开始处if(*Len

        【4】在usb_cdc_if.c中,调整USB发送函数

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{uint8_t result = USBD_OK;/* USER CODE BEGIN 7 *///注释旧代码
//  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
//  if (hcdc->TxState != 0){
//    return USBD_BUSY;
//  }
//  USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len);
//  result = USBD_CDC_TransmitPacket(&hUsbDeviceFS);//新增新代码uint32_t TimeStart = HAL_GetTick();USBD_CDC_HandleTypeDef *hcdc =  (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;while(hcdc->TxState){if(HAL_GetTick()-TimeStart > 10)return USBD_BUSY;elsebreak;}USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf,  Len);result =  USBD_CDC_TransmitPacket(&hUsbDeviceFS);TimeStart = HAL_GetTick();while(hcdc->TxState){if(HAL_GetTick()-TimeStart > 10)return USBD_BUSY;}/* USER CODE END 7 */return result;
}

        【5】在usb_cdc_if.c中,实现USB打印输出函数USB_printf定义

/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */
#include 
void USB_printf(const char *format, ...)//USB模拟串口的打印函数
{va_list args;uint32_t length;va_start(args, format);length = vsnprintf((char  *)UserTxBufferFS, APP_TX_DATA_SIZE, (char  *)format, args);va_end(args);CDC_Transmit_FS(UserTxBufferFS, length);
}
/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */

        【6】在main.c文件中,添加USB驱动头文件支持

/* USER CODE BEGIN Includes */
#include "../../ICore/led/led.h"
#include "../../ICore/oled/oled.h"
#include "../../USB_DEVICE/App/usbd_cdc_if.h"
/* USER CODE END Includes */

        【7】在main主函数初始化处

  /* USER CODE BEGIN 2 */OLED_init();//设置OLED蓝色背景显示BSP_LCD_Clear_DMA(LCD_DISP_BLUE);printf("OLED_Clear_DMA\r\n");/* USER CODE END 2 */

         【8】在main主函数循环体内实现

  /* USER CODE BEGIN WHILE */while (1){//USB模拟串口的查寻接收处理(其编程原理与USART1串口收发相同)if(USB_RX_STA!=0)//判断是否有数据{OLED_printf(10,42,"%.*s",USB_RX_STA, USB_RX_BUF);Toggle_led1();USB_RX_STA=0;//数据标志位清0memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0HAL_Delay(10);//等待}/* USER CODE END WHILE */

四、编译及下载

        编译下载,该开发板原理框图,需要将跳线帽重新插拔设置,相当于原理的USB-ST-LINK连接到USB_MCU上,即原理lpusart通信及ST-LINK下载的USB接口改为连接到USB_MCU的DM/DP引脚上实现通信。

         更改调线帽后,打开串口工具,发送数据,顺利在点(10,42)位置绘制输入文字,LED1等会切换状态。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...