1、硬件GPIO引脚使用情况:
GPIO[49:55、57]对应磁卡器的RCP[3]、RDD[3]、CLS、NPWN
2、磁卡各引脚的使用情况:
CLS 刷卡开始为下降沿,磁卡走行中保持低电频,走向结束上升沿,无磁卡走行时保持高电频
RCP记录采样频率,每半个周期的幅度为100千欧 14毫秒;620千欧 60毫秒,前半周期高电,后半周期为低频
RDD数据采样端,当采样引脚RCP为高电频(前半周期)时,该段开始采样
CLS 为共用引脚,RCP、RDD在磁卡不同的情况下分别使用1-3个不同的引脚
3、实现读取磁卡数据的思路:
思路一:
A.CLS下降沿时发生中断,置bit计数器为0,以便记录最终得到数据量(以bit为单位);上升沿时,返回逻辑中断向量,唤醒IST
B.RCP上升沿时发生中断,使用时钟中断(2-3微妙发生一次),RDD端进行数据采样;RCP下降沿时关闭时钟中断,根据RDD数据采样计算最终数据,将数据保存至共享的内存空间,以便磁卡驱动来读取数据
思路二:
A. CLS下降沿时发生中断,置位计数器为0,以便记录最终得到数据量(以bit为单位);上升沿时结束中
B.RCP上升沿时发生中断,使用while语句以轮询方式,采样RDD段的数据;RCP下降沿时,根据RDD数据采样计算最终数据,将数据保存至共享的内存空间,以便磁卡驱动来读取数据
4、实现步骤:
1)、CLS端中断机制的建立,
2)、RCP端中断机制的建立
3)、时钟中断机制的建立(暂时忽略,数据采样工作在RCP上升沿发生中断时进行一次)
5、具体实现方法:
比较觉得:思路二轮询采样RDD数据线的方式不合适,其效率比较低,并且,对于采样的时机比较难把握,因此思路一成为首选方案。按照思路一,已经实现磁卡的读写功能。
1)、中断机制的建立:
a. BSP中定义中断的逻辑值。如:wince60/PlatForm/XXX/src/inc/bsp_cfg.h中添加定义
#define SYSINTR_MYINTR (SYSINTR_FIRMWARW+23)
b. 在BSP的OAL层intr.c文件中,添加具体的物理中断的定义以及中断处理代码。
根据硬件连接情况及资料得知,需要将相关中断是作为IRQ_GPIOXX_2的子中断进行处理。在XXX/SoC/PXA310…/OAL/INTR/intr.c中,IRQ_GPIOXX_2的相关处理会调用到XXX/ src /oal/oallib/intr.c中的中断处理函数BSPIntrActiveIrq()(该函数会返回对应得物理中断号)、BSPIntrDisableIrq()、BSPIntrDoneIrq()、BSPIntrEnableIrq()、BSPIntrInit()、BSPIntrRequestIrqs()等。因此,在XXX/ src /oal/oallib/intr.c中添加相应得物理中断的定义和处理代码,如:
#define IRQ_GPIO55_MCARD_CLS_R (IRQ_MONAHANS_MAX + 17)
需要注意的是,定义物理中断号的同时,不要忘记修改IRQ_XXX_GPIO_MAX等的定义,至于具体实现操作的代码,就是根据需要来修改了。
c. 修改OEMInterruptHandler()函数对应逻辑中断和物理中断
在这里添加的这个中断GPIO55_R的物理中断号,就是用于在读卡结束时(GPIO55号引脚回有上升沿的跳变),对应逻辑中断SYSINTR_MYINTR,唤起相应的中断程序。对于逻辑中断和物理中断的对应,是由XXX/SoC/PXA310…/OAL/INTR/intr.c中的OEMInterruptHandler()函数来完成的,它会调用BSPIntrActiveIrq(),然后,根据返回的物理中断值来修改sysIntr值。
[小结]:如果一切顺利,那么,到此有关于由IRQ_GPIOXX_2的子中断引起的中断机制就建立完毕了,重新编译生成新的nk.bin就可以了。该中断与非IRQ_GPIOXX_2的中断相比可能会麻烦一些。对于非IRQ_GPIOXX_2的中断,直接在XXX/SoC/PXA310…/OAL/INTR/intr.c文件中修改代码即可。
2)、用户层对内核数据的使用:
a.对于数据的读取,是在RCP引脚的发生跳变的时候进行的,因此,代码是写在XXX/ src /oal/oallib/intr.c中的,在RCP[n]引脚发生中断时,读数据、并将数据保存下来,以便读卡结束时驱动层可以读到数据。具体读数据的函数代码如下:(一共有三个磁道需要分别读写数据、进行保存,每个磁道的物理特性不同)
void ReadDataFromRDD(UINT32 XLLP_GPIO_BIT_RDD)
{
switch(XLLP_GPIO_BIT_RDD){
case XLLP_GPIO_BIT_CIF_DD5:
if (g_bitIndex1 == MAX_BIT_NUMBER)// MAX_BIT_NUMBER=8
{
g_bitIndex1 = 0;
g_byteIndex1 += 1;
}
if (g_byteIndex1 > MAX_BYTE_NUMBER)// MAX_BYTE_NUMBER=1024
{
return;
}
if (g_pGPIORegs->gplr1 & XLLP_GPIO_BIT_RDD)//读数据寄存器的值
{
g_chBuf1[g_byteIndex1] &= ~(1< //三个磁道使用的均是负逻辑
}
else
{
g_chBuf1[g_byteIndex1] |= (1 << g_bitIndex1);
}
g_bitIndex1++;
break;
//data type is tract2
case XLLP_GPIO_BIT_CIF_DD3:
……
break;
//data type is tract3
case XLLP_GPIO_BIT_CIF_DD1:
……
break;
default:
break;
}
return;
}
b.使用KernelIoControl ()来完成数据由OAL层向驱动层的传输。
(有些东西具体什么作用不是很清楚,都是是仿照现有BSP中其他使用了KernelIoControl的代码写的)
首先,在XXX/ SRC/INC/ioctl_cfg.h文件中,宏定义一个资源号,该资源号是作为CTL_CODE的第二个参数使用的;宏定义KernelIoControl 中需要的IOControlID。如:
#define MAGNETIC_CARD_DATA_TRANS 4003
#define IOCTL_HAL_MAGNETIC_CARD_TRANS
CTL_CODE(FILE_DEVICE_HAL, (MAGNETIC_CARD_DATA_TRANS), METHOD_BUFFERED, FILE_ANY_ACCESS)
其次,在XXX/ SRC/INC/ioctl_tab.h中,添加映射,如:
{ IOCTL_HAL_MAGNETIC_CARD_TRANS, 0,OALIoCtlHalTransMagneticCardData},
最后,在XXX/ SRC/INC/ioctl.c中添加OALIoCtlHalTransMagneticCardData ()函数的具体代码
c. 使用DeviceIoControl(对应驱动层的XXX_IOControl)或者XXX_Read函数,把数据传递给用户层。
通过以上的操作,直接使用GPIO控制读取磁卡信息的功能已经实现,并且在用户层的测试程序中得到了正确的数据。我也是第一次接触中断机制、第一次从内核中读取数据,可能理解的还不是很透彻。如果有问题,还请大家指出,呵呵,不过,请不要讲一些过于极端的话(偶会被打击的失去信心的),谢谢^_^