做一个U盘的学习路线
最近想研究一个U盘,然后顺便熟悉一下USB协议。因为USB协议比较复杂, 常用的复杂外设除了WiFi,Ethernet,SDIO和USB这些就是USB了,学习USB的时候肯定要拿一个东西下手,所以简单了解之后准备了下列资料:
前期准备
1.《圈圈教你玩USB》。这本书比较经典,但是拿的芯片比较老了,在淘宝上搜索发现这本书配套的PDIUSBD12有现成的独立模块使用。因为手头上正好有一个STM32开发板,可以用来对接它。STM32之前用来对接红外线后来被闲置(参考这篇http://www.cnblogs.com/tanhangbo/p/4740702.html), 这时候正好用上。

左边是淘宝买的模块,中间是圈圈的书本,右边是买书送的PCB,没有用上。
2.《USB开发大全》,《linux那些事儿》这两本书买了备用
3.USB一些相关资料包,和USB的系列spec,算作储备。前期已经了解了一些USB的基本架构,学习起来可以再回顾下。
4.USB的抓包软件,抓包硬件。抓包软件抓到的包可能会漏掉一些东西,而且会加上一些系统调用,使用会模糊不清。而抓包软件可以抓到真实的包,就像wifi的sniffer一样,一定要看到真实的包才有标准答案,不然学习起来会迷路。USB的抓包器相对于逻辑分析仪比较昂贵,购买USB1.1协议的即可。
5.准备好你的耐心,因为这里涉及多个协议,这是最重要的。
移植代码
因为选择了STM32作为主体而不是51单片机,所以代码难免需要移植一下,这是一个初期的障碍,但是评估起来问题不大。因为需要移植的是GPIO相关的东西,所以只要注意一些细节就可以了。移植过程中遇到的一个比较大的问题是,D12并口的GPIO不要给它拉高,否则通讯会出错。我之前使用的时候发现一直没有通(通过并口读取D12的硬件ID),后来加入了逻辑分析仪之后竟然可以了,于是想到GPIO的硬件问题,最后把上拉改成悬空就可以了。因为STM32的GPIO的API有点绕,所以要仔细对待。
移植到STM32的HAL代码:
/**
Init GPIOA as input or Output
*/
void GPIOA_Init(int input)
{
GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
if (input == 1)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //GPIO_Mode_IN_FLOATING
else
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO_Mode_Out_PP GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOA, &GPIO_InitStructure); } void HAL_GPIO_Data_AS_Input()
{
//GPIO_DeInit(GPIOA);
GPIOA_Init(1);
} void HAL_GPIO_Data_AS_Output()
{
//GPIO_DeInit(GPIOA);
GPIOA_Init(0);
} u8 HAL_GPIO_Read_Data()
{
return GPIO_ReadInputData(GPIOA) & 0xFF;
} /**
GPIOB_6 = RD -- Output
GPIOB_7 = WR -- Output
GPIOB_8 = INT -- Input
GPIOB_9 = A0 -- Output
*/
void GPIOB_Init()
{ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /** Output */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure); /** Input */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING ;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &GPIO_InitStructure); } /**
Write one byte to GPIOA0~GPIO7
*/
void HAL_GPIO_Write_Data(unsigned char byte)
{
#if 0
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (byte & 0x01));
GPIO_WriteBit(GPIOA, GPIO_Pin_1, (byte & (0x01 << 1)));
GPIO_WriteBit(GPIOA, GPIO_Pin_2, (byte & (0x01 << 2)));
GPIO_WriteBit(GPIOA, GPIO_Pin_3, (byte & (0x01 << 3)));
GPIO_WriteBit(GPIOA, GPIO_Pin_4, (byte & (0x01 << 4)));
GPIO_WriteBit(GPIOA, GPIO_Pin_5, (byte & (0x01 << 5)));
GPIO_WriteBit(GPIOA, GPIO_Pin_6, (byte & (0x01 << 6)));
GPIO_WriteBit(GPIOA, GPIO_Pin_7, (byte & (0x01 << 7)));
#else
uint16_t data = GPIO_ReadOutputData(GPIOA) & 0xFF00; //read high 8 byte
GPIO_Write(GPIOA, (data|byte)); //write high&low byte
#endif } void HAL_GPIO_Write_RD(int val)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_6, val); } void HAL_GPIO_Write_WR(int val)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_7, val); } void HAL_GPIO_Write_A0(int val)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_9, val);
} int HAL_GPIO_Read_INT()
{
return GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8);
} void HAL_GPIO_Init()
{
GPIOA_Init(0);
GPIOB_Init();
} /**
PA0 ~ PA7 test PASS
*/
void GPIOA_Test()
{ int i = 0;
GPIOA_Init(0);
while (1) {
printf("Read = %08x\r\n", GPIOB, HAL_GPIO_Read_Data());
//GPIOA_Write_Byte(0x55);
//delay_ms(1000);
///GPIOA_Write_Byte(0xaa);
os_sleep(1);
}
}
圈圈代码里面的中文太多了,出于强迫症给它整理格式、加入自定义的打印并且加上颜色。

使用的时候HID和USB-TTL的例子都没问题,后面的U盘里面就有一些问题了,这里有一些SCSI命令的响应是没有的,手动给它添加上去,试过ubuntu14.04和win10都没有通,经常卡在文件系统的Read(10)这里,猜测是速度上不去,后面更换STM32自带的USB试试看。目前成功的例子是linux2.6内核的板子成功给它挂载上去并且读取到里面的TXT文件。
对于U盘来说有包括SCSI指令和FAT文件系统层的东西,这些都需要去了解,巩固。
心得
1.USB协议本身主要是要实现一些基本的描述符,告诉主机自己是谁,有哪些参数(类似SDIO的CCCR/FBR/CIS),实际的数据传输流程是为上层协议做准备的。一开始可能对USB数据包本身比较感兴趣,后续更多的问题存在于应用协议。
2.对于U盘来说要在USB基础上了解SCSI和FAT文件系统协议协议格式,重头戏都是在这里的。
3.USB可玩性比较高,可以实现标准的HID或者自定义单各种设备。比如USB网卡和CH340这些模块都是自定义的vendor specific设备。
展望
目前还是有一些问题需要解决的
1.将圈圈的代码写死二进制的方式全部改掉(包括USB的标准请求/SCSI指令/FAT格式),换成结构体的表示,手头上有linux内核代码和ecos的代码,可以移植过来。光跑别人的代码可能理解不深,自己重写一遍才能深刻理解。
2.在STM32上跑通U盘的例子。目前STM32有了现成的U盘历程,可以先移植过来看看效果,如果效果不好就将D12的代码移植过来。
3.在windows和ubuntu上面调通U盘
4.STM32作为SDIO host,做一个USB读卡器。
5.总结整理文档,形成自己的USB代码库
6.准备好耐心一步步积累吧
做一个U盘的学习路线的更多相关文章
- VPS用来配置上网外,还可以做一个同步盘
我曾经在一个活动的博文里说过,男人必须要有一个VPS和一个树莓派,VPS这个东西,以后会是中国男人的一种必备技能,今天又有一个小伙伴请教我VPS的用法,我就简单说说我目前使用的情况.首先我希望你能有点 ...
- 重装window 7系统,从做一个u盘启动盘,到装系统,很不错
老毛桃U盘启动盘制作工具是现在最流行的U盘装系统和维护电脑的专用工具,一是制作简单,几乎100%支持所有U盘一键制作为启动盘,不必顾虑以前量产U盘考虑专用工具的问题.二是制作后工具功能强大,支持GHO ...
- ios 学习路线总结
学习方法 面对有难度的功能,不要忙着拒绝,而是挑战一下,学习更多知识. 尽量独立解决问题,而不是在遇到问题的第一想法是找人. 多学习别人开源的第三方库,能够开源的库一定有值得学习的地方,多去看别的大神 ...
- 我的Android学习路线(一)
最近实在是闲的无聊,本着不能让自己的时间白白流失的目的,我就决定完成一下之前的诺言:把 Android 开发学了.正好手头有一本<Android 4编程入门经典>,于是便用两天时间把视图部 ...
- Android开发音视频方向学习路线及资源分享,学完还怕什么互联网寒冬?
接触Android音视频这一块已经有一段时间了,跟普通的应用层开发相比,的确更花费精力.期间为了学习音视频的录制,编码,处理也看过大大小小的几十个项目.总体感觉就是知识比较零散,对刚入门的朋友比较不友 ...
- Android学习路线(二十四)ActionBar Fragment运用最佳实践
转载请注明出处:http://blog.csdn.net/sweetvvck/article/details/38645297 通过前面的几篇博客.大家看到了Google是怎样解释action bar ...
- Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment
你能够把fragment看成是activity的模块化部分.它拥有自己的生命周期,接受它自己的输入事件,你能够在activity执行时加入或者删除它(有点像是一个"子activity&quo ...
- WEB学习路线2019完整版(附视频教程+网盘下载地址)
WEB学习路线2019完整版(附视频教程+网盘下载地址).适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利.高薪水的职业了.所以现在学习web前端开发的技术人员也是 ...
- Python学习路线2019升级版(课程大纲+视频教程+网盘资源下载)
2019最新Python全栈+人工智能学习路线升级版 全面涵盖前端.后端.爬虫.数据挖掘.人工智能等课程(课程大纲+视频教程+网盘资源下载)! 学习路线四大亮点: 1.人工智能三大主流框架全覆盖 2. ...
随机推荐
- Docker部署Sql Server 2019实践
1. 拉取SqlServer2019镜像 sudo docker pull mcr.microsoft.com/mssql/server:2019-latest 2. 创建容器+挂载: sudo do ...
- 【原创】一文彻底搞懂安卓WebView白名单校验
前言 近两年公司端侧发现的漏洞很大一部分都出在WebView白名单上,针对这类漏洞安全编码团队也组织过多次培训,但是这种漏洞还是屡见不鲜.下面本人就结合产品中容易出现问题的地方,用实例的方式来总结一下 ...
- 网络安全学习阶段性总结:SQL注入|SSRF攻击|OS命令注入|身份验证漏洞|事物逻辑漏洞|目录遍历漏洞
目录 SQL注入 什么是SQL注入? 掌握SQL注入之前需要了解的知识点 SQL注入情况流程分析 有完整的回显报错(最简单的情况)--检索数据: 在HTTP报文中利用注释---危险操作 检索隐藏数据: ...
- Nmap 常用命令及抓包分析
1.主机发现:主机发现也称为ping扫描,但是Nmap中主机发现的技术已经不是简单的采用ping工具发送简单的ICMP回声请求报文.用户完全可以通过使用列表扫描(-sL)或者通过关闭ping(-P0) ...
- Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
一.问题由来 下午的时候,电脑用得好好的,突然一下死机,么办法只能够重新启动.再次打开IDEA的时候,之前打开的所有的项目 信息都不在了,我重新打开项目,然后就出现问题,所有的类都报红了,这让我很是意 ...
- C# 排序列表(SortedList)
SortedList 类代表了一系列按照键来排序的键/值对,这些键值对可以通过键和索引来访问. 排序列表是数组和哈希表的组合.它包含一个可使用键或索引访问各项的列表.如果您使用索引访问各项,则它是一个 ...
- 通过location响应头实现重定向
package day08; import java.io.IOException; import javax.servlet.ServletException; import javax.servl ...
- Java的GUI组件的布局管理器
1 import java.awt.BorderLayout; 2 import java.awt.FlowLayout; 3 import java.awt.Font; 4 import java. ...
- sparksql的三种join实现
join 是sql语句中的常用操作,良好的表结构能够将数据分散在不同的表中,使其符合某种范式,减少表冗余,更新容错等.而建立表和表之间关系的最佳方式就是Join操作. sparksql作为大数据领域的 ...
- 刷题-力扣-122. 买卖股票的最佳时机 II
122. 买卖股票的最佳时机 II 题目链接 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell ...