Chinaunix首页 | 论坛 | 博客
  • 博客访问: 132892
  • 博文数量: 55
  • 博客积分: 1870
  • 博客等级: 上尉
  • 技术积分: 540
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-21 20:51
文章分类

全部博文(55)

文章存档

2011年(27)

2009年(3)

2008年(25)

我的朋友

分类: C/C++

2011-05-04 13:57:19

声明:本文转载于http://www.cnblogs.com/kingst,版权归黑金动力社区(http://www.heijin.org)所有。 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部分的代码如下

01#------------------------USB---------------------------------------#
02set_location_assignment PIN_117 -to USB_DB[0]
03set_location_assignment PIN_118 -to USB_DB[1]
04set_location_assignment PIN_127 -to USB_DB[2]
05set_location_assignment PIN_128 -to USB_DB[3]
06set_location_assignment PIN_133 -to USB_DB[4]
07set_location_assignment PIN_134 -to USB_DB[5]
08set_location_assignment PIN_135 -to USB_DB[6]
09set_location_assignment PIN_137 -to USB_DB[7]
10 
11set_location_assignment PIN_113 -to USB_A0
12set_location_assignment PIN_115 -to USB_WR
13set_location_assignment PIN_116 -to USB_nINT
14set_location_assignment PIN_114 -to USB_RD

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

软件开发

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

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

01#define USB_DB_NAME "/dev/USB_DB"
02#define USB_DB_TYPE "altera_avalon_pio"
03#define USB_DB_BASE 0x00001840
04......
05#define USB_NINT_NAME "/dev/USB_nINT"
06#define USB_NINT_TYPE "altera_avalon_pio"
07#define USB_NINT_BASE 0x00001850
08......
09#define USB_WR_NAME "/dev/USB_WR"
10#define USB_WR_TYPE "altera_avalon_pio"
11#define USB_WR_BASE 0x00001860
12......
13#define USB_RD_NAME "/dev/USB_RD"
14#define USB_RD_TYPE "altera_avalon_pio"
15#define USB_RD_BASE 0x00001870
16...... 
17#define USB_A0_NAME "/dev/USB_A0"
18#define USB_A0_TYPE "altera_avalon_pio"
19#define USB_A0_BASE 0x00001880
20......

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

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

01#ifndef __usb_h__
02#define __usb_h__
03//-----------------Include files-------------------------//
04#include "system.h"
05//----------------- CH375 DEFINE-------------------------//
06//下面部分是USB寄存器地址,这部分定义可以看CH376的芯片手册
07#define USB_HOST    0X06
08#define USB_DEVICE  0x02
09#define USB_DISABLE 0X00
10 
11#define RESET_ALL   0X05
12#define CHECK_EXIST 0X06
13#define SET_USB_ID  0X12
14#define SET_USB_MODE    0X15
15#define GET_STATUS  0X22
16#define UNLOCK_USB  0X23
17#define RD_USB_DATA 0X28
18#define WR_USB_DATA5    0X2A
19#define WR_USB_DATA7    0X2B
20#define GET_IC_VER  0X01
21#define ENTER_SLEEP 0X03
22#define CHK_SUSPEND 0X0B
23#define RD_USB_DATA0    0X27
24 
25#define RET_SUCCESS 0X51
26#define RET_ABORT   0X5B
27 
28#define INT_EP2_OUT 0x02
29#define INT_EP2_IN  0x0a
30 
31//host
32#define DISK_READ   0X54
33#define DISK_RD_GO  0X55
34#define DISK_READY  0X59
35#define DISK_INIT   0X51
36//status
37#define USB_INT_CONNECT 0x15
38#define USB_INT_DISCONNECT 0X16
39#define USB_INT_SUCCESS 0X14
40#define USB_INT_DISK_READ   0X1D
41//-----------------bus define----------------------------//
42/*下面是USB的接口部分定义,这次我没有像以往那样定义结构体,是为了让大家感受一下各种形式的编程。大家要注意PIO_USB_DB_DIR的定义,通过以前的讲解,不知道大家是否理解,它是USB数据线的方向控制寄存器的定义,知道为什么要+4么,大家自己考虑吧,不明白就看看附录中的有关PIO问题解析部分内容吧*/
43#define PIO_USB_DB      *(volatile unsigned long int *)USB_DB_BASE
44#define PIO_USB_WR      *(volatile unsigned long int *)USB_WR_BASE
45#define PIO_USB_RD      *(volatile unsigned long int *)USB_RD_BASE
46#define PIO_USB_A0      *(volatile unsigned long int *)USB_A0_BASE
47#define PIO_USB_INT     *(volatile unsigned long int *)USB_INT_BASE
48#define PIO_USB_DB_DIR  *(volatile unsigned long int *)(USB_DB_BASE+4)
49 
50#define VID 0X0FFE
51#define PID 0X1000
52 
53typedef struct{
54    char receive_buffer[200];
55    int send_ok_flag;
56    int receive_ok_flag;
57}USB_T;
58//-----------------Extern function------------------------//
59 
60extern USB_T usb;
61extern int initialize_usb(void);
62extern int set_usb_mode(unsigned char);
63extern int send_string_to_usb(char *str,int str_len);
64extern void write_command_to_usb(unsigned char command);
65extern void write_data_to_usb(unsigned char data);
66 
67#endif //__usb_h__

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

clip_image014

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

001/*
002 * ==================================================================
003 *       Filename:  usb.c
004 *   Description: 
005 *        Version:  1.0.0
006 *        Created:  2010.4.16
007 *       Revision:  none
008 *       Compiler:  Nios II 9.0 IDE
009 *         Author:  马瑞 (AVIC)
010 *          Email:  avic633@gmail.com 
011 * =================================================================
012 */
013//-----------------Include files-------------------------//
014#include "../inc/usb.h"
015#include "altera_avalon_pio_regs.h"
016#include "sys/alt_irq.h"
017#include
018#include
019//-----------------Function Prototype--------------------//
020void write_command_to_usb(unsigned char command);
021void write_data_to_usb(unsigned char data);
022unsigned char read_data_from_usb(void);
023void delay(void);
024//-----------------Variable------------------------------//
025 
026USB_T usb;
027//-----------------Function------------------------------//
028 
029/*
030 * ===  FUNCTION  ===================================================
031 *          Name:  irq_usb
032 * Description:   中断函数
033 * =================================================================
034 */
035void irq_usb(void)
036{
037    unsigned int i;
038    unsigned char interrupt_status,data_len;
039    //  static int times=0;
040 
041    write_command_to_usb(GET_STATUS);
042 
043    interrupt_status=read_data_from_usb();
044 
045    switch(interrupt_status){
046        //Device
047        case INT_EP2_OUT:
048 
049            write_command_to_usb(RD_USB_DATA);
050            data_len=read_data_from_usb();
051 
052            for(i=0;i
053                            usb.receive_buffer[i]=read_data_from_usb();
054            usb.receive_buffer[i]='\0';
055 
056            usb.receive_ok_flag=1;
057 
058            break;
059 
060        case INT_EP2_IN:
061            write_command_to_usb(UNLOCK_USB);
062            usb.send_ok_flag=1;
063            break;
064 
065        default :break;
066 
067    }
068 
069    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(USB_NINT_BASE,0x00);
070}
071 
072/*
073 * ===  FUNCTION  ===================================================
074 *          Name:  send_string_to_usb
075 *  Description:  发送字符串
076 * =================================================================
077 */
078int send_string_to_usb(char *str,int str_len)
079{
080    int i;
081 
082    write_command_to_usb(WR_USB_DATA7);
083    write_data_to_usb(str_len);
084 
085    for(i=0;i
086 
087    return 0;
088}
089/*
090 * ===  FUNCTION  ===================================================
091 *          Name:  initialize_usb
092 *  Description:  初始化USB
093 * =================================================================
094 */
095int initialize_usb(void)
096{
097    PIO_USB_RD=1;
098    PIO_USB_WR=1;
099    PIO_USB_A0=1;
100    usb.receive_ok_flag=0;
101 
102    // enable the io interrupt
103    IOWR_ALTERA_AVALON_PIO_IRQ_MASK(USB_NINT_BASE,1);
104    IOWR_ALTERA_AVALON_PIO_EDGE_CAP(USB_NINT_BASE,0);
105 
106    alt_irq_register(USB_NINT_IRQ,NULL,irq_usb);
107 
108    set_usb_mode(USB_DEVICE);
109 
110    return 0;
111}
112/*
113 * ===  FUNCTION  ===================================================
114 *           Name:  usb_usb_mode
115 *  Description:  设置USB模式
116 * =================================================================
117 */
118int set_usb_mode(unsigned char type)
119{
120    write_command_to_usb(SET_USB_MODE);
121    write_data_to_usb(type);
122    read_data_from_usb();
123 
124    if((read_data_from_usb())==0x51)return 0;
125    else return -1;
126 
127}
128/*
129 * ===  FUNCTION  ===================================================
130 *          Name:   write_command_to_usb
131 *  Description:   写命令
132 * =================================================================
133 */
134void write_command_to_usb(unsigned char command)
135{
136    //A0
137    PIO_USB_A0=1;
138 
139    //DB DIR output
140    PIO_USB_DB_DIR=0xff;
141 
142    PIO_USB_DB=command;
143 
144    PIO_USB_WR=0;
145    PIO_USB_WR=1;
146}
147/*
148 * ===  FUNCTION  ===================================================
149 *          Name:  delay
150 *  Description:  延时
151 * =================================================================
152 */
153void delay(void)
154{
155    int i;
156    for(i=0;i<1000;i++);
157}
158/*
159 * ===  FUNCTION  ===================================================
160 *           Name:  write_data_to_usb
161 *  Description:  写数据
162 * =================================================================
163 */
164void write_data_to_usb(unsigned char data)
165{
166    //A0
167    PIO_USB_A0=0;
168 
169    //DB DIR output
170    PIO_USB_DB_DIR=0xff;
171 
172    PIO_USB_DB=data;
173 
174    usleep(20);
175    PIO_USB_WR=0;
176    delay();
177    usleep(20);
178    PIO_USB_WR=1
179}
180/*
181 * ===  FUNCTION  ===================================================
182 *          Name:  read_data_from_usb
183 *  Description:  读数据
184 * =================================================================
185 */
186 
187unsigned char read_data_from_usb(void)
188{
189    unsigned char data=0;
190 
191    //A0
192    PIO_USB_A0=0;
193 
194    //DB DIR output
195    PIO_USB_DB_DIR=0;
196 
197    PIO_USB_RD=0;
198    delay();
199    data=PIO_USB_DB;
200    PIO_USB_RD=1;
201 
202    return data;
203}

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

01#include
02#include
03#include "../inc/usb.h"
04 
05int main()
06{
07    unsigned char tmp[] = "Hello USB!\n";
08 
09    initialize_usb();
10 
11    while(1){
12        if(usb.receive_ok_flag){
13            printf("%s\n",usb.receive_buffer);
14            usb.receive_ok_flag = 0;
15        }
16 
17        send_string_to_usb(tmp,sizeof(tmp));
18        usleep(100000);
19    }
20    return 0;
21}

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

     首先,去南京沁恒的网站下载驱动,下载地址是:,CH376的驱动跟CH372,CH375是一样的。

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

clip_image016

上位机编程

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

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

clip_image018

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

clip_image020

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

clip_image022

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

阅读(1426) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~