ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

ISO7816-3协议精讲:复位时序、字符帧与ATR解析

ISO7816-3协议精讲:复位时序、字符帧与ATR解析 一张IC卡从插入到通信7816到底规管了哪几件事搞嵌入式这么多年接触过不少刚入行的朋友拿到一个读卡模块调了半天读不到卡最后发现是APDU收发时序不对或者复位应答压根没出来。其实智能卡通信不是玄学它就是一条线上的电平变化再加上一套非常严谨的时序规则。这套规则的核心就是ISO7816协议。尤其是7816-3这一部分它规定了卡和读卡器之间怎么打招呼、怎么传输一个字节、怎么确认彼此的身份。现在市面上大量接触式IC卡比如社保卡、银行卡、门禁卡、部分SIM卡底层都跑这玩意儿。你如果要做读卡终端、嵌入式支付设备、或者自己DIY一个智能卡读写器7816-3是你第一道绕不过去的坎。这篇我打算把ISO7816协议里最基础、也是最重要的三件事拆开揉碎讲清楚复位Reset、字符帧Character Frame、ATRAnswer To Reset。这三个概念是后续理解T0/T1协议、APDU命令交互的基础。注意这只是一个系列的第一篇先把地基打牢。在进入具体时序之前先建立一个整体概念。7816协议分了很多部分而我们平时说的接触式IC卡通信主要涉及这几个层面物理层卡的尺寸、触点位置就是卡上那8个镀金触点编号C1到C8。电气层VCC电源、GND地、CLK时钟、RST复位、I/O数据线这几根线的电压标准和电平逻辑。传输层字节怎么在I/O线上传这就是字符帧会话层卡片复位之后怎么上报能力这就是ATR应用层卡片和终端之间跑APDU指令这是7816-4的内容。如果你做的是驱动开发物理层和电气层通常是硬件工程师帮你搞定的但你作为写代码的人至少要清楚时序约束长什么样。否则你连逻辑分析仪抓出来的波形都看不懂更别提排查问题了。复位不是简单拉低IO冷复位与热复位背后的时序逻辑冷复位上电瞬间的仪式感先聊冷复位Cold Reset。冷复位发生的场景是终端给卡上电的那一刻。整个过程的顺序非常重要很多人踩坑就是在这里。标准的冷复位时序是这样的VCC先上电并稳定在工作电压范围。对于5V卡就是4.75V到5.25V这个区间3V卡是2.7V到3.3V。CLK时钟信号开始输出并且要稳定。时钟频率一般在1MHz到5MHz之间最常见的标准值是3.5712MHz和4MHz。I/O线进入接收态也就是说读卡器侧把I/O线置为高电平通过上拉电阻拉高。RST保持低电平持续至少400个时钟周期指的是CLK的周期。RST拉高此刻起卡片必须在400到40000个时钟周期之间把ATR的第一个字节送上I/O线。这个RST低电平至少400个CLK周期的要求是给卡片内部电路一个准备时间。卡片内部也有自己的复位逻辑需要一个稳定的时钟来触发初始化。如果你RST拉得太早卡片可能还没准备好直接导致后续没有响应。另外还要注意RST拉高之后卡片返回ATR是有时间上限的。上限是40000个时钟周期。如果超过这个时间I/O线上还没有动静终端可以断定这张卡有问题或者没插好。热复位不重新上电也能让卡重新说话热复位Warm Reset和冷复位的区别在于VCC和CLK不中断只是把RST拉低一段时间再拉高。热复位的场景很常见比如你的程序想重新读取一张卡的ATR或者卡片进入某种异常状态需要重启但是又不想断电重来。这时候就可以在卡片正常运行期间直接把RST拉到低电平保持至少400个时钟周期然后再拉起来。热复位的时序约束和冷复位类似也是要求在RST拉高之后的400到40000个时钟周期内卡片发出ATR的第一个字节。这里有一个常见的误解很多初学者以为热复位期间I/O线上的数据是无效的随便拉高拉低无所谓。其实不对。在RST拉低期间I/O线状态也有要求终端应该让I/O处于接收态即高电平。如果此时I/O被别的东西占用或者拉低卡片内部可能会misdetect导致复位流程异常。看门狗与复位的类比同样是复位目的完全不同说到这个我特别想提醒一点ISO7816的复位和单片机里的复位是两个概念虽然都叫Reset但完全是不同层面的东西。单片机复位是MCU自己重启程序从头跑跟看门狗超时等有关。而7816的复位是终端主动对卡片发起的握手流程。卡片并不运行你的程序它只是一个有状态的外部设备。在调试的时候如果卡片没响应别想当然地认为给它一个复位信号它就会好。你得按协议检查复位信号时序是否合规。曾经有个项目我们一直怀疑卡的问题换了好几张卡都一样最后抓波形发现RST低电平只维持了200个时钟周期卡片压根没来得及初始化。这就是典型的时序违规。对比项冷复位热复位VCC重新上电保持不变CLK从无到有保持不变RST上电后拉低至少400周期再拉高运行中拉低至少400周期再拉高使用场景卡片插入、终端上电程序主动重启卡片逻辑字符帧拆解起始位、数据位、奇偶校验与ETU的精确计算一个字符在总线上长什么样ISO7816的传输层用的是异步半双工串行通信。一根I/O线既要接收也要发送。所谓字符帧就是传输一个字节的基本单元。一个完整的字符帧由以下几部分组成起始位1个位时间的低电平。数据位8个位时间低位先传LSB first。奇偶校验位1个位时间。保护时间至少2个位时间的高电平作为字符之间的间隔。这里位时间有一个专门的名词叫ETUElementary Time Unit。一个ETU就是传送一个bit需要的时间。默认情况下ETU的计算公式是ETU 372 / f其中f是CLK时钟频率。以最常见的3.5712MHz为例一个ETU大约是104.17微秒。为什么是372这个数字这是协议的历史遗留因为早期卡片内部的时钟分频逻辑需要一个整数分频系数来从CLK里出一个内部baud clock。372这个值成了T0协议的默认值一直被沿用到现在。你可以把它类比成串口的波特率。传统串口115200表示每秒传115200个bit而7816的波特率就是 f/372。也就是说在默认情况下I/O线上的电平变化速度是固定的快慢取决于你给卡供的时钟频率。奇偶校验是强制的别把它当可选7816的字符帧采用奇校验Odd Parity。规则是8个数据位加上校验位逻辑1的总数必须是奇数。举个例子如果你要发送0x55这个字节二进制是01010101里面有4个1。为了让总1的个数变成奇数校验位就需要是1。这样加上校验位总共有5个1满足奇校验。如果你发送0x00二进制全是00个1。那校验位就需要是1让总数变成1个1。同样满足奇校验。这个校验机制的作用是保证单bit错误能被发现。在智能卡这种对可靠性要求很高的场景里这是强制要求。我在实际调试中真的见过有实现偷懒不发送校验位的结果就是卡片端解析出来的数据全是错的。所以如果你是自己做读卡器校验位的计算一定要严格按协议来。ETU的初始值不是永远的保护时间和溢出条件在ATR阶段双方的通信都按初始ETU进行。但ATR完成之后通过PPSProtocol Parameter Selection过程双方可以协商一个更快的速率。这涉及到PPS请求和应答属于7816-3后续章节的内容这第一篇先不展开。不过有一点值得在这儿提一句就算速率变了字符帧的基本结构不会变还是起始位数据位校验位保护时间。变的只是每个bit所占用的时间宽度。那么多快的电平变化算有效多快算误码协议里还有一个参数叫接收器容差。简单说接收方允许单个位的时间长度在标准ETU的±某个百分比范围内波动。如果误差太大接收方就会判定为溢出错误丢弃这个字符。这个机制拿串口的帧错误来类比是最好理解的。ATR逐字节过一遍从TS到历史字节协议反馈的完整解码TS字节第一字节决定了你和卡说话的方式复位成功后卡片发出的第一串数据就是ATR。ATR的第一个字节叫TS它的作用极其特殊它告诉终端接下来所有的字节是按正向约定还是反向约定来解析。如果TS 0x3B表示正向约定Direct Convention意思就是逻辑1对应高电平逻辑0对应低电平。这也是最常见的取值。如果TS 0x3F则表示反向约定Inverse Convention逻辑1和0恰好反转。为什么需要这个约定因为在7816的物理层I/O线的空闲态是高电平。但不同厂家的卡片内部逻辑可能采用不同的极性设计。如果没有TS这个协调机制终端就无法正确解析后续的数据。这个设计有点像串口通信中的极性配置只是7816通过ATR第一个字节就完成了协商。值得注意的是ATR本身的第一个字符TS在传输时是按照特定规则来的。无论后续是正向还是反向约定TS这个字符本身的解析是通过I/O线电平的特定跳变完成的。简单理解就是终端电路都知道起始位是下降沿后面8个数据位按时间窗口采样然后看TS的值来判断约定。T0字节接口字节的目录紧跟着TS的是T0这个字节相当于一个目录告诉你后面跟着哪些接口字节以及总共多少个。T0的高4位b8到b5表示TA1到TD1之后还跟着多少个后续接口字节组。说实话T0的高半字节是个计数器它代表后面还会出现多少组TA/TB/TC/TD系列接口字节。T0的低4位则是一个标志掩码对应TA1、TB1、TC1、TD1是否存在bit4对应TD1是否存在bit3对应TC1是否存在bit2对应TB1是否存在bit1对应TA1是否存在举例说明如果T0 0x68高半字节6表示后面还有6组后续接口字节低半字节8表示TD1存在。这些后续字节里包含了全局参数比如时钟停止支持、最大时钟频率、编程电压等信息。老一点的协议还有编程电压Programming Voltage的概念比如TB1里编码了VPP电压值。现在的卡片基本都是5V、3V、1.8V供电编程电压这个字段实际意义已经不大但理解ATR结构时还是会遇到。我建议你不要跳过因为有时候老卡或者特殊应用卡还是会用到这些字段。接口字节一个个去理解 TA、TB、TC、TD 的意义接口字节是一组变长的数据用来告诉终端卡片支持哪些电气参数。常见的包括TA1编码时钟速率默认值为0x11时表示比值372。实际上TA1的取值直接反映出当前用的分频因子。如果TA1存在你要用它的值来重新计算实际ETU。TB1包含编程电压相关参数还用低4位表示最大编程电流。前面说了这个字段现在基本不关心。TC1表示额外保护时间Extra Guard Time。默认情况下字符间的保护时间是2个ETUTC1可以把这个值扩展。TC1 0表示使用默认值。TD1表示是否支持后续的TD2、TA2等以及T协议类型。看到这你应该明白了ATR并不仅仅是一个你好的信号它更像是一张能力清单。卡片在宣布自己支持什么协议、需要什么电压、怎么通信。常见的ATR字节串比如3B 68 00 00 00 73 C8 40 00 00 90 00 573B表示正向约定68后面跟着历史字节。如果你用逻辑分析仪抓出来这么一串并通过ATR解析工具识别出PIV-II卡之类的结论整个过程其实就是上面这些字段的逐项解码。历史字节与TCKATR的最后一块拼图说完接口字字节还有一个叫历史字节Historical Bytes的部分。它在T0指定的接口字节全部送完之后出现用来存放卡生产商定义的个性化信息。最多可以放15个字节。这部分的内容不是标准强制的通常包括卡片类型、应用标识等。ATR的传输顺序是TS、T0、接口字节、历史字节、TCK如果想通过T1协议传输TCK必须存在它是对前面所有ATR字节做异或校验的结果。TCK的校验逻辑很简单从T0开始到TCK前一个字节所有字节异或的结果加上TCK本身最终等于0。也就是 TCK ^ T0 ^ 接口字节 ^ 历史字节 0。如果校验失败说明ATR传输过程中有错误通信应该终止。如果你收到的ATR末尾没有TCK说明协议类型是T0也就是异步半双工字符传输协议。如果TCK存在通常意味着卡片支持T1即块传输协议。这个在后续的T1详解里会展开。复位拿不到ATR时怎么办实测排查路径与关键陷阱我遇到过的完全没反应三种最可能的原因前面讲完了原理必须落地到实际排错。调试7816卡最常见的问题就是插卡之后完全抓不到ATRI/O线上一点动静都没有。这种情况我是真的遇到过很多次总结起来原因通常出在三个地方第一VCC上电时序不对。有些设计把RST拉高和VCC上电做成了同步操作但卡片要求RST必须在VCC稳定之后保持低电平至少400个CLK周期然后再拉高。如果RST拉得太快卡片内部电源还没稳定上电复位逻辑不会触发。第二CLK没有稳定就执行复位。有些MCU的方案里时钟初始化需要一点时间。如果CLK频率还没稳定卡片收到的时钟毛刺会导致内部逻辑紊乱。此时你给再标准的复位时序也没用。第三I/O线没配置上拉。7816的I/O是开漏结构必须由终端侧外接上拉电阻把I/O线拉到高电平。如果遗漏了这个上拉电阻或者上拉电阻阻值太大卡片驱动I/O的能力不够高电平就会软绵绵终端采到的波形就可能出现误判。下面是几个常见异常对照现象可能原因排查方向I/O线一直低无任何跳变I/O逻辑被卡死终端未释放总线查终端GPIO方向配置确认是否处于接收态有跳变但很稀疏间隔不规律CLK频率不稳或过低示波器量CLK波形确认频率在1-5MHz范围有完整字符帧但ATR校验失败极性约定解析反了验证TS是0x3B还是0x3F对照你的解析代码RST拉高后等了很久才有数据卡片初始化时间长确认没有超时40000个时钟周期是否足够用逻辑分析仪抓时序的正确姿势调试7816逻辑分析仪是必备工具。我习惯至少用4个通道去抓CLK、RST、I/O、VCC。虽然VCC看起来没什么可抓的但把它也抓上可以从波形上直接定位上电时序是否符合规范。采样率方面我建议不低于10MHz。因为3.5712MHz的CLK一个周期才280ns左右如果你的采样率只有1MHz根本分辨不出CLK边沿的位置。用20MHz以上的采样率更稳妥。拿到波形后第一步先看VCC上升沿和CLK起始点的关系。再量RST低电平持续了多少个CLK周期。把光标放在RST拉高的边沿然后数到I/O线上第一个起始位下降沿看看这个间隔是否在400到40000个CLK周期之间。这些都是最基础的检查。另外有一个容易被忽略的点终端的I/O驱动方向切换。在复位阶段终端先处于接收态I/O上拉但RST拉高后卡片要发送ATRI/O总线很快会被卡片驱动。如果你的终端和卡之间加了74LVC系列电平转换芯片方向切换的延迟也有可能导致第一个字符被吃掉。一个做过的调试案例波形正常却读不出ATR说一个印象很深的案例。当时做一个金融级别的读卡器初始化流程写好了上电复位也做了但就是收不到ATR。用逻辑分析仪抓RST时序完全合规VCC稳定CLK波形干干净净I/O线上也确实有数据跳变。当时同事一度怀疑是卡问题换了三四张卡都一样。后来我把波形放大到单个字符级别发现了一个诡异的地方起始位之后的第一个数据位电平变化时间点比我预期的晚了大半个ETU。也就是说字符的位长度不均匀。我推测是卡片内部时钟分频逻辑对初始相位很敏感而终端发送复位时序时CLK的起始相位没有对齐。解决办法很朴素在RST拉高之前给CLK多跑几百个周期让卡片内部锁相环或者分频器完全锁定。调整之后ATR马上就能正常读取了。这个经验告诉我们协议上标着至少400周期你就老老实实多给一点尤其在量产环境里余量永远是好东西。ATR解析完之后下一件必须做的事别急着高兴PPS协商才是提速的关键很多人拿到ATR就以为万事大吉直接开始发APDU。这在默认速率下确实能跑但某些场景下会很慢。比如一次文件读写要传几千个字节按照默认ETU372/f去跑一秒钟只能传大概2.4KB以3.5712MHz算而现代卡的硬件能力远不止这个速度。想要提速就得通过PPS协商把分频因子从372降到更小的值比如设置成31或者更小。PPS请求的格式大致是PPSS、PPS0、PPS1可选和PCK校验。终端发完PPS请求后卡会回复一个相同格式的PPS应答只有完全匹配才算协商成功。如果卡没有回复或者回复的内容和请求不一致就保持当前参数不变继续用默认速率通信。这个处理逻辑一定要做好否则协商失败会导致整条通信链路挂死。协议栈的角度7816-3在整个体系里扮演什么角色把ISO7816-3放到整个7816系列里看它是数据链路层和一部分物理层的位置。它定义了卡怎么被激活、一个bit怎么传、一个字节怎么构成、启动时怎么握手。而7816-4定义了文件系统和APDU指令7816-8/9偏向安全操作。如果你连7816-3都没吃透直接上手调APDU遇到问题会非常痛苦。因为APDU解析错误的根因往往就藏在字符帧的时序、校验位、或者复位时没协商好参数里。我自己带过的工程师凡是复用协议栈但不懂底层的排查起问题来基本全靠猜。相反把这一层搞透的看波形就像看串口log一样自然。实操中对于ATR解析工具的建议调试时我建议备一个好用的ATR解析工具。很多开源软件都有现成功能输入ATR字节串直接把TS、T0、接口字节、历史字节逐字段解读出来。我个人会配合一个自己写的小脚本把字节串按协议规则dump成结构体方便调试时快速定位。不过工具只是辅助最重要的是有手动解码能力。我见过有人完全依赖工具工具报unknown就懵了。一旦你搞清楚字节串里每一位的意义遇到不认识的卡也能从原始字节里推断出大致能力这是做底层驱动的基本功。最后一段关于这篇内容我还有几句实在话写到这里最基础的复位、字符帧、ATR三块就都过了一遍。ISO7816是个老协议但它设计得非常精巧。很多新协议里的东西比如协商机制、校验机制、极性约定、异步时序都从这上面能找到影子。吃透它你以后看任何串行总线协议都会轻松很多。和我一起共事过的硬件工程师常说一句话IC卡不是玄学它只是把时序写在了文档里。你要做的是严格按文档去执行然后给足余量。这句话我越做越觉得对。接下来有时间我会继续写7816系列的后续PPS协商、T0协议、T1协议以及如何处理不同卡片厂的差异化实现。如果你也有在调试7816时遇到的奇葩问题欢迎一起聊聊我在实践中积累的那些波形数据和总结后面也可以分专题整理出来。
返回列表