第1章 ZLG/CF驱动使用
1.1 基于 LPC2210 的 ZLG/CF 驱动使用
CF 卡有 PC 卡 I/O,MEMORY 及 True IDE 等 3 种模式,而 True IDE 模式兼容 IDE 硬盘,该模式比其它的两种模式更实用,是 3 种模式中使用较多的一种。本节中描述 CF 卡在
True IDE 模式下的应用。
使用 LPC2210 的通用可编程 I/O 口,模拟产生 ATA 设备的读写时序,实现对 CF 卡及
IDE 硬盘等 ATA 设备读写操作。使用 LPC2210 的 GPIO 功能,可以非常灵活而简单地实现
ATA 读写时序。
1.1.1 LPC2210 与 CF 卡及 IDE 硬件连接
LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘的硬件接线图分别如图 1.1、图 1.2 所示。
ATA_DASP
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25
26
26
27
27
28
28
29
29
30
30
31
31
32
32
33
33
34
34
35
35
36
36
37
37
38
38
39
39
40
40
41
41
42
42
43
43
44
44
45
45
46
46
47
47
48
48
49
49
50
50
J17
HEADER 25X2_CF
ATA_DASP
D4
LED
VCC
P2.24_D24
P2.25_D25
P2.26_D26
P2.27_D27
P2.28_D28
P2.29_D29
P2.30_D30
P2.31_D31
P1.20
P0.21_PWM5
P0.19_M AT1.2
P0.20_M AT1.3
VDD3.3
VDD3.3
P0.17_CAP1.2
P0.22_M AT0.0
VDD3.3
P1.25
P1.24
P2.18_D18
P2.17_D17
P2.16_D16
P1.16
P1.17
P1.18
VDD3.3
P1.19
P2.23_D23
P2.22_D22
P2.21_D21
P2.20_D20
P2.19_D19
R94
1K
图 1.1 LPC2210 与 CF 卡接线图
注意,图 1.1 中 CF 卡的 CSEL 引脚直接接地,开发板上的 CF 卡已被配置为主设备。 IDE 硬盘的主从配置,通过硬盘上的跳线选择。
GND
P2.23_D23 P2.24_D24
P2.22_D22 P2.25_D25
P2.21_D21 P2.26_D26
P2.20_D20 P2.27_D27
P2.19_D19 P2.28_D28
P2.18_D18 P2.29_D29
P2.17_D17 P2.30_D30
P2.16_D16 P2.31_D31
GND
GND
GND
P0.17_CA P1.2
P0.21_PW M 5
P0.22_MAT0.0
P0.18_CA P1.3
P0.19_MAT1.2
P0.20_MAT1.3
GND
GND
GND
1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22
23 24
25 26
27 28
29 30
31 32
33 34
35 36
37 38
39 40
J3
IDE/USER_COM
NC
R32
10K
P1.16
P1.17
P1.18
P1.19 P1.20
P1.21
P1.24
P1.25
VDD3.3
R31
10K
R33
10K
R13
10K
VDD3.3
ATA_DASP
D4
LED
VCC
ATA_DASP
R94
1K
P1.23
图 1.2 LPC2210 与 IDE 硬盘接线图
表 1.1 为 LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘引脚连接分配表,表中描述了各
GPIO 引脚与 CF 卡及 IDE 硬盘对应的控制信号线,根据表中的描述配置 LPC2210 相关的寄存器。
表 1.1 LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘连接引脚分配
LPC2210 CF 卡 IDE 硬盘 I/O LPC2210 CF 卡 IDE 硬盘 I/O
*P0.17 -RESET -RESET O *P1.17 A01 DA1 O
*P2.16~P2.31 D00~D15 DD0~DD15 I,O *P1.16 A00 DA0 O
P0.18 DMARQ I *P1.19 -CS0 -CS0 O
*P0.19 -IOWR -DIOW O P1.23 CSEL O
*P0.21 -IORD -DIOR O P1.24 -IOCS16 -IOCS16 I
P0.22 IORDY IORDY I P1.25 -PDIAG -PDIAG I
P1.21 -DMACK I *P1.18 A02 DA2 O
P0.20 INTRQ INTRQ I *P1.20 -CS1 -CS1 O
注,1.I/O 输入与输出是相对于 LPC2210 来说的,I 为 LPC2210 的输入,O 为输出。
2.表中“*”号的引脚,为使用到的引脚,其它引脚不需使用,但需要配置为适当的状态。
根据图 1.1、图 1.2 和表 1.1 所描述,为相关的引脚定义有意义的标号,如程序清单 1.1
所示。
程序清单 1.1 ATA 接口连接引脚定义
/* EeayARM2200 和 IDE 接口连接 */
#ifdef ATA_BUS_AT_8bit /*8 位总线*/
#define ATA_DATA 0x00ff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2,23 */
#else /*16 位总线*/
#define ATA_DATA 0xffff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2,31 */
#endif
#define IDE_A0 (1<<16) /* EeayARM2200 和 IDE 接口直接相连,p1,16 */
#define IDE_A1 (1<<17) /* EeayARM2200 和 IDE 接口直接相连,p1.17 */
#define IDE_A2 (1<<18) /* EeayARM2200 和 IDE 接口直接相连,p 1.18 */
#define IDE_CS0 (1<<19) /* EeayARM2200 和 IDE 接口直接相连,p 1.19 */
#define IDE_CS1 (1<<20) /* EeayARM2200 和 IDE 接口直接相连,p1,20 */
#define IDE_DMACK (1<<21) /* EeayARM2200 和 IDE 接口直接相连,p1.21 */
#define IDE_CSEL (1<<23) /* EeayARM2200 和 IDE 接口直接相连,p1.23 */
#define IDE_IOCS16 (1<<24) /* EeayARM2200 和 IDE 接口直接相连,p1.24 */
#define IDE_PDIAG (1<<25) /* EeayARM2200 和 IDE 接口直接相连,p1.25 */
#define IDE_RST (1<<17) /* EeayARM2200 和 IDE 接口直接相连,p0.17 */
#define IDE_DMAREQ (1<<18) /* EeayARM2200 和 IDE 接口直接相连,p0.18 */
#define IDE_WR (1<<19) /* EeayARM2200 和 IDE 接口直接相连,p0.1 9 */
#define IDE_INTRQ (1<<20) /* EeayARM2200 和 IDE 接口直接相连,p0.20 */
#define IDE_RD (1<<21) /* EeayARM2200 和 IDE 接口直接相连,p0.2 1 */
/* EeayARM2200 */
#define Addr_CS_at_P1 (IDE_A0 + IDE_A1 +IDE_A2 + IDE_CS0 + IDE_CS1) (1)
#define MASK_DATA (~ATA_DATA) (2)
1.1.2 函数接口的实现
1.ATA 设备寄存器读写函数
IDE_A0,IDE_A1,IDE_A2 地址信号引脚和 IDE_CS0,IDE_CS1 片选信号引脚都是在
LPC2210 的 P1 口上,正好由这些信号线确定 ATA 设备一个具体寄存器的地址;为了便于地址的设定,将 P1 口上同时为高电平的信号引脚定义为 Addr_CS_at_P1 宏,如程序清单 1.1(1)
所示。
为了便于数据总线的方向改变和数值输出,可定义数据输出的屏蔽值 MASK_DATA.如程序清单 1.1(2)所示。
模拟读 ATA 设备寄存器步骤如下,
(1) 关系统中断,预防在读寄存器操作中产生中断;
(2) 准备读取设备数据信号,设置 GPIO 模拟 ATA 接口数据的引脚为输入状态;
(3) 设置寄存器的相应地址;
(4) 使读 ATA 设备寄存器的信号引脚为低电平;
(5) 读取 GPIO 模拟 ATA 接口数据的引脚的电平 (这时数据线上的值应为设备寄存器中的值),并调整数据位置;
(6) 使读 ATA 设备寄存器的信号引脚为高电平;
(7) 如果 ATA 设备( CF 卡)是 8 位总线模式,并且操作的是数据寄存器( 16 位),则需重复 (3),(4),(5)步,再整合成 16 位的数据。
(8) 取消 ATA 设备寄存器地址的选择。
(9) 开系统中断。
GPIO 模拟读 ATA 设备寄存器的函数如程序清单 1.2 所示,ATA 设备各寄存器地址宏定义如程序清单 1.5 所示。
程序清单 1.2 读取 ATA 设备寄存器函数
#ifdef ATA_BUS_AT_8bit
uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数 */
{
uint16 res ;
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入 (ATA_DATA 为输入 )*/
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
/*读低字节 */
IO0CLR = IDE_RD; /*读信号脚置低 */
res = (uint8)((IO2PIN&ATA_DATA) >>16); /*读取数据 */
IO0SET = IDE_RD; /*使读信号为高 */
/*读高字节 */
if(reg==ATA_REG_DATA) /*如果读数据寄存器,读高字节 */
{
IO0CLR = IDE_RD; /*读信号脚置低 */
res += (uint16)((IO2PIN&ATA_DATA)>>8); /*读取数据 */
IO0SET = IDE_RD; /*使读信号为高 */
}
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
OS_EXIT_CRITICAL(); /*开中断 */
return res; /*返回数值 */
}
#else
uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数 */
{
uint16 res ;
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入 (ATA_DATA 为输入 )*/
IO1CLR = Addr_CS_at_P1; /*控所硬盘引脚信号输出 (输出高电平 )*/
IO1SET = reg; /*控所硬盘引脚信号输出 (输出低电平 )*/
IO0CLR = IDE_RD; /*读信号脚置低 */
res = (uint16)(IO2PIN >>16); /*读取数据 */
IO0SET = IDE_RD;
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
OS_EXIT_CRITICAL(); /*开中断 */
return res;
}
#endif
写 ATA 设备寄存器步骤如下,
(1) 关系统中断,预防在写寄存器操作中产生中断;
(2) 设置 GPIO 模拟 ATA 接口数据的引脚为输出状态,准备输出数据到设备数据线;
(3) 设置 ATA 设备寄存器的相应地址;
(4) 设置 GPIO 模拟 ATA 接口数据的引脚的电平为要写到设备的值;
(5) 使写 ATA 设备寄存器信号引脚为低电平;
(6) 使写 ATA 设备寄存器信号引脚为高电平;
(7) 如果 ATA 设备( CF 卡)是 8 位总线模式,并且操作的是数据寄存器( 16 位),则需重复 (3),(4),(5)步。
(8) 取消 ATA 设备寄存器地址的选择。
(9) 设置 GPIO 模拟 ATA 接口的数据总线引脚为输入状态,释放总线。
(10) 开系统中断。
LPC2210 的 GPIO 引脚模拟写 ATA 设备寄存器的函数如程序清单 1.3 所示,ATA 设备各寄存器地址宏定义如程序清单 1.5 所示。
程序清单 1.3 写 ATA 设备寄存器函数
#ifdef ATA_BUS_AT_8bit
void SYS_PortOut(uint32 reg,uint16 data) /*使用 8 位数据总线 */
{
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出 */
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
/*写低字节 */
IO2CLR = ATA_DATA; /*数据总线上输出全为低电平 */
IO2SET = data<<16; /*输出数据值为 1 的位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
if(reg==ATA_REG_DATA) /*如果访问的寄存器为 16 位的数据寄存器 */
{ /*写高字节 */
IO2CLR = ATA_DATA; /*数据线输出全为低电平 */
IO2SET = data<<8; /*输出高电平的数据位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
}
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
IO2DIR &= MASK_DATA; /*使数据线为输入,降低功耗 */
OS_EXIT_CRITICAL(); /*开中断 */
}
#else
void SYS_PortOut(uint32 reg,uint16 data) /*使用 16 位总线 */
{
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出 */
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
IO2CLR = ATA_DATA; /*数据总线上输出全为低电平 */
IO2SET = data<<16; /*输出数据高位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
IO2DIR &= MASK_DATA; /*使数据线为输入,降低功耗 */
OS_EXIT_CRITICAL(); /*开中断 */
}
#endif
开中断及关中断函数如程序清单 1.4 所示。
程序清单 1.4 开、关总中断函数
#ifndef UCOSII (1)
#define NoInt 0x80
/* 关中断 */
__inline OS_ENTER_CRITICAL(void)
{
__asm
{
MRS R0,CPSR
ORR R0,R0,#NoInt
MSR CPSR_c,R0
}
}
/* 开中断 */
__inline OS_EXIT_CRITICAL(void)
{
__asm
{
MRS R0,CPSR
BIC R0,R0,#NoInt
MSR CPSR_c,R0
}
}
#endif
(1) 如果驱动用于 uC/OS-II 操作系统,则不需要编译这两个开、关中断函数,因为在
uC/OS-II 中已定义了这两个函数。
SYS_PortIn()和 SYS_PortOut()函数通过使用程序清单 1.5中定义的 ATA 设备寄存器的地址的宏作为参数,实现对 ATA 设备各寄存器的读写操作。
ZLG/CF 驱动读写 ATA 设备寄存器的函数如程序清单 1.6 所示。
程序清单 1.5 设备寄存器地址宏定义
/*GPIO 引脚影射寄存器地址*/
#define ATA_REG_DATA IDE_CS1 /*数据寄存器*/
#define ATA_REG_ERR (IDE_CS1 + IDE_A0) /*读错误寄存器*/
#define ATA_REG_FEATURE (IDE_CS1 + IDE_A0) /*写功能寄存器*/
#define ATA_REG_SECCNT (IDE_CS1 + IDE_A1) /*扇区计数器*/
#define ATA_REG_SECTOR (IDE_CS1 + IDE_A1 + IDE_A0) /*扇区号*/
#define ATA_REG_CYLI_LOW (IDE_CS1 + IDE_A2) /*柱面低 8 位*/
#define ATA_REG_CYLI_HIGH (IDE_CS1 + IDE_A2 + IDE_A0) /*柱面 高8位*/
#define ATA_REG_DEVICE_HEAD (IDE_CS1 + IDE_A2 + IDE_A1) /*选择主从,模式,磁头*/
#define ATA_REG_COMMAND (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*写命令寄存器*/
#define ATA_REG_STATUS (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*读状态寄存器*/
#define ATA_REG_CONTROL (IDE_CS0 + IDE_A2 + IDE_A1) /*写控制寄存器*/
#define ATA_REG_ASTATUS (IDE_CS0 + IDE_A2 + IDE_A1) /*读辅助状态寄存器*/
程序清单 1.6 读写设备相关寄存器接口函数
/*驱动与硬件对 ATA 设备寄存器操作接口 */
#define GetData() SYS_PortIn(ATA_REG_DATA) /*读数据寄存器,与驱动接口 */
#define SetData(x) SYS_PortOut(ATA_REG_DATA,x) /*写数据寄存器,与驱动接口 */
#define GetERR() SYS_PortIn(ATA_REG_ERR) /*读错误寄存器,与驱动接口 */
#define SetFeature(x) SYS_PortOut(ATA_REG_FEATURE,x) /*写特征寄存器,与驱动接口 */
#define GetSECCNT() SYS_PortIn(ATA_REG_SECCNT) /*读扇区计数寄存器,与驱动接口 */
#define SetSECCNT(x) SYS_PortOut(ATA_REG_SECCNT,x) /*写扇区计数寄存器,与驱动接口 */
#define GetSector() SYS_PortIn(ATA_REG_SECTOR) /*读扇区寄存器,与驱动接口 */
#define SetSector(x) SYS_PortOut(ATA_REG_SECTOR,x) /*写扇区寄存器,与驱动接口 */
#define GetCylinderLow() SYS_PortIn(ATA_REG_CYLINDER_LOW) /*读柱面低寄存器,与驱动接口 */
#define SetCylinderLow(x) SYS_PortOut(ATA_REG_CYLINDER_LOW,x)/*写柱面低寄存器,与驱动接口 */
#define GetCylinderHigh() SYS_PortIn(ATA_REG_CYLI_HIGH) /*读柱面高 8 位寄存器,与驱动接口 */
#define SetCylinderHigh(x) SYS_PortOut(ATA_REG_CYLI_HIGH,x) /*写柱面高 8 位寄存器,与驱动接口 */
#define GetDeviceHead() SYS_PortIn(ATA_REG_DEVICE_HEAD) /*读设备磁头寄存器,与驱动接口 */
#define SetDeviceHead(x) SYS_PortOut(ATA_REG_DEVICE_HEAD,x)/*写设备磁头寄存器,与驱动接口 */
#define GetStatus() SYS_PortIn(ATA_REG_STATUS) /*读状态寄存器,与驱动接口 */
#define SetCommand(x) SYS_PortOut(ATA_REG_COMMAND,x) /*写命令寄存器,与驱动接口 */
2.硬件复位函数
系统中定义了 IDE_RST 引脚控制 ATA 设备的硬件复位。如程序清单 1.7 所示。
程序清单 1.7 硬件复位函数
/*******************************************************************************************
** 函数名称,SYS_IdeHardReset
** 功能描述,ATA 设备硬件复位
** 输 入,无
** 输 出,无
** 全局变量,
** 调用模块,SYS_WaitInUS(),等待微秒函数。
*******************************************************************************************/
void SYS_IdeHardReset(void)
{
IOCLR = IDE_RST; /*复位引脚置低 */
SYS_WaitInUS(30); /*延时大于 25 微秒 */
IOSET = IDE_RST; /*复位引脚置高 */
SYS_WaitInUS(5000); /*延时大于 2 毫秒 */
}
/*******************************************************************************************
** 函数名称,SYS_WaitInUS
** 功能描述,延时等级约 1 微秒函数,该函数根据系统时间不同与不同,但不应少到 1 微秒。
** 输 入,times,延时时间等级
** 输 出,无
** 全局变量,
** 调用模块,
*******************************************************************************************/
void SYS_WaitInUS(uint32 times)
{ uint32 c;
for(;0<times;times--)
for(c=0;c<5;c++);
}
3.设备检测函数
该函数用于检测 CF 卡插入及拔出,ZLG/CF 驱动要求系统必须提供该函数,即使系统中没有设计检测 CF 卡插入及拔出功能。
4.模拟 ATA 接口初始化函数
使用 LPC2210 的 GPIO 模拟 ATA 接口,定义了各引脚为输入或输出(见表 1.1) 。在使用我们定义好的引脚前,必须对 LPC2210 相关的寄存器进行配置。详见 1.1.3 小节。
1.1.3 LPC2210 相关寄存器配置
使用 GPIO 模拟 ATA 接口相关的寄存器只有几个,PINSEL1,PINSEL2,IO0DIR、
IO1DIR,IO2DIR,IO0SET,IO0CLR,IO1SET,IO1CLR,IO2SET,IO2CLR 等。
1.1 基于 LPC2210 的 ZLG/CF 驱动使用
CF 卡有 PC 卡 I/O,MEMORY 及 True IDE 等 3 种模式,而 True IDE 模式兼容 IDE 硬盘,该模式比其它的两种模式更实用,是 3 种模式中使用较多的一种。本节中描述 CF 卡在
True IDE 模式下的应用。
使用 LPC2210 的通用可编程 I/O 口,模拟产生 ATA 设备的读写时序,实现对 CF 卡及
IDE 硬盘等 ATA 设备读写操作。使用 LPC2210 的 GPIO 功能,可以非常灵活而简单地实现
ATA 读写时序。
1.1.1 LPC2210 与 CF 卡及 IDE 硬件连接
LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘的硬件接线图分别如图 1.1、图 1.2 所示。
ATA_DASP
1
1
2
2
3
3
4
4
5
5
6
6
7
7
8
8
9
9
10
10
11
11
12
12
13
13
14
14
15
15
16
16
17
17
18
18
19
19
20
20
21
21
22
22
23
23
24
24
25
25
26
26
27
27
28
28
29
29
30
30
31
31
32
32
33
33
34
34
35
35
36
36
37
37
38
38
39
39
40
40
41
41
42
42
43
43
44
44
45
45
46
46
47
47
48
48
49
49
50
50
J17
HEADER 25X2_CF
ATA_DASP
D4
LED
VCC
P2.24_D24
P2.25_D25
P2.26_D26
P2.27_D27
P2.28_D28
P2.29_D29
P2.30_D30
P2.31_D31
P1.20
P0.21_PWM5
P0.19_M AT1.2
P0.20_M AT1.3
VDD3.3
VDD3.3
P0.17_CAP1.2
P0.22_M AT0.0
VDD3.3
P1.25
P1.24
P2.18_D18
P2.17_D17
P2.16_D16
P1.16
P1.17
P1.18
VDD3.3
P1.19
P2.23_D23
P2.22_D22
P2.21_D21
P2.20_D20
P2.19_D19
R94
1K
图 1.1 LPC2210 与 CF 卡接线图
注意,图 1.1 中 CF 卡的 CSEL 引脚直接接地,开发板上的 CF 卡已被配置为主设备。 IDE 硬盘的主从配置,通过硬盘上的跳线选择。
GND
P2.23_D23 P2.24_D24
P2.22_D22 P2.25_D25
P2.21_D21 P2.26_D26
P2.20_D20 P2.27_D27
P2.19_D19 P2.28_D28
P2.18_D18 P2.29_D29
P2.17_D17 P2.30_D30
P2.16_D16 P2.31_D31
GND
GND
GND
P0.17_CA P1.2
P0.21_PW M 5
P0.22_MAT0.0
P0.18_CA P1.3
P0.19_MAT1.2
P0.20_MAT1.3
GND
GND
GND
1 2
3 4
5 6
7 8
9 10
11 12
13 14
15 16
17 18
19 20
21 22
23 24
25 26
27 28
29 30
31 32
33 34
35 36
37 38
39 40
J3
IDE/USER_COM
NC
R32
10K
P1.16
P1.17
P1.18
P1.19 P1.20
P1.21
P1.24
P1.25
VDD3.3
R31
10K
R33
10K
R13
10K
VDD3.3
ATA_DASP
D4
LED
VCC
ATA_DASP
R94
1K
P1.23
图 1.2 LPC2210 与 IDE 硬盘接线图
表 1.1 为 LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘引脚连接分配表,表中描述了各
GPIO 引脚与 CF 卡及 IDE 硬盘对应的控制信号线,根据表中的描述配置 LPC2210 相关的寄存器。
表 1.1 LPC2210 的 GPIO 引脚与 CF 卡及 IDE 硬盘连接引脚分配
LPC2210 CF 卡 IDE 硬盘 I/O LPC2210 CF 卡 IDE 硬盘 I/O
*P0.17 -RESET -RESET O *P1.17 A01 DA1 O
*P2.16~P2.31 D00~D15 DD0~DD15 I,O *P1.16 A00 DA0 O
P0.18 DMARQ I *P1.19 -CS0 -CS0 O
*P0.19 -IOWR -DIOW O P1.23 CSEL O
*P0.21 -IORD -DIOR O P1.24 -IOCS16 -IOCS16 I
P0.22 IORDY IORDY I P1.25 -PDIAG -PDIAG I
P1.21 -DMACK I *P1.18 A02 DA2 O
P0.20 INTRQ INTRQ I *P1.20 -CS1 -CS1 O
注,1.I/O 输入与输出是相对于 LPC2210 来说的,I 为 LPC2210 的输入,O 为输出。
2.表中“*”号的引脚,为使用到的引脚,其它引脚不需使用,但需要配置为适当的状态。
根据图 1.1、图 1.2 和表 1.1 所描述,为相关的引脚定义有意义的标号,如程序清单 1.1
所示。
程序清单 1.1 ATA 接口连接引脚定义
/* EeayARM2200 和 IDE 接口连接 */
#ifdef ATA_BUS_AT_8bit /*8 位总线*/
#define ATA_DATA 0x00ff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2,23 */
#else /*16 位总线*/
#define ATA_DATA 0xffff0000 /* EeayARM2200 和 IDE 接口直接相连,p2.16~p2,31 */
#endif
#define IDE_A0 (1<<16) /* EeayARM2200 和 IDE 接口直接相连,p1,16 */
#define IDE_A1 (1<<17) /* EeayARM2200 和 IDE 接口直接相连,p1.17 */
#define IDE_A2 (1<<18) /* EeayARM2200 和 IDE 接口直接相连,p 1.18 */
#define IDE_CS0 (1<<19) /* EeayARM2200 和 IDE 接口直接相连,p 1.19 */
#define IDE_CS1 (1<<20) /* EeayARM2200 和 IDE 接口直接相连,p1,20 */
#define IDE_DMACK (1<<21) /* EeayARM2200 和 IDE 接口直接相连,p1.21 */
#define IDE_CSEL (1<<23) /* EeayARM2200 和 IDE 接口直接相连,p1.23 */
#define IDE_IOCS16 (1<<24) /* EeayARM2200 和 IDE 接口直接相连,p1.24 */
#define IDE_PDIAG (1<<25) /* EeayARM2200 和 IDE 接口直接相连,p1.25 */
#define IDE_RST (1<<17) /* EeayARM2200 和 IDE 接口直接相连,p0.17 */
#define IDE_DMAREQ (1<<18) /* EeayARM2200 和 IDE 接口直接相连,p0.18 */
#define IDE_WR (1<<19) /* EeayARM2200 和 IDE 接口直接相连,p0.1 9 */
#define IDE_INTRQ (1<<20) /* EeayARM2200 和 IDE 接口直接相连,p0.20 */
#define IDE_RD (1<<21) /* EeayARM2200 和 IDE 接口直接相连,p0.2 1 */
/* EeayARM2200 */
#define Addr_CS_at_P1 (IDE_A0 + IDE_A1 +IDE_A2 + IDE_CS0 + IDE_CS1) (1)
#define MASK_DATA (~ATA_DATA) (2)
1.1.2 函数接口的实现
1.ATA 设备寄存器读写函数
IDE_A0,IDE_A1,IDE_A2 地址信号引脚和 IDE_CS0,IDE_CS1 片选信号引脚都是在
LPC2210 的 P1 口上,正好由这些信号线确定 ATA 设备一个具体寄存器的地址;为了便于地址的设定,将 P1 口上同时为高电平的信号引脚定义为 Addr_CS_at_P1 宏,如程序清单 1.1(1)
所示。
为了便于数据总线的方向改变和数值输出,可定义数据输出的屏蔽值 MASK_DATA.如程序清单 1.1(2)所示。
模拟读 ATA 设备寄存器步骤如下,
(1) 关系统中断,预防在读寄存器操作中产生中断;
(2) 准备读取设备数据信号,设置 GPIO 模拟 ATA 接口数据的引脚为输入状态;
(3) 设置寄存器的相应地址;
(4) 使读 ATA 设备寄存器的信号引脚为低电平;
(5) 读取 GPIO 模拟 ATA 接口数据的引脚的电平 (这时数据线上的值应为设备寄存器中的值),并调整数据位置;
(6) 使读 ATA 设备寄存器的信号引脚为高电平;
(7) 如果 ATA 设备( CF 卡)是 8 位总线模式,并且操作的是数据寄存器( 16 位),则需重复 (3),(4),(5)步,再整合成 16 位的数据。
(8) 取消 ATA 设备寄存器地址的选择。
(9) 开系统中断。
GPIO 模拟读 ATA 设备寄存器的函数如程序清单 1.2 所示,ATA 设备各寄存器地址宏定义如程序清单 1.5 所示。
程序清单 1.2 读取 ATA 设备寄存器函数
#ifdef ATA_BUS_AT_8bit
uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数 */
{
uint16 res ;
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入 (ATA_DATA 为输入 )*/
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
/*读低字节 */
IO0CLR = IDE_RD; /*读信号脚置低 */
res = (uint8)((IO2PIN&ATA_DATA) >>16); /*读取数据 */
IO0SET = IDE_RD; /*使读信号为高 */
/*读高字节 */
if(reg==ATA_REG_DATA) /*如果读数据寄存器,读高字节 */
{
IO0CLR = IDE_RD; /*读信号脚置低 */
res += (uint16)((IO2PIN&ATA_DATA)>>8); /*读取数据 */
IO0SET = IDE_RD; /*使读信号为高 */
}
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
OS_EXIT_CRITICAL(); /*开中断 */
return res; /*返回数值 */
}
#else
uint16 SYS_PortIn(uint32 reg) /*8 位总线的读寄存器函数 */
{
uint16 res ;
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR & MASK_DATA; /*定义输出口其它为输入 (ATA_DATA 为输入 )*/
IO1CLR = Addr_CS_at_P1; /*控所硬盘引脚信号输出 (输出高电平 )*/
IO1SET = reg; /*控所硬盘引脚信号输出 (输出低电平 )*/
IO0CLR = IDE_RD; /*读信号脚置低 */
res = (uint16)(IO2PIN >>16); /*读取数据 */
IO0SET = IDE_RD;
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
OS_EXIT_CRITICAL(); /*开中断 */
return res;
}
#endif
写 ATA 设备寄存器步骤如下,
(1) 关系统中断,预防在写寄存器操作中产生中断;
(2) 设置 GPIO 模拟 ATA 接口数据的引脚为输出状态,准备输出数据到设备数据线;
(3) 设置 ATA 设备寄存器的相应地址;
(4) 设置 GPIO 模拟 ATA 接口数据的引脚的电平为要写到设备的值;
(5) 使写 ATA 设备寄存器信号引脚为低电平;
(6) 使写 ATA 设备寄存器信号引脚为高电平;
(7) 如果 ATA 设备( CF 卡)是 8 位总线模式,并且操作的是数据寄存器( 16 位),则需重复 (3),(4),(5)步。
(8) 取消 ATA 设备寄存器地址的选择。
(9) 设置 GPIO 模拟 ATA 接口的数据总线引脚为输入状态,释放总线。
(10) 开系统中断。
LPC2210 的 GPIO 引脚模拟写 ATA 设备寄存器的函数如程序清单 1.3 所示,ATA 设备各寄存器地址宏定义如程序清单 1.5 所示。
程序清单 1.3 写 ATA 设备寄存器函数
#ifdef ATA_BUS_AT_8bit
void SYS_PortOut(uint32 reg,uint16 data) /*使用 8 位数据总线 */
{
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出 */
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
/*写低字节 */
IO2CLR = ATA_DATA; /*数据总线上输出全为低电平 */
IO2SET = data<<16; /*输出数据值为 1 的位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
if(reg==ATA_REG_DATA) /*如果访问的寄存器为 16 位的数据寄存器 */
{ /*写高字节 */
IO2CLR = ATA_DATA; /*数据线输出全为低电平 */
IO2SET = data<<8; /*输出高电平的数据位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
}
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
IO2DIR &= MASK_DATA; /*使数据线为输入,降低功耗 */
OS_EXIT_CRITICAL(); /*开中断 */
}
#else
void SYS_PortOut(uint32 reg,uint16 data) /*使用 16 位总线 */
{
OS_ENTER_CRITICAL(); /*关中断 */
IO2DIR = IO2DIR | ATA_DATA; /*设置数据总线为输出 */
IO1CLR = Addr_CS_at_P1; /*地址与片选信号都为低电平 */
IO1SET = reg; /*地址高电平位输出,完成地址的设置 */
IO2CLR = ATA_DATA; /*数据总线上输出全为低电平 */
IO2SET = data<<16; /*输出数据高位 */
IO0CLR = IDE_WR; /*写信号为低电平,保持大于 165nS*/
IO0SET = IDE_WR; /*写信号脚置高 [与低 >162ns]*/
IO1SET = Addr_CS_at_P1; /*输出控制信号置高 */
IO2DIR &= MASK_DATA; /*使数据线为输入,降低功耗 */
OS_EXIT_CRITICAL(); /*开中断 */
}
#endif
开中断及关中断函数如程序清单 1.4 所示。
程序清单 1.4 开、关总中断函数
#ifndef UCOSII (1)
#define NoInt 0x80
/* 关中断 */
__inline OS_ENTER_CRITICAL(void)
{
__asm
{
MRS R0,CPSR
ORR R0,R0,#NoInt
MSR CPSR_c,R0
}
}
/* 开中断 */
__inline OS_EXIT_CRITICAL(void)
{
__asm
{
MRS R0,CPSR
BIC R0,R0,#NoInt
MSR CPSR_c,R0
}
}
#endif
(1) 如果驱动用于 uC/OS-II 操作系统,则不需要编译这两个开、关中断函数,因为在
uC/OS-II 中已定义了这两个函数。
SYS_PortIn()和 SYS_PortOut()函数通过使用程序清单 1.5中定义的 ATA 设备寄存器的地址的宏作为参数,实现对 ATA 设备各寄存器的读写操作。
ZLG/CF 驱动读写 ATA 设备寄存器的函数如程序清单 1.6 所示。
程序清单 1.5 设备寄存器地址宏定义
/*GPIO 引脚影射寄存器地址*/
#define ATA_REG_DATA IDE_CS1 /*数据寄存器*/
#define ATA_REG_ERR (IDE_CS1 + IDE_A0) /*读错误寄存器*/
#define ATA_REG_FEATURE (IDE_CS1 + IDE_A0) /*写功能寄存器*/
#define ATA_REG_SECCNT (IDE_CS1 + IDE_A1) /*扇区计数器*/
#define ATA_REG_SECTOR (IDE_CS1 + IDE_A1 + IDE_A0) /*扇区号*/
#define ATA_REG_CYLI_LOW (IDE_CS1 + IDE_A2) /*柱面低 8 位*/
#define ATA_REG_CYLI_HIGH (IDE_CS1 + IDE_A2 + IDE_A0) /*柱面 高8位*/
#define ATA_REG_DEVICE_HEAD (IDE_CS1 + IDE_A2 + IDE_A1) /*选择主从,模式,磁头*/
#define ATA_REG_COMMAND (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*写命令寄存器*/
#define ATA_REG_STATUS (IDE_CS1 + IDE_A2 + IDE_A1 + IDE_A0) /*读状态寄存器*/
#define ATA_REG_CONTROL (IDE_CS0 + IDE_A2 + IDE_A1) /*写控制寄存器*/
#define ATA_REG_ASTATUS (IDE_CS0 + IDE_A2 + IDE_A1) /*读辅助状态寄存器*/
程序清单 1.6 读写设备相关寄存器接口函数
/*驱动与硬件对 ATA 设备寄存器操作接口 */
#define GetData() SYS_PortIn(ATA_REG_DATA) /*读数据寄存器,与驱动接口 */
#define SetData(x) SYS_PortOut(ATA_REG_DATA,x) /*写数据寄存器,与驱动接口 */
#define GetERR() SYS_PortIn(ATA_REG_ERR) /*读错误寄存器,与驱动接口 */
#define SetFeature(x) SYS_PortOut(ATA_REG_FEATURE,x) /*写特征寄存器,与驱动接口 */
#define GetSECCNT() SYS_PortIn(ATA_REG_SECCNT) /*读扇区计数寄存器,与驱动接口 */
#define SetSECCNT(x) SYS_PortOut(ATA_REG_SECCNT,x) /*写扇区计数寄存器,与驱动接口 */
#define GetSector() SYS_PortIn(ATA_REG_SECTOR) /*读扇区寄存器,与驱动接口 */
#define SetSector(x) SYS_PortOut(ATA_REG_SECTOR,x) /*写扇区寄存器,与驱动接口 */
#define GetCylinderLow() SYS_PortIn(ATA_REG_CYLINDER_LOW) /*读柱面低寄存器,与驱动接口 */
#define SetCylinderLow(x) SYS_PortOut(ATA_REG_CYLINDER_LOW,x)/*写柱面低寄存器,与驱动接口 */
#define GetCylinderHigh() SYS_PortIn(ATA_REG_CYLI_HIGH) /*读柱面高 8 位寄存器,与驱动接口 */
#define SetCylinderHigh(x) SYS_PortOut(ATA_REG_CYLI_HIGH,x) /*写柱面高 8 位寄存器,与驱动接口 */
#define GetDeviceHead() SYS_PortIn(ATA_REG_DEVICE_HEAD) /*读设备磁头寄存器,与驱动接口 */
#define SetDeviceHead(x) SYS_PortOut(ATA_REG_DEVICE_HEAD,x)/*写设备磁头寄存器,与驱动接口 */
#define GetStatus() SYS_PortIn(ATA_REG_STATUS) /*读状态寄存器,与驱动接口 */
#define SetCommand(x) SYS_PortOut(ATA_REG_COMMAND,x) /*写命令寄存器,与驱动接口 */
2.硬件复位函数
系统中定义了 IDE_RST 引脚控制 ATA 设备的硬件复位。如程序清单 1.7 所示。
程序清单 1.7 硬件复位函数
/*******************************************************************************************
** 函数名称,SYS_IdeHardReset
** 功能描述,ATA 设备硬件复位
** 输 入,无
** 输 出,无
** 全局变量,
** 调用模块,SYS_WaitInUS(),等待微秒函数。
*******************************************************************************************/
void SYS_IdeHardReset(void)
{
IOCLR = IDE_RST; /*复位引脚置低 */
SYS_WaitInUS(30); /*延时大于 25 微秒 */
IOSET = IDE_RST; /*复位引脚置高 */
SYS_WaitInUS(5000); /*延时大于 2 毫秒 */
}
/*******************************************************************************************
** 函数名称,SYS_WaitInUS
** 功能描述,延时等级约 1 微秒函数,该函数根据系统时间不同与不同,但不应少到 1 微秒。
** 输 入,times,延时时间等级
** 输 出,无
** 全局变量,
** 调用模块,
*******************************************************************************************/
void SYS_WaitInUS(uint32 times)
{ uint32 c;
for(;0<times;times--)
for(c=0;c<5;c++);
}
3.设备检测函数
该函数用于检测 CF 卡插入及拔出,ZLG/CF 驱动要求系统必须提供该函数,即使系统中没有设计检测 CF 卡插入及拔出功能。
4.模拟 ATA 接口初始化函数
使用 LPC2210 的 GPIO 模拟 ATA 接口,定义了各引脚为输入或输出(见表 1.1) 。在使用我们定义好的引脚前,必须对 LPC2210 相关的寄存器进行配置。详见 1.1.3 小节。
1.1.3 LPC2210 相关寄存器配置
使用 GPIO 模拟 ATA 接口相关的寄存器只有几个,PINSEL1,PINSEL2,IO0DIR、
IO1DIR,IO2DIR,IO0SET,IO0CLR,IO1SET,IO1CLR,IO2SET,IO2CLR 等。