USB的初始化

前言 

     最近学习了USB2.0的一些知识,这里就当笔记,回顾记录一下,参考的资料是B站的刘凯老师STM32 培训教程和龙虎老师的USB应用精粹分析,如果有哪些错误的理解,也希望大佬们指点一二,谢谢!

前面也说了USB的一些基本概念,但是作为软件开发学习的时候看这些还是空洞,我还是更喜欢看代码,从代码里知道整个工作流程,然后从这些工作流程反推一些USB的知识,我后面是以ST的USB官方例程来看这些,下面就是我个人的一些理解,简单讲一下USB的初始化过程。

是这个版本的代码

b6f82da5aea8457a89dba6064b3784e5.png

无论学习单片机哪个外设的开发,寄存器的学习是一定要的,

1.USB_ISTR寄存器,

他是USB的中断状态寄存器,当事务完成一次传输的时候, CTR位置都会被硬件置位。

事务传输针对的端点号就在EP_ID[3:0]中,

如果是方向呢?从机到主机?还是主机到从机?他是在DIR位上,

如果DIR为1则代表一个OUT事务完成,DIR为0则代表一个IN事务完成

注意:CTR DIR EP_ID 都是只读的。我们要做的就是读取这三个位上的信息做不同处理

0158c4071a464d2d8637802474e05999.png

2.USB_EPnR寄存器

他是端点寄存器,当USB_ISTR寄存器DIR为0的时候则代表一个IN事务完成,此时CTR_TX就会被硬件置位,如果是DIR为1的时候,代表一个OUT事务完成,此时CTR_RX就会被硬件置位,那如果是SETUP事件呢,那么相应CTR_RX和SETUP位都会被置位,那么我们通过判断SETUP位,就能指代发生的是OUT事件还是SETUP事件。

cb09ff0ad8184e168c0c9d57ebcbcd2b.png

3.USB_CNTR寄存器

adca9d7bb74d4863b95ef6291d725c2e.png

代码环节

简单介绍了几个寄存器,我们就进入代码环节了.

1.第一个就是 usb_regs.h 头文件

为了方便我们使用USB控制器,官方定义了大量的宏定义来便捷我们操作底层寄存器,我其实我们以后用到别的芯片时候可以把他们复制过来,改写一下就好了。我简单介绍一下吧,_SetCNTR函数就是用来设置 USB_CNTR寄存器,_GetCNTR函数就是用来获取CNTR寄存器的值,_pEPTxAddr函数用来设置端点对应发送包缓冲区的起始地址,_pEPRxCount函数用来设置接收包缓冲区的字节数

be4ddd5182e24952a1dadc06ec085de4.png2.看看USB控制器如何被初始化

首当其冲肯定就是main.c,前面两个设置中断优先级和设置USB控制时钟,

最重要的就是USB_Init();

b74252a651904dbc90e916ccabc2cc85.png

1.USB_Init()被定义在usb_init.c中6be95087e39e43f69c4f483c7d6ba481.png

首先注意在这里面定义了几个全局变量,都是很重要的

第一个就是 EPindex 用来保存当前的端点号,指出当前传输完成的事务是针对哪个端点,

对应我们上面USB_ISTR寄存器中的EP_ID[3:0],实际工作中我们会把其数据读出来放在EPindex中

DEVICE_INFO,DEVICE_PROP,USB_STANDARD_REQUESTS 这三个结构体都在usb_core.h

2.usb_core.h

a1d056ed9b9b4cefabfe30721afe8d01.png

(1)DEVICE_INFO结构体就是用来保存当前设备的相关信息

前五个字段表示接收到的请求,也就是主机通过控制管道往设备发送SETUP事务中的数据包信息

而剩下的那些uint8_t类型的变量表示当前设备的控制管道状态 特征 配置  接口信息  就是设备接收到主机请求的执行结果 (其实这里说的基本都是端点0 的枚举时刻 )

最后那个结构体ENDPOINT_INFO ,他有几个成员,分别就是以下作用

获取描述符的时候

wLength表示设备有多少个数据需要发送

wOffset表示要发送的描述符数组的偏移量

PacketSize表示每次发送数据包的字节大小

函数指针CopyData指向数据发送或接收的函数

(2)DEVICE_PORP表示设备属性结构体

前十个都是函数指针,函数指针就是某个函数的入口地址,这些函数具体是我们实现的,也就是回调函数

(3) USB_STANDARD_REQUESTS结构体是用来响应主机的标准请求

这个结构体里也都是函数指针,用户代码和标准请求管理之间的接口

中断掩码变量 wInterrupt_Mask  默认为0被用来设置USB_CNTR寄存器

来看看USB_Init()做了啥事吧

(1)首先就是把代表设备信息的全局变量赋值给 pInformation 指针 也就是后面我们操控设备信息都可以直接用指针了。

(2)接下来我们设置控制状态为 2  就是USB_core.h 中的输入数据状态

这个结构体 _CONTROL_STATE里面(控制传输分为初始设置时期,数据时期这个可选,状态时期,这三种时期,因为在进行一个个事务传输的时候,USB控制器只知道一个个事务是不知道所处在的状态的,比如控制传输初始建立时期后出现了一个IN事务,那么他到底是数据时期还是状态时期呢,这时候这个结构体就起作用了 )

(3)就是将Device_Property结构体的地址赋值给pProperty指针

Device_Property这个结构体里都是函数,pProperty指针里都是函数指针,为了解耦,都是回调函数了

(4)就是将User_Standard_Requests结构体的地址赋值给pUser_Standard_Requests指针

(5)最后pProperty指针调用了初始化函数 进行初始化 执行的是void Joystick_init(void)

08fd44ba216543bcbd96e0903ad76b77.png

  Get_SerialNum();//更新设备序列号里的字符串描述符
  pInformation->Current_Configuration = 0; //表示当前设备未配置


  PowerOn 函数 

c8f069df6e51411cbdbc0ed1938c731d.png

 (1)拉低控制三极管开关电路的引脚为PD9 让上拉电阻与D+信号线相连,不过这里硬件直接相连了。

 (2)设置USB_CNTR寄存器的FRES位,置一,强制复位,同时清除PDWN位,退出断电模式

 (3)紧接着又全部清除了USB_ISTR寄存器中所有的中断请求位置,

    然后仅仅使能了CNTR寄存器里USB复位,挂起,唤醒这三个中断屏蔽位

  USB_SIL_Init();

又全部清除一遍ISTR寄存器

然后使能了 IMR_MSK 对应的 正确传输(CTR)  出错(ERR) 唤醒(WKUP)挂起(SUSP)

复位(RESET) 帧首(SOF) 期望帧首(ESOF) 这些中断掩码位(固件库里是有响应这些中断的中断服务函数)

c1ae453639c3458a8d347de1588706fc.png

6d18608236c84dc1b2ba09df9159c293.png

最后 设备状态bDeviceState设置为未连接UNCONNECTED ,枚举以后才是已连接

学习做的一些笔记写的可能有点乱

 

  • 17
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值