电子工程专辑
UBM China

用DSP的GPIO管脚实现与IC卡通信

上网日期: 2003年11月30日 ?? 作者: zhangbin, 张彬 ?? 我来评论 字号:放大 | 缩小 分享到:sina weibo tencent weibo tencent weibo


打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮

1.扫描左侧二维码
2.点击右上角的分享按钮
3.选择分享给朋友

关键字:IC卡? 存储卡? 智能卡? DSP?

IC卡可以分为接触式的和非接触式(射频卡),本文主要讨论存储卡智能卡(CPU卡)这两种接触式IC卡的结构特点和读写操作,详细叙述如何使用DSP的GPIO(通用输入输出)管脚实现与各种IC卡进行通信,并给出了DSP函数实现。

常见与IC卡连接的都是基于单片机的系统,但是某些应用要求IC卡读写终端具有较强的实时运算和控制能力,这时DSP就是最好的选择。以TI公司的C5409为例,它的8根HPI管脚(HD0~HD7)可以配置成GPIO使用,配置方法是在复位时将HPI16管脚置高或者HPIENA管脚置低,这样就可以通过配置DSP内部GPIOCR和GPIOSR两个寄存器来控制这8根GPIO管脚的输出和输入。GPIOCR寄存器的低8位用来控制每个GPIO管脚的方向,若管脚为输出则对应位设为“1”,若为输入则设为“0”(DSP复位后GPIOCR缺省值为“0”,即GPIO管脚默认为输入)。GPIOSR寄存器的低8位用来控制每个GPIO管脚的值,若为输出,向对应位写“1”,则该管脚输出高,写“0”则该管脚输出低;若为输入,则对应位的值为管脚上输入的值,向其写操作无效。图1:存储卡管脚结构示意图。

下面给出了控制GPIO的函数(控制低两位GPIO管脚,即HD0和HD1):


#define gpio_dir *(short *)0x3c


#define gpio_val *(short *)0x3d //定义两个寄存器的地址


void gpio_setval(short i,short j) //设置GPIO的输出


{


if(i==0) //控制HD0管脚


gpio_val=gpio_val&0xfffe; //设为0


else if(i==1)


gpio_val=gpio_val|0x0001; //设为1


if(j==0) //控制HD1管脚


gpio_val=gpio_val&0xfffd;


else if(j==1)


gpio_val=gpio_val|0x0002;


wait();


}


void gpio_setdir(short i) //控制GPIO的方向


{


if(i==1)


gpio_dir=gpio_dir|0x0001; //设为输出图2:开始、停止状态和确认信号的时序图。


else if(i==0)


gpio_dir=gpio_dir&0xfffe; //设为输入


}


short gpio_getval(short i) //读入GPIO的值


{


short j;


if(i==0) j=gpio_val&0x0001;


else if(i==1) j=(gpio_val&0x0002)>>1;


return j;


}

常见的接触式IC卡可以分为存储卡和智能卡(又叫作CPU卡),下面分别介绍DSP如何与这两种卡进行连接通信。

DSP和存储卡的连接

存储卡只具有简单存储功能,实际上是一片串行EEPROM的IC卡模式,以Atmel公司的AT24C16SC为例,它实质上就是两线串行EEPROM AT24C16,两者接口时序基本一样。存储卡的管脚如图1所示。AT24C16SC同时支持3V和5V,访问速度分别可以达到100Kbps(3V)和400Kbps(5V);内部容量为16Kb,分为128页,每页16字节;双向数据线(SDA)为OD(Open-Drain)驱动,需要加上拉电阻才能正常通信。

存储卡的访问时序为I2C标准时序。首先,正常通信中只有在时钟线(SCL)为低时SDA才可变化,即在SCL为高时,SDA必须保持状态(数据有效期),而在SCL为高时,SDA的变化表示下面两种控制状态:

开始状态:当SCL为高时,SDA由高变低表示一个开始状态,通常任何操作前均需要一个开始状态;

停止状态:当SCL为高时,SDA由低变高表示一个停止状态,通常跟在每个操作后,从而将卡置于等待模式。

在读写中,地址和数据都是按照8位的大小进行传输,接收的一方需要返回一个ACK信号表示确认,这个ACK信号是在第9位的位置返回一个“0”来表示。如在读卡的时候,DSP在收到8位后,在第9个时钟应向卡发送“0”表示收到了正确的数据,同时要求卡继续发送下一个8位数据,如果没有这个ACK信号,则将会中止当前读操作返回等待模式。写卡的时候,卡在收到DSP发送的地址和数据后也应该返回ACK信号以表示收到了正确的命令。开始和停止状态、确认信号时序如图2所示。

一个读写操作的开始需要先发送一个器件地址(device图3:数据有效时序。 address)字节,该字节的高4位是“1010”,接着3位是卡的高位地址,如AT24C16SC需要有11位地址(2K字节的大小),高3位地址就是这里来指示,最后1位是读写控制位,若为“1”,则表示后面进行一个读操作,若为“0”,则表示后面进行一个写操作。

写卡操作分为字写和页写。字写时,当发送完器件地址字节(最后1位为“0”指明写操作)后,接着再发送一个字地址(word address)字节,即为卡的低8位地址,然后就可送入一个字节的数据,最后发送停止状态。对于页写时,可以连续发送16个字节后再发送停止状态,需要注意的是,当页写时,低4位地址在卡内部自动递增,当到达页末地址时会自动返回页首地址,所以要正确发送停止状态,否则继续写入的字节就会覆盖原来的数据。

读卡操作分为读当前地址、读任意地址和顺序读几种方式。几种方式大同小异,下面主要介绍读任意地址的操作,另两种方式都较简单。读任意地址时,在发送完器件地址字节(最后1位为“1”指明读操作)后,发送字地址字节,这一过程是装载要读的地址,下面再发送一个器件地址字节(同样最后1位为“1”指明读操作),然后便可从卡读到一个连续8位数据,然后DSP发送停止状态(而不是ACK信号)结束读操作。

通过以上介绍可以看出,DSP与存储卡连接的关键就是如何做出SCL和SDA的时序,也就是I2C时序。用DSP的两根GPIO分别连接存储卡的SCL和SDA,然后同时设置两者的高低关系并且正确改变连接SDA那根GPIO的输入和输出方向,我们就可以解决这个问题。例如,对于图3这个数据有效期的时序,我们可以将两根GPIO依次设置为:“01”、“11”、“01”,需要注意的是,改变状态之间需要插入等待周期,因为DSP的工作时钟很高,其GPIO的改变远高于I2C时序的要求。

下面给出一个写卡函数:


short write_ic(short page,short addr,short length,short *buff)


//page-要访的问高3位地址,addr-要访问的低8位地址,length-要写入的数据长度,通常为16,buff-要写入的数据


{


short device_address,ack,i,loop=0;图4:智能卡管脚结构示意图。


start_ic(); //发送一个开始状态


device_address=0xa0|(page<<1);


put_ic(device_address); //发送器件地址字节,0xa0表示写


gpio_setdir(0); //改变GPIO方向为输入


ack=1;


do


{


ack=get_ic();


loop++;


if(loop>10000)


return 0;


}while(ack!=0); //等待读入确认信号,否则超时退出


device_address=addr; //要访问的低8位地址


put_ic(device_address); //发送字地址字节


gpio_setdir(0);


ack=1;


do


{


ack=get_ic();


loop++;图5:卡的复位应答信息组成。


if(loop>10000)


return 0;


}while(ack!=0);


for(i=0;i


{


put_ic(*buff++);


dir(0);


ack=1;


do


{


ack=get_ic();


}while(ack!=0);


} //写入数据


stop_ic();


return 1;


}


void put_ic(short c)


{


short temp,i;


gpio_setdir(1); //改变GPIO为输出


for(i=7;i>=0;i--)


{


temp=1<


temp=c&temp;


temp=temp<


if(temp==0)


{


gpio_setval(0,0); //设置两根GPIO的输出


gpio_setval(1,0);


gpio_setval(0,0);


}


else if(temp==1)


{


gpio_setval(0,1);


gpio_setval(1,1);


gpio_setval(0,1);


}


}


}

DSP和智能卡的连接

智能卡是IC卡中最高级的一种,其内部一般有CPU、ROM、RAM和EEPROM等资源,卡内一般都驻有智能卡操作系统(COS),该操作系统对卡进行维护和管理并解释终端的各种命令。由于卡内有CPU和RAM,所以可以根据需要进行一些运算和数据加密,同时卡内的EEPROM也可以存放一些用户资料(容量也较存储卡大)。智能卡的管脚如图4所示。

智能卡的操作遵循ISO7816-3规范,通信时序类似于双向RS-232通信协议(RS-232是单向的)。首先,操作前需要对卡进行激活,激活过程必须保证智能卡的触点接触良好。激活的步骤为:VCC供电,RST为低,I/O设为输入,提供CL,然后对卡进行复位。复位分为冷复位和热复位,两者区别在于冷复位时RST由低变高,而热复位时RST由高变低再变高,在复位后,卡应有复位应答;接受到卡正确的复位应答后,DSP可以向卡发送命令;取卡前需要进行释放,步骤顺序与激活相反:RST变低,CLK变低,VCC掉电。

卡的复位应答可以告诉终端一些卡的原始信息,它的组成如图5所示:

TS:初始化字节,用来进行位同步和指示后续通信的编码方式,例如0x3f表示反码编码,0x3b表示正常编码;


T0:格式字节,高4位用来指示是否传输TA1、TB1、TC1、TD1,低4位用来指示有多少个历史字符;


TAi、TBi、TCi:接口字节,用来设置操作的一些参数,比如速率,保护时间,编程电压等;


TDi:接口字节,高4位用来指示是否传输TAi+1、TBi+1、TCi+1,低4位用来指示传输类型T。T=0,字符半双工模式;T=1,块半双工模式,其他的T值保留。我们常用T=0即字符模式;


T1~TK:历史字符,由制卡商提供;图6:访问卡的时序图。


TCK:校验位,是T0~TK所有字节的异或,T=0时不传此字节。


访问卡的时序如图6所示。

可以看出,1个字节帧由13位组成,1个开始位、8个数据位、1个校验位和2个保护时间位。在外部提供时钟方式(常用方式)下,上图中每个位所占的时间(ETU,Elementary Time Unit)默认为外部时钟周期的372倍,如当外部时钟为3.57M时,1/ETU约为9600,即工作在9600速率下。保护时间默认为2个ETU,最大可以为254个ETU。

DSP与智能卡的连接跟存储卡有些差异。首先,智能卡比存储卡多一个RST管脚用来对CPU进行复位,可以使用DSP的一根GPIO来控制;存储卡的CLK为通信时钟,速度不高,没有速率要求,可以随时停止,只要时序关系正确即可,可以由DSP的GPIO实现;但智能卡的CLK为卡内CPU的工作时钟,速度很高(通常介于1M~5M),并且要求稳定,用DSP的GPIO来提供该时钟是不可能的,因为DSP的GPIO的翻转速度有限制,并且高速翻转必定占用大量DSP系统资源。因此可以使用DSP的一个串口McBSP的发送时钟CLKX来提供智能卡时钟。同时,还需要DSP的一根GPIO来连接智能卡的I/O信号,跟智能卡一样的是,I/O线同样是双向的,需要正确改变DSP的GPIO方向,但不同的是智能卡的I/O有精确的速率要求,即为CLK速率的1/372,可以采用DSP内部的定时器来结合GPIO实现。

选择DSP内部定时器的周期为提供时钟的串口时钟周期的372/8倍,当每个定时器中断到来时进行一次GPIO操作,这样等于是8倍频输出和采入数据,即操作的最小周期是1/8个ETU,从而确保了精度。从实现上看,上述过程类似于用定时器和GPIO来实现RS-232协议。需要注意的是,为了保证中断响应和系统资源,定时器中断程序中最好不进行GPIO操作,而只作标志位设置,GPIO操作留给读写函数实现。下面为一个读卡函数的实现。

void readword_sim(unsigned short *buff,unsigned short length)


//buff-读入的数据放的buffer,length-读入的长度


{


short tempbit,tempbyte,i,j,bitcount,parry;


rw=0; //设置GPIO为读


for(j=0;j


{


bitcount=0;


while(!bitcount)


{


ready=0;


while(!ready);


if(simdata==0) bitcount=1;


} //读入开始位


tempbyte=0;


bitcount=0;


for(;bitcount<11;)


{


tempbit=0;


for(i=0;i<8;i++)


{


ready=0;


while(!ready);


if(simdata==1)


tempbit=tempbit+(1<


} //读入一位的8倍采样


if((tempbit&0x18)==0 && bitcount==0)


bitcount++;


else if(bitcount>0 && bitcount<9)


{


if((tempbit&0x18)!=0)


tempbyte=tempbyte+(1<


bitcount++;


} //组成一个字节


else if(bitcount==9)


{


if((tempbit&0x18)!=0)


parry=1;


else parry=0;


bitcount++;


} //读入校验位


else if(bitcount==10) bitcount++; //保护时间


}


buff[j]=tempbyte;


}


}


shorterrupt void tshort() //定时器中断


{


if(ready==0)


{


if(rw==0)


simdata=gpio_getval();


ready=1;


}


}


上面的程序实现了智能卡的读写协议,余下的就是对卡发送命令即可,关于命令的结构和定义本文不作阐述。

作者:张彬


研究生


北京邮电大学


Email: bingo@263.net






我来评论 - 用DSP的GPIO管脚实现与IC卡通信
评论:
*? 您还能输入[0]字
分享到: 新浪微博 qq空间
验证码:
????????????????
?

关注电子工程专辑微信
扫描以下二维码或添加微信号“eet-china”

访问电子工程专辑手机网站
随时把握电子产业动态,请扫描以下二维码

?

5G网络在提供1Gbps至10Gbps吞吐量方面具有很好的前途, 并且功耗要求比今天的网络和手机都要低,同时还能为关键应用提供严格的延时性能。本期封面故事将会与您分享5G的关键技术发展,以及在4G网络上有怎样的进步。

?
?
有问题请反馈
推荐到论坛,赢取4积分X