声明:本文为原创作品,版权归本博文作者所有,如需转载,请注明出处http://www.cnblogs.com/kingst/

上一节,我们讲了USB的设备模式,可以实现计算机与黑金开发板的数据通信。这一节,我们以上一节为基础,研究一下如何利用CH376芯片来实现U盘的读写。

大家都知道,不管是U盘,SD卡,还是我们经常用到的电脑硬盘,都存在文件的建立,存取,修改等操作。从系统角度来说,负责管理这些工作的我们称之为文件管理系统,简称文件系统。经常用电脑的人对这个概念一定很熟悉,比如我们在装系统的时候,不可避免的会遇到选择何种文件系统(除非你用GHOST,呵呵),FAT32还是NTFS等等,这个就是文件系统。文件系统是对文件存储器空间进行组织和分配,负责文件的存储并对存入的文件进行保护和检索的系统,具体地说,他负责为用户建立文件、存入、读出、修改、转储文件爱你,控制文件的存取,当用户不再使用时撤销文件等。

在U盘中,同样存在文件系统。大家熟知的,当我们想格式化U盘的时候,我们也需要选择文件系统类型,如下图所示

因此,如果要想通过U盘来实现开发板与电脑之间的数据交换,那么,在开发板上也也应该在FAT规范下通过文件的形式存取U盘中的数据。不过,CH376已经把这个工作为我们做好了。

CH376在芯片内部集成了FAT文件系统,支持 FAT32、FAT16和FAT12,符合WINDOWS的文件系统格式。这种无微不至的“关怀”实在令我们感动啊,因为这样我们就不需要在自己动手编写了文件系统了,为我们减少了很多的工作量,剩下的时间看看世界杯还是很不错哦,呵呵。

CH376对U盘文件的读写方式分为两种:扇区模式和字节模式。

扇区模式下,以扇区(每扇区通常是512字节)为基本单位对U盘文件进行读写,所以读写速度略快,但是通常情况下需要额外的文件数据缓冲区,额外的文件数据缓冲区必须是扇区长度512 的整数倍,所以适用于RAM多、数据量大、频繁读写数据的单片机系统。扇区读写的子程序主要有扇区读CH376SecRead 和扇区写CH376SecWrite。

字节模式下,以字节为基本单位对U盘文件进行读写,少则 1 字节,多则 65535字节,读写速度略慢,但是不需要额外的文件数据缓冲区,使用方便,适用于 RAM 少(从几字节到几十 K 都可以)、数据量小或者数据零碎、不经常读写数据的单片机系统。但是,因为闪存只能进行有限次擦写,如果频繁地向U盘写入零碎的数据,可能会缩短U 盘中闪存的使用寿命。

下面,我们就通过我们黑金开发板来实践一下,看如何使用CH376来实现U盘的读取的。

在南京沁恒的官方网站上,为我们提供了CH376相关的例程,不过都是基于单片机的,我们需要移植到NIOS II下实现。

首先,我们需要自己来写USB的底层驱动,这个跟上一节的USB驱动稍有不同。我们在driver下建立hal.c文件,如下所示

/** =====================================================================================**       Filename:  usb.c**    Description:  ch376底层驱动**        Version:  1.0.0*        Created:  2010.4.16*       Revision:  none*       Compiler:  Nios II 9.0 IDE**         Author:  马瑞 (AVIC)*          Email:  avic633@gmail.com  ** =====================================================================================*/
//-----------------Include files-------------------------//
#include "../inc/hal.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include <unistd.h>
#include <stdio.h>
#include "../inc/ch376inc.h"
#include "system.h"//-----------------Function Prototype--------------------//
void xWriteCH376Cmd(unsigned char command);
void xWriteCH376Data(unsigned char data);
unsigned char xReadCH376Data(void);
unsigned int mInitCH376Host(void);
void delay(void);
int set_usb_mode(unsigned char type);
unsigned char Query376Interrupt(void);
void irq_usb(void * context,unsigned int id);
void mDelaymS(int ms);
//-----------------Variable------------------------------//USB_T usb;
/* * ===  FUNCTION  ======================================================================*         Name:  set_usb_mode*  Description:  设置工作模式 * =====================================================================================*/
int set_usb_mode(unsigned char type)
{xWriteCH376Cmd(SET_USB_MODE);xWriteCH376Data(type);xReadCH376Data();if((xReadCH376Data()) == CMD_RET_SUCCESS)return 0;else return -1;
}
/* * ===  FUNCTION  ======================================================================*         Name:  xWriteCH376Cmd*  Description:  写命令 * =====================================================================================*/
void xWriteCH376Cmd(unsigned char command)
{//A0PIO_USB_A0=1;//DB DIR outputPIO_USB_DB_DIR=0xff;PIO_USB_DB=command;PIO_USB_WR=0;PIO_USB_WR=1;
}
/* * ===  FUNCTION  ======================================================================*         Name:  delay*  Description:  延时 * =====================================================================================*/
void delay(void)
{int i;for(i=0;i<1000;i++);
}
/* * ===  FUNCTION  ======================================================================*         Name:  xWriteCH376Data*  Description:  写数据 * =====================================================================================*/
void xWriteCH376Data(unsigned char data)
{//A0PIO_USB_A0=0;//DB DIR outputPIO_USB_DB_DIR=0xff;PIO_USB_DB=data;   usleep(20);PIO_USB_WR=0;delay();usleep(20);PIO_USB_WR=1;
}
/* * ===  FUNCTION  ======================================================================*         Name:  xReadCH376Data*  Description:  读数据 * =====================================================================================*/unsigned char xReadCH376Data(void)
{unsigned char data=0;//A0PIO_USB_A0=0;//DB DIR outputPIO_USB_DB_DIR=0;PIO_USB_RD=0;delay();data=PIO_USB_DB;PIO_USB_RD=1;return data;
}
/* * ===  FUNCTION  ======================================================================*         Name:  mInitCH376Host*  Description:  初始化* =====================================================================================*/
unsigned int mInitCH376Host(void)
{PIO_USB_RD=1;PIO_USB_WR=1;PIO_USB_A0=1;usb.receive_ok_flag=0;usb.send_ok_flag=0;//enable the io interruptIOWR_ALTERA_AVALON_PIO_IRQ_MASK(USB_NINT_BASE,0);IOWR_ALTERA_AVALON_PIO_EDGE_CAP(USB_NINT_BASE,0);set_usb_mode(USB_HOST);return USB_INT_SUCCESS;
}
/* * ===  FUNCTION  ======================================================================*         Name:  Query376Interrupt*  Description:  读取中断引脚 * =====================================================================================*/
unsigned char Query376Interrupt( void )
{return(PIO_USB_NINT?TRUE:FALSE);
}
/* * ===  FUNCTION  ======================================================================*         Name:  mDelaymS*  Description:  延时 * =====================================================================================*/
void mDelaymS(int ms)
{usleep(1000*ms);
}

接下来,我们需要在inc下建立hal.h文件

/** =====================================================================================**       Filename:  hal.c**    Description:  ch376底层驱动**        Version:  1.0.0*        Created:  2010.4.16*       Revision:  none*       Compiler:  Nios II 9.0 IDE**         Author:  马瑞 (AVIC)*          Email:  avic633@gmail.com  ** =====================================================================================*/
#ifndef __usb_h__
#define __usb_h__//-----------------Include files-------------------------//
#include "system.h"//------------------Data struct--------------------------////----------------- CH375 DEFINE-------------------------////common
#define USB_HOST    0X06
#define USB_DEVICE  0x02
#define USB_DISABLE 0X00#define RESET_ALL   0X05
#define CHECK_EXIST 0X06
#define SET_USB_ID  0X12
#define SET_USB_MODE    0X15
#define GET_STATUS  0X22
#define UNLOCK_USB  0X23
#define RD_USB_DATA 0X28
#define WR_USB_DATA5    0X2A
#define WR_USB_DATA7    0X2B
#define GET_IC_VER  0X01
#define ENTER_SLEEP 0X03
#define CHK_SUSPEND 0X0B
#define RD_USB_DATA0    0X27#define RET_SUCCESS 0X51
#define RET_ABORT   0X5B#define INT_EP2_OUT 0x02
#define INT_EP2_IN  0x0a//host
#define DISK_READ   0X54
#define DISK_RD_GO  0X55#define DISK_READY  0X59
#define DISK_INIT   0X51//status#define USB_INT_CONNECT 0x15//----------------------------USB HOST---------------------------//
#define CMD_RET_SUCCESS     0x51            /* 命令操作成功 */
#define CMD_RET_ABORT       0x5F            /* 命令操作失败 *///------------------------bus define----------------------------//
//usb
#define PIO_USB_DB      *(volatile unsigned long int *)USB_DB_BASE
#define PIO_USB_WR      *(volatile unsigned long int *)USB_WR_BASE
#define PIO_USB_RD      *(volatile unsigned long int *)USB_RD_BASE
#define PIO_USB_A0      *(volatile unsigned long int *)USB_A0_BASE
#define PIO_USB_NINT     *(volatile unsigned long int *)USB_NINT_BASE#define PIO_USB_DB_DIR  *(volatile unsigned long int *)(USB_DB_BASE+4)#define VID 0X0FFE
#define PID 0X1000typedef struct{char receive_buffer[200];int send_ok_flag;int receive_ok_flag;}USB_T;
//-----------------Extern function------------------------//extern USB_T usb;
extern void xWriteCH376Cmd(unsigned char command);
extern void xWriteCH376Data(unsigned char data);
extern unsigned char xReadCH376Data(void);
extern unsigned int mInitCH376Host(void);
extern unsigned char Query376Interrupt(void);
extern void mDelaymS(int ms);#endif //__usb_h__

上面属于底层驱动部分,如果想实现U盘的读取,还需要处理文件系统子程序file_sys.c,官方已有提供,我们将其加入到drvier下。将头文件file_sys.h放到inc下。

将上述内容都设置好以后,我们需要编写一个测试程序。官方提供了很多的例程,大家可以讲我们编写的底层驱动替换下自带的就可以 。

下面程序演示字节读写,文件枚举,用于将U盘中的/C51/CH376HFT.C文件中的前200个字符显示出来,如果找不到原文件CH376HFT.C,那么该程序将显示C51子目录下所有以CH376开头的文件名,如果找不到C51子目录,那么该程序将显示根目录下的所有文件名。

/** =====================================================================================**       Filename:  host.c**    Description:  **        Version:  1.0.0*        Created:  2010.4.16*       Revision:  none*       Compiler:  Nios II 9.0 IDE**         Author:  马瑞 (AVIC)*          Email:  avic633@gmail.com  ** =====================================================================================*/
#include "../inc/ch376inc.h"
#include "../inc/hal.h"
#include "../inc/file_sys.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>UINT8 buf[64];void host(void) {UINT8   i, s;UINT8   TotalCount;UINT16  RealCount;P_FAT_DIR_INFO  pDir;s = mInitCH376Host( );  /* 初始化CH376 */while ( 1 ) {printf( "Wait Udisk/SD\n" );/* 检查U盘是否连接,等待U盘插入*/while (CH376DiskConnect()!=USB_INT_SUCCESS ){              usleep( 1000*100 );  /* 没必要频繁查询 */printf("USB FAILURE\n");}for ( i = 0; i < 100; i ++ ) {  /* 最长等待时间,100*50mS */usleep( 1000*50 );printf( "Ready ?\n" );s = CH376DiskMount( );  /* 初始化磁盘并测试磁盘是否就绪 */if ( s == USB_INT_SUCCESS ) break;  /* 准备好 */else if ( s == ERR_DISK_DISCON ) break;  /* 检测到断开,重新检测并计时 */if ( CH376GetDiskStatus( ) >= DEF_DISK_MOUNTED && i >= 5 ) break;  /* 有的U盘总是返回未准备好,不过可以忽略,只要其建立连接MOUNTED且尝试5*50mS */}if ( s == ERR_DISK_DISCON ) {  /* 检测到断开,重新检测并计时 */printf( "Device gone\n" );continue;}if ( CH376GetDiskStatus( ) < DEF_DISK_MOUNTED ) {  /* 未知USB设备,例如USB键盘、打印机等 */printf( "Unknown device\n" );goto UnknownUsbDevice;}i = CH376ReadBlock( buf );  /* 如果需要,可以读取数据块CH376_CMD_DATA.DiskMountInq,返回长度 */if ( i == sizeof( INQUIRY_DATA ) ) {  /* U盘的厂商和产品信息 */buf[ i ] = 0;printf( "UdiskInfo: %s\n", ((P_INQUIRY_DATA)buf) -> VendorIdStr );}/* 读取原文件 */printf( "Open\n" );strcpy( buf, "\\C51\\CH376HFT.C" );  /* 源文件名,多级目录下的文件名和路径名必须复制到RAM中再处理,而根目录或者当前目录下的文件名可以在RAM或者ROM中 */printf("buf:%s\n",buf);s = CH376FileOpenPath( buf );  /* 打开文件,该文件在C51子目录下 */if ( s == ERR_MISS_DIR || s == ERR_MISS_FILE ) {  /* 没有找到目录或者没有找到文件 *//* 列出文件,完整枚举可以参考EXAM13全盘枚举 */if ( s == ERR_MISS_DIR ) strcpy( buf, "\\*" );  /* C51子目录不存在则列出根目录下的文件 */else strcpy( buf, "\\C51\\CH376*" );  /* CH376HFT.C文件不存在则列出\C51子目录下的以CH376开头的文件 */printf( "List file %s\n", buf );s = CH376FileOpenPath( buf );  /* 枚举多级目录下的文件或者目录,输入缓冲区必须在RAM中 */while ( s == USB_INT_DISK_READ ) {  /* 枚举到匹配的文件 */CH376ReadBlock( buf );  /* 读取枚举到的文件的FAT_DIR_INFO结构,返回长度总是sizeof( FAT_DIR_INFO ) */pDir = (P_FAT_DIR_INFO)buf;  /* 当前文件目录信息 */if ( pDir -> DIR_Name[0] != '.' ) {  /* 不是本级或者上级目录名则继续,否则必须丢弃不处理 */if ( pDir -> DIR_Name[0] == 0x05 ) pDir -> DIR_Name[0] = 0xE5;  /* 特殊字符替换 */pDir -> DIR_Attr = 0;  /* 强制文件名字符串结束以便打印输出 */printf( "*** EnumName: %s\n", pDir -> DIR_Name );  /* 打印名称,原始8+3格式,未整理成含小数点分隔符 */}xWriteCH376Cmd( CMD0H_FILE_ENUM_GO );  /* 继续枚举文件和目录 */s = Wait376Interrupt( );}}else {  /* 找到文件或者出错 */TotalCount = 200;  /* 准备读取总长度 */printf( "从文件中读出的前%d个字符是:\n",(UINT16)TotalCount );while ( TotalCount ) {  /* 如果文件比较大,一次读不完,可以再调用CH376ByteRead继续读取,文件指针自动向后移动 */if ( TotalCount > sizeof(buf) ) i = sizeof(buf);  /* 剩余数据较多,限制单次读写的长度不能超过缓冲区大小 */else i = TotalCount;  /* 最后剩余的字节数 */s = CH376ByteRead( buf, i, &RealCount );  /* 以字节为单位读取数据块,单次读写的长度不能超过缓冲区大小,第二次调用时接着刚才的向后读 */TotalCount -= (UINT8)RealCount;  /* 计数,减去当前实际已经读出的字符数 */for ( s=0; s!=RealCount; s++ ) printf( "%C", buf[s] );  /* 显示读出的字符 *///printf("%s",buf);if ( RealCount < i ) {  /* 实际读出的字符数少于要求读出的字符数,说明已经到文件的结尾 */printf( "\n" );printf( "文件已经结束\n" );break;}}printf( "Close\n" );s = CH376FileClose( FALSE );  /* 关闭文件 */}UnknownUsbDevice:printf( "Take out\n" );while ( CH376DiskConnect( ) == USB_INT_SUCCESS ) {  /* 检查U盘是否连接,等待U盘拔出 */usleep( 1000*100 );}usleep( 1000*100 );}
}

好了,这节内容就到此结束了。有关FAT文件系统部分内容,建议大家自己搜索相关资料,对它进一步了解,对程序的理解很有好处。谢谢大家!

【连载】【FPGA黑金开发板】NIOSII那些事儿--USB主机模式(二十一)相关推荐

  1. 【连载】【FPGA黑金开发板】NIOS II那些事儿--硬件开发(一)

     声明:本文为原创作品,版权归黑金动力社区(http://www.heijin.org)所有,如需转载,请注明出处http://www.cnblogs.com/kingst/ 前言 从今天开始,NIO ...

  2. FPGA黑金开发板mini版新鲜出炉!!!

        功能描述: 1 – EP2C5Q208C ALTERA FPGA芯片 2 –64Mbit SDRAM 3 –2M*8bit FLASH 4 - EPCS1配置芯片 5 - 20M有源晶振 6 ...

  3. FPGA黑金开发板第一帖

    从今天起,此博客将专注于NIOS II的研究,以及对FPGA黑金开发板的技术支持.如果大家有任何的意见及建议,请留言.

  4. FPGA黑金开发板勘误

    FPGA黑金开发板(型号OSH-2-8)已发现两处勘误:   核心板上的红框的扩展口(图1所示)有两处丝印标注错误,图2中69脚和70脚标注错位,图3中的84脚和86脚指示错位,大家使用时请注意.

  5. FPGA黑金开发板 CYCLONE IV核心板全新上市!!!!

    FPGA:                          EP4CE15F17C8N SDRAM:                       256Mbit    (16M*16bit) SRA ...

  6. 【连载】【FPGA黑金开发板】Verilog HDL那些事儿--12864(ST7565P)液晶驱动(十三)...

    声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/ 4.2 ...

  7. 【连载】【FPGA黑金开发板】NIOS II那些事儿--LED实验(四)

    声明:本文为原创作品,版权归本博文作者所有,如需转载,请注明出处http://www.cnblogs.com/kingst/ 这一节,我将给大家讲解第一个与硬件有关的程序,虽然内容简单,却极具代表性. ...

  8. 【连载】【FPGA黑金开发板】Verilog HDL那些事儿--12864(ST7565P)液晶驱动(十三)

    声明:本文转载于http://www.cnblogs.com/kingst,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有. 4.2 实验十二:12864(ST ...

  9. 【连载】【FPGA黑金开发板】Verilog HDL那些事儿--数码管电路驱动(八)

    声明:本文为原创作品,版权归akuei2及黑金动力社区(http://www.heijin.org)共同所有,如需转载,请注明出处http://www.cnblogs.com/kingst/ 3.1 ...

最新文章

  1. Practical Vim 第一章 第二章
  2. 禁用JavaScript之后,你的网站表现如何?
  3. mysql的调试与分析_mysql日志管理分析调试实例_MySQL
  4. 自动化集成:Pipeline整合Docker容器
  5. 垃圾邮件过滤——学习笔记
  6. 最全Handler解读,持续补充...
  7. 记HTML5 a 标签的一个小坑 1
  8. Caffe︱构建lmdb数据集、binaryproto均值文件及各类难辨的文件路径名设置细解
  9. [洛谷U22157]刷水题(数位dp)(hash)
  10. 2021年系统集成项目管理工程师(软考中级)连夜整理考前重点
  11. 移动互联智慧杭州、技术精英引领中国
  12. MTK 修改ro.hardware 获取cpu 和固件版本号方法
  13. RK3066和AML8726-MX方案对比 频率与功耗 / 性能 / 方案成本
  14. BOOST元状态机用户手册之三教程(Meta State Machine (MSM))(1)——基本前端及例程
  15. 集成框架 -- 快手接入
  16. OpenCV简单实现PhotoShop图层混合
  17. 23种设计模式——模板模式
  18. C语言运算符优先级口诀
  19. 从瀑布开发模式到敏捷开发模式(scrum)的思路转换
  20. 各种管理系统的UML建模图

热门文章

  1. 模型量化(3):ONNX 模型的静态量化和动态量化
  2. 小陈WEB漏洞扫描器 V2.0
  3. 杂谈——常用的浏览器请求头User - Agent大全
  4. Python 装饰器解析
  5. 时间集合中获取最接近的时间
  6. 网络直播对企业品牌的影响
  7. MacBook Pro M1 安装 Docker
  8. P42-前端基础-浮动塌陷最终解决方案
  9. TPM零知识学习四 —— tpm2-tss源码安装
  10. C++:输入长方体长宽高计算体积(使用构造函数)。