从开始接触,到驱动编写调试完成,前前后后花费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