ARM9 2440硬件SPI驱动程序-NRF24L01

从开始接触,到驱动编写调试完成,前前后后花费10多天,网上浏览了一下,目前还没有找到硬件SPI控制NRF24L01的驱动程序,绝大多数都是软件SPI,但是软件SPI不好,不稳定,既然都写驱动程序了,肯定要用硬件SPI啦,这样才能学到东西。学习的过程中,通过看韦东山的SPI视频,和参考他写的两个驱动程序。这个驱动可以通过ioctl切换接收和发送模式,通过read,write选择接收数据还是发送数据,废话少说,上代码


#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <sound/core.h>
#include <linux/spi/spi.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include "nrf.h"
/* 构造注册 spi_driver */
#define RX_MODE   0xf1
#define TX_MODE   0xf2
static int major;
static struct class *class;

static int spi_NRF24L01_ce_pin;
static unsigned char *ker_buf;
static struct spi_device *spi_NRF24L01_dev;
static unsigned char  opencount = 0;
static volatile int int_flag = 0;
static DECLARE_WAIT_QUEUE_HEAD(nrf24l01_waitq);   /*生成一个等待队列头wait_queue_head_t,名字为nrf24l01_waitq*/
static  unsigned char TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x10};    //本地地址
static  unsigned char RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x10};    //接收地址
struct pin_desc{
                unsigned int pin;
                unsigned int key_val;
};/*引脚描述结构体*/
struct pin_desc pins_desc[2]={  /*按下时 :0x01 0x02   ... 松开始0x81 0x 82 ...*/
               {S3C2410_GPG(0),0x01},

};

 static uint8  TxBuf[TxBufSize]={
 0x01,0x02,0x03,0x4,0x05,0x06,0x07,0x08,
 0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
 0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24,
 0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32,
};
static  uint8  RxBuf[RxBufSize]={0};

static void NRF24L01_Set_CE(char val)
{
    s3c2410_gpio_setpin(spi_NRF24L01_ce_pin, val);
}
/*寄存器访问函数:用来设置 24L01 的寄存器的值。基本思路就是通过 WRITE_REG 命令(也
就是 0x20+寄存器地址)把要设定的值写到相应的寄存器地址里面去,并读取返回值。对于
函数来说也就是把 value 值写到 reg 寄存器中*/
static unsigned char SPI_RW_Reg(unsigned char reg,unsigned char value)
{
    unsigned char status;
    unsigned char tx_buf[2];
    unsigned char rx_buf[2];
    tx_buf[0] = reg;
    tx_buf[1] = value;
    spi_write(spi_NRF24L01_dev, tx_buf, 2);
    status = rx_buf[0]; 
    return (status);        
}

/*读取寄存器值的函数:基本思路就是通过 READ_REG 命令(也就是 0x00+寄存器地址),把
寄存器中的值读出来。对于函数来说也就是把 reg 寄存器的值读到 reg_val 中去*/
static void SPI_Read(int *pMID, int *pDID,unsigned char reg)
{
    unsigned char tx_buf[2];
    unsigned char rx_buf[2];
    tx_buf[0] = reg;
    tx_buf[1] = 0x00;
    spi_write_then_read(spi_NRF24L01_dev, tx_buf, 2, rx_buf, 2);
    *pMID = rx_buf[0];
    *pDID = rx_buf[1];  
}
 /*接收缓冲区访问函数:主要用来在接收时读取 FIFO 缓冲区中的值。基本思路就是通过
READ_REG 命令把数据从接收 FIFO(RD_RX_PLOAD)中读出并存到数组里面去*/
//static unsigned char SPI_Read_Buf(unsigned char reg,unsigned char * ker_buf,unsigned char bytes)
static void SPI_Read_Buf(unsigned char reg, unsigned char * buf, int len)
{
    /* spi_write_then_read规定了tx_cnt+rx_cnt < 32
     * 所以对于大量数据的读取,不能使用该函数
     */
    unsigned char i=0;  
    unsigned char tx_buf[1];
    unsigned char tx_buf1[len];
    struct spi_transfer t[] = {
            {
                .tx_buf     = tx_buf,
                .len        = 1,
            },
            {
                .tx_buf     = tx_buf1,
                .rx_buf     = buf,
                .len        = len,
            },
        };
    struct spi_message  m;
    for(i=0;i<len;i++)
    {
        tx_buf1[i]=0;
    }
    tx_buf[0] = reg;
    spi_message_init(&m);
    spi_message_add_tail(&t[0], &m);
    spi_message_add_tail(&t[1], &m);
    spi_sync(spi_NRF24L01_dev, &m);   
}

/*发射缓冲区访问函数:主要用来把数组里的数放到发射 FIFO 缓冲区中。基本思路就是通过
WRITE_REG 命令把数据存到发射 FIFO(WR_TX_PLOAD)中去*/
static void SPI_Write_Buf(unsigned char addr, unsigned char *buf, int len)
{

   unsigned char tx_buf[1];
   //unsigned char RX_ADDRESS1[RX_ADR_WIDTH+1]={addr,0x34,0x43,0x10,0x10,0x01};
   //spi_write(spi_NRF24L01_dev, RX_ADDRESS1, RX_ADR_WIDTH+1); /*单独使用这个函数也可以*/
    struct spi_transfer t[] = {
            {
                .tx_buf     = tx_buf,
                .len        = 1,
            },
            {
                .tx_buf     = buf,
                .len        = len,
            },
        };
    struct spi_message  m;
    tx_buf[0]=addr;
    spi_message_init(&m);
    spi_message_add_tail(&t[0], &m);
    spi_message_add_tail(&t[1], &m);
    spi_sync(spi_NRF24L01_dev, &m); 


}
static unsigned char nRF24L01_RxPacket(unsigned char* rx_buf)
{
    unsigned char revale=0;
    unsigned char sta;
    int a,b;
    SPI_Read(&a,&b,STATUS);  // 读取状态寄存其来判断数据接收状况
    sta=b;
    //printk("the value of STATUS :%02x   :%02x \n",sta,a);
    SPI_RW_Reg(WRITE_REG+STATUS,sta);   //接收到数据后RX_DR,TX_DS,MAX_PT都置高为1,
    if(sta & RX_OK)    // 判断是否接收到数据
    {
        SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);//read receive payload from RX_FIFO buffer
        SPI_RW_Reg(FLUSH_RX,0xff);
        revale =1;              //取数据完成标志
    }

    return revale;
} 
static unsigned char nRF24L01_TxPacket(unsigned char* tx_buf,int size)
{
    unsigned char sta;
    int a,b;
     NRF24L01_Set_CE(0);
     //SPI_Write_Buf(WR_TX_PLOAD, TxBuf, TX_PLOAD_WIDTH); // Writes data to TX payload
   SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // Writes data to TX payload
     NRF24L01_Set_CE(1);
    udelay(100); 

    SPI_Read(&a,&b,STATUS);  // 读取状态寄存其来判断数据发送状况
    sta=b;
    NRF24L01_Set_CE(0);
    SPI_RW_Reg(WRITE_REG+STATUS,sta);   //清除TX_DS或MAX_RT中断标志
    NRF24L01_Set_CE(1);

    if(sta & MAX_TX)    // 判断是否达到最大重发次数
    {
        SPI_RW_Reg(FLUSH_RX,0x00);  //清除TX FIFO寄存器
         printk("the MAX \n");
       return MAX_TX;
    }
    if(sta & TX_OK)    //发送成功
    { 
    printk("write ok \n");
       return TX_OK;

    }
    printk("write error  \n");
    return 0xff ;//其他原因发送失败
} 
static irqreturn_t nrf_irq(int irq,void * dev_id)
{

    //   printk("welcome to irq\n");

       int_flag=1;  /*表示中断发生了i*/
       wake_up_interruptible(&nrf24l01_waitq); /*唤醒休眠的进程*/  

       return IRQ_RETVAL(IRQ_HANDLED);
}
static unsigned char RX_Mode(void)
{      
      // int mid, did;
      // int i;
       uint8 buf[5];

         NRF24L01_Set_CE(0);
      SPI_Write_Buf(WRITE_REG + RX_ADDR_P0,RX_ADDRESS, RX_ADR_WIDTH);    
     // SPI_Write_Buf(WRITE_REG + TX_ADDR,    TX_ADDRESS, TX_ADR_WIDTH);    
         SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0
         SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0
         SPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40
         SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);
         SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f);//参数收发必须一致
         SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);   // Set PWR_UP bit, enable CRC(2 bytes)& Prim:RX. RX_DR enabled
        NRF24L01_Set_CE(1); 
    /*  
          SPI_Read(&mid, &did, EN_AA);
           printk("SPI Flash ID: %02x\n", did);
          SPI_Read(&mid, &did, EN_RXADDR);
           printk("SPI Flash ID: %02x\n", did);
          SPI_Read(&mid, &did, RF_CH);
           printk("SPI Flash ID: %02x\n", did);
          SPI_Read(&mid, &did, RX_PW_P0);
           printk("SPI Flash ID: %02x\n", did);
          SPI_Read(&mid, &did, RF_SETUP);
           printk("SPI Flash ID: %02x\n", did);
          SPI_Read(&mid, &did, CONFIG);
           printk("SPI Flash ID: %02x\n", did);
    SPI_Read_Buf(READ_REG  + RX_ADDR_P0, buf, RX_ADR_WIDTH); 
    printk("RX_ADDR_P0:");
    for(i=0;i<5;i++)
     printk("%2x ",buf[i]);
     printk("\n");  */
     SPI_Read_Buf(READ_REG  + RX_ADDR_P0, buf, RX_ADR_WIDTH); 
     if(buf[0]==RX_ADDRESS[0])
         printk("Rx_Mode ready:\n");
     else 
         printk("Rx_Mode set error:\n");
}
static unsigned char TX_Mode(void)
{
          //int mid, did;
          int i;
          uint8 buf[5];
         NRF24L01_Set_CE(0);
      SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);
      SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH);
         SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // Enable Auto.Ack:Pipe0
         SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // Enable Pipe0
         SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x4a); // 500us + 86us, 10 retrans...
         SPI_RW_Reg(WRITE_REG + RF_CH, 40); // Select RF channel 40
         SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f); // TX_PWR:0dBm, Datarate:2Mbps,LNA:HCURR
         SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);   // Set PWR_UP bit, enable CRC(2 bytes)& Prim:RX. RX_DR enabled
         NRF24L01_Set_CE(1); 
    SPI_Read_Buf(READ_REG  + TX_ADDR, buf, RX_ADR_WIDTH);
 /*    printk("TX_ADDR   :");
    for(i=0;i<5;i++)
     printk("%2x ",buf[i]);
     printk("\n"); */
     if(buf[0]==TX_ADDRESS[0])
         printk("Tx_Mode ready:\n");
     else 
         printk("Tx_Mode set error:\n");
}
 static long NRF24L01_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{   
    printk("int ther \n");
    switch (cmd)
    {
        case RX_MODE:
        {
            RX_Mode();
            break;
        }
        case TX_MODE:
        {
            TX_Mode();
            break;
        }
    }
    return 0;
}
static ssize_t NRF24L01_read(struct file *file,char __user *buf, size_t size, loff_t *ppos)
{   
     /*如果没有数据接收,进入休眠状态*/
        wait_event_interruptible(nrf24l01_waitq,int_flag);
     printk("in driver,nrf24l01_read wait done:%d\n",int_flag);
     nRF24L01_RxPacket(RxBuf);
     copy_to_user(buf,RxBuf,size);
     int_flag = 0; //标志清零
    return 1;
} 
static ssize_t NRF24L01_write(struct file *file,const char __user *buf, size_t size, loff_t *ppos)
{   

      printk("int driver write : \n");
     copy_from_user(ker_buf,buf,size);
     printk("%d",size);
     nRF24L01_TxPacket(ker_buf,size);
    return 1;
} 
static int NRF24L01_open(struct inode *node, struct file *file)
{
   uint8 err;
  if(opencount == 1)
    return -EBUSY;
    ker_buf = kmalloc(4096, GFP_KERNEL);
   err = request_irq(IRQ_EINT11,nrf_irq,IRQ_TYPE_EDGE_FALLING,"Irq_Rec",1);//注册并设置IRQ_EINT11中断,处理函数为
   if( err ){
     disable_irq(IRQ_EINT11);
     free_irq(IRQ_EINT11,1);
      return -EBUSY;
   } 
    return 0;
}
static unsigned int nrf24l01_poll( struct file *file,struct poll_table_struct *wait)
{
     unsigned int  mask = 0;
     poll_wait(file,&nrf24l01_waitq,wait);
     if ( int_flag)
     mask |= POLLIN | POLLRDNORM;
    return mask;
} 
static int nrf24l01_release(struct inode *node, struct file *file)
{
  opencount--;
// free_irq(IRQ_EINT8,&pins_desc[0]);
  free_irq(IRQ_EINT11,1);
  kfree(ker_buf);
  printk( "NRF24L01  released !\n");
  return 0;
}
static struct file_operations NRF24L01_ops = {
    .owner            = THIS_MODULE,
    .open             = NRF24L01_open,
    .unlocked_ioctl   = NRF24L01_ioctl,
    .read             = NRF24L01_read,
    .write            = NRF24L01_write, 
    .release          = nrf24l01_release,
    .poll             = nrf24l01_poll,
};

static int __devinit spi_NRF24L01_probe(struct spi_device *spi)
{
    spi_NRF24L01_dev = spi;
    spi_NRF24L01_ce_pin = S3C2410_GPF(5);
    s3c2410_gpio_cfgpin(spi_NRF24L01_ce_pin, S3C2410_GPIO_OUTPUT);
    //ker_buf = kmalloc(4096, GFP_KERNEL);

    /* 注册一个 file_operations */
   major = register_chrdev(0, "NRF24L01", &NRF24L01_ops);

    class = class_create(THIS_MODULE, "NRF24L01");

    /* 为了让mdev根据这些信息来创建设备节点 */
    device_create(class, NULL, MKDEV(major, 0), NULL, "NRF24L01"); /* /dev/NRF24L01 */


    return 0;
}

static int __devexit spi_NRF24L01_remove(struct spi_device *spi)
{

    device_destroy(class, MKDEV(major, 0));
    class_destroy(class);
    unregister_chrdev(major, "NRF24L01");
    return 0;
}


static struct spi_driver spi_NRF24L01_drv = {
    .driver = {
        .name   = "NRF24L01",
        .owner  = THIS_MODULE,
    },
    .probe      = spi_NRF24L01_probe,
    .remove     = __devexit_p(spi_NRF24L01_remove),
};

static int spi_NRF24L01_init(void)
{
    return spi_register_driver(&spi_NRF24L01_drv);
}

static void spi_NRF24L01_exit(void)
{
    spi_unregister_driver(&spi_NRF24L01_drv);
}

module_init(spi_NRF24L01_init);
module_exit(spi_NRF24L01_exit);
MODULE_DESCRIPTION("OLED SPI Driver");
MODULE_AUTHOR("weidongshan@qq.com,www.100ask.net");
MODULE_LICENSE("GPL");


这个是头文件 nrf.h


//NRF24L01
#define TX_ADR_WIDTH    5        // 5 uint8s TX address width
#define RX_ADR_WIDTH    5        // 5 uint8s RX address width
#define TX_PLOAD_WIDTH  32    // 20 uint8s TX payload
#define RX_PLOAD_WIDTH  32       // 20 uint8s TX payload

//NRF24L01寄存器指令
#define READ_REG        0x00    // 读寄存器指令
#define WRITE_REG       0x20    // 写寄存器指令
#define RD_RX_PLOAD     0x61    // 读取接收数据指令
#define WR_TX_PLOAD     0xA0    // 写待发数据指令
#define FLUSH_TX        0xE1    // 冲洗发送 FIFO指令
#define FLUSH_RX        0xE2    // 冲洗接收 FIFO指令
#define REUSE_TX_PL     0xE3    // 定义重复装载数据指令
#define NOP             0xFF    // 保留

//SPI(nRF24L01)寄存器地址
#define CONFIG          0x00  // 配置收发状态,CRC校验模式以及收发状态响应方式
#define EN_AA           0x01  // 自动应答功能设置
#define EN_RXADDR       0x02  // 可用信道设置
#define SETUP_AW        0x03  // 收发地址宽度设置
#define SETUP_RETR      0x04  // 自动重发功能设置
#define RF_CH           0x05  // 工作频率设置
#define RF_SETUP        0x06  // 发射速率、功耗功能设置
#define STATUS          0x07  // 状态寄存器
#define OBSERVE_TX      0x08  // 发送监测功能
#define CD              0x09  // 地址检测          
#define RX_ADDR_P0      0x0A  // 频道0接收数据地址
#define RX_ADDR_P1      0x0B  // 频道1接收数据地址
#define RX_ADDR_P2      0x0C  // 频道2接收数据地址
#define RX_ADDR_P3      0x0D  // 频道3接收数据地址
#define RX_ADDR_P4      0x0E  // 频道4接收数据地址
#define RX_ADDR_P5      0x0F  // 频道5接收数据地址
#define TX_ADDR         0x10  // 发送地址寄存器
#define RX_PW_P0        0x11  // 接收频道0接收数据长度
#define RX_PW_P1        0x12  // 接收频道0接收数据长度
#define RX_PW_P2        0x13  // 接收频道0接收数据长度
#define RX_PW_P3        0x14  // 接收频道0接收数据长度
#define RX_PW_P4        0x15  // 接收频道0接收数据长度
#define RX_PW_P5        0x16  // 接收频道0接收数据长度
#define FIFO_STATUS     0x17  // FIFO栈入栈出状态寄存器设置

#define MAX_TX          0x10  //达到最大发送次数中断
#define TX_OK           0x20  //TX发送完成中断
#define RX_OK           0x40  //接收到数据中断

#define TxBufSize    32
#define RxBufSize    32

typedef unsigned int uint16 ;
typedef unsigned char uint8 ;

程序下载地址可见:http://download.csdn.net/download/qq_26742291/9839014

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值