代码是从用C写的单片机移植到linux上的,单片机的SPI通讯当然是直接IO口模拟的:
void SPIWriteByte(unsigned char SPIData)
{
unsigned char SPICount; // Counter used to clock out the data
for (SPICount = 0; SPICount < 8; SPICount++)
{
if (SPIData & 0x80)
{
SET_SPI_MOSI;
}
else
{
CLR_SPI_MOSI;
} nop();nop();
CLR_SPI_CK;nop();nop();
SET_SPI_CK;nop();nop();
SPIData <<= 1;
}
}
unsigned char SPIReadByte(void)
{
unsigned char SPICount; // Counter used to clock out the data
unsigned char SPIData;
SPIData = 0;
for (SPICount = 0; SPICount < 8; SPICount++) // Prepare to clock in the data to be read
{
SPIData <<=1; // Rotate the data
CLR_SPI_CK;
nop();
nop(); // Raise the clock to clock the data out of the MAX7456
if(STU_SPI_MISO)
{
SPIData|=0x01;
}
SET_SPI_CK;
nop();
nop(); // Drop the clock ready for the next bit
} // and loop back
return (SPIData); // Finally return the read data
}
要移植到linux上,刚开始的时候把这两个函数直接修改成linux标准的spi_read, spi_write,读写都成功发送出去了,可是得不到正确的数据
后来继续看单片机的代码,发现有些地方是读了之后马上写,或者写地址之后马上写值,如:
SPIWriteByte(ucAddr);
ucResult=SPIReadByte();
和
SPIWriteByte(ucAddr);
SPIWriteByte(value);
上述函数是分两次调用前面的读写函数,而linux下有标准的读写或者连写函数,将上述修改如下即可:
读写用spi_write_then_read(rc522_spi, &ucAddr, 1, &ucResult, 1)代替,而连写则用:
struct spi_transfer st[2];
struct spi_message msg;
spi_message_init( &msg );
memset( st, 0, sizeof(st) );
st[ 0 ].tx_buf = &ucAddr;
st[ 0 ].len = 1;
spi_message_add_tail( &st[0], &msg );
st[ 1 ].tx_buf = &value;
st[ 1 ].len = 1;
spi_message_add_tail( &st[1], &msg );
spi_sync( rc522_spi, &msg );
修改后,重新编译KO,可以读到卡号,输入密钥,也能正常读写IC卡了
要注意为了避免一张放在可读区域内的IC卡被多次读到,读完一次后用命令写卡将卡进入休眠状态,还有在循环检测区域内卡片代码中,不要复位RC522芯片,否则刚才休眠的卡将当新卡处理,即还是可以多次读到。
还有一点,SPI的工作模式要选对,如下一幅网上画的图片:
这是四种工作模式的时序图,而linux spi.h头文件中定义这四种模式为:
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
mode 0:时钟空闲时候为低电平,时钟
第一个上升沿开始采集(或发送)数据 (
第一个上升沿:先升后降,即第一个时钟采样)
mode 1:时钟空闲时候为低电平,时钟
第一个下降沿开始采集(或发送)数据 (
第一个下降沿:先升后降,即第二个时钟采样)
mode 2:时钟空闲时候为高电平,时钟
第一个下降沿开始采集(或发送)数据 (
第一个下降沿:先降后升,即第一个时钟采样)
mode 3:时钟空闲时候为高电平,时钟
第一个上升沿开始采集(或发送)数据 (
第一个上升沿:先降后升,即第二个时钟采样)
RC522才用mode 0或者mode 3均可工作。