代码是从用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均可工作。

GitHub 加速计划 / li / linux-dash
10.39 K
1.2 K
下载
A beautiful web dashboard for Linux
最近提交(Master分支:2 个月前 )
186a802e added ecosystem file for PM2 4 年前
5def40a3 Add host customization support for the NodeJS version 4 年前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐