最近太多的网友发邮件给我要nrf24l01的驱动程序 现在贴出来供需要的人参考
/*******************************************************************************
* 此驱动程序是linux下nrf24l01的设备驱动程序,驱动程序由两部分组成:
* 1、nrf24l01.c
* 2、nrf24l01.h ,linux版本是2.6.24,ARM平台为博创“三剑客”up—Star2410
* Author:dengtao_deng
* Email:linuxembe@126.com
* QQ:990027753 Embed
* nrf24l01.c
*******************************************************************************/
#include <linux/irq.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/major.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>//printk()
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>//u8,u16,u3……
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/sched.h>//和任务相关
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <asm/uaccess.h>//copy_to_user(),copy_from_user()
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <linux/spinlock.h>
#include <asm/system.h>
#include <asm/io.h> //readx(), writex()
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <asm/irq.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include "nrf24l01.h"
#define RX_DR SPI_Read(STATUS)&1
uchar TX_ADDRESS[]={0x34,0x43,0x10,0x10,0x01};//这个应该是要发送到的地址,不确定
uchar RX_ADDRESS[]={0x34,0x43,0x10,0x10,0x01};//接收地址
/********************************************************************************************************/
#define NRF_NAME "S3C2440_NRF" //设备驱动名称
static int NRF_MAJOR = 258; //主设备号
struct nrf_dev
{
struct cdev cdev;
char dataTx[TX_PLOAD_WIDTH];
char dataRx[RX_PLOAD_WIDTH];
};
struct nrf_dev *nrf_devp;
/********************************************************************************************************/
//底层驱动函数
ulong status_32; //暂存状态32位
//初始化各种IO口的输入、输出设置
void GPIO_CONFIG_PINS(void){
s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPIO_OUTPUT); //CSN --TOUT0
s3c2410_gpio_cfgpin(S3C2410_GPB1,S3C2410_GPIO_OUTPUT); //MOSI--TOUT1
s3c2410_gpio_cfgpin(S3C2410_GPB4,S3C2410_GPIO_OUTPUT); //SCK---TCLK0
s3c2410_gpio_cfgpin(S3C2410_GPG11,S3C2410_GPIO_OUTPUT);//CE----TCLK1
s3c2410_gpio_cfgpin(S3C2410_GPH9,S3C2410_GPIO_INPUT); //IRQ---CLKOUT0
s3c2410_gpio_cfgpin(S3C2410_GPE7,S3C2410_GPIO_INPUT); //MISO--SDDATA0
}
//延时函数
void delay(int n)
{
int m,k;
for(m=0;m<10;m++)
for(k=0;k<n;k++){}
}
// 写一个字节到24L01,同时读出一个字节
uchar SPI_RW(uchar byte)
{
uchar bit_ctr;
for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
{
if(byte & 0x80)
s3c2410_gpio_setpin(S3C2410_GPB1,1); //MOSI
else
s3c2410_gpio_setpin(S3C2410_GPB1,0); //MOSI
byte = (byte << 1); // shift next bit into MSB..
s3c2410_gpio_setpin(S3C2410_GPB4,1);//SCK
if(s3c2410_gpio_getpin(S3C2410_GPE7))
{ //MISO
byte |= 1<<0;
}else
{
byte |= 0<<0;
}
s3c2410_gpio_setpin(S3C2410_GPB4,0); //SCK
}
return(byte); // return read byte
}
/******************************************************************************
* 读取寄存器值的函数:基本思路就是通过READ_REG 命令(也就是0x00+寄存器地址),把
* 寄存器中的值读出来。对于函数来说也就是把reg 寄存器的值读到reg_val 中去。
******************************************************************************/
uchar SPI_Read(uchar reg)
{
uchar reg_val;
s3c2410_gpio_setpin(S3C2410_GPB0,0); //CSN
SPI_RW(reg); // Select register to read from..
reg_val = SPI_RW(0xff); // ..then read registervalue
s3c2410_gpio_setpin(S3C2410_GPB0,1); //CSN
return(reg_val); // return register value
}
/****************************************
* 向寄存器reg写一个字节,同时返回状态字节
*****************************************/
uchar SPI_RW_Reg(uchar reg, uchar value)
{
uchar status;
s3c2410_gpio_setpin(S3C2410_GPB0,0); //CSN
status = SPI_RW(reg); // select register
SPI_RW(value); // ..and write value to it..
s3c2410_gpio_setpin(S3C2410_GPB0,1); //CSN
return(status); // return nRF24L01 status byte
}
/***************************************
*读出bytes字节的数据
****************************************/
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bytes)
{
uchar status,byte_ctr;
s3c2410_gpio_setpin(S3C2410_GPB0,0); //CSN
status = SPI_RW(reg); // Select register to write to and read status byte
for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
pBuf[byte_ctr] = SPI_RW(0);
s3c2410_gpio_setpin(S3C2410_GPB0,1); //CSN
return(status); // return nRF24L01 status byte
}
/*************************************
*写入bytes字节的数据
**************************************/
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bytes)
{
uchar status,byte_ctr;
s3c2410_gpio_setpin(S3C2410_GPB0,0); //CSN
status = SPI_RW(reg);
for(byte_ctr=0; byte_ctr<bytes; byte_ctr++)
SPI_RW(*pBuf++);
s3c2410_gpio_setpin(S3C2410_GPB0,1); //CSN
return(status);
}
/*************************************
* 启动NRF24L01发送一次数据
* txbuf:待发送数据首地址
* 返回值:发送完成状况
**************************************/
uchar TxPacket(uchar *txbuf)
{
uchar sta;
int i=0;
printk("TxPacket\n");
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,0); //CE
SPI_Write_Buf(WR_TX_PLOAD,txbuf,TX_PLOAD_WIDTH);//写数据到TX BUF 32个字节
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,1); //CE
printk("WAIT FOR IRQ TO READY\n");
i=0;
while(i<2000&&s3c2410_gpio_getpin(S3C2410_GPH9))
{//GET_IRQ()){//等待发送完成
i++;
}
sta=SPI_Read(STATUS); //读取状态寄存器的值
SPI_RW_Reg(WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
if(sta&MAX_TX)//达到最大重发次数
{
printk("MAX_TX reached!\n");
SPI_RW_Reg(FLUSH_TX,0xff);//清除TX FIFO寄存器
return MAX_TX;
}
else
{
printk("MAX_TX not reached yet!\n");
}
if(sta&TX_OK)//发送完成
{
printk("TX OK!\n");
return TX_OK;
}
printk("TX FAILED!\n");
return 0xff;//其他原因发送失败
}
/**********************************************
* 启动NRF24L01发送一次数据
* txbuf:待发送数据首地址
* 返回值:0,接收完成;其他,错误代码
**********************************************/
uchar RxPacket(uchar *rxbuf)
{
uchar sta;
sta=SPI_Read(STATUS); //读取状态寄存器的值
SPI_RW_Reg(WRITE_REG+STATUS,sta); //清除TX_DS或MAX_RT中断标志
if(sta&RX_OK)//接收到数据
{
SPI_Read_Buf(RD_RX_PLOAD,rxbuf,RX_PLOAD_WIDTH);//读取数据
SPI_RW_Reg(FLUSH_RX,0xff);//清除RX FIFO寄存器
printk("Data received!\n");
return 0;
}
return 1;//没收到任何数据
}
/********************************************
* 该函数初始化NRF24L01到RX模式
* 设置RX地址,写RX数据宽度,选择RF频道,波特率和LNA HCURR
* 当CE变高后,即进入RX模式,并可以接收数据了
*********************************************/
void SET_RX_Mode(void)
{
int i;
GPIO_CONFIG_PINS(); //设置引脚
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,0); //CE
SPI_Write_Buf(WRITE_REG+RX_ADDR_P0,(uchar*)RX_ADDRESS,RX_ADR_WIDTH);//写RX节点地址
SPI_RW_Reg(WRITE_REG+EN_AA,0x01); //使能通道0的自动应答
SPI_RW_Reg(WRITE_REG+EN_RXADDR,0x01);//使能通道0的接收地址
SPI_RW_Reg(WRITE_REG+RF_CH,40); //设置RF通信频率
SPI_RW_Reg(WRITE_REG+RX_PW_P0,RX_PLOAD_WIDTH);//选择通道0的有效数据宽度
SPI_RW_Reg(WRITE_REG+RF_SETUP,0x0f);//设置TX发射参数,0db增益,2Mbps,低噪声增益开启
SPI_RW_Reg(WRITE_REG+CONFIG, 0x0f);//配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,1); //CE
}
/***********************************************
* 该函数初始化NRF24L01到TX模式
* 设置TX地址,写TX数据宽度,设置RX自动应答的地址,
* 填充TX发送数据,选择RF频道,波特率和LNA HCURR
* PWR_UP,CRC使能
*当CE变高后,即进入RX模式,并可以接收数据了
*CE为高大于10us,则启动发送.
***********************************************/
void SET_TX_Mode(void)
{
int i;
GPIO_CONFIG_PINS();//设置引脚
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,0); //CE
SPI_Write_Buf(WRITE_REG+TX_ADDR,(uchar*)TX_ADDRESS,TX_ADR_WIDTH);//写TX节点地址
SPI_Write_Buf(WRITE_REG+RX_ADDR_P0,(uchar*)RX_ADDRESS,RX_ADR_WIDTH); //设置TX节点地址,主要为了使能ACK
SPI_RW_Reg(WRITE_REG+EN_AA,0x01); //使能通道0的自动应答
SPI_RW_Reg(WRITE_REG+EN_RXADDR,0x01); //使能通道0的接收地址
SPI_RW_Reg(WRITE_REG+SETUP_RETR,0x1a);//设置自动重发间隔时间:500us + 86us;最大自动重发次数:10次
SPI_RW_Reg(WRITE_REG+RF_CH,40); //设置RF通道为40
SPI_RW_Reg(WRITE_REG+RF_SETUP,0x0f); //设置TX发射参数,0db增益,2Mbps,低噪声增益开启
SPI_RW_Reg(WRITE_REG+CONFIG,0x0e); //配置基本工作模式的参数;PWR_UP,EN_CRC,16BIT_CRC,接收模式,开启所有中断
SPI_RW_Reg(WRITE_REG+STATUS,0x0);
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,1); //CE
}
/***********************************************
* 初始化24L01的IO口
************************************************/
void NRF24L01_Init(void)
{
int i;
printk("NRF24L01_Init\n");
GPIO_CONFIG_PINS();//设置引脚
//initial io
for(i=0;i<5;i++)
{
s3c2410_gpio_setpin(S3C2410_GPG11,0); //CE
s3c2410_gpio_setpin(S3C2410_GPB0,1); //CSN
s3c2410_gpio_setpin(S3C2410_GPB4,0); //SCK
}
for(i=0;i<5;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,1); //CE
SPI_RW_Reg(WRITE_REG + CONFIG, 0x0); // Set PWR_UP bit, enable CRC(2 bytes) & Prim:RX. RX_DR enabled..
SPI_RW_Reg(WRITE_REG + EN_AA, 0x0);
SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x0); // Enable Pipe0
SPI_RW_Reg(WRITE_REG + SETUP_AW, 0x03); // Setup address width=5 bytes
SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x0); // 500us + 86us, 10 retrans...
SPI_RW_Reg(WRITE_REG + RF_CH, 0);
SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0); // TX_PWR:0dBm, Datarate:1Mbps, LNA:HCURR
SPI_RW_Reg(WRITE_REG + RX_PW_P0, 0x0);
//SPI_Write_Buf(WRITE_REG + TX_ADDR, (uchar*)TX_ADDRESS, TX_ADR_WIDTH);
//SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, (uchar*)TX_ADDRESS, TX_ADR_WIDTH);
for(i=0;i<10;i++)
s3c2410_gpio_setpin(S3C2410_GPG11,1); //CE
}
/**********************************************
* 检测24L01是否存在
* 返回值:0,成功;1,失败
***********************************************/
uchar NRF24L01_Check(void)
{
uchar i;
uchar buf[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
GPIO_CONFIG_PINS();//设置引脚
//SET_IRQ(1);
SPI_Write_Buf(WRITE_REG+TX_ADDR,buf,5);//写入5个字节的地址.
SPI_Read_Buf(TX_ADDR,buf,5); //读出写入的地址
printk("buffer is: ");
for(i=0;i<5;i++)
printk("%X ",buf[i]);
printk("\n");
for(i=0;i<5;i++)if(buf[i]!=0XA5)break;
if(i!=5)return 1;//检测24L01错误
return 0; //检测到24L01
}
/*********************************************************************************/
/***********************
* 底层驱动函数结束
************************/
/*********************************************************************************/
/***********************************
* 驱动设备函数
************************************/
static int nrf_open(struct inode *inode,struct file *filp)
{
filp->private_data=nrf_devp;
while(NRF24L01_Check())
{ //检测24L01是否存在
printk("-----------------------------------\n");
printk("NRF24L01 not detected!\n");
printk("exiting...\n");
printk("-----------------------------------\n");
}
printk("-----------------------------------\n");
printk("NRF24L01 detected!\n");
printk("NRF24L01 initiated!\n");
printk("-----------------------------------\n");
return 0;
}
static int nrf_release(struct inode *inode,struct file *filp)
{
printk("-----------------------------\n");
printk("NRF24L01 closed\n");
printk("------------------------------\n");
return 0;
}
//-----------------------------------------------------------------------------------------------------------
static ssize_t nrf_read(struct file *filp,char __user *buf,size_t count)
{
int m;
struct nrf_dev *dev=filp->private_data;
SET_RX_Mode();
m=0;
while(m <20)
{
//printk("m*****************=%d\n",m);
if(!RxPacket(dev->dataRx))
{ //接收一个包的数据
for(m=0;m<RX_PLOAD_WIDTH;m++)
// printk("received: 0x%X \n",dev->dataRx[m]);
count= copy_to_user(buf,dev->dataRx,RX_PLOAD_WIDTH);
return RX_PLOAD_WIDTH;
}
m++;
}
return 0;
// return count;
}
static ssize_t nrf_write(struct file *filp,char __user *buf,size_t count)
{
int i=0;
struct nrf_dev *dev=filp->private_data;
//获得设备结构体的指针
copy_from_user(dev->dataTx,buf,TX_PLOAD_WIDTH);
NRF24L01_Init();
delay(100);
SET_TX_Mode();
delay(10);
while(i<20 && TxPacket(dev->dataTx) != TX_OK)
{
i++;
}
if(i<20)
printk("send succeed!\n");
return 0;
}
/*********************************************************************************************/
static const struct file_operations nrf_fops=
{
.owner=THIS_MODULE,
.open=nrf_open,
.release=nrf_release,
.read=nrf_read,
.write=nrf_write,
};
static void nrf_setup_cdev(struct nrf_dev *dev,int index)
{
int err,devno=MKDEV(NRF_MAJOR,index);
printk("-----------------------------------\n");
cdev_init(&dev->cdev,&nrf_fops); //初始化设备
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&nrf_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk("S3C2440_NRF dev setup error\n");
else
printk("S3C2440_NRF dev setup succeed\n");
printk("-----------------------------------\n");
}
static int __init nrf_init(void)
{
int ret;
dev_t devno=MKDEV(NRF_MAJOR,0);
if(NRF_MAJOR)//申请设备号
ret=register_chrdev_region(devno,1,NRF_NAME);
else//动态申请设备号
{
ret=alloc_chrdev_region(&devno,0,1,NRF_NAME);
NRF_MAJOR=MAJOR(devno);
}
if(ret<0)
{
printk("apply device failed!\n");
return ret;
}
//动态申请设备结构体的内存
nrf_devp=kmalloc(sizeof(struct nrf_dev),GFP_KERNEL);
if(!nrf_devp)//申请失败
{
ret=-ENOMEM;
printk("apply device memory failed!\n");
goto fail_malloc;
}
memset(nrf_devp,0,sizeof(struct nrf_dev));
//设备初始化
nrf_setup_cdev(nrf_devp,0);
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return ret;
}
static void __exit nrf_exit(void)
{
unregister_chrdev(NRF_MAJOR,NRF_NAME);
printk("S3C2440_NRF dev exit!\n");
}
/*******************************************************************************/
module_init(nrf_init);
module_exit(nrf_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("jingtao_deng");
MODULE_DESCRIPTION("NRF24L01 DRIVER FOR S3C2440");
/*
* jingtao_deng
* nrf24l01.h
*/
//GPB
#define GPBCON (unsigned long)ioremap(0x56000010,4)
#define GPBDAT (unsigned long)ioremap(0x56000014,4)
#define GPBUP (unsigned long)ioremap(0x56000018,4)
//GPF
#define GPFCON (unsigned long)ioremap(0x56000050,4)
#define GPFDAT (unsigned long)ioremap(0x56000054,4)
#define GPFUP (unsigned long)ioremap(0x56000058,4)
//GPG
#define GPGCON (unsigned long)ioremap(0x56000060,4)
#define GPGDAT (unsigned long)ioremap(0x56000064,4)
#define GPGUP (unsigned long)ioremap(0x56000068,4)
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
//相关命令的宏定义,原理参见《spi接口指令.jpg》
// SPI(nRF24L01) commands
#define READ_REG 0x00 // Define read command to register
#define WRITE_REG 0x20 // Define write command to register
#define RD_RX_PLOAD 0x61 // Define RX payload register address
#define WR_TX_PLOAD 0xA0 // Define TX payload register address
#define FLUSH_TX 0xE1 // Define flush TX register command
#define FLUSH_RX 0xE2 // Define flush RX register command
#define REUSE_TX_PL 0xE3 // Define reuse TX payload register command
#define NOP 0xFF // Define No Operation, might be used to read status register
//***************************************************//
// SPI(nRF24L01) registers(addresses)
#define CONFIG 0x00 // 'Config' register address
#define EN_AA 0x01 // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02 // 'Enabled RX addresses' register address
#define SETUP_AW 0x03 // 'Setup address width' register address
#define SETUP_RETR 0x04 // 'Setup Auto. Retrans' register address
#define RF_CH 0x05 // 'RF channel' register address
#define RF_SETUP 0x06 // 'RF setup' register address
#define STATUS 0x07 // 'Status' register address
#define OBSERVE_TX 0x08 // 'Observe TX' register address
#define CD 0x09 // 'Carrier Detect' register address
#define RX_ADDR_P0 0x0A // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F // 'RX address pipe5' register address
#define TX_ADDR 0x10 // 'TX address' register address
#define RX_PW_P0 0x11 // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12 // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13 // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14 // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15 // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16 // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address
#define MAX_TX 0x10 //达到最大发送次数中断
#define TX_OK 0x20 //TX发送完成中断
#define RX_OK 0x40 //接收到数据中断
//24L01发送接收数据宽度定义
#define TX_ADR_WIDTH 5 //5字节的地址宽度
#define RX_ADR_WIDTH 5 //5字节的地址宽度
#define TX_PLOAD_WIDTH 32 //2字节的用户数据宽度
#define RX_PLOAD_WIDTH 32 //2字节的用户数据宽度
//functions
void delay(int n);
void SET_CSN(uchar uc); //设置CSN位
void SET_CE(uchar uc); //设置CE位
void SET_SCK(uchar uc); //设置SCK位
void SET_MOSI(uchar uc); //设置MOSI位
void SET_IRQ(uchar uc); //设置IRQ位
uchar GET_MISO(void); //从MISO获取数据
uchar GET_IRQ(void); //从IRQ获取数据
uchar SPI_RW(uchar byte);
uchar SPI_RW_Reg(uchar reg, uchar value);
uchar SPI_Read(uchar reg);
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bytes);
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bytes);
uchar TxPacket(uchar *rxbuf); //接收一个包的数据
uchar TxPacket(uchar *txbuf); //发送一个包的数据
void RX_Mode(void);
void TX_Mode(void);
uchar NRF24L01_Check(void); //检查24L01是否存在
本文档提供了Linux环境下针对nRF24L01无线通信模块的设备驱动程序代码,包括初始化、读写操作、中断处理等关键函数。代码适用于2.6.24版本的Linux内核,ARM平台为博创“三剑客”up—Star2410。驱动程序涉及GPIO配置、SPI通信、中断处理等功能,实现了数据的发送和接收。
2874

被折叠的 条评论
为什么被折叠?



