精简ISA总线信号
英创公司的嵌入式主板产品,如ESM7000、ESM335x等,均配置有精简ISA总线接口,基本的精简ISA总线由8位地址数据总线(分时复用)+ 4条控制信号组成,通过异步操作的读写总线周期,来实现对外部逻辑单元的控制。精简ISA总线的最大优点是硬件接口简单、应用程序接口简单,读写速度可达4MB/s,特别适合在嵌入式系统中使用。实现主板与用户专用接口电路的控制与数据传输。
精简ISA总线核心的12条信号线定义如下:
信号名称 | 信号功能简要说明 |
ISA_AD0 | 地址数据总线,LSB |
ISA_AD1 | 地址数据总线 |
ISA_AD2 | 地址数据总线 |
ISA_AD3 | 地址数据总线 |
ISA_AD4 | 地址数据总线 |
ISA_AD5 | 地址数据总线 |
ISA_AD6 | 地址数据总线 |
ISA_AD7 | 地址数据总线,MSB |
ISA_RDn | 总线数据读控制信号,低电平有效 |
ISA_WEn | 总线数据写控制信号,低电平有效 |
ISA_ADVn | 总线地址锁存控制信号,低电平有效 |
ISA_CSn | 总线周期片选控制信号,低电平有效 |
上表的12条信号直接从ESMARC主板引出,再配置上总线复位信号和中断信号(通常由主板的GPIO信号来实现),就可驱动各种接口单元了。
精简ISA总线时序
基本的总线时序包括读总线周期和写总线周期。以下时序来自ESM7000嵌入式主板的精简ISA总线,ESM335x的精简ISA总线时序也完全同样的,其扩展外设逻辑电路可直接互换。
异步读总线周期时序
异步写总线周期时序
对异步读写操作,一个完整的读写操作时间包括上述的总线操作周期和总线周期间隔,大约在240ns – 250ns,对应着4MB/s – 4.2MB/s的数据读写速度。锁存的地址也是8-bit,对应精简ISA总线的寻址能力是256个8-bit寄存器,这对绝大多数嵌入式应用已足够使用。
WinCE平台编程方法
ESM7000和ESM335x均支持Windows CE平台(WEC7),对精简ISA总线配置了相应的驱动程序。用户的应用程序只需通过对其驱动程序进行操作,即可实现对ISA总线的读写操作。为方便应用调用,封装了几个基本操作函数:
HANDLE ISA_Open( LPCWSTR lpDevName )
{
return CreateFile(lpDevName, // name of device
GENERIC_READ|GENERIC_WRITE, // desired access
FILE_SHARE_READ|FILE_SHARE_WRITE, // sharing mode
NULL, // security attributes (ignored)
OPEN_EXISTING, // creation disposition
FILE_FLAG_RANDOM_ACCESS, // flags/attributes
NULL);
}
BOOL ISA_Close( HANDLE hISA)
{
return CloseHandle( hISA );
}
BOOL ISA_ReadUchar(HANDLE hISA, DWORD dwPortOffset, PBYTE pBuf)
{
DWORD dwBufSize = sizeof(BYTE);
DWORD dwNbBytesRead = 0;
*pBuf = (BYTE)(dwPortOffset & 0xFF);
return ReadFile(hISA, pBuf, dwBufSize, &dwNbBytesRead, NULL);
}
BOOL ISA_WriteUchar(HANDLE hISA, DWORD dwPortOffset, BYTE ucValue)
{
WORD wValue;
DWORD dwBufSize = sizeof(WORD);
DWORD dwNbBytesWritten = 0;
wValue = (WORD)(dwPortOffset & 0xFF);
wValue = (wValue << 8) | ucValue;
return WriteFile(hISA, &wValue, dwBufSize, &dwNbBytesWritten, NULL);
}
BOOL ISA_ReadWord(HANDLE hISA, DWORD dwPortOffset, WORD* pBuf)
{
DWORD dwBufSize = sizeof(WORD);
DWORD dwNbBytesRead = 0;
*pBuf = (WORD)(dwPortOffset & 0xFE);
return ReadFile(hISA, pBuf, dwBufSize, &dwNbBytesRead, NULL);
}
BOOL ISA_WriteWord(HANDLE hISA, DWORD dwPortOffset, WORD wValue)
{
DWORD dwValue;
DWORD dwBufSize = sizeof(DWORD);
DWORD dwNbBytesWritten = 0;
dwValue = (dwPortOffset << 16) | wValue;
return WriteFile(hISA, &dwValue, dwBufSize, &dwNbBytesWritten, NULL);
}
打开设备文件Handle
HANDEL hISA = ISA_Open( _T("ISA1:"));
if( hISA == INVALID_HANDLE_VALUE) {
// error processing
}
读操作
DWORD dwPortOffSet = 0; // 0x00 .. 0xFF
BYTE ucValue;
WORD wValue;
BOOL bRet;
// read a byte
bRet = ISA_ReadUchar(hISA, dwPortOffSet, &ucValue);
// read a word
bRet = ISA_ReadWord(hISA, dwPortOffSet, &wValue);
写操作
DWORD dwPortOffSet = 0; // 0x00 .. 0xFF
BYTE ucValue = 0x55;
WORD wValue = 0x55aa;
BOOL bRet;
// write a byte
bRet = ISA_WriteUchar(hISA, dwPortOffSet, ucValue);
// write a word
bRet = ISA_WriteWord(hISA, dwPortOffSet, wValue);
关闭设备文件Handle
ISA_Close(hISA);
Linux平台编程方法
ESM7000和ESM335x均支持Linux平台(Linux-4.x.x),对精简ISA总线配置了相应的驱动程序。在为用户的应用程序封装的函数中,除支持常规的端口读写外,同时支持了Linux特有的mmap操作,以提高读写速度。封装函数如下:
unsigned char *isa_base = NULL;
unsigned int map_size = 4096;
// return >= 0: return file handle
// return < 0: return failed code
int isa_open()
{
int fd;
fd = open("/dev/em_isa", O_RDWR);
if(fd < 0) {
return fd;
}
isa_base = (unsigned char*)mmap(0,map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (isa_base == MAP_FAILED) {
printf("%s mmap failed\n", __func__);
isa_base = NULL;
close(fd);
return -1;
}
return fd;
}
int isa_close(int fd)
{
if(isa_base != NULL) {
munmap(isa_base, map_size);
isa_base = NULL;
}
return close(fd);
}
// offset: port address in isa bus
unsigned char isa_read(int fd, unsigned int offset)
{
unsigned char val_b;
int rc;
offset &= 0xff;
if(isa_base != NULL) {
unsigned short int val_w;
val_w = *((unsigned short int*)(isa_base + (offset << 1)));
val_b = (unsigned char)(val_w & 0xff);
return val_b;
}
val_b = offset;
rc = read(fd, &val_b, sizeof(unsigned char));
if(rc < 0) {
// read error
printf("%s failed %d\n", __func__, rc);
}
return val_b;
}
// offset: port address in isa bus
void isa_write(int fd, unsigned int offset, unsigned char val_b)
{
unsigned short int val_w;
int rc;
offset &= 0xff;
if(isa_base != NULL) {
val_w = val_b;
*((unsigned short int*)(isa_base + (offset << 1))) = val_w;
return;
}
val_w = ((offset & 0xff) << 8) | val_b;
rc = write(fd, &val_w, sizeof(unsigned short int));
if(rc < 0) {
// write error
printf("%s failed %d\n", __func__, rc);
}
}
// offset: port address in isa bus
unsigned short int isa_read16(int fd, unsigned int offset)
{
unsigned short int val_w;
int rc;
// 2-byte alignment is required for offset
offset &= 0xfe;
if(isa_base != NULL) {
unsigned int val;
val = *((unsigned int*)(isa_base + (offset << 1)));
val_w = (unsigned short int)((val >> 8) | (val & 0x00ff));
return val_w;
}
val_w = (unsigned short int)offset;
rc = read(fd, &val_w, sizeof(unsigned short int));
if(rc < 0) {
// read error
printf("%s failed %d\n", __func__, rc);
}
return val_w;
}
// offset: port address in isa bus
void isa_write16(int fd, unsigned int offset, unsigned short int val_w)
{
unsigned int val;
int rc;
// 2-byte alignment is required for offset
offset &= 0xfe;
if(isa_base != NULL) {
val = val_w;
val = ((val << 8) & 0x00ff0000) | (val & 0x000000ff);
*((unsigned int*)(isa_base + (offset << 1))) = val;
return;
}
val = (offset << 16) | val_w;
rc = write(fd, &val, sizeof(unsigned int));
if(rc < 0) {
// write error
printf("%s failed %d\n", __func__, rc);
}
}
打开设备文件Handle
//open file
int fd = isa_open();
if(fd < 0) {
//open file failed
printf("open file = %d\n", fd);
return fd;
}
读操作
unsigned int offset = 0x00;
unsigned int value;
// read a byte
value = isa_read(fd, offset);
// read a word
value = isa_read16(fd, offset);
写操作
unsigned int offset = 0x00;
unsigned int value = 0x55aa;
// write a byte, lower byte
value = isa_write(fd, offset, value);
// write a word
value = isa_write16(fd, offset, value);
关闭设备文件Handle
isa_close(fd);