ARM9 2440硬件SPI驱动程序-NRF24L01

来源:互联网 发布:淘宝商品被删除怎么办 编辑:程序博客网 时间:2024/06/05 14:39

从开始接触,到驱动编写调试完成,前前后后花费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   0xf2static 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    32typedef unsigned int uint16 ;typedef unsigned char uint8 ;

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

0 0
原创粉丝点击