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
- ARM9 2440硬件SPI驱动程序-NRF24L01
- stm8 nrf24l01 硬件spi成功,解决bug
- NRF24L01驱动程序
- Tiny4412上编写SPI驱动程序驱动NRF24L01 2.4G无线模块
- ARM9的SPI
- nRF24L01 C51 发送接收驱动程序
- nRF24L01 AVR 发送接收驱动程序
- nRF24L01 MSP430 发送接收驱动程序
- linux下的nrf24l01驱动程序
- NRF24L01实现msp430单片机通信(SPI)
- STM32 软件模拟SPI时序驱动NRF24L01
- 无线图像(视频)传输系统ARM9+Atmega16+OV7620+nrf24l01
- ARM9硬件接口学习专题
- ARM9硬件接口学习专题
- ARM9硬件接口学习专题
- SPI驱动程序设计
- SPI master驱动程序概述
- SPI驱动程序设计
- 浅淡Webservice、WSDL三种服务访问的方式(附案例)
- LVM介绍及使用
- COJ-1060-Nearest Sequence
- scala中yield的使用
- 关于spring AOP的浅薄理解
- ARM9 2440硬件SPI驱动程序-NRF24L01
- 编写C语言的注意事项
- 网络仿真软件的对比
- React同构直出优化总结
- 线性回归的来历
- Android框架之路——OkGo的使用
- 使用Wrapper创建java的window系统服务
- bzoj1576[Usaco2009 Jan]安全路径Travel(堆优化dijkstra+并查集)
- IOS使用OpenAL播放音频文件