文章目录
官网demo
软件代码在官网是存在的:STSW-STM32046
开发板对应的是 : en.stm32_f105-07_f2_f4_usb-host-device_lib\Project\USB_Device_Examples\AUDIO\readme.txt
基于官网demo考虑的事情
产品特性:
usb标准
全速?
hid?
硬件设计
软件设计
ST官网提供的usb代码的架构及接口
usb代码的架构及接口
我们在 USB (三)STM32 USB 代码库中写到了usb开发相关的文件,此次以 usb device 开发为例,考虑以下事情
文件为什么按照官方提供的文件夹分类(即ST的usb架构)
USB部分需要哪些文件,缺不缺文件
哪些文件需要修改,怎么改
上位机与下位机通信流程(抓出来) // 其中包括 上位机 对下位机的显示部分
上位机需不需要驱动
上位机有没有通用软件可以控 usb device?如果有,控一下
USB 数据流程
USB中断
// OUT 是 host -> device , 是以 host 为 目标 说的
// IN 是 host <- device
// 异常向量表中 有 一下 异常入口 需要实现
OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 In
//当上位机发送数据时,中断产生
OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 Out
//当下位机发送数据时,中断产生
OTG_HS_WKUP_IRQHandler
// 目前没有实现
OTG_HS_IRQHandler
// 发生了很多次
STM32F40X的与OTG相关的异常向量表如下
OTG_FS_WKUP_IRQHandler // USB OTG FS Wakeup through EXTI line interrupt // stm32 官方库的例子有些会 enable
// 参考 STM32_USB-Host-Device_Lib_V2.2.0/Project/USB_Device_Examples/Composite_Examples/MSC_HID_Composite/src/stm32fxxx_it.c
OTG_FS_IRQHandler // USB OTG FS global Interrupt
OTG_HS_WKUP_IRQHandler // USB OTG HS Wakeup through EXTI interrupt // stm32 官方库的例子有些会 enable
OTG_HS_IRQHandler // USB OTG HS global interrupt
// 参考 https://blog.csdn.net/sinat_20006769/article/details/79081244
--- 这两个 FS 和 HS 通用
OTG_HS_EP1_OUT_IRQHandler // USB OTG HS End Point 1 Out global interrupt
OTG_HS_EP1_IN_IRQHandler // USB OTG HS End Point 1 In global interrupt
所以 组合有两种
FS : OTG_FS_IRQHandler & OTG_FS_WKUP_IRQHandler & OTG_HS_EP1_OUT_IRQHandler & OTG_HS_EP1_IN_IRQHandler
HS : OTG_HS_IRQHandler & OTG_HS_WKUP_IRQHandler & OTG_HS_EP1_OUT_IRQHandler & OTG_HS_EP1_IN_IRQHandler
各个中断的发生时刻
只要插上usb ,就会一直 有 OTG_HS_IRQHandler 会进入 // 断开就没有了
上位机发送数据给 下位机, OTG_HS_EP1_OUT_IRQHandler 才会进入
下位机发送数据给 上位机, OTG_HS_EP1_IN_IRQHandler 才会进入
枚举 复位 挂起 唤醒
- OTG_HS_WKUP_IRQHandler
唤醒应该在 OTG_HS_WKUP_IRQHandler // TODO
- OTG_HS_IRQHandler
OTG_HS_IRQHandler ->
USBD_OTG_ISR_Handler
DCD_HandleUSBSuspend_ISR // 拔掉usb动作1
USBD_DCD_INT_fops->Suspend (pdev); // 即 USBD_DCD_INT_cb->Suspend // 即 USBD_Suspend
pdev->dev.usr_cb->DeviceSuspended(); // 即 USR_cb-> DeviceSuspended // 即 USBD_USR_DeviceSuspended
DCD_OTG_ISR // 拔掉usb动作2
USBD_DCD_INT_fops->DevDisconnected (pdev);
USBD_USR_DeviceDisconnected
DCD_SessionRequest_ISR // 连接动作1
USBD_DCD_INT_fops->DevConnected (pdev);
USBD_USR_DeviceConnected
DCD_HandleUsbReset_ISR // 连接动作2
USBD_DCD_INT_fops->Reset(pdev);
USBD_USR_DeviceReset
DCD_HandleOutEP_ISR // 连接动作3
USBD_DCD_INT_fops->SetupStage(pdev); // 即USBD_SetupStage
USBD_StdDevReq
USBD_GetDescriptor // 获取描述符
pbuf = pdev->dev.usr_device->GetDeviceDescriptor(pdev->cfg.speed, &len);
USBD_CtlSendData (pdev,pbuf,len);
USBD_SetConfig
USBD_SetCfg
USBD_DCD_INT_fops->DeviceConfigured(pdev);
USBD_USR_DeviceConfigured
DCD_HandleResume_ISR // 没调用过
...
USBD_USR_DeviceResumed
TODO : USBD_USR_DeviceResumed 在什么是时候 被调用
usb device 收数据 以 MSC 为例
- OTG_HS_EP1_OUT_IRQHandler
OTG_HS_EP1_OUT_IRQHandler
USBD_OTG_EP1OUT_ISR_Handler
USBD_DCD_INT_fops->DataOutStage(pdev , 1); //即USBD_DataOutStage
//usb device 库 中的 core 部分 usbd_core.c 决定了 这个 函数指针的值
pdev->dev.class_cb->DataOut(pdev, epnum);//即USBD_MSC_DataOut
//sb device 库 中的 class 部分 usbd_msc_core.c 提供了 USBD_MSC_DataOut
//在 USBD_Init 中被指定
MSC_BOT_DataOut
gUsbRecPacket.DataPtr = pdev->dev.out_ep[1].xfer_buff;
gUsbRecPacket.Len = pdev->dev.out_ep[1].xfer_count;
g_Req ++;
usb device 发数据 以 MSC 为例
- OTG_HS_EP1_IN_IRQHandler
// 1. 产生中断(是发送完时产生的中断)
DCD_EP_Tx(&USB_OTG_dev, MSC_IN_EP, ptr, len); // ptr 为 数据起始地址, len 为长度
USB_OTG_EPStartXfer(pdev, ep );
USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPTSIZ, deptsiz.d32);
USB_OTG_MODIFY_REG32(&pdev->regs.DREGS->DIEPEMPMSK, 0, fifoemptymsk);
// 开启传输, 下面就会进入 OTG_HS_EP1_IN_IRQHandler 中断
USB_OTG_WRITE_REG32(&pdev->regs.INEP_REGS[ep->num]->DIEPCTL, depctl.d32);
// 2. 实际发送过程,
// 是硬件自己做的
// 3. 发送完成时的中断
OTG_HS_EP1_IN_IRQHandler
USBD_OTG_EP1IN_ISR_Handler (&USB_OTG_dev);
USBD_DCD_INT_fops->DataInStage(pdev , 1); // 即 USBD_DataInStage
pdev->dev.class_cb->DataIn(pdev, epnum); // 即USBD_MSC_DataIn
MSC_BOT_DataIn
gSentCount++;
应用处理流程
收 是 中断收的
发 是 拷贝数据到FIFO中,然后让硬件发的,硬件发完会产生中断
如果要 在 应用中 通过 usb 收发数据,怎么弄
1. "中断收完了" 需要让应用知晓 , 然后 应用 去 处理 收到的 usb数据(在全局变量中)
2. 发数据的时候, 直接 写 硬件寄存器 "驱使硬件自动发送" , 然后等待 "处理完成中断" 就行了
stm32f405 有 一个 端点 : EL1 , 有没有 EL0 ? // 好像EL1 是 默认可用的
端点,实际上是设备硬件上具有一定大小的数据缓冲区。
USB系统中,每一个端点都有唯一的地址,是有设备地址和端点号给出的。
// TODO 默认设置端点0用作控制传输端点,其他端点必须在设备被主机配置后才能使用。
端点可以描述为数据源或接收器,并且仅存在于USB设备中。
可以从USB主机接收或等待将其存储在端点上的数据。
可以将端点配置为USB规范中定义的四种传输类型之一(控制传输,中断传输,同步传输和批量传输)。
在硬件限制内,可以使用USB协议栈配置端点(例如,将端点限制为某种传输类型)。
例如
EP0(控制传输,双向,0x00,0x80),
EP1(批量传输,双向,0x01,0x81),
EP2(同步传输,双向,0x02,0x82)。
端点充当一种缓冲区。
设备收数据
USB主机的客户端可以将数据发送到端点1。
来自USB主机的数据将发送到OUT端点1。
准备就绪后,微控制器上的程序将立即读取数据。
设备发数据
由于程序无法自由访问USB总线(USB总线由USB主机控制),因此必须将返回数据写入IN端点1。
IN端点1中的数据将保留在那里,直到主机向端点1发送一个IN数据包以请求数据为止。
一个设备最多可以有16个OUT和16个IN端点。// 端点的总数和每个端点支持的功能由硬件定义。
每个端点只能有一个传输方向。// TODO?
端点 0仅用于控制传输,不能分配任何其他功能。// TODO?
OUT始终是指从主机指向设备的方向。
IN始终指指向主机的方向。
其他
描述符
USBD_DEVICE USR_desc =
{
USBD_USR_DeviceDescriptor, // 返回 VID和PID , 设备类在这里吗 ? TODO
USBD_USR_LangIDStrDescriptor,
USBD_USR_ManufacturerStrDescriptor,
USBD_USR_ProductStrDescriptor, // 返回 设备名
USBD_USR_SerialStrDescriptor,
USBD_USR_ConfigStrDescriptor,
USBD_USR_InterfaceStrDescriptor,
};
USBD_Init(&USB_OTG_dev,USB_OTG_HS_CORE_ID,&USR_desc,&USBD_MSC_cb,&USR_cb);
pdev->dev.class_cb = class_cb;
pdev->dev.usr_cb = usr_cb;
pdev->dev.usr_device = pDevice;
USBD_SetupStage
USBD_StdDevReq
USBD_GetDescriptor
pbuf = pdev->dev.usr_device->GetDeviceDescriptor(pdev->cfg.speed, &len);
USBD_CtlSendData (pdev,pbuf,len);