分类:
2009-05-25 20:27:38
经过前面一节的处理后,在虚拟机底下的Linux与独立的Linux下的并口编程是一样的了。本节主要讨论在Linux如何通过操作前面提到的3个寄存器来达到操作并口管脚的目的。
Linux下应用程序运行在保护模式下,不能直接对IO端口进行存取,需先通过ioperm取得端口的控制权。Linux的ioperm系统调用允许本地读/写访问系统的IO端口,但仅限于0-0x3FF这1024个端口,其它端口的访问级别可通过iopl更改。ioperm系统调用的形式如下:
#include
#include
int ioperm(unsigned long port, unsigned long num, int turn_on);
在这个系统调用中,port指端口的基地址,num是连续的端口数目,turn_on表明是获得控制权(turn_on=1),还是释放控制权(turn_on=0)。
Jflash源码中,ioperm(LPT1, 3, 1)即:获取并口1的基地址开始之后连续三个端口(数据寄存器、状态寄存器和控制寄存器)的控制权。
在获取控制权后,即可以通过outb和inb等相关函数对IO端口进行写、读操作。
Jflash中相关代码如下:
#define _inp(a) inb(a)
#define _outp(a, d) outb(d, a)
#define OutputPpt(value) _outp((unsigned short)validPpt, value)// 将value写入validPpt,即写入数据寄存器,最后通过并口输出
#define InputPpt() _inp((unsigned short)(validPpt+0x1))// 读入状态寄存器的数值,实际是读取状态寄存器对应的并口管脚
上一小节中讨论了Jlash源码中最基础的三条函数,本节继续讨论Jflash中并口操作相关的其它函数。
/********************************************************************
* 功能: 设置port 端口开始之后的3个地址为可访问
* 参数: port: 欲设置访问权限的端口
* 返回值: 成功返回1, 失败返回0
********************************************************************/
static int io_access_on(unsigned long port)
{
if (ioperm (port, 3, 1)) {
perror("ioperm()");
return 0;
}
if (ioperm (0x80, 1, 1)) {
perror("ioperm()");
return 0;
}
return 1;
}
/********************************************************************
* 功能: 设置port 端口开始之后的3个地址为不可访问
* 参数: port: 欲设置访问权限的端口
* 返回值: 无
********************************************************************/
static void io_access_off( unsigned long port )
{
ioperm (port, 3, 0);
ioperm (0x80, 1, 0);
}
/********************************************************************
* 功能: 获取有效的端口号
* 参数: 无
* 返回值: 成功返回LPT1-LPT3中有效的端口, 失败返回0
********************************************************************/
int GetValidPpt(void)
{
if( io_access_on(LPT1) ){// LPT1是否可访问
_outp(LPT1, 0x55);// 若LPT1可访问,则通过写入0x55再读入对比来确认其是否可操作
if((int)_inp(LPT1) == 0x55)
return LPT1;
io_access_off(LPT1);
}
……// 如上依次检测LPT2、LPT3是否可访问
return 0;
}
/********************************************************************
* 功能: 设置并口为兼容模式
* 说明: 由于大部分PC 在PC 中已设置并口为ECP 或EPP模式, 故本程序中没必要再设置
********************************************************************/
#define ECP_ECR (0x402)
#define ECR_STANDARD (0x0)
#define ECR_DISnERRORINT (0x10)
#define ECR_DISDMA (0x0)
#define ECR_DISSVCINT (0x4)
void SetPptCompMode(void)
{
//configure the parallel port at the compatibility mode.
//_outp(validPpt+ECP_ECR, ECR_STANDARD | ECR_DISnERRORINT | ECR_DISDMA | ECR_DISSVCINT);
}
关于JTAG引脚与并口的连接,用户可以根据自己的想法进行,只要与软件中设定能对应就ok。目前,有两种所谓“标准”接法:Sdt 和 Wiggler 接法。
下表列出来这两种接法:
表4.5 JTAG与并口的硬件连接
JTAG管脚 |
SDT接法 |
Wiggler接法 | ||
并口管脚 |
并口管脚号 |
并口管脚 |
并口管脚号 | |
TCK |
D0 |
2 |
D2 |
4 |
TMS |
D1 |
3 |
D1 |
3 |
TDI |
D6 |
8 |
D3 |
5 |
TDO |
Select/STATUS[4] |
13 |
Busy/STATUS[7] |
11 |
nTRST |
D2 |
4 |
D0 |
2 |
这里有个问题要着重注意下:Wiggler采用Busy脚做为TDO,其管脚在并口硬件上有个反向器。所以我们需要将读入的电平反向;SDT接法则没有这个必要。
上面讨论的是在linux底下做JTAG开发。本章简单讨论下windows下的JTAG开发。有兴趣者可查看我的源码。
从Jflash源码来看,除了并口操作要用到IO口,是与OS相关的,其它都符合ANSI C,不需要做移植。也就是说,只要解决好windows下的并口编程就ok了。
在windows NT架构的操作系统(如XP)底下,应用程序同样不能直接访问IO口,我们同样需要先获取IO端口的控制权,而后使用API去操作他们。
为了在windows下实现对并口的访问,我们必须安装一些驱动或程序库。可能的手段主要有:
1. winio程序库
WinIO程序库允许在32位的Windows应用程序中通过物理地址直接对I/O端口和物理内存进行存取操作。通过使用一种内核模式的设备驱动器和其它几种底层编程技巧,它绕过了Windows系统的保护机制。
2. GIVEIO驱动
安装该驱动后,应用程序可以直接通过IO的物理地址进行直接访问。
Windows下的SJF烧写程序都使用了该驱动。这也是为什么在用SJF烧写vivi等Bootloader前必须先安装GIVEIO驱动的原因。
关于GIVEIO的源码以及如何使用它,大家可到网上搜索下载,也可参考SJF源码。
在使用GIVEIO驱动取得访问权后,可使用底下两个接口直接操作IO端口:
#include
int _inp(unsigned short port);
port参数为指定的输入端口号。调用后,它从port参数指定的端口读入并返回一个字节,输入值可以是在0—255范围内的任意无符号整数值。
int _outp(unsigned short port, int databyte);
port 参数为指定的输出端口号,databyte 参数为输出的值。调用后,它将databyte参数指定的值输出到port 参数指定的端口并返回该值。databyte 可以是0—255范围内的任何整数值。
这两个函数都没有错误值返回。在Win98下可以直接用, 但在NT下必须要挂驱动程序。
当使用转并口设备时,并口端口号会比较特殊。这时,我们只需再定义一个LPT4,并在ppt.c的GetValidPpt函数中增加对该并口的支持就ok了。
我的PCI转并口设备的端口号是0xC400,以下是我新增的代码:
#define LPT4 0x0C400
int GetValidPpt(void)
{
……
if( io_access_on(LPT3) ){
_outp(LPT3, 0x55);
if((int)_inp(LPT3) == 0x55)
return LPT3;
io_access_off(LPT3);
}
return 0;
}