26.02.2013 Views

第1章ZLG/CF 驱动使用 - Read

第1章ZLG/CF 驱动使用 - Read

第1章ZLG/CF 驱动使用 - Read

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

第1章 ZLG/<strong>CF</strong> <strong>驱动使用</strong><br />

1.1 基于 LPC2210 的 ZLG/<strong>CF</strong> <strong>驱动使用</strong><br />

<strong>CF</strong> 卡有 PC 卡 I/O、MEMORY 及 True IDE 等 3 种模式,而 True IDE 模式兼容 IDE 硬<br />

盘,该模式比其它的两种模式更实用,是 3 种模式中使用较多的一种。本节中描述 <strong>CF</strong> 卡在<br />

True IDE 模式下的应用。<br />

使用 LPC2210 的通用可编程 I/O 口,模拟产生 ATA 设备的读写时序,实现对 <strong>CF</strong> 卡及<br />

IDE 硬盘等 ATA 设备读写操作。使用 LPC2210 的 GPIO 功能,可以非常灵活而简单地实现<br />

ATA 读写时序。<br />

1.1.1 LPC2210 与 <strong>CF</strong> 卡及 IDE 硬件连接<br />

LPC2210 的 GPIO 引脚与 <strong>CF</strong> 卡及 IDE 硬盘的硬件接线图分别如图 1.1、图 1.2 所示。<br />

P2.19_D19<br />

P2.20_D20<br />

P2.21_D21<br />

P2.22_D22<br />

P2.23_D23<br />

P1.19<br />

VDD3.3<br />

P1.18<br />

P1.17<br />

P1.16<br />

P2.16_D16<br />

P2.17_D17<br />

P2.18_D18<br />

P1.24<br />

VCC<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

10<br />

11<br />

12<br />

13<br />

14<br />

15<br />

16<br />

17<br />

18<br />

19<br />

20<br />

21<br />

22<br />

23<br />

24<br />

25<br />

R94<br />

1K<br />

J17<br />

1<br />

2<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

9<br />

10<br />

11<br />

12<br />

13<br />

14<br />

15<br />

16<br />

17<br />

18<br />

19<br />

20<br />

21<br />

22<br />

23<br />

24<br />

25<br />

26<br />

27<br />

28<br />

29<br />

30<br />

31<br />

32<br />

33<br />

34<br />

35<br />

36<br />

37<br />

38<br />

39<br />

40<br />

41<br />

42<br />

43<br />

44<br />

45<br />

46<br />

47<br />

48<br />

49<br />

50<br />

HEADER 25X2_<strong>CF</strong><br />

D4<br />

LED<br />

26<br />

27<br />

28<br />

29<br />

30<br />

31<br />

32<br />

33<br />

34<br />

35<br />

36<br />

37<br />

38<br />

39<br />

40<br />

41<br />

42<br />

43<br />

44<br />

45<br />

46<br />

47<br />

48<br />

49<br />

50<br />

图 1.1 LPC2210 与 <strong>CF</strong> 卡接线图<br />

VDD3.3<br />

ATA_DASP<br />

P1.25<br />

P2.24_D24<br />

P2.25_D25<br />

P2.26_D26<br />

ATA_DASP<br />

P2.27_D27<br />

P2.28_D28<br />

P2.29_D29<br />

P2.30_D30<br />

P2.31_D31<br />

P1.20<br />

P0.21_PWM5<br />

P0.19_M AT1.2<br />

VDD3.3<br />

P0.20_M AT1.3<br />

VDD3.3<br />

P0.17_CAP1.2<br />

P0.22_M AT0.0<br />

注意:图 1.1 中 <strong>CF</strong> 卡的 CSEL 引脚直接接地,开发板上的 <strong>CF</strong> 卡已被配置为主设备。IDE 硬盘的主从<br />

配置,通过硬盘上的跳线选择。


R13<br />

10K<br />

R33<br />

10K<br />

VDD3.3<br />

P0.17_CAP1.2<br />

P2.23_D23<br />

P2.22_D22<br />

P2.21_D21<br />

P2.20_D20<br />

P2.19_D19<br />

P2.18_D18<br />

P2.17_D17<br />

P2.16_D16<br />

GND<br />

P0.18_CAP1.3<br />

P0.19_MAT1.2<br />

P0.21_PWM 5<br />

P0.22_MAT0.0<br />

P1.21<br />

P0.20_MAT1.3<br />

P1.17<br />

P1.16<br />

P1.19<br />

ATA_DASP<br />

J3<br />

1<br />

3<br />

5<br />

7<br />

9<br />

11<br />

13<br />

15<br />

17<br />

19<br />

21<br />

23<br />

25<br />

27<br />

29<br />

31<br />

33<br />

35<br />

37<br />

39<br />

2<br />

4<br />

6<br />

8<br />

10<br />

12<br />

14<br />

16<br />

18<br />

20<br />

22<br />

24<br />

26<br />

28<br />

30<br />

32<br />

34<br />

36<br />

38<br />

40<br />

GND<br />

P2.24_D24<br />

P2.25_D25<br />

P2.26_D26<br />

P2.27_D27<br />

P2.28_D28<br />

P2.29_D29<br />

P2.30_D30<br />

P2.31_D31<br />

NC<br />

GND<br />

GND<br />

GND<br />

P1.23<br />

GND<br />

P1.24<br />

P1.25<br />

P1.18<br />

P1.20<br />

GND<br />

VCC<br />

R94<br />

1K<br />

IDE/USER_COM<br />

D4<br />

LED<br />

ATA_DASP<br />

图 1.2 LPC2210 与 IDE 硬盘接线图<br />

R31<br />

10K<br />

VDD3.3<br />

表 1.1 为 LPC2210 的 GPIO 引脚与 <strong>CF</strong> 卡及 IDE 硬盘引脚连接分配表,表中描述了各<br />

GPIO 引脚与 <strong>CF</strong> 卡及 IDE 硬盘对应的控制信号线,根据表中的描述配置 LPC2210 相关的寄<br />

存器。<br />

表 1.1 LPC2210 的 GPIO 引脚与 <strong>CF</strong> 卡及 IDE 硬盘连接引脚分配<br />

LPC2210 <strong>CF</strong> 卡 IDE 硬盘 I/O LPC2210 <strong>CF</strong> 卡 IDE 硬盘 I/O<br />

*P0.17 -RESET -RESET O *P1.17 A01 DA1 O<br />

*P2.16~P2.31 D00~D15 DD0~DD15 I 、O *P1.16 A00 DA0 O<br />

P0.18 DMARQ I *P1.19 -CS0 -CS0 O<br />

*P0.19 -IOWR -DIOW O P1.23 CSEL O<br />

*P0.21 -IORD -DIOR O P1.24 -IOCS16 -IOCS16 I<br />

P0.22 IORDY IORDY I P1.25 -PDIAG -PDIAG I<br />

P1.21 -DMACK I *P1.18 A02 DA2 O<br />

P0.20 INTRQ INTRQ I *P1.20 -CS1 -CS1 O<br />

注:1.I/O 输入与输出是相对于 LPC2210 来说的,I 为 LPC2210 的输入,O 为输出。<br />

2.表中“*”号的引脚,为使用到的引脚,其它引脚不需使用,但需要配置为适当的状态。<br />

根据图 1.1、图 1.2 和表 1.1 所描述,为相关的引脚定义有意义的标号,如程序清单 1.1<br />

所示。<br />

/* EeayARM2200 和 IDE 接口连接 */<br />

#ifdef ATA_BUS_AT_8bit /*8 位总线*/<br />

程序清单 1.1 ATA 接口连接引脚定义<br />

#define ATA_DATA 0x00ff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2.23 */<br />

#else /*16 位总线*/<br />

#define ATA_DATA 0xffff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2.31 */<br />

#endif<br />

R32<br />

10K


#define IDE_A0 (1


义如程序清单 1.5 所示。<br />

#ifdef ATA_BUS_AT_8bit<br />

程序清单 1.2 读取 ATA 设备寄存器函数<br />

uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数*/<br />

{<br />

}<br />

#else<br />

uint16 res ;<br />

OS_ENTER_CRITICAL(); /*关中断*/<br />

IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入(ATA_DATA 为输入)*/<br />

IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平*/<br />

IO1SET = reg; /*地址高电平位输出,完成地址的设置*/<br />

/*读低字节*/<br />

IO0CLR = IDE_RD; /*读信号脚置低*/<br />

res = (uint8)((IO2PIN&ATA_DATA) >>16); /*读取数据*/<br />

IO0SET = IDE_RD; /*使读信号为高*/<br />

/*读高字节*/<br />

if(reg==ATA_REG_DATA) /*如果读数据寄存器,读高字节*/<br />

{<br />

}<br />

IO0CLR = IDE_RD; /*读信号脚置低*/<br />

res += (uint16)((IO2PIN&ATA_DATA)>>8); /*读取数据*/<br />

IO0SET = IDE_RD; /*使读信号为高*/<br />

IO1SET = Addr_CS_at_P1; /*输出控制信号置高*/<br />

OS_EXIT_CRITICAL(); /*开中断*/<br />

return res; /*返回数值*/<br />

uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数*/<br />

{<br />

}<br />

uint16 res ;<br />

OS_ENTER_CRITICAL(); /*关中断*/<br />

IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入(ATA_DATA 为输入)*/<br />

IO1CLR = Addr_CS_at_P1; /*控所硬盘引脚信号输出(输出高电平)*/<br />

IO1SET = reg; /*控所硬盘引脚信号输出(输出低电平)*/<br />

IO0CLR = IDE_RD; /*读信号脚置低*/<br />

res = (uint16)(IO2PIN >>16); /*读取数据*/<br />

IO0SET = IDE_RD;<br />

IO1SET = Addr_CS_at_P1; /*输出控制信号置高*/<br />

OS_EXIT_CRITICAL(); /*开中断*/<br />

return res;


#endif<br />

写 ATA 设备寄存器步骤如下:<br />

(1) 关系统中断,预防在写寄存器操作中产生中断;<br />

(2) 设置 GPIO 模拟 ATA 接口数据的引脚为输出状态,准备输出数据到设备数据线;<br />

(3) 设置 ATA 设备寄存器的相应地址;<br />

(4) 设置 GPIO 模拟 ATA 接口数据的引脚的电平为要写到设备的值;<br />

(5) 使写 ATA 设备寄存器信号引脚为低电平;<br />

(6) 使写 ATA 设备寄存器信号引脚为高电平;<br />

(7) 如果 ATA 设备(<strong>CF</strong> 卡)是 8 位总线模式,并且操作的是数据寄存器(16 位),则<br />

需重复(3)、(4)、(5)步。<br />

(8) 取消 ATA 设备寄存器地址的选择。<br />

(9) 设置 GPIO 模拟 ATA 接口的数据总线引脚为输入状态,释放总线。<br />

(10) 开系统中断。<br />

LPC2210 的 GPIO 引脚模拟写 ATA 设备寄存器的函数如程序清单 1.3 所示,ATA 设备<br />

各寄存器地址宏定义如程序清单 1.5 所示。<br />

#ifdef ATA_BUS_AT_8bit<br />

程序清单 1.3 写 ATA 设备寄存器函数<br />

void SYS_PortOut(uint32 reg, uint16 data) /*使用 8 位数据总线*/<br />

{<br />

}<br />

OS_ENTER_CRITICAL(); /*关中断*/<br />

IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出*/<br />

IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平*/<br />

IO1SET = reg; /*地址高电平位输出,完成地址的设置*/<br />

/*写低字节*/<br />

IO2CLR = ATA_DATA; /*数据总线上输出全为低电平*/<br />

IO2SET = data


#else<br />

void SYS_PortOut(uint32 reg, uint16 data) /*使用 16 位总线*/<br />

{<br />

}<br />

#endif<br />

OS_ENTER_CRITICAL(); /*关中断*/<br />

IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出*/<br />

IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平*/<br />

IO1SET = reg; /*地址高电平位输出,完成地址的设置*/<br />

IO2CLR = ATA_DATA; /*数据总线上输出全为低电平*/<br />

IO2SET = data


}<br />

#endif<br />

(1) 如果驱动用于 uC/OS-II 操作系统,则不需要编译这两个开、关中断函数,因为在<br />

uC/OS-II 中已定义了这两个函数。<br />

SYS_PortIn()和 SYS_PortOut()函数通过使用程序清单 1.5 中定义的 ATA 设备寄存器的地<br />

址的宏作为参数,实现对 ATA 设备各寄存器的读写操作。<br />

ZLG/<strong>CF</strong> 驱动读写 ATA 设备寄存器的函数如程序清单 1.6 所示。<br />

/*GPIO 引脚影射寄存器地址*/<br />

程序清单 1.5 设备寄存器地址宏定义<br />

#define ATA_REG_DATA IDE_CS1 /*数据寄存器*/<br />

#define ATA_REG_ERR (IDE_CS1 + IDE_A0) /*读错误寄存器*/<br />

#define ATA_REG_FEATURE (IDE_CS1 + IDE_A0) /*写功能寄存器*/<br />

#define ATA_REG_SECCNT (IDE_CS1 + IDE_A1) /*扇区计数器*/<br />

#define ATA_REG_SECTOR (IDE_CS1 + IDE_A1 + IDE_A0) /*扇区号*/<br />

#define ATA_REG_CYLI_LOW (IDE_CS1 + IDE_A2) /*柱面低 8 位*/<br />

#define ATA_REG_CYLI_HIGH (IDE_CS1 + IDE_A2 + IDE_A0) /*柱面高8位*/<br />

#define ATA_REG_DEVICE_HEAD (IDE_CS1 + IDE_A2 + IDE_A1) /*选择主从,模式,磁头*/<br />

#define ATA_REG_COMMAND (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*写命令寄存器*/<br />

#define ATA_REG_STATUS (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*读状态寄存器*/<br />

#define ATA_REG_CONTROL (IDE_CS0 + IDE_A2 + IDE_A1) /*写控制寄存器*/<br />

#define ATA_REG_ASTATUS (IDE_CS0 + IDE_A2 + IDE_A1) /*读辅助状态寄存器*/<br />

/*驱动与硬件对 ATA 设备寄存器操作接口*/<br />

程序清单 1.6 读写设备相关寄存器接口函数<br />

#define GetData() SYS_PortIn(ATA_REG_DATA) /*读数据寄存器,与驱动接口*/<br />

#define SetData(x) SYS_PortOut(ATA_REG_DATA,x) /*写数据寄存器,与驱动接口*/<br />

#define GetERR() SYS_PortIn(ATA_REG_ERR) /*读错误寄存器,与驱动接口*/<br />

#define SetFeature(x) SYS_PortOut(ATA_REG_FEATURE,x) /*写特征寄存器,与驱动接口*/<br />

#define GetSECCNT() SYS_PortIn(ATA_REG_SECCNT) /*读扇区计数寄存器,与驱动接口*/<br />

#define SetSECCNT(x) SYS_PortOut(ATA_REG_SECCNT,x) /*写扇区计数寄存器,与驱动接口*/<br />

#define GetSector() SYS_PortIn(ATA_REG_SECTOR) /*读扇区寄存器,与驱动接口*/<br />

#define SetSector(x) SYS_PortOut(ATA_REG_SECTOR,x) /*写扇区寄存器,与驱动接口*/<br />

#define GetCylinderLow() SYS_PortIn(ATA_REG_CYLINDER_LOW) /*读柱面低寄存器,与驱动接口*/<br />

#define SetCylinderLow(x) SYS_PortOut(ATA_REG_CYLINDER_LOW,x)/*写柱面低寄存器,与驱动接口*/<br />

#define GetCylinderHigh() SYS_PortIn(ATA_REG_CYLI_HIGH) /*读柱面高 8 位寄存器,与驱动接口*/<br />

#define SetCylinderHigh(x) SYS_PortOut(ATA_REG_CYLI_HIGH,x) /*写柱面高 8 位寄存器,与驱动接口*/<br />

#define GetDeviceHead() SYS_PortIn(ATA_REG_DEVICE_HEAD) /*读设备磁头寄存器,与驱动接口*/<br />

#define SetDeviceHead(x) SYS_PortOut(ATA_REG_DEVICE_HEAD,x)/*写设备磁头寄存器,与驱动接口*/<br />

#define GetStatus() SYS_PortIn(ATA_REG_STATUS) /*读状态寄存器,与驱动接口*/<br />

#define SetCommand(x) SYS_PortOut(ATA_REG_COMMAND,x) /*写命令寄存器,与驱动接口*/<br />

2.硬件复位函数


系统中定义了 IDE_RST 引脚控制 ATA 设备的硬件复位。如程序清单 1.7 所示。<br />

程序清单 1.7 硬件复位函数<br />

/*******************************************************************************************<br />

** 函数名称: SYS_IdeHardReset<br />

** 功能描述: ATA 设备硬件复位<br />

** 输 入: 无<br />

** 输 出: 无<br />

** 全局变量:<br />

** 调用模块: SYS_WaitInUS(),等待微秒函数。<br />

*******************************************************************************************/<br />

void SYS_IdeHardReset(void)<br />

{<br />

}<br />

IOCLR = IDE_RST; /*复位引脚置低*/<br />

SYS_WaitInUS(30); /*延时大于 25 微秒*/<br />

IOSET = IDE_RST; /*复位引脚置高*/<br />

SYS_WaitInUS(5000); /*延时大于 2 毫秒*/<br />

/*******************************************************************************************<br />

** 函数名称: SYS_WaitInUS<br />

** 功能描述: 延时等级约 1 微秒函数,该函数根据系统时间不同与不同,但不应少到 1 微秒。<br />

** 输 入: times,延时时间等级<br />

** 输 出: 无<br />

** 全局变量:<br />

** 调用模块:<br />

*******************************************************************************************/<br />

void SYS_WaitInUS(uint32 times)<br />

{ uint32 c;<br />

}<br />

for(;0


表 1.2 描述了 PINSEL1 相关位的配置。<br />

表 1.2 PINSEL1 相关位的配置<br />

PINSEL1(0xE002C004) 描述 配置值(二进制)<br />

� PINSEL2 寄存器<br />

1:0 引脚 P0.16 根据其它需要定义 XX<br />

7:2 使引脚 P0.19:17 为 GPIO 000000<br />

13:8 使引脚 P0.22:20 为 GPIO 000000<br />

15:14 引脚 P0.23 根据其它需要定义 XX<br />

23:16 引脚 P0.27:24 根据其它需要定义 XXXXXXXX<br />

31:24 引脚 P0.31:28 根据其它需要定义 XXXXXXXX<br />

表 1.3 描述了 PINSEL2 相关位的配置。<br />

表 1.3 PINSEL2 相关位的配置<br />

PINSEL2(0xE002C014) 描述 配置值(二进制)<br />

1:0 保留 00<br />

3:2 使引脚 P1.36:26 为调试端口<br />

使引脚 P1.25 为 GPIO<br />

5:4 使 P2.31:16 为非数据总线 D31:16 01<br />

7:6 根据其它需要设置 XX<br />

11:8 假设使用片外 RAM、FLASH,使用低 16 位总线<br />

假设使用片外 RAM、FLASH,使能 WE、CS1<br />

01<br />

X00X<br />

15:12 根据其它需要设置 XXXX<br />

19:16 根据其它需要设置 00XX<br />

23:20 使能 P2.29:28,其它根据需要设置;<br />

假设使用片外 RAM、FLASH,使能 A0<br />

X000<br />

27:24 假设使用片外 RAM、FLASH,使能 A1:23 XXXX<br />

31:28 保留 0000<br />

� IO0DIR 寄存器<br />

即:PINSEL2 = (PINSEL2 & 0x0f8cf9c0) | 0x00000014。<br />

根据表 1.1 的描述,配置 IO0DIR 寄存器的位,见表 1.4。<br />

表 1.4 IO0DIR 寄存器配置<br />

IO0DIR 描述 配置值(二进制)<br />

7:0 根据其它需要设置 XXXXXXXX<br />

15:8 根据其它需要设置 XXXXXXXX<br />

23:16 配置引脚 P0.17、P0.19、P0.21 为输出<br />

配置引脚 P0.18、P0.20、P0.22 为输入<br />

X010101X<br />

31:24 根据其它需要设置 XXXXXXXX


� IO1DIR 寄存器<br />

即:IO0DIR= (PINSEL2 & 0xff81ffff) | 0x002a0000。<br />

根据表 1.1 的描述,配置 IO1DIR 寄存器的位,见表 1.5。<br />

表 1.5 IO1DIR 寄存器配置<br />

IO1DIR 描述 配置值(二进制)<br />

� IO2DIR 寄存器<br />

7:0 根据其它需要设置 XXXXXXXX<br />

15:8 根据其它需要设置 XXXXXXXX<br />

23:16 配置引脚 P1.16、P1.17、P1.18、P1.19、<br />

P1.20、P1.23 输出<br />

配置引脚 P1.21 为输入<br />

31:24 配置 P1.24、P1.25 为输入;<br />

根据其它需要设置<br />

根据表 1.1 的描述,配置 IO2DIR 寄存器的位,见表 1.6。<br />

表 1.6 IO2DIR 寄存器配置<br />

1X011111<br />

XXXXXX00<br />

IO2DIR 描述 配置值(二进制)<br />

7:0 根据其它需要设置 XXXXXXXX<br />

15:8 根据其它需要设置 XXXXXXXX<br />

23:16 读操作时设为输入,写操作时设为输出,初<br />

始化时设为输入<br />

31:24 读操作时设为输入,写操作时设为输出,初<br />

始化时设为输入<br />

� IO0SET、IO0CLR、IO1SET、IO1CLR、IO2SET、IO2CLR 寄存器<br />

00000000<br />

00000000<br />

改变各个 GPIO 输出引脚的状态位是通过 IO0SET、IO0CLR、IO1SET、IO1CLR、IO2SET、<br />

IO2CLR 等寄存器设置的。初始化设置如表 1.7 所示,在读写 ATA 设备寄存器函数中分别<br />

进行适当的设置(如程序清单 1.2 和程序清单 1.3 所示)。<br />

表 1.7 初始化时 GPIO 输出引脚电平设置<br />

寄存器 描述 配置值(十六进制)<br />

IO0SET 初始化 P0.17、P0.19、P0.21 输出高电平 002A0000H<br />

IO0CLR 初始化时不需要配置 -<br />

IO1SET P1.19、P1.20 输出高电平 00180000H<br />

IO1CLR P1.16、P1.17、P1.18、P1.23 输出低电平 00870000H<br />

IO2SET 初始化时引脚 P2.31:16 为输入,该寄存器不需要配置 -<br />

IO2CLR 初始化时引脚 P2.31:16 为输入,该寄存器不需要配置 -<br />

根据以上寄存器的描述,使用模拟 ATA 接口前需对以上寄存器进行设置,对相关寄存器<br />

的设置也就是模拟 ATA 接口总线的初始化。再根据表 1.1 描述各引脚的输入或输出特性,设


置各 GPIO 引脚为相应的状态。如程序清单 1.8 所示。<br />

程序清单 1.8 ATA 接口初始化函数<br />

/*******************************************************************************************<br />

** 函数名称: ATA_BusIni<br />

** 功能描述: ATA 总线初始化<br />

** 输 入: 无<br />

** 输 出: 出错返回 0<br />

** 全局变量:<br />

** 调用模块:<br />

*******************************************************************************************/<br />

void ATA_BusIni(void)<br />

{<br />

}<br />

PINSEL1 &= 0xffffc003; /*使用到的 P0 口 GPIO 引脚设置*/<br />

PINSEL2 = (PINSEL2 & 0x0f8cf9c0) | 0x00000014; /*使用到的 P1 及 P2 口 GPIO 引脚设置*/<br />

IO0DIR &= (~(IDE_DMAREQ + IDE_INTRQ)); /*P0 相关输入引脚初始化*/<br />

IO0DIR |= (IDE_RST + IDE_WR + IDE_RD); /*P0相关输出引脚初始化*/<br />

IO1DIR &= (~(IDE_DMACK + IDE_IOCS16 + IDE_PDIAG)); /*P1 相关输入引脚初始化*/<br />

IO1DIR|= (IDE_A0+IDE_A1+IDE_A2+IDE_CS0+IDE_CS1+IDE_CSEL);/*P1 相关输出引脚初始化*/<br />

IO2DIR &= (~ATA_DATA); /*数据总线初始化为输入*/<br />

IO0SET = IDE_RST + IDE_WR + IDE_RD; /*<strong>CF</strong> 卡复位引脚及读写信号引脚初始输出高电平*/<br />

IO1SET = IDE_CS0 + IDE_CS1; /*<strong>CF</strong> 卡片选初始化输入高电平*/<br />

IO1CLR = IDE_A0 + IDE_A1 +IDE_A2 + IDE_CSEL; /*地址初始化*/<br />

1.1.4 中间件使用演示<br />

<strong>CF</strong> 卡及 IDE 硬盘等大容量设备,通常都是以一定的文件格式存贮的。常用的文件格式<br />

为 FAT12、FAT16、FAT32,ZLG/FS 文件管理系统支持以上格式。该演示程序结合 ZLG/<strong>CF</strong><br />

驱动及 ZLG/FS 文件管理系统,实现对 <strong>CF</strong> 卡及 IDE 硬盘等大容量存贮设备文件创建及文件<br />

存取等操作。<br />

1.编写文件系统的低层函数<br />

参考 ZLG/FS 文件系统驱动程序设计指南,结合 ZLG/FC 中间件很容易编写出基于<br />

ZLG/FS 文件管理系统 <strong>CF</strong> 存储卡的低层驱动。如程序清单 1.9 所示。<br />

#include "config.h"<br />

程序清单 1.9 ZLG/FS 文件系统 <strong>CF</strong> 卡驱动<br />

/*******************************************************************************************<br />

** 函数名称: <strong>CF</strong>Cammand<br />

** 功能描述: 底层驱动程序与上层的接口程序<br />

**<br />

** 输 入: Cammand:DISK_INIT:驱动程序初始化


** DISK_CLOSE:关闭驱动器(移除驱动程序)<br />

** DISK_CREATE_BOOT_SECTOR:重建引导扇区<br />

** DISK_READ_SECTOR:读扇区<br />

** DISK_WRITE_SECTOR:写扇区<br />

** Parameter:剩余参数<br />

** 输 出: DISK_READ_OK:读扇区完成<br />

** DISK_READ_NOT_OK:读扇区失败<br />

** DISK_WRITE_OK:写扇区完成<br />

** DISK_WRITE_NOT_OK:写扇区失败<br />

** DISK_INIT_OK:初始化完成<br />

** DISK_INIT_NOT_OK:初始化失败<br />

** BAD_DISK_COMMAND:无效的命令<br />

** 全局变量: 无<br />

** 调用模块: 无<br />

******************************************************************************************/<br />

{<br />

uint16 rt;<br />

uint16 <strong>CF</strong>Cammand(uint8 Cammand, void *Parameter)<br />

Disk_RW_Parameter * Dp;<br />

Disk_Info *DiskInfo;<br />

Dp = (Disk_RW_Parameter *)Parameter;<br />

switch (Cammand)<br />

{<br />

case DISK_INIT: /*设备初始化*/<br />

rt = DISK_INIT_NOT_OK;<br />

if(ATA[0].ATAIsOK == TRUE) (1)<br />

{<br />

}<br />

break;<br />

DiskInfo = GetEmptyDiskInfoAddr();<br />

if (DiskInfo != NULL)<br />

{<br />

}<br />

case DISK_CLOSE:<br />

rt = RETURN_OK;<br />

break;<br />

DiskInfo->DiakCommand = <strong>CF</strong>Cammand;<br />

DiskInfo->RsvdForLow = GetVolumeFirstSect(0); (2)<br />

rt = DISK_INIT_OK;<br />

case DISK_READ_SECTOR: /*读扇区*/<br />

rt = DISK_READ_NOT_OK;<br />

if(ATA_<strong>Read</strong>Sector(0,(uint16*)Dp->Buf, Dp->SectorIndex + Dp->RsvdForLow,1)) (3)<br />

{


}<br />

}<br />

return rt;<br />

}<br />

break;<br />

rt = DISK_READ_OK;<br />

case DISK_WRITE_SECTOR: /*写扇区*/<br />

rt = DISK_WRITE_NOT_OK;<br />

if(ATA_WriteSector(0,(uint16*)Dp->Buf, Dp->SectorIndex + Dp->RsvdForLow,1)) (4)<br />

{<br />

}<br />

default:<br />

break;<br />

rt = DISK_WRITE_OK;<br />

rt = BAD_DISK_COMMAND;<br />

break;<br />

(1) 只有当 ATA 设备 0 可用时,才进行低层驱动初始化;<br />

(2) 获取逻辑驱动器的起始扇区号,该函数源程序如程序清单 1.10 所示。<br />

(3) “Dp->SectorIndex”为文件管理系统要读取的逻辑扇区号,“Dp->RsvdForLow”为<br />

设备逻辑扇区的起始扇区号;ZLG/FS 读取的是逻辑扇区号,而逻辑扇区号与设备的实际扇<br />

区号可能不一致(与设备格式化有关),因此在读扇区操作时,应将逻辑扇区号转换为设备<br />

中的实际的物理扇区号;物理扇区号为逻辑扇区号与逻辑扇区起始扇区号之和。<br />

(4) 写扇区操作也需和读扇区操作一样,应将需要写逻辑扇区号转换为设备中的实际的<br />

物理扇区号。<br />

对于 <strong>CF</strong> 卡和 IDE 硬盘等大容量存贮器,初 FAT 文件管理系统格式化后,在逻辑盘的<br />

起始扇区前通常会包含隐藏扇区;包含隐藏扇区的 <strong>CF</strong> 卡或 IDE 硬盘,在设备的物理扇区的<br />

0 号扇区(逻辑分区表)中特定的位置记录了逻辑盘的起始的物理扇区号;而 ZLG/FS 文件<br />

系统是面向逻辑盘的操作,所以在初始化低层设备驱动时,需获取逻辑盘的起始物理扇区号,<br />

如程序清单 1.10 所示。<br />

uint32 GetVolumeFirstSect(uint8 Device)<br />

{<br />

uint8 buffer[512];<br />

uint32 RelaStaSect;<br />

程序清单 1.10 获取逻辑盘的起始扇区号<br />

ATA_<strong>Read</strong>Sector(Device,(uint16 *)buffer,0,1); (1)<br />

if((buffer[510]==0x55)&&(buffer[511]==0xAA)) (2)<br />

{<br />

if(((buffer[0]==0xEB)&&(buffer[2]==0x90))||(buffer[0] == 0xE9)) (3)<br />

{<br />

}<br />

RelaStaSect = 0;


}<br />

}<br />

else<br />

{<br />

}<br />

return RelaStaSect;<br />

RelaStaSect = buffer[454]+ (4)<br />

buffer[455]*0x100 +<br />

buffer[456]*0x10000 +<br />

buffer[457]*0x1000000;<br />

(1) 读设备的 0 号扇区。<br />

(2) 如果该扇区为有效的分区表,该扇区的最后两个字节数据必为 0x55 和 0xAA。<br />

(3) 如果该扇区为 DOS 引导扇区,该扇区的首字节必为 0xEB 或 0xE9,如果首字节为<br />

0xEB 则第 2 个字节必为 0x90;如果设备的 0 号扇区为 DOS 引导扇区,则逻辑盘前没有隐<br />

含扇区,即逻辑盘起始扇区号为 0 号扇区。<br />

(4) 如果该扇区为有效的分区表,则该扇区的 454—457 节字保存的值为第一个卷(逻<br />

辑盘)的起始扇区号。<br />

2.创建 ADS 工程<br />

使用工程模板创建基于 uC/OS-II 的工程,将 ZLG/FS 文件管理系统的相关文件和<br />

ZLG/<strong>CF</strong> 驱动添加到工程;将 uC/OS-II 源码程序及 ARM 的移值代码拷贝到适当的文件夹。<br />

ZLG/FS 文件管理系统的配置使用默认值即可;由于 ZLG/FS 文件管理系统至少使用<br />

uC/OS-II 操作系统 2 个事件,而 ZLG/<strong>CF</strong> <strong>驱动使用</strong> 1 个信号量事件,所示配置 uC/OS-II 操<br />

作系统的事件数不能少于 3 个。<br />

添加相关的头文件到“config.h”文件中,如程序清单 1.11 所示。<br />

/* ZLG/FS需包含的头文件 */<br />

程序清单 1.11 添加头文件及配置<br />

#include "fat.h" (1)<br />

#include "OSFile.h" (2)<br />

extern char *strupr(char *Str); (3)<br />

extern uint16 <strong>CF</strong>Cammand(uint8 Cammand, void *Parameter); (4)<br />

/*系统与 ZLG/<strong>CF</strong> 驱动接口函数的头文件*/<br />

#include "SysATA.H" (5)<br />

/* <strong>CF</strong> 存储卡需配置及包含的头文件 */<br />

#define UCOSII (6)<br />

#include "IDE.H" (7)<br />

(1) ZLG/FS 文件管理系统所包含的头文件。<br />

(2) ZLG/FS 文件管理系统基于 uC/OS-II 所需的头文件。<br />

(3) strupr()函数的外部声明。strupr()是标准库的函数,但是由于 ADS 编译器库没有包含


该函数,所以需要编写该函数。<br />

(4) <strong>CF</strong>Cammand()为基于 ZLG/FS 文件管理系统读写 <strong>CF</strong> 卡的底层驱动,该函数详见程序<br />

清单 1.9。<br />

(5) 系统与 ZLG/<strong>CF</strong> 驱动相关的接口函数所在“SysATA.c”文件的头文件。<br />

(6) ZLG/<strong>CF</strong> 驱动基于 uC/OS-II 操作系统,需要定义“UCOSII”宏。<br />

(7) ZLG/<strong>CF</strong> 驱动文件的头文件。<br />

建立一个任务 TaskStart(),并在该任务初始化 ATA 接口、ZLG/FS 文件管理系统及对 <strong>CF</strong><br />

卡的文件进行操作。演示程序中:创建“ARM&FAT”文件夹;打开或创建“单片机.TXT”<br />

文件,并在该文件末端插入一段字符。演示程序如程序清单 1.12 所示。<br />

#include "config.h"<br />

OS_STK TaskStk[1024];<br />

OS_STK TaskStartStk[1024];<br />

{<br />

}<br />

char *cp;<br />

cp = Str;<br />

程序清单 1.12 编写任代码<br />

char *strupr(char *Str) (1)<br />

while (*cp != 0)<br />

{<br />

}<br />

if (*cp >= 'a' && *cp


ZLG/FS是广州周立功单片机发展有限公司开发的面向嵌入式系统开发的小型文件系统,\r\n\<br />

是 ZLG 系列中间件的重要成员之一。它是与 FAT12、FAT16、FAT32 高度兼容的文件系统,可以\r\n\<br />

直接与个人电脑交换文件。它是可移植的、可固化的文件系统,可以用于前后台系统,也可\r\n\<br />

用于多任务环境。目前 ZLG/FS 的最新版本为 1.0。\<br />

\r\n\<br />

\r\n*********************************ARM 开发部门************************************\r\n";<br />

{<br />

}<br />

void TaskStart (void *pdata)<br />

HANDLE FHandle;<br />

pdata = pdata;<br />

SYS_BusIni(); /*ATA总线初始化*/ (6)<br />

ATA_INI(); /*ATA 设备初始化*/ (7)<br />

OSAddFileDriver(<strong>CF</strong>Cammand); /*增加 ATA 设备 0*/ (8)<br />

FHandle = OSFileOpen(FileName, "rw"); (9)<br />

OSFileSeek(FHandle,0, SEEK_END); (10)<br />

OSFileWrite(WritFileData, sizeof(WritFileData), FHandle); (11)<br />

OSFileClose(FHandle); (12)<br />

OSMakeDir("a:\\ARM&FATS"); (13)<br />

OSAllCacheWriteBack();<br />

OSRemoveFileDriver(0);<br />

while (1);<br />

(1) 由于 ADS 编译器库中没有包含 strupr()函数,但该函数在 ZLG/FS 文件管理系统中<br />

使用到,所以必须编写该函数,该函数具有将小写字母转化为大写功能。<br />

(2) 创建 TaskStart()任务。该任务对 ZLG/<strong>CF</strong> 驱动进行初始化,并对 <strong>CF</strong> 卡的文件进行操<br />

作。<br />

(3) 创建 OSFileTask 任务。该任务为 ZLG/FS 文件管理系统的服务任务,详见文件管理系<br />

统章节。<br />

(4) 将在 <strong>CF</strong> 卡内打开或创建的文件名。<br />

(5) 将插入到打开文件末尾的字符串。<br />

(6) 模拟 ATA 总线接口的初始化。<br />

(7) 初始化 ATA 接口上的设备。<br />

(8) 为 ZLG/FS 文件系统增加 <strong>CF</strong> 卡的驱动。<br />

(9) 打开或创建“单片机.txt”文件,OSFileOpen()函数详见 ZLG/FS 文件管理系统章节。<br />

(10) 将指针移到打开文件的末尾,OSFileSeek()函数详见 ZLG/FS 文件管理系统章节。<br />

(11) 插入(5)中的字符串到文件的指定位置,OSFileWrite()函数详见 ZLG/FS 文件管<br />

理系统章节。<br />

(12) 关闭文件,OSFileClose()函数详见 ZLG/FS 文件管理系统章节。


(13) 创建“ARM&FATS”文件夹,OSMakeDir()函数详见 ZLG/FS 文件管理系统章节。<br />

3.程序演示步骤<br />

(1) 将 EasyARM2200 开发板配套光盘中的“<strong>CF</strong>_IDE_EXEMPLE”文件夹内容拷到硬盘,<br />

并将所有只读属性文件改为可写。<br />

(2) 将 uC/OS-II 操作系统的源代码,拷贝到“<strong>CF</strong>_IDE_EXEMPLE\uCOSII_FAT_<strong>CF</strong>\<br />

SOURCE”文件夹,由于 uC/OS-II 的版权原因,配套光盘没有提供源代码。<br />

(3) 使用 ADS1.2 打开“\<strong>CF</strong>_IDE_EXEMPLE\uCOSII_FAT_<strong>CF</strong>\file\ uCOSII_FAT_<strong>CF</strong>.mcp”<br />

工程文件。<br />

(4) 编译工程,并进入硬件调试状态。<br />

(5) 插入 <strong>CF</strong> 卡或接入 IDE 硬盘;如果接入的是 IDE 硬盘,则需将硬盘设置为主设备,<br />

并连接上 IDE 硬盘电源(IDE 硬盘电源可由电脑电源提供,开发板不提供硬盘电源)。<br />

注意:<strong>CF</strong> 存储卡或 IDE 硬盘应已被格式化,未格式化的磁盘 ZLG/FS 不能识别。<br />

(6) 调试程序,直到程序结束。<br />

(7) 验证演示程序结果。<br />

(8) 将 USB1.1 PACK 插入 EasyARM2200 开发板的 PACK 座上。<br />

(9) 使用 AXD 装载“\<strong>CF</strong>_IDE_EXEMPLE\mass\mass_Data\Debug\mass.axf”USB 大容量<br />

类调试文件,然后全速运行程序(使用 EasyJTAG 硬件仿真)。<br />

(10) 连接上 USB 接口线,USB1.1 PACK 枚举及初始化完成后,“我的电脑”里会出现<br />

一个可移动的磁盘。<br />

注意:如果是第一次使用该程序,电脑需要安装驱动程序;Win98/Me 的驱动在“\<strong>CF</strong>_IDE_EXEMPLE\<br />

mass\D12MassStorage_SW(Win98_Ver1.0)”文件夹中,Win2000/XP 系统不需驱动;驱动安装步骤与<br />

一般 U 盘安装步骤一样。<br />

(11) 点击打开新发现的磁盘,就可以发现演示程序创建的“ARM&FATS”文件夹和“单<br />

片机.txt”文件;点击打开“单片机.txt”文件,就可以看到文件末尾插入的字符串。<br />

注意:光盘中的 USB 大容量程序只是为了验证本演示程序的结果,本书中并没有介绍 USB 大容量类程序<br />

内容;如果对 USB 大容量类程序感兴趣,敬请留意周立功单片机发展有限公司出版的相关图书。

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!