Tiny4412上编写SPI驱动程序驱动NRF24L01 2.4G无线模块

硬件平台  :友善之臂Ting4412

                 : NRF24L01 2.4G无线模块SPI接口

内核版本:Linux3.5

硬件连接方式


以前在STM32F103C8T6上使用STM32的SPI控制器驱动过NRF24L01 2.4G无线模块,最近学习Linux设备驱动,刚好同学手边有一个Tiny4412开发板就当是练练手,顺便学习学习Linux下SPI设备驱动的编写。

NRF24L01 2.4G无线模块的SPI驱动暂时只是调试通过,能够实现Tiny4412通过NRF24L01 2.4G无线模块发送数据,暂时没写成字符设备驱动,在内核定时器中调用spi_write函数不断发送数据。

通信现象:



STM32没接到数据就会报错,如下:


一旦加载驱动模块,就立马接收正常,如下:


......................................................................................只说流程,不说原理............................................................................

1、构造struct spi_board_info对象,这里我们暂时构造两个,方便以后在SPI0控制器上挂载两个NFR24L01设备,实现相互收发数据。

struct s3c64xx_spi_csinfo cs0={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(2),//片选引脚
};
struct s3c64xx_spi_csinfo cs1={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(4),//片选引脚
};
static struct spi_board_info nrf24l01_spi_info[]={
	{
		.modalias		=	DEV_NAME_01,
		.max_speed_hz	= 	10*1000*1000,//最大时钟,需比设备要求的时钟大,暂选10Mhz
		.bus_num		=	0,/*exynos4412 的spi0控制器*/
		.chip_select	=	EXYNOS4_GPX3(2),/*由spi master确定其最大值*/
		.mode			=	SPI_MODE_0,
		.platform_data	=   (void*)EXYNOS4_GPX3(3), /*平台数据,作为NRF24LXX的CE引脚*/
		.controller_data=	(void*)&cs0,
	},
	{
		.modalias		=	DEV_NAME_02,
		.max_speed_hz	= 	10*1000*1000,//最大时钟,需比设备要求的时钟大,暂选10Mhz
		.bus_num		=	0,/*exynos4412 的spi0控制器*/
		.chip_select	=	EXYNOS4_GPX3(4),/*由spi master确定其最大值*/
		.mode			=	SPI_MODE_0,
		.platform_data	=   (void*)EXYNOS4_GPX3(5), /*平台数据,作为NRF24LXX的CE引脚*/
		.controller_data=	(void*)&cs1,
	},
};


2、注册它,内核会依据构造的struct spi_board_info 对象创建对应的struct spi_device对象。

在init函数中注册构造好的truct spi_board_info对象static struct spi_board_info nrf24l01_spi_info[]

static int __init demo_init(void)
{
	printk(KERN_INFO"current func is-------------------------------------------%s\n",__FUNCTION__);
	/*spi_register_board_info 
	 *依照spi_board_info 和spi_master的bus_num比较,匹配成功会生成一个对应的spi_device对象
	 */
	return spi_register_board_info(nrf24l01_spi_info,ARRAY_SIZE(nrf24l01_spi_info));
}
看看spi_register_board_info干了什么?

int spi_register_board_info(struct spi_board_info const *info, unsigned n)
//master和bi->board_info的bus_nus比较,相等则调用spi_new_device创建spi_device对象
	spi_match_master_to_boardinfo(master, &bi->board_info);调用spi_new_device
		spi_new_device(struct spi_master *master,struct spi_board_info *chip)
			int spi_add_device(struct spi_device *spi)//注册struct spi_device
			   /*spi_add_device注册struct spi_device时候会做一些判断,一会进去分析 */
分析spi_new_device

int spi_register_board_info(struct spi_board_info const *info, unsigned n)
//master和bi->board_info的bus_nus比较,相等则调用spi_new_device创建spi_device对象
	spi_match_master_to_boardinfo(master, &bi->board_info);调用spi_new_device
		spi_new_device(struct spi_master *master,struct spi_board_info *chip)
			int spi_add_device(struct spi_device *spi)//注册struct spi_device
			   /*spi_add_device注册struct spi_device时候会做一些判断,比如我们第一步构造
			    *static struct spi_board_info中的chip_select会和spi_master的num_chipselect做比较
				*要求设置我们的片选信号不能大于spi_master的num_chipselect
				*	if (spi->chip_select >= spi->master->num_chipselect) {
				*	dev_err(dev, "cs%d >= max %d\n",spi->chip_select,spi->master->num_chipselect);
				*	return -EINVAL;//直接报错返回,导致我们不能注册spi_device对象......
				*   这个问题怎么解决?我们直接修改spi主控器驱动就好了。
                                *}
				* 修改 vi arch/arm/mach-exynos/mach-tiny4412.c中设置spi控制器函数
				* s3c64xx_spi0_set_platdata(NULL,0,1)这个函数就好了,内核默认设置
				* 最大片选值为1,也就是说默认最多支持1个spi设备,那好了我们把它修改
				* 大一些就好了,直接修改到0xffff,保证它一定能注册成功。
				*/





至于程序中 struct s3c64xx_spi_csinfo cs0 和struct s3c64xx_spi_csinfo cs1怎么来的?为什么需要这两个?这个是安装驱动后看内核看内核打印错误信息找出来的。出错的地方为 drivers\spi\spi-s3c64xx.c的static int s3c64xx_spi_setup(struct spi_device *spi)函数中报if (IS_ERR_OR_NULL(cs)) {
dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select);
return -ENODEV;
}意思是cs为空,那么追溯cs,发现 spi_device spi->controller_data = cs;那好,我们就在 static struct spi_board_info nrf24l01_spi_info[]添加.controller_data= (void*)&cs0即可。

struct s3c64xx_spi_csinfo cs0={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(2),
};
struct s3c64xx_spi_csinfo cs1={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(4),
};

好了下面编译成模块,但是编译的时候报WARNING: "spi_register_board_info"/nrf24xx_spi_device.ko] undefined!第一感觉是


spi_register_board_info相关的头文件没有,但是相关spi的头文件都加了,查资料发现原来是linux3.5源码中没有将spi_register_board_info函数导出符号表。那好,就编译进内核得了,将nrf24xx_spi_device.c复制drivers/spi目录下,修改Makefile,将nrf24xx_spi_device.c编译进内核。下面先给出nrf24xx_spi_device.c源码。


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

/******************硬件相关的信息****************/
#define DEV_NAME_01  "nrf24xx_spi_01"
#define DEV_NAME_02  "nrf24xx_spi_02"

#define DEV1_CS_PIN	  EXYNOS4_GPX3(2)
#define DEV2_CS_PIN	  EXYNOS4_GPX3(4)

#define DEV1_CE_PIN	  EXYNOS4_GPX3(3)
#define DEV2_CE_PIN	  EXYNOS4_GPX3(5)
/*
	片选引脚接在GPX3_2
*/
struct s3c64xx_spi_csinfo cs0={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(2),//片选引脚
};
struct s3c64xx_spi_csinfo cs1={
	.fb_delay = 0,
	.line	=	EXYNOS4_GPX3(4),//片选引脚
};
static struct spi_board_info nrf24l01_spi_info[]={
	{
		.modalias		=	DEV_NAME_01,
		.max_speed_hz	= 	2*1000*1000,//最大时钟,需比设备要求的时钟大,暂选2Mhz
		.bus_num		=	0,/*exynos4412 的spi0控制器*/
		.chip_select	=	EXYNOS4_GPX3(2),/*由spi master确定其最大值*/
		.mode			=	SPI_MODE_0,
		.platform_data	=   (void*)EXYNOS4_GPX3(3), /*平台数据,作为NRF24LXX的CE引脚*/
		.controller_data=	(void*)&cs0,
	},
	{
		.modalias		=	DEV_NAME_02,
		.max_speed_hz	= 	2*1000*1000,//最大时钟,需比设备要求的时钟大,暂选2Mhz
		.bus_num		=	0,/*exynos4412 的spi0控制器*/
		.chip_select	=	EXYNOS4_GPX3(4),/*由spi master确定其最大值*/
		.mode			=	SPI_MODE_0,
		.platform_data	=   (void*)EXYNOS4_GPX3(5), /*平台数据,作为NRF24LXX的CE引脚*/
		.controller_data=	(void*)&cs1,
	},
};

static int __init demo_init(void)
{
	printk(KERN_INFO"current func is-------------------------------------------%s\n",__FUNCTION__);
	/*spi_register_board_info 
	 *依照spi_board_info 和spi_master的bus_num比较,匹配成功会生成一个对应的spi_device对象
	 */
	return spi_register_board_info(nrf24l01_spi_info,ARRAY_SIZE(nrf24l01_spi_info));
}

static void __exit demo_exit(void)
{
	printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);	
}
module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

make zImage,启动内核。在sys/bus/spi/devices目录下出现下面spi0.220 spi0.222两个节点,如图:


 其中0表示bus_num,220和222表示我们的static struct spi_board_info nrf24l01_spi_info[0]的.chip_select = EXYNOS4_GPX3(2),//这个宏的值就是220同理222就是EXYNOS4_GPX3(4),默认内核只创建spi0.0、spi2.0。注意现在只是在内核中创建了spi_device,还没nrf24xx的驱动。nrf24xx_spi_driver就是在STM32程序基础上简单的修修改改就好了,对比Tiny4412和STM32的程序你会发现关于nrf24l01的代码名字是一样的。

..............................................................下面就直接给出nrf24xx_spi_driver.c的源码.........................................................................

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "nrf24xx.h"

#define DEVICE_NUM	1
#define GPX3CON  0x11000C60
#define GPX3DAT	 0x11000C64

#define DEV_NAME_01  "nrf24xx_spi_01"
#define DEV_NAME_02  "nrf24xx_spi_02"
#define DEV_NAME	DEV_NAME_01


#define DEV1_CS_PIN	  EXYNOS4_GPX3(2)
#define DEV2_CS_PIN	  EXYNOS4_GPX3(4)

#define DEV1_CE_PIN	  EXYNOS4_GPX3(3)
#define DEV2_CE_PIN	  EXYNOS4_GPX3(5)

unsigned char TX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01}; //发送地址
unsigned char RX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01};


static struct work_struct work;
struct timer_list timer;
struct spi_device *nrf24xx_spi;

static int nrf24l01_spi_probe(struct spi_device *spi);
static int nrf24l01_spi_remove(struct spi_device *spi);

void Nrf24L10_RX_Mode(void);
void Nrf24L10_TX_Mode(void);
unsigned char SPI1_ReadBuf(unsigned char reg,unsigned char *buf,unsigned char length);
unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length);
unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data);
void Active_Nrf24l10(unsigned char cmd);
unsigned int SPI1_Read_Reg(unsigned char reg,unsigned char *status);
unsigned char Nrf24l10_SendBuf(unsigned char* data_buffer, unsigned char length);
unsigned char Nrf24l0_ReceiveBuf(unsigned char *buf);
unsigned char Nrf24l10_Irq(void);

char tmp=0,counter =0;
static struct spi_driver nrf24l01_spi_driver={
	.driver={
		.name 	= DEV_NAME,
		.bus    =&spi_bus_type,
		.owner  = THIS_MODULE,
	},
	.probe = nrf24l01_spi_probe,
	.remove =__devexit_p(nrf24l01_spi_remove),
};

static void timer_function(unsigned long counter)
{
	//printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
	tmp = tmp?0:1;
	gpio_set_value(DEV2_CE_PIN,tmp);	
	mod_timer(&timer,jiffies+HZ);	
	schedule_work(&work);
	
}
/*中断底半部中发送数据*/
static void irqBottom(struct work_struct *work)
{
	char wbuf[50]={0};
	int ret =0;
//	char reg = EN_AA;
	counter = counter>30? 0:counter;
	sprintf(wbuf,"Message Comes From Linux -%d %c",counter,'\0');
	counter++;
	ret = Nrf24l10_SendBuf(wbuf,RX_PLOAD_WIDTH_32);//该函数会导致休眠,不能在中断函数中使用
	printk("Message Send to STM3 .......%d\n",counter);
}
static int nrf24l01_spi_probe(struct spi_device *spi)
{
	nrf24xx_spi = spi;
	printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
	printk(KERN_INFO"max_speed_hz:%d\n",spi->max_speed_hz);	
	printk(KERN_INFO"chip_select:%d\n",spi->chip_select);	
	INIT_WORK(&work, irqBottom);
	s3c_gpio_cfgpin(DEV1_CS_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
	s3c_gpio_cfgpin(DEV2_CS_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
	
	s3c_gpio_cfgpin(DEV1_CE_PIN, S3C_GPIO_OUTPUT);//设置片选为输出
	s3c_gpio_cfgpin(DEV2_CE_PIN, S3C_GPIO_INPUT);//设置片选为输出
	Nrf24L10_TX_Mode();
	init_timer(&timer);//初始化内核定时器
	timer.function = timer_function;  
	add_timer(&timer);		
	return 0;
}

static int nrf24l01_spi_remove(struct spi_device *spi)
{
	printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
	del_timer(&timer);
	return 0;
}

static int __init demo_init(void)
{
	int err;
	printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
	err = spi_register_driver(&nrf24l01_spi_driver);
	return err;
}

static void __exit demo_exit(void)
{	
	printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);
	spi_unregister_driver(&nrf24l01_spi_driver);
}

module_init(demo_init);
module_exit(demo_exit);
MODULE_LICENSE("GPL");

void Nrf24L10_RX_Mode(void)
{
	Active_Nrf24l10(0);//进入设置模式
	SPI1_SendBuf(WRITE_REG1 + RX_ADDR_P0, RX_ADDRESS, TX_ADR_WIDTH_5);         //数据通道0发送地址,最大5个字节
	SPI1_Write_Register(WRITE_REG1 + EN_AA, 0x01);    // 使能通道0-通道5接收自动应答	 
	SPI1_Write_Register(WRITE_REG1 + EN_RXADDR, 0x01); 	//接收通道0-5 使能
	SPI1_Write_Register(WRITE_REG1 + RF_CH, 40);         // 选择射频工作频道0   范围0-127  频道选择寄存器
	SPI1_Write_Register(WRITE_REG1+RX_PW_P0,RX_PLOAD_WIDTH_32);
	SPI1_Write_Register(WRITE_REG1 + RF_SETUP, 0x0f);   	
	SPI1_Write_Register(WRITE_REG1 + CONFIG, 0x0f);     
	Active_Nrf24l10(1);//激活发送
}

void Nrf24L10_TX_Mode(void)
{	
	Active_Nrf24l10(0);
	SPI1_SendBuf(WRITE_REG1 + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH_5);  //数据通道0发送地址,最大5个字节
	SPI1_SendBuf(WRITE_REG1 + RX_ADDR_P0, RX_ADDRESS, TX_ADR_WIDTH_5);//数据通道0发送地址,最大5个字节

	SPI1_Write_Register(WRITE_REG1 + EN_AA, 0x01);// 使能通道0-通道5接收自动应答	 
	SPI1_Write_Register(WRITE_REG1 + EN_RXADDR, 0x01);//接收通道0-5 使能
	SPI1_Write_Register(WRITE_REG1+SETUP_RETR,0x1a);
	SPI1_Write_Register(WRITE_REG1 + RF_CH, 40);// 选择射频工作频道0   范围0-127  频道选择寄存器
	SPI1_Write_Register(WRITE_REG1 + RF_SETUP, 0x0f);   	
	SPI1_Write_Register(WRITE_REG1 + CONFIG, 0x0e);   
	Active_Nrf24l10(1);	// 使能发送模式
}

unsigned int SPI1_Read_Reg(unsigned char reg,unsigned char *status)
{
	unsigned char wbuf=reg;
	struct spi_message	m;
	struct spi_transfer	t[2] = {
		{
			.tx_buf		= &wbuf,
			.len		= 1,			
		},
		{
			.rx_buf		= status,
			.len		= 1,
		},	
	};
	spi_message_init(&m);
	spi_message_add_tail(&t[0], &m);
	spi_message_add_tail(&t[1], &m);	
	return spi_sync(nrf24xx_spi, &m);  
}

unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data)
{
	unsigned char wbuf[2]={0};
	
	struct spi_message	m;
	struct spi_transfer	t = {
		.tx_buf		= wbuf,
		.len		= 2,	
	};
	//printk(KERN_INFO"current func is-----%s\n",__FUNCTION__);	
	wbuf[0]=reg;
	wbuf[1]=data;
	spi_message_init(&m);
	spi_message_add_tail(&t, &m);
	return spi_sync(nrf24xx_spi, &m);  
}

/*
	SPI1发送一个缓冲区
*/

unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
	struct spi_message	m;
	unsigned char wbuf=reg;
	struct spi_transfer	t[2] = {
		{
			.tx_buf		= &wbuf,
			.len		= 1,			
		},
		{
			.tx_buf		= buf,
			.len		= length,
		},
			
	};
	spi_message_init(&m);
	spi_message_add_tail(&t[0], &m);
	spi_message_add_tail(&t[1], &m);	
	return spi_sync(nrf24xx_spi, &m);
}
unsigned char SPI1_ReadBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
	unsigned char wbuf=reg;
	struct spi_message	m;
	struct spi_transfer	t[2] = {
		{
			.tx_buf		= &wbuf,
			.len		= 1,	
		},
		{
			.rx_buf		= buf,
			.len		= length,	
		}

		};
	spi_message_init(&m);
	spi_message_add_tail(&t[0], &m);
	spi_message_add_tail(&t[1], &m);	
	return spi_sync(nrf24xx_spi, &m);
}
void Active_Nrf24l10(unsigned char cmd)
{
	gpio_set_value(DEV2_CE_PIN,cmd);
}

unsigned char Nrf24l0_ReceiveBuf(unsigned char *buf)
{
	unsigned char status = 0;
	SPI1_Read_Reg(STATUS,&status);
	SPI1_Write_Register(WRITE_REG1 +STATUS ,status);//清除相应的标志位
	if(status & RX_OK)
	{
		SPI1_ReadBuf(RD_RX_PLOAD,buf,RX_PLOAD_WIDTH_32);
		SPI1_Write_Register(FLUSH_RX,0xff);
		return RX_OK;																	//接收成功返回RX_OK
	}	
	return OTHER_ERROR;
}

unsigned char Nrf24l10_SendBuf(unsigned char* data_buffer, unsigned char length)
{
	unsigned char status = 0;
	Active_Nrf24l10(0);
	SPI1_SendBuf(WR_TX_PLOAD,data_buffer,TX_PLOAD_WIDTH_32);//写数据到TX BUF  32个字节
//	SPI1_SendBuf(WR_TX_PLOAD,data_buffer,length);//写数据到TX BUF  32个字节
	Active_Nrf24l10(1);
	while(1 == Nrf24l10_Irq())//等待发送完成事件
	{
		//printk("Nrf24l10_Irq..............\n");
		schedule_timeout(HZ/50);//HZ=100 , 每10ms jiffies+1
	}
	SPI1_Read_Reg(STATUS,&status);
	SPI1_Write_Register(WRITE_REG1 +STATUS ,status);//清除相应的标志位
	if(status & TX_OK)
	{
		return TX_OK;																	//接收成功返回RX_OK
	}else if(status & MAX_RET_FLAG)
	{
		SPI1_Write_Register(FLUSH_TX,0xff);	
		return MAX_RET_FLAG;																	//否则返回ERROR
	}	
	return OTHER_ERROR;
}
unsigned char Nrf24l10_Irq(void)
{
	return gpio_get_value(DEV2_CE_PIN);
}


编译驱动,并加载模块,在sys/bus/spi/drivers/目录下出现我们的nrf24xxspi驱动,如下图:


..................................................................................下面直接给出STM32的源码.........................................................................

#include "NRF24L10_Driver.h"
#include "delay.h"

unsigned char TX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01}; //发送地址
unsigned char RX_ADDRESS[TX_ADR_WIDTH_5]={0x34,0x43,0x10,0x10,0x01};
 
/*
	初始化Nrf24l10的端口,作为SPI输出
				STM32F10X	NRF24L10
				PA2		IRQ
				PA3		CE		(Chip Enable)高电平有效,低电平时用来设置Nrf24l10高电平时传输数据
	SPI1_NSS 		PA4 		CSN		(Chip Select Not)	片选引脚低电平有效
	SPI1_SCK 		PA5 		SCK		主模式下 						推挽复用输出
	SPI1_MISO 		PA6 		MISO		全双工模式/主模式下 	浮空输入或带上拉输入
	SPI1_MOSI 		PA7 		MOSI		全双工模式/主模式 推挽复用输出
*/
void Nrf24l10_GPIO_Init(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;
		/*开启GPIOA的时钟和复用功能的时钟*/
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);  		

		//		SPI1_SCK 			PA5 				SCK					主模式下 						推挽复用输出
		//		SPI1_MOSI 		PA7 				MOSI				全双工模式/主模式 推挽复用输出

		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_7;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;          //复用功能(推挽)输出  SPI2
		GPIO_Init(GPIOA, &GPIO_InitStructure);

		//SPI1_MISO 		PA6 				MISO				全双工模式/主模式下 	浮空输入或带上拉输入
		
		GPIO_InitStructure.GPIO_Pin 	= 	GPIO_Pin_6;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode 	= 	GPIO_Mode_IN_FLOATING;          //复用功能(推挽)输出  SPI2
		GPIO_Init(GPIOA, &GPIO_InitStructure);
		
		//	PA3					CE					(Chip Enable)高电平有效,低电平时用来设置Nrf24l10高电平时传输数据
		//	SPI1_NSS 			PA4 				CSN					(Chip Select Not)	片选引脚低电平有效
		GPIO_InitStructure.GPIO_Pin 	= 	GPIO_Pin_3|GPIO_Pin_4;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode 	= 	GPIO_Mode_Out_PP;          	//推挽输出
		GPIO_Init(GPIOA, &GPIO_InitStructure);
		
		/*IRQ引脚配置为输入*/
		GPIO_InitStructure.GPIO_Pin 	= 	GPIO_Pin_2;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStructure.GPIO_Mode 	= 	GPIO_Mode_IPU;          		//上拉输入模式
		GPIO_Init(GPIOA, &GPIO_InitStructure);	
}


/*
	NRF24L10片选信号,低电平有效,cmd=1选中,=0取消选中
*/
void Chip_SelectOrNot(unsigned char cmd)
{
	if(cmd==0)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_4);
	}else{

		GPIO_ResetBits(GPIOA,GPIO_Pin_4);
	}
}
/*
	激活NRF24L10的数据传输功能cmd=1,激活,=0时候数据传输功能禁止,但是此模式下可用来配置NRF24L10功能
*/
void Active_Nrf24l10(unsigned char cmd)
{
	if(cmd==1)
	{
		GPIO_SetBits(GPIOA,GPIO_Pin_3);
	}else{

		GPIO_ResetBits(GPIOA,GPIO_Pin_3);
	}
}
/*
	Nrf24l10的IRQ引脚是否低电平
*/
unsigned char Nrf24l10_Irq(void)
{
	return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2);
}


void Nrf24L10_SPI1_Configuration(void)
{
	SPI_InitTypeDef  SPI_InitStructure;
	/*开启外设时钟*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
	/*设置SPI1的工作模式*/
	SPI_InitStructure.SPI_Direction 				= SPI_Direction_2Lines_FullDuplex;   //全双工  
  SPI_InitStructure.SPI_Mode 							= SPI_Mode_Master;						   //主模式
  SPI_InitStructure.SPI_DataSize 					= SPI_DataSize_8b;					   //8位
  SPI_InitStructure.SPI_CPOL 							= SPI_CPOL_Low;						   //时钟极性 空闲状态时,SCK保持低电平
  SPI_InitStructure.SPI_CPHA							= SPI_CPHA_1Edge;						   //时钟相位 数据采样从第一个时钟边沿开始
  SPI_InitStructure.SPI_NSS 							= SPI_NSS_Soft;							   //软件产生NSS
  SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;  //波特率控制 72MHz/16 = 4.5MHz
  SPI_InitStructure.SPI_FirstBit 					= SPI_FirstBit_MSB;				   //数据高位在前
  SPI_InitStructure.SPI_CRCPolynomial 		= 7;							   //CRC多项式寄存器初始值为7 
  SPI_Init(SPI1, &SPI_InitStructure);
  /* 使能SPI2  */
  SPI_Cmd(SPI1, ENABLE);   
}

void NRF24L10_Init(void)
{
	Nrf24l10_GPIO_Init();
	Nrf24L10_SPI1_Configuration();
}

/*
	SPI1发送一个字节的数据
*/
unsigned char SPI1_Send_Byte(unsigned char data)
{
  /* 循环检测发送缓冲区是否是空 */
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET)
	{
				Delay_us(100);
	}
  SPI_I2S_SendData(SPI1, data);
  /* 等待接收数据,循环检查接收数据缓冲区 */
  while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)
	{
				Delay_us(100);
	}
  /* 返回读出的数据 */
  return SPI_I2S_ReceiveData(SPI1);
}
/*
	SPI1向指定寄存器发送一字节的数据
*/
unsigned char SPI1_Write_Register(unsigned char reg,unsigned char data)
{
	unsigned char ret =0;
	Chip_SelectOrNot(1);
	SPI1_Send_Byte(reg);
	ret = SPI1_Send_Byte(data);
	Chip_SelectOrNot(0);	
	return ret;
}
/*
	SPI1发送一个缓冲区
*/

unsigned char SPI1_SendBuf(unsigned char reg,unsigned char *buf,unsigned char length)
{
	unsigned char status=0;
	unsigned char i=0;
	Chip_SelectOrNot(1);
	status = SPI1_Send_Byte(reg);
	for(i=0; i
新手整整搞了3天才调通,还有有些地方说的不好,见谅。就当是记笔记。

你可能感兴趣的:(Linux设备驱动,嵌入式,硬件)