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

  • 相关阅读:
    绑定方法与与绑定方法
    组合 多态 封装
    继承
    面向对象
    函数进阶
    文件操作
    字符编码
    python基本数据类型及操作
    IDEA 错误: 找不到符号
    Spring+MVC Controller层接收App端请求的中文参数乱码问题。
  • 原文地址:https://www.cnblogs.com/tanhangbo/p/8969511.html
Copyright © 2020-2023  润新知