月度归档:2014年08月

CPU卡调试总结

CPU卡内部自带COS,有严格的密钥管理系统。相比M1来说,要复杂的多。我用的是复旦微电子的FM1208 CPU卡,读卡芯片用的是FM1702.FM1702有并口和SPI接口两种方式。NXP的RC500,RC531只有并口接口。用SPI接口,可以省下单片机很多IO口。

下面是开发过程中我觉得比较重要的地方,总结在下面:

1、 CPU卡的操作步骤:寻卡-防冲突-选卡-ATS,前面三步和M1操作完全一样,属于ISO14443A前面三层的操作,ATS成功后就进入ISO14443A-4协议层了,也就进入了CPU卡的操作层。

2、 PPS是可以不做的,只有RATS的返回值表明其接收能力大于PCD的发送即可。PPS用来设置通信时的波特率,通过RATS命令响应数据07 77 80 A0 02 47 56可以判断该卡仅支持106K波特率。所以PCD也没有通过PPS指令修改通信波特率的必要了。当然PPS指令重新按106K波特率设置一下也是可以的,RATS以及后续的PCD指令都需要加上CRC的。

3、 ISO14443-4只规定到PPS指令,后续的指令都需要由CPU卡内部的软件COS来解释,所以卡片完成SELECT,通过RATS和PPS指令后,必须发COS支持的指令。发COS支持的指令一般都需要加CRC的。

4、 发送取随机数命令00 84 00 00 04,根据块格式规定,除了发送这个指令外,还要发送PCB和CID,即实际发送的字符是0A 01 00 84 00 00 04,0A01这两个字节必须加在每个指令字符串的前面,并且块号不能重复,即如果你连续2次取随机数,需如下发送:0A 01 00 84 00 00 04 ,0B 01 00 84 00 00 04.即第一个字节的最后一位要不断变化。

5、 取随机数命令可取4字节或8字节。若取随机数命令下条指令为外部认证,则外部认证数据用指定的外部认证密钥解密后与该随机数进行比较。外部认证命令要求CPU卡存在用于外部认证的密钥。在满足该密钥的使用条件,且该密钥未被锁死时才能执行此命令。将命令中的数据用指定外部认证密钥解密,然后与先前产生的随机数进行比较,若一致则表示认证通过,置安全状态寄存器为该密钥规定的后续状态值,错误计数器恢复成初始值,若比较不一致则认证失败,可再试错误数减一,且不改变安全状态寄存器的值。

继续阅读

EM ID卡号格式

   1、EM ID卡卡号格式0:10位十六进制的ASCII字符串,即10 Hex格式。 如:某样卡读出十六进制卡号为:“01026f6c3a”。

   2、EM ID卡卡号格式1:将格式1中的后8位,转换为10位十进制卡号,即8H—10D。即将“026f6c3a”转换为:“0040856634”。

   3、EM ID卡卡号格式2:将格式1中的后6位,转换为8位十进制卡号,即6H—8D。即将“6f6c3a”转换为:“07302202”。

   4、EM ID卡卡号格式3:将格式1中的倒数第5、第6位,转换为3位十进制卡号,再将后4位,转换为5位十进制卡号,中间用“,”分开,即“2H + 4H”。
      即将2H“ 6f”转换为:“111”,4H “6c3a”转为“27706”。 最终将2段号连在一起输出为“111,27706”。

   5、EM ID卡卡号格式4:将格式1中后8位的前4位,转换为5位十进制卡号,再将后4位,转换为5位十进制卡号,中间用“,”分开,即“4Hex + 4Hec”。
      照此推算结果为:00623,27706 (4H+4H)

UCOS-II OS_CPU_IRQ_ISR函数移植

在有中断发生时,程序跳到OS_CPU_IRQ_ISR处执行。OS_CPU_IRQ_ISR函数在OS_CPU_A.S中。

clip_image002

在分析这个移植代码前,先了解下发生IRQ中断时,ARM的处理流程:

1、 会把当前的CPSR的值拷贝到SPSR_irq

2、 把PC的值拷贝到LR_irq

3、 强制进入IRQ异常模式

4、 强制进入ARM状态

5、 禁止IRQ中断

6、 PC=0X18,跳转到OS_CPU_IRQ_ISR

上面这些都是硬件自动完成的。

继续阅读

UCOS-II OSIntCtxSw函数移植

clip_image002

OSIntCtxSw()的代码的OSCtxSw()下半部分的代码基本上一样。因为OSIntCtxSw()是在OSINTEXIT()中调用的。也就是在中断服务程序中调用的。在进入中断服务时,寄存器值已经被保存到了被中断任务的堆栈里。所以OSIntCtxSw()里不需要再保存。

OSIntCtxSw()得到待运行任务的任务控制块地址,根据控制块地址得到待运行任务的堆栈指针。然后把待运行任务的堆栈内容放到寄存器中,实现任务切换功能。

UCOS-II的OSCtxSw函数移植

OSCtxSw()函数把被中止任务的断点指针和CPU的寄存器值保存到该任务的堆栈中,并从待运行任务的堆栈中得到其堆栈指针,把待运行任务堆栈中的存储的CPU通用寄存器的内容恢复到CPU的通用寄存器中,最后使CPU获得待运行任务的断点指针。

任务切换函数OSCtxSw()一般有2种方法实现。一种是软中断,周立功的LPC资料上都是这么用的。一种是用子程序调用,我现在做的这个项目就是这么实现的。

在OS_CPU.H中定义

#define OS_TASK_SW() OSCtxSw()

OSCtxSw()函数在OS_CPU_A.S中:

OSCtxSw

STMFD SP!, {LR} ;PC (1)

STMFD SP!, {R0-R12, LR} ;R0-R12 LR (2)

MRS R4, CPSR ;Push CPSR (3)

STMFD SP!, {R4}

LDR R4, =OSTCBCur ; OSTCBCur->OSTCBStkPtr = SP; (4)

LDR R5, [R4] ;(5)

STR SP, [R5] ;(6)

;BL OSTaskSwHook ; OSTaskSwHook(); (7)

LDR R4, =OSPrioCur ; OSPrioCur = OSPrioHighRdy (8)

LDR R5, =OSPrioHighRdy ;(9)

LDRB R6, [R5] ;(10)

STRB R6, [R4] ;(11)

LDR R4, =OSTCBCur ; OSTCBCur = OSTCBHighRdy; ;(12)

LDR R6, =OSTCBHighRdy ;(13)

LDR R6, [R6] ;(14)

STR R6, [R4] ;(15)

LDR SP, [R6] ; SP = OSTCBHighRdy->OSTCBStkPtr; ;(16)

LDMFD SP!, {R4} ;POP CPSR ;(17)

MSR CPSR_cxsf, R4 ;(18)

LDMFD SP!, {R0-R12, LR, PC} ;(19)

OS_Sched (void)函数在OS_CORE.C中:

void OS_Sched (void)

{

#if OS_CRITICAL_METHOD == 3

OS_CPU_SR cpu_sr = 0;

#endif

OS_ENTER_CRITICAL();

if (OSIntNesting == 0) {

if (OSLockNesting == 0) {

OS_SchedNew();

if(OSPrioHighRdy!=OSPrioCur) {

OSTCBHighRdy = OSTCBPrioTbl[OSPrioHighRdy];

#if OS_TASK_PROFILE_EN > 0

OSTCBHighRdy->OSTCBCtxSwCtr++;

#endif

OSCtxSwCtr++; OS_TASK_SW();

}

}

}

OS_EXIT_CRITICAL();

}

在ADS中通过汇编语言可以看到,OS_TASK_SW();语句对应的汇编语句是 BL OSCtxSW

继续阅读

UCOS-II OSStartHighRdy函数移植

UCOS-II启动多任务环境的函数是OSStart();用户在调用OSStart()前,必须已经建立了一个或多个任务。OSStart()最终调用OSStartHighRdy()运行多任务启动前优先级最高的任务。OSStartHighRdy()代码是用汇编写的,在文件OS_CPU_A.S中。

函数如下:

clip_image002

代码分析如下:

1:进入系统模式,并关闭IRQ,FIQ中断

2:调用OSTaskSwHook(),这是钩子函数,一般为空,用户可以视需要自己添加内容。也可以不调用。

3、LDR R4, =OSRunning的LDR是伪指令,‘=’是LDR作为伪指令和标准指令的区别。

这条指令的作用是把变量OSRunning的地址送给R4。OSRunning是UCOS系统己经启动的一个标识,它在调用UCOS中的OSStart时被置为1。

4、OS_EXT OS_TCB *OSTCBHighRdy;

OSTCBHighRdy是一个指针,指向最高优先级任务的任务控制块,任务控制块的第一个内容是任务的堆栈指针,所以OSTCBHighRdy地址存的值也就是任务控制块的堆栈指针。

LDR R4, =OSTCBHighRdy

LDR R4, [R4]

LDR SP, [R4]

这3条指令是把最高优先级任务的堆栈指针送到ARM的SP寄存器中

5、LDMFD SP!, {R4}

从任务堆栈中取出最后压入堆栈的CPSR的值,送到R4,!表示SP自动加4

MSR CPSR_cxsf, R4

c - control field mask byte (PSR[7:0])
x - extension field mask byte (PSR[15:8])
s - status field mask byte (PSR[23:16)
f - flags field mask byte (PSR[31:24]).

把R4的值保存到CPSR中。

6、LDMFD SP!, {R0-R12, LR, PC}

把堆栈的数据送到R0-R12,LR,PC,系统开始执行最高优先级任务。

UCOS开关中断函数移植

OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()用来关中断和开中断。在执行临界段代码时要关中断,如果中断打开,临界段代码中的一些全局变量值可能会被中断服务子程序代码改变,或者因为中断引起的任务切换被其它任务函数改变。

何谓“临界段”?在网上搜了下:

临界段也称为关键代码段,它是指一个小代码段。在它能够执行前,它必须独占对某些共享资源的访问权。一旦线程执行进入了临界段。就意味着它获得了这些共享资源的访问权。那么在该线程处于临界段内的期间,其它同样需要独占这些共享资源的线程就必须等待,直到获得资源的线程离开临界段而释放资源。

在LPC2214上移植这两个函数。

在OS_CPU.H中定义

采用第三种实现方法:

#define OS_CRITICAL_METHOD 3

定义一个数据类型OS_CPU_SR

typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */

采用第3中方式,需要在UCOS-II函数中定义一个变量:

OS_CPU_SR cpu_sr;

用来保存CPU的状态寄存器值。

定义关中断宏和开中断宏

#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}

#define OS_EXIT_CRITICAL() {OS_CPU_SR_Restore(cpu_sr);}

函数声明:

#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */

OS_CPU_SR OS_CPU_SR_Save(void);

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr);

#endif

以上都是在OS_CPU.H文件中的。

NO_INT EQU 0xC0 ; Mask used to disable interrupts (Both FIR and IRQ)

OS_CPU_SR_Save()和OS_CPU_SR_Restore()函数用汇编语言编写,在OS_CPU_A.S文件中

OS_CPU_SR_Save

MRS R0,CPSR 1

ORR R1,R0,#NO_INT 2

MSR CPSR_c,R1 3

BX LR 4

继续阅读

UCOS-II系统使用FIQ中断

有些产品需要及时检测外部的输入信号,这时要采用中断。LPC2214的中断分为FIQ和IRQ.FIQ可以嵌套IRQ中断。把需要及时处理的输入信号配置成FIQ中断。

ARM中设计FIQ中断是为了在快速处理的场合使用。如果也在FIQ里面进行任务调度则需要对任务状态进行保存和恢复处理。这样和用IRQ相比,优势并不明显。

在移植时为了加快FIQ处理,在FIQ里面不进行任务调度,仅仅是按照ATPCS的规定,保存一些不被用户FIQ处理程序保护的寄存器,然后调用用户FIQ处理子程序。调用完毕后恢复不被用户FIQ处理子程序保护的寄存器,退出。

在FIQ中断地址0x0000001c处定义

LDR PC,FIQ_ADDR

FIQ_Addr DCD FIQ_Handler

FIQ_Handler

STMFD SP!, {R0-R3, LR} ; 入栈

BL FIQ_Exception ; 调快速中断程序

LDMFD SP!, {R0-R3, LR} ; 出栈

SUBS PC, LR, #4 ; 返回当初的地址

在发生FIQ中断时,ARM硬件进入FIQ异常模式,禁止IRQ,FIQ中断,跳转到0x0000001c处执行。也就是开始执行FIQ_Handler函数。

void FIQ_Exception(void)

{

……

}

继续阅读

ping命令本质

嵌入式产品开发中使用网络功能时常要使用PING命令来测试网络连接是否正常。那么发送PING命令时,电脑发送的到底是什么数据呢?

例如ping 192.168.1.179

电脑会先发送一个ARP数据包

clip_image002

FF FF FF FF FF FF 00 24 1D B8 D8 1D 08 06

是以太网帧的头部,总共14字节,前6个字节为以太网的目的MAC地址,因为开始PING命令时,电脑并不知道IP为179的设备的MAC地址,所以PING命令会先通过广播的方式把ARP请求数据包发送出去,FF FF FF FF FF FF就是广播地址,同一网段上的所有以太网接口都会接收到广播的数据包。00 24 1D B8 D8 1D 08 06是以太网源地址,也就是发送PING命令的电脑的MAC地址。

08 06是帧类型,表示当前是ARP包。

继续阅读

根据年月日计算星期

在门禁系统中要用到星期,但是在设置时间的时候,一般只设置年月日时分秒,不会去设置星期,那么如何根据年月日来得到星期?

计算星期可以用蔡勒(Zeller)公式(只适合于1582年10月15日之后的情形):

     w=y+[y/4]+[c/4]-2c+[26(m+1)/10]+d-1

公式中的符号含义如下:
     c:世纪(年的高两位数);
     y:年(年的低两位数);
     m:月(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月
来计算,比如2005年1月1日要看作2004年的13月1日来计算);
     d:日;
     []代表取整,即只要整数部分。
     w:星期;w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,
        5-星期五,6-星期六

以2005年2月14日为例:c=20,y=4,m=14,d=14
     w = 4 + [4/4] + [20/4] – 2*20 + [26*(14+1)/10] + 14 – 1
       = 4 + 1     + 5      – 40   + 39             + 14 – 1
       = 22 (除以7余1)
所以2005年2月14日是星期一。

继续阅读

第 1 页,共 2 页12