Global Sources
電子工程專輯
 
電子工程專輯 > 射頻/無線
 
 
射頻/無線  

用DSP的GPIO接腳實現與IC卡通訊

上網時間: 2003年11月30日     打印版  Bookmark and Share  字型大小:  

關鍵字:IC卡  儲存卡  智慧卡  DSP  SIM卡 

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’則該接腳輸出低;若為輸入,則對應位的值為接腳上輸入的值,向其寫作業無效。下面給出了控制GPIO的函數(控制低兩位元GPIO接腳,即HD0和HD1):


#define gpio_dir *(short *)0x3c圖1:儲存卡接腳結構示意圖。


#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; //設為輸出


Velse 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和儲存卡的連接圖2:開始、停止狀態和確認訊號的時序圖。

儲存卡只具有簡單儲存功能,實際上是一片串列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 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;


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();圖3:數據有效時序。


loop++;


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<<(-i);


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所示。圖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:歷史字符,由制卡商提供;


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作業留給讀寫函數實現。下面為一個讀卡函數的實現。圖5:卡的復位應答資訊組成。

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-1));


bitcount++;


} //組成一個位元組圖6:存取卡的時序圖。


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]個字
*驗證碼:
 
論壇熱門主題 熱門下載
 •   將邁入40歲的你...存款多少了  •  深入電容觸控技術就從這個問題開始
 •  我有一個數位電源的專利...  •  磷酸鋰鐵電池一問
 •   關於設備商公司的工程師(廠商)薪資前景  •  計算諧振轉換器的同步整流MOSFET功耗損失
 •   Touch sensor & MEMS controller  •  針對智慧電表PLC通訊應用的線路驅動器
 •   下週 深圳 llC 2012 關於PCB免費工具的研討會  •  邏輯閘的應用


EE人生人氣排行
 
返回頁首