热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【连载】【FPGA黑金开发板】NIOSII那些事儿USB设备模式(十九)

声明:本文为原创作品,版权归本博文作者所有,如需转载,请注明出处http:www.cnblogs.comkingst简介这一

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

 P6152176

简介

      这一节,我们来讲讲黑金开发板USB部分的内容。黑金开发板上使用的USB芯片是南京沁恒公司的CH376,它支持USB 设备(DEVICE)方式和USB(HOST) 主机方式,并且内置了USB 通讯协议的基本固件,内置了处理Mass-Storage海量存储设备的专用通讯协议的固件,内置了SD 卡的通讯接口固件,内置了FAT16和FAT32 以及FAT12 文件系统的管理固件,支持常用的USB 存储设备(包括U 盘/USB 硬盘/USB 闪存盘/USB 读卡器)和SD 卡(包括标准容量SD 卡和高容量HC-SD 卡以及协议兼容的MMC 卡和TF 卡)。

clip_image002

      由于芯片内部集成了USB通讯协议的基本固件,因此,免去了我们自己编写USB通讯协议的麻烦了。不仅如此,它还集成了文件系统的管理固件,那么,我们不就可以直接读取U盘中的内容了?事实就是这样的,真的方便了很多哦。下面我们就来看看这款芯片到底有多好用吧。

硬件开发

      首先,我们看看这部分电路,如下图所示,我们采用的是8位总线模式,电路结构非常简单,与FPGA相连的一共有12根线,其中8根数据线,1根中断线,3根控制线。

clip_image004

      下面,我们就在软核中添加USB部分的模块,其实都是通过PIO模块控制的。添加后如下图所示,其中USB_DB为8位输出PIO;USB_WR,USB_RD,USB_A0都是1位输出PIO。

clip_image006

而USB_nINT为输入PIO,而且电平中断,如下图设置,

clip_image008

都设置好以后,自动分配地址,中断,接下来就可以编译了。

      编译好以后,回到Quartus界面,整理好以后,如下图所示,要记得USB_DB数据线是双向的,因此,一定要用分配bidir双向引脚,而不要用output。

clip_image010

      下面是中断引脚部分,由于我们是低电平中断,而NIOS电平中断只支持高电平中断,所以我们需要加一个非门,如下图示所示

clip_image012

      都设置好以后,我们就可以分配引脚了,TCL脚本有关USB部分的代码如下

#------------------------USB---------------------------------------#
set_location_assignment PIN_117 -to USB_DB[0]
set_location_assignment PIN_118 -to USB_DB[1]
set_location_assignment PIN_127 -to USB_DB[2]
set_location_assignment PIN_128 -to USB_DB[3]
set_location_assignment PIN_133 -to USB_DB[4]
set_location_assignment PIN_134 -to USB_DB[5]
set_location_assignment PIN_135 -to USB_DB[6]
set_location_assignment PIN_137 -to USB_DB[7]set_location_assignment PIN_113 -to USB_A0
set_location_assignment PIN_115 -to USB_WR
set_location_assignment PIN_116 -to USB_nINT
set_location_assignment PIN_114 -to USB_RD

分配好引脚以后,大家就可以编译了。

软件开发

      USB分主机模式和设备模式,这两种模式硬件部分是相同的,只是在软件编程方面有些不同。这一节,我们来讲设备模式,也就是开发板通过USB接口与主机(电脑)相连,实现开发板与电脑的数据通信。

      我们首先打开NIOS II 9.0 IDE软件,还是老过程,首先编译一遍,Ctril+b。编译成功以后,我们在system.h中会看到USB部分的代码,如下表所示

#define USB_DB_NAME "/dev/USB_DB"
#define USB_DB_TYPE "altera_avalon_pio"
#define USB_DB_BASE 0x00001840
......
#define USB_NINT_NAME "/dev/USB_nINT"
#define USB_NINT_TYPE "altera_avalon_pio"
#define USB_NINT_BASE 0x00001850
......
#define USB_WR_NAME "/dev/USB_WR"
#define USB_WR_TYPE "altera_avalon_pio"
#define USB_WR_BASE 0x00001860
......
#define USB_RD_NAME "/dev/USB_RD"
#define USB_RD_TYPE "altera_avalon_pio"
#define USB_RD_BASE 0x00001870
......
#define USB_A0_NAME "/dev/USB_A0"
#define USB_A0_TYPE "altera_avalon_pio"
#define USB_A0_BASE 0x00001880
......

      下面,我们来添加USB部分的代码。

      首先,我们建立一个在inc下面建立一个usb.h文件,内容如下

#ifndef __usb_h__
#define __usb_h__
//-----------------Include files-------------------------//
#include "system.h"
//----------------- CH375 DEFINE-------------------------//
//下面部分是USB寄存器地址,这部分定义可以看CH376的芯片手册
#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
#define USB_INT_DISCONNECT 0X16
#define USB_INT_SUCCESS 0X14
#define USB_INT_DISK_READ 0X1D
//-----------------bus define----------------------------//
/*下面是USB的接口部分定义,这次我没有像以往那样定义结构体,是为了让大家感受一下各种形式的编程。大家要注意PIO_USB_DB_DIR的定义,通过以前的讲解,不知道大家是否理解,它是USB数据线的方向控制寄存器的定义,知道为什么要+4么,大家自己考虑吧,不明白就看看附录中的有关PIO问题解析部分内容吧*/
#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_INT *(volatile unsigned long int *)USB_INT_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 int initialize_usb(void);
extern int set_usb_mode(unsigned char);
extern int send_string_to_usb(char *str,int str_len);
extern void write_command_to_usb(unsigned char command);
extern void write_data_to_usb(unsigned char data);#endif //__usb_h__

      接下来,我们看看CH376的时序图,如下图所示

clip_image014

     我们就根据上面的时序图编写驱动部分,在driver中建立一个usb.c文件,内容如下表所示

/** ==================================================================* Filename: usb.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 files-------------------------//
#include "../inc/usb.h"
#include "altera_avalon_pio_regs.h"
#include "sys/alt_irq.h"
#include
#include
//-----------------Function Prototype--------------------//
void write_command_to_usb(unsigned char command);
void write_data_to_usb(unsigned char data);
unsigned char read_data_from_usb(void);
void delay(void);
//-----------------Variable------------------------------//USB_T usb;
//-----------------Function------------------------------///* * === FUNCTION ===================================================* Name: irq_usb* Description: 中断函数* =================================================================*/
void irq_usb(void)
{unsigned int i;unsigned char interrupt_status,data_len;// static int times=0;write_command_to_usb(GET_STATUS);interrupt_status=read_data_from_usb();switch(interrupt_status){//Devicecase INT_EP2_OUT:write_command_to_usb(RD_USB_DATA);data_len=read_data_from_usb();for(i=0;i}/* * === FUNCTION ===================================================* Name: send_string_to_usb* Description: 发送字符串* =================================================================*/
int send_string_to_usb(char *str,int str_len)
{int i;write_command_to_usb(WR_USB_DATA7);write_data_to_usb(str_len);for(i=0;i}
/* * === FUNCTION ===================================================* Name: initialize_usb* Description: 初始化USB* =================================================================*/
int initialize_usb(void)
{PIO_USB_RD=1;PIO_USB_WR=1;PIO_USB_A0=1;usb.receive_ok_flag=0;// enable the io interruptIOWR_ALTERA_AVALON_PIO_IRQ_MASK(USB_NINT_BASE,1);IOWR_ALTERA_AVALON_PIO_EDGE_CAP(USB_NINT_BASE,0);alt_irq_register(USB_NINT_IRQ,NULL,irq_usb);set_usb_mode(USB_DEVICE);return 0;
}
/* * === FUNCTION ===================================================* Name: usb_usb_mode* Description: 设置USB模式* =================================================================*/
int set_usb_mode(unsigned char type)
{write_command_to_usb(SET_USB_MODE);write_data_to_usb(type);read_data_from_usb();if((read_data_from_usb())==0x51)return 0;else return -1;}
/* * === FUNCTION ===================================================* Name: write_command_to_usb* Description: 写命令* =================================================================*/
void write_command_to_usb(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: write_data_to_usb* Description: 写数据* =================================================================*/
void write_data_to_usb(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: read_data_from_usb* Description: 读数据* =================================================================*/unsigned char read_data_from_usb(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;
}

      编写好驱动以后,我们需要编写主函数测试代码

#include
#include
#include "../inc/usb.h"int main()
{unsigned char tmp[] = "Hello USB!\n";initialize_usb();while(1){ if(usb.receive_ok_flag){printf("%s\n",usb.receive_buffer);usb.receive_ok_flag = 0;}send_string_to_usb(tmp,sizeof(tmp));usleep(100000);}return 0;
}

      程序都写完了,但工作还没有结束,如果要想调试,我们首先还需要在你的电脑上安装CH376的驱动。

     首先,去南京沁恒的网站下载驱动,下载地址是:http://www.wch.cn/download/list.asp?id=66,CH376的驱动跟CH372,CH375是一样的。

双击CH372DRV.EXE,开始安装驱动,如下图所示,点击INSTALL,直接安装就可以了。

clip_image016

上位机编程

      为了调试,我们还需要上位机的软件来配合,就像串口调试精灵的一个东西。这部分工作属于上位机部分的内容了。我在这里简单介绍一下吧。

南京沁恒网站提供了上位机需要的静态库函数和头文件,下载地址是:http://www.wch.cn/download/list.asp?id=28,我们可以利用他们构建自己的上位机。我使用的是NI公司的Labwindows/CVI 8.1,当然大家也可以使用VC等软件开发。

clip_image018

我感觉这个软件还是蛮好用的,大家可以研究一下。写好的上位机面板如下图所示,

clip_image020

      我们可以利用它进行简单的发送和接收,软件还不够完善。下面简单介绍一下使用方法,首先需要将FPGA运行起来,然后点击上位机的打开按钮。如果是接收的话,点击Reveive,每点一次接收一次。如果发送的话,将你发送的数据写到上面的输入框中,点击Send,每点一次发送一次。如下图示

clip_image022

      好了,到这里,有关USB的设备模式的内容就讲完了。下一节,我们将讲解有关USB主模式的内容,也就是如何读取U盘等相关内容。谢谢大家!



推荐阅读
  • 下载器,就是一种网络工具,从网络中接收自己想要的数据。下载器是一个网络客户端。它的下载流程无非就是客户端连接服务器端,然后发送资源下载请求 ... [详细]
  • c语言自定义BOOL函数C语言没有BOOL类型变量boolean类型是C++所独有的由于使用BOOL类型可以使代码更具有可读性,很多编程者都在C中自己定义了类似的应用,一般方法有两 ... [详细]
  • Matlab中利用mex编译Opencv实现画板绘图功能
    图形绘制是标记和可视化数据的重要方法.通过在Matlab中集成画板绘图功能,可为科学计算提供便利.1设置Matlab支持Opencv编译操作系统:麒麟14.04(基于Ubu ... [详细]
  • oracle text db2,从Oracle 到DB2(一)
    在实际的软件项目的开发过程中,特别是在企业的应用系统集成(EAI)项目中广大开发人员经常遇到不同关系型数据库之间的数据移植问题。笔者根据自己在工作中的不同数据库数据移 ... [详细]
  • 使用临时文件tmpnam该函数的功能是产生一个唯一的文件名系统回味该文件分配一块内存来保存临时变量例如下面的代码#includeintmain(){charnam ... [详细]
  • 这篇文章主要讲解了“GradeBook类怎么定义”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Grad ... [详细]
  • 猪猪猫.CNWINXPSP2电脑城装机12DVD[豪华版]
    直接下载地址http:bt.jujumao.cn点击下载种子下载信息[点击浏览该文件:2007-12-19猪猪猫.cn-winxpsp2电脑城装机12豪华版.torrent]| ... [详细]
  • 是的,可以在RDSMySqlEngine中进行Master-Master复制。但它需要一些操作与实例。先决条件:1)为启用二进制日志记录创建两个实例的只 ... [详细]
  • 一、在androidStudio中实现tabs比较简单,新建项目就可以选择tabs模板进行创建,默认实现tabs功能:直接运行项目就可以看到效果:可以说非常简单,但是我们在实际开发 ... [详细]
  • 【实践】基于RTThread的智慧路灯案例实验分享
    之前分享了基于LiteOS的智慧农业案例实验分享基于LiteOS的智慧农业案例实验分享,阅读量挺不错,看样子大家都挺喜欢这种实验。那咱们就再来一个类似的实验:基于RT-Thread ... [详细]
  • 阿里云大数据计算服务MaxCompute (原名 ODPS)
     MaxCompute是阿里EB级计算平台,经过十年磨砺,它成为阿里巴巴集团数据中台的计算核心和阿里云大数据的基础服务。去年MaxCompute做了哪些工作,这些工作背后的原因是什 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了迭代数组的问题相关的知识,希望对你有一定的参考价值。我在浏 ... [详细]
  • 一、域名解析记录说明记录类型A:用来指定域名的IPv4地址(如:8.8.8.8),如果需要将域名指向一个IP ... [详细]
  • socket8 [命名管道]
    ::命名管道不但能实现同一台机器上两个进程通信,还能在网络中不同机器上的两个进程之间的通信机制。与邮槽不同,命名管道是采用基于连接并且可靠的传输方式,所以命名管道传输数据只能一对一 ... [详细]
  • 我是python小白一枚,对kivy开发手机app产生了兴趣,并没感觉到kivy写代码有多难,折腾打包成手机apk倒是花了好长时间,走过了大大小小的坑,这里把经验记录下来,供大家参 ... [详细]
author-avatar
手机用户2602906305_849
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有