找回密码
 立即注册
查看: 1543|回复: 0

关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问

[复制链接]

1

主题

0

回帖

27

积分

新手上路

积分
27
发表于 2023-7-3 18:12:37 | 显示全部楼层 |阅读模式
本帖最后由 shisheng 于 2023-7-4 20:59 编辑

大家好这里是新人shisheng

知道stc单片机有集合了USB功能后就买了两片试试,效果还是很不错的,最开始还是用lib库,然后觉得限制有些大所以开始学USB协议研读USB的源码,用的是stc32单片机demo中的《74-MSC(Mass Storage Class)协议范例》
然后也是抽空注释了几天,大概把库函数的关键底层操作注释清晰了,后面更多的解读工作要求我要学会USB的各种协议,所以先把现在的工作结果放出来,给各位想学和正在学USB功能的同学减少一些工作量。

学习usb功能所需的前置知识点:
1.stc单片机USB模块相关寄存器和操作方法:在技术手册的25章《USB通用串行总线》,主要需要知道的几个知识点:
    ·单片机的USB是以一个模块的形式存在的,CPU主要通过操作间址地址寄存器和和数据寄存器实现cpu和USB模块的通信,所有数据包括读写寄存器值、USB接收发送数据,都是通过数据寄存器实现的,通过间址地址寄存器寻址,所以对USB模块的操作只有间址地址寄存器和数据寄存器两个操作窗口
    ·需要发送或者接收的数据,都需要先放到模块的FIFO中,或者从FIFO中读取,而数据发送的具体动作(添加数据帧头尾、同步帧、电平变化等)都在模块中实现,我们不需要考虑,只需要根据USB协议规则修改寄存器(其实在源代码中都写好了只要按规范调用就行),FIFO中的数据只是协议中的数据包,而不是完整的发送出去和接收进来的的电平变化
    ·USB功能代码的执行都在USB中断中进行的,所以在主函数中看不到,需要到usb.c的中断入口开始看起
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-1.png
2.USB数据包的构成、USB通讯原理、USB协议规范,USB各种类协议,是一个非常大的内容,各位同学可以去https://www.usbzh.com/article/detail-843.html学习,站长是一个非常友爱的人,感兴趣的可以进Q群技术交流,都是非常厉害的大佬们;USB协议部分主要需要知道的几个知识点:
    ·USB电平变化规则:了解差分信号、下拉电阻等存在的作用,USB传输中如何表示0和1
    ·USB通信中端口0固定是控制端口,不能传输主要数据(比如说往U盘复制的数据,是通过其他端口写进去的),主机想设置、轮询、广播、跟哪个端口通讯都会在端口0(控制端口)发送相关命令(令牌包),比如主机要给端口2发送或读取数据:是先端口0发送setup令牌包->端口0发送OUT令牌包->端口2发送数据包->端口0接收握手包
    ·每个端口都分IN端口和OUT端口,这里的IN、OUT是相对于主机而言的,所以单片机收到的数据其实是在OUT端口的FIFO中,要发送的数据是装填进IN端口的FIFO中,
    ·USB2.0包packet的组成:只要了解你在FIFO中拿到的只是数据包(packet content),而在这个数据包的前后还有附加的内容,这些是USB模块给你生成好的,在用示波器查看的时候可以认出来就行
    ·清楚传输管道、事务、packet包、令牌包、数据包、握手包之间的关系:数据在管道中传输,令牌等包加上头尾的帧内容叫做packet包,事务是令牌数据等包的顺序组合,事务不能被打断
    ·了解USB令牌包、数据包、握手包:令牌包固定是主机发给设备,数据包是实际数据传输部分,握手包方向跟数据包方向相反
    ·USB标准请求(可以认为就是setup类型数据包)、标准请求的数据结构、如果想开发USB设备,这个是一定要啃透的,学习链接:https://www.usbzh.com/article/detail-417.html
    ·USB各种类协议(比如MSC、HID类)建议先从MSC学起,再学HID,是很常用的两种类型
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-2.png

以下是MSC范例的简单讲解,详细的大家可以下载带注释的工程看看:

1.程序初始化
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-3.png
    主要初始化IO口、EEPROM的IAP配置、USB模块初始化,可以看见主程序中是没有任何代码的,因为USB的代码全部都在USB中断中执行,也就是说在设备插入主机后会非常频繁的进出USB中断,这点在写用户程序时要注意中断嵌套、特别是总中断开关的操作

2.USB中断的进入
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-4.png
    所有的USB事件都会进入USB中断,具体是哪些USB事件,是需要软件自己查寄存器确认的,这里首先要注意,USB的中断寄存器设置有两种,一种是中断设置位(是用户在写程序时,需不需要用这个中断),一种是中断允许位(中断产生后,软件查询是不是这个产生中断),USB的中断种类是特别多的,一次USB中断事件中不一定只有一种中断,有可能有多个中断被置1,都需要软件轮询并执行相应操作。
    在这个代码中可以看见中断产生后会首先保存USB现场,读取保存各种中断,然后根据USB设备的状态和中断类型,会执行各种操作,在接入电脑的一瞬间,首先执行的是usb_setup()函数,单片机将自己的USB设置、类型告知主机,并完成初始化、地址分配
    考虑到USB模块的操作窗口小,中断中有大量的判断语句,我觉得stc单片机的USB带宽是非常有限的,而实际上也是,单文件的拷贝,在批量传输下速度还是可以接受的,但在多文件拷贝中会有大量的修改操作,速度会变得特别慢

3.usb_setup函数的进入
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-5.png
    注意setup函数的进入是寄存器中usb中断标志决定的!也就是发生了主机发送了令牌包,模块解码配置好而确定的
    在switch函数之前只是常规的中断后状态重置动作,switch后才开始是接受到的数据包的解码动作,要注意的是,我们在FIFO拷贝下来的数据其实是usb传输中的第二个包,也就是setup令牌包后面跟着的DATA0包,这里我把这个DATA0包称做setup类型数据包,因为这个包一定要接着setup令牌包后面,且存放到哪个端口里,也是setup令牌包确定的,这里可以认为,接受到的令牌包在usb模块里面就解码完成了,根据setup令牌包配置了一些寄存器,并指明后续数据包存放的端口号
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-6.png

    setup函数进入后关键动作就是解码setup包并将usb标准设置、类设置厂家请求返回给主机,也就是图片中的usb_req_std();usb_req_class();usb_req_vendor();函数,这里的知识点涉及到usb各种协议,暂时不讲解,我也没学清楚,就大家结合链接自行学习吧,代码里面也是有注释的。
    这里就当作完成了usb_setup函数并跳出,这样就完成了一次USB中断,完成了USB插入主机并进行配置的一小部分,这个过程会持续好几轮,直至完成初始化和地址分配

4.第二轮USB中断的进入
    这里我们先认为USB的配置都完成了并分配了地址,开始进行设备的主要工作,比如MSC设备就变成了U盘,HID设备就变成了鼠标键盘其他的
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-7.png

    还是从中断入口看起,以MSC设备U盘为例子,在这里发送过来的OUT/IN令牌包已经完成解码了,并将相应端口的中断标志置1(在stc技术文档中叫做允许位),在这里因为已经设置好了MSC传输端口是端口1(可以看usb_desc.c里面配置描述符)主机发送OUT令牌包会指明向端口1发送数据,所以这里端口1的OUT中断允许位会被置1,进入usb_out_ep1()函数。
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-1.png
    进入usb_out_ep1()函数后进入scsi_process(),这是一种储存设备的通讯协议,在这里面进行解码,最终调用memory.c中的函数,将后续数据包的内容写到EEPROM中,至此完成了U盘插入到主机识别、写入数据的所有动作,协议这些我没学透就不讲解了

关于读《74-MSC(Mass Storage Class)协议范例》源码中遇到的问题和疑问
1.USB.c中函数void usb_out_ep3()函数索引值可能错误:
   在USB.c中函数void usb_out_ep3()函数的INDEX、Buffer的索引值为2,值应该是写错了应该是3,因为这个值是端口号的索引值,这样会导致使用端口3会和端口2冲突,我在源代码中没有修改,不知道还有没有其他关联的代码,希望官方完善一下
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-2.png


2.usb.c中BYTE InEpState、BYTE OutEpState两个变量的作用不太清楚
BYTE InEpState、BYTE OutEpState这两个变量只在初始化、和初始化命令中使用到,其次就是某些端口中断中作为if判断语句的条件被使用,但是在哪里被修改却没有找到,大概可以看出是用来保存各个端口状态的变量
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-3.png


3.usb.h中外部声明变量UsbBuffer[256]没看到实际定义
也没看到在哪里用到,用途不明,可能是给用户使用的?
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-4.png

4.usb_desc.c中的PACKET0、PACKET1两个包的用途不清楚
   大概可以看出是1个数据0数据包和数据1数据包,但是在很多地方被用到,比如说获取最大逻辑储存单元数命令的回复、主机向设备接收者、接口接收者发送有效数据时的回复,没有明确的用途,这里猜测是通讯协议中常用的两种类型所以定义出来简化使用,
关于stc32demo示例《74-MSC(Mass Storage Class)协议范例》源码解读和疑问-5.png

希望有大佬可以解惑[感谢][感谢]

这个源码解读工作暂时到此,大家可以跟着代码运行顺序读下去,结合着注释大概能知道整个USB功能的运行模式
源码中有很多地方可以完善的,比如像端点OUT中断中需要修改源码才能实现端点处理数据的功能、PACKET0、PACKET1包的用途等如果可以修改代码将这些解耦出来,那么源码就真的不用动了,只要按需求设置各种描述符、写数据处理的实现函数就可以实现很灵活的USB功能了





74-MSC(Mass Storage Class)协议范例带注释.zip

168.39 KB, 下载次数: 101

MSC协议范例带注释

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-17 03:52 , Processed in 0.129841 second(s), 49 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表