做一个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.准备好耐心一步步积累吧

原文地址:https://www.cnblogs.com/tanhangbo/p/8969511.html

时间: 2024-08-26 09:50:48

做一个U盘的学习路线的相关文章

VPS用来配置上网外,还可以做一个同步盘

我曾经在一个活动的博文里说过,男人必须要有一个VPS和一个树莓派,VPS这个东西,以后会是中国男人的一种必备技能,今天又有一个小伙伴请教我VPS的用法,我就简单说说我目前使用的情况.首先我希望你能有点Linux基础. 一.搬瓦工的VPS非常实惠,推出过年付4刀的低配主机,内存只有64M,可惜如今已经售磬,我使用的是有家主机年付100元的小主机,内存128M,也算是低配了,通常的概念是,如此低的内存,用来跑WordPress肯定很吃力,所以大家只是用来做个上网服务器.关于这个用法,请参考秋水逸冰的

嵌入式学习容易吗?该如何选择一个好的嵌入式学习路线?

嵌入式开发大概要学习那些知识呢?凌阳教育的老师说对于嵌入式开发我们要从它的最基本的步骤开始学习 1.基础知识: 目的:能看懂硬件工作原理,但重点在嵌入式软件,特别是操作系统级软件,那将是我的优势. 科目:数字电路.计算机组成原理.嵌入式微处理器结构. 汇编语言.C/C++.编译原理.离散数学. 数据结构和算法.操作系统.软件工程.网络.数据库. 主攻书籍:the c++ programming language(一直没时间读).数据结构-C2. 2.学习linux: 目的:深入掌握linux系统

重装window 7系统,从做一个u盘启动盘,到装系统,很不错

老毛桃U盘启动盘制作工具是现在最流行的U盘装系统和维护电脑的专用工具,一是制作简单,几乎100%支持所有U盘一键制作为启动盘,不必顾虑以前量产U盘考虑专用工具的问题.二是制作后工具功能强大,支持GHO.ISO系统文件,支持原版系统安装.三是兼容性强,支持最新型主板与笔记本,多个PE版本供选择,基本杜绝蓝屏现像. 一.制作前准备(注意:操作前备份好u盘数据) 1.电脑内存不能小于512MB 2.U盘的容量大于512MB 3.下载老毛桃U盘启动盘制作工具Build 20120501 下载地址:htt

我的Android学习路线(一)

最近实在是闲的无聊,本着不能让自己的时间白白流失的目的,我就决定完成一下之前的诺言:把 Android 开发学了.正好手头有一本<Android 4编程入门经典>,于是便用两天时间把视图部分的代码全部敲了一遍. 然后寻思着这么一个现阶段的入门学习路线: 撸一个计算器出来,并且做到屏幕自动适配. 利用四大组件,给计算器加入各种鬼畜功能. 之前在入门 Java 的时候,老师在教我们 Java 图形界面之后便叫我们制作一个计算器,算是对图形界面的入门.其实当时写计算器的时候我偷了个懒,布局使用了绝对

Android学习路线(二十四)ActionBar Fragment运用最佳实践

通过前面的几篇博客,大家看到了Google是如何解释action bar和fragment以及推荐的用法.俗话说没有demo的博客不是好博客,下面我会介绍一下action bar和fragment在实战中的应用,以及相关demo源码,希望和大家相互交流. 了解过fragment的同学们应该都知道,fragment是android 3.0版本才出现的的,因此如果要在支持android 3.0一下版本的工程中使用fragment的话是需要添加Support Library的.具体如何添加我就不再赘述

Java新手的学习路线

互联网的飞速发展,带动了大批IT行业发展.而Java作为众多语言中最稳定的一个,深受各种软件开发公司的喜爱.目前java技术不但薪资待遇高,而且发展前景好,让许多人都向java领域发展,也引发了人们的学习热情.所以今天写了一个Java新手的学习路线,推荐Java新手看一下. 怎么学Java?这是新手问的最多的一个问题.想要学好Java,首先要明白Java体系设计到得三个方面:J2SE,J2EE,J2ME.软件开发者经常说到的JDK,就主要指的J2SE,它是三者的基础,如果J2SE学得好,很容易拓

Android学习路线(二十一)运用Fragment构建动态UI——创建一个Fragment

你可以把fragment看成是activity的模块化部分,它拥有自己的生命周期,接受它自己的输入事件,你可以在activity运行时添加或者删除它(有点像是一个"子activity",你可以在不同的activity中重用它).本课将向你展示如何使用Support Libaray继承 Fragment 类来让你的应用能够兼容正在运行Android 1.6的设备. 提示: 如果你决定你的应用需求的最低API级别是11或者更高,那么你不需要使用Support Library,你可以直接使用

Android学习路线(五)开启另一个Activity

在完成了 上一篇课程后,你已经有了一个应用.这个应用展示了一个包含一个文本框和一个按钮的activity(一个单独的界面).在这次的课程中,你将会通过在MainActivity中添加一些代码,来让当给你点击Send按钮时能够跳转到另一个activity中. 响应Send按钮 为了响应按钮的点击事件,打开fragment_main.xml 布局文件,然后在 <Button> 元素中加入android:onClick属性: <Button     android:layout_width=&

Python最佳学习路线,选一个发展方向努力吧!

一.概述 2019年Python语言可以说是火的一塌糊涂,作为一门将近20年的计算机语言,直到最近才流行起来,真是可以说是大器晚成.说句实在话,Python语言的大火与人工智能这门科学是密不可分的.那么Python只能做人工智能吗?答案:肯定不是.Python作为小白入门的计算机语言在合适不过了.那我们一起来看看Python语言最好的学习路线是什么,我给大家整理一份学习路线图,大家可以参考看一下. **创一个小群,供大家学习交流聊天 如果有对学python方面有什么疑惑问题的,或者有什么想说的想