基于Linux和4412处理器实现SPI接口的RF控制

         本文介绍了基于4412(4核,cotex-A9)和Linux,基于SPI接口控制RF无线模块,代码和分析总结如下,便于以后查阅,只要是ARM-LINUX平台都可以参考:

#include "spiRf2401.h"

int spiOpen(void)
{
	int spifd=0;
	spifd = open("/dev/spidev0.0", O_RDWR);
	
	if ( spifd < 0 ) 
	{
		return -1;
	}
	else
	{
		return spifd;
	}
}

int gpioOpen(void)
{
	int gpiofd=0;
	gpiofd = open("/dev/use_gpio_0", O_RDWR);
	if ( gpiofd < 0 ) 
	{
		return -1;
	}
	else
	{
		return gpiofd;
	}
}

void spiClose(int spifd)
{
	close(spifd);
	printf("spi close\n");
}

void gpioClose(int gpiofd)
{
	close(gpiofd);
	printf("gpiofd close\n");
}

int spiSet(int fd)
{
	int ret = 0;
    uChar mode=0, mode1=0;
    uChar bits = 8, bits1=0;
    uint32_t speed = 4000000, speed1=0;  //4MHz

	// spi mode
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
	{
		printf("can't set spi mode\n");
		return -1;
	}
	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode1);
	if (ret == -1)
	{
		printf("can't get spi mode\n");
		//return -1;
	}
	
	
	// bits per word
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
	{
		printf("can't set bits per word\n");
		return -1;
	}
	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits1);
	if (ret == -1)
	{
		printf("can't get bits per word\n");
		//return -1;
	}
	// max speed hz
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
	{
		printf("can't set max speed hz\n");
		return -1;
	}
	
	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed1);
	if (ret == -1)
	{
		printf("can't get max speed hz\n");
		//return -1;
	}
    printf("spi mode: %d\n", mode1);
    printf("bits per word: %d\n", bits1);
    printf("max speed: %d Hz (%d KHz)\n", speed1, speed1/1000);
    printf("spi_set(): OK \n");
	return 0;
}

void nRF24L01Init(int gpiofd)
{
	//CSN_1
	//SCLK_0
	//IRQ_1
	
    ioctl(gpiofd, 12, 0);   //spi0
    //ioctl(gpiofd, 13, 0);  //spi1
    //printf("nRF24L01_init(): OK \n");
}

int SCSPI_Write_TX_ADDR_reg(int spifd,uChar reg, uChar *pBuf, uChar len)
{
	int status;
	uChar i, j;
	struct spi_ioc_transfer transfer_data[1];
	uChar	W_buf[32], R_buf[32];
	
	if (len > ((sizeof(W_buf)) - 1))
    {
        len = (sizeof(W_buf)) - 1;
    }
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
 
	W_buf[0] = reg;
	
	for(i=1,j=0; j<len; i++,j++) {
		W_buf[i] = pBuf[j];
	}
	
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = len + 1;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SCSPI_Write_TX_ADDR_reg():SPI_IOC_MESSAGE");
		return -1;
	}
	
	return 0;
}


int SCSPI_Read_TX_ADDR_reg(int spifd,uChar reg, uChar *pBuf, uChar len)
{
	int status, i = 0;
	struct spi_ioc_transfer transfer_data[1];
	uChar	W_buf[32], R_buf[32];
	
	if (len > ((sizeof(W_buf)) - 1))
    {
        len = (sizeof(W_buf)) - 1;
    }
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
	
	W_buf[0] = reg;
	for(i=1; i<len+1; i++)
	{
		W_buf[i] = 0xff;
	}
	
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = len + 1;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SCSPI_Read_TX_ADDR_reg():SPI_IOC_MESSAGE");
		return -1;
	}
	
	for(i=0; i<(len+1); i++)
	{
		pBuf[i] = R_buf[i+1];  //R_buf[0] is the return flag
	}
	return 0;
}
 
int rfBeginTransfer(int spifd,uChar value,uChar *pBuf1)
{
	int status;
	struct spi_ioc_transfer transfer_data[1];
	uChar	W_buf[2]={0,0}, R_buf[2]={0,0};
	
	memset(transfer_data, 0, sizeof transfer_data);
	
	W_buf[0] = value;
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = 1;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("rfBeginTransfer():SPI_IOC_MESSAGE");
		return -1;
	}
	
	pBuf1[0] = R_buf[0]; 
	pBuf1[1] = R_buf[1]; 
	
	return 0;
}

/**********************************************************************
* 函数名称 : NRF24L01_SelCheck_Exist
*  函数功能 : 判断NRF24L01是否存在或损坏,
*             方法: 向NRF24L01写5个数据然后再读回来进行比较,
*                   相同时返回值:1,表示存在;否则返回0,表示不存在。
**********************************************************************/
int  nRF2401SelfCheckExist(int spifd)
{
	  uChar  selfCheck_buf_0[5]={0XA5,0XA5,0XA5,0XA5,0XA5};
	  uChar  selfCheck_buf_1[5]={0,0,0,0,0};
	  uChar  i;

	  SCSPI_Write_TX_ADDR_reg(spifd,SCWRITE_REG+SCTX_ADDR, selfCheck_buf_0, 5);
	  SCSPI_Read_TX_ADDR_reg(spifd,SCREAD_REG+SCTX_ADDR, selfCheck_buf_1, 5);
	 
	  for( i = 0 ; i < 5 ; i++ )
	  {
		  printf("selfCheck_buf_1[%d]=%#x\n",i,selfCheck_buf_1[ i ]);
		  if( selfCheck_buf_1[ i ] != 0xA5 )
		  {
			  break;					   
		  }
	  }

	  if( i == 5 )
	  {
		  return 0 ; 
	  }
	  else
	  {
		  return -1 ; 
	  }

}	


/*
  待机模式Ⅰ:
  (1)处于上电状态
  (2)不管是发送还是接收模式,只要CE为低电平,此时进入待机模式Ⅰ
  (3)此时无数据传输
  待机模式Ⅱ:
  (1)处于上电状态
  (2)处于发送模式,即PRIM_RX位为0
  (3)发送端TX FIFO寄存器为空,并且CE为高电平时进入待机模式Ⅱ
  其他注意:
  (1)在待机模式期间,配置寄存器内存保持不变
  (2)根据RF芯片手册的时序说明,掉电模式到待机模式的转换时间最长不能超过1.5ms,
       最小无限制,待机模式到发送/接收模式最大不能超过130us
  (3)CE高电平持续时间不能少于10us
  (4)CSN为低电平,CE上升沿的延迟时间不能少于4us
  (5)RF在掉电模式转入发射模式或接收模式前必须经过1.5ms的待机模式
 */
void TX_Mode(int gpiofd,int spifd,uChar *addr,uChar * txBuf)
{	
	//CE_0;	 待机模式Ⅰ开始
    ioctl(gpiofd, XEINT12_B, LOW);

	SPI_Write_Reg(spifd,WRITE_REG+CONFIG, 0x0e);
	SPI_Write_Reg(spifd,FLUSH_TX, 0xff);
	
	SPI_Write_Buf(spifd,WRITE_REG+TX_ADDR, addr, TX_ADR_WIDTH);
	SPI_Write_Buf(spifd,WRITE_REG+RX_ADDR_P0, addr, RX_ADR_WIDTH);
	SPI_Write_Buf(spifd,WR_TX_PLOAD,txBuf,TX_PLOAD_WIDTH);//装入数据
	
	SPI_Write_Reg(spifd,WRITE_REG+EN_AA, 0x01);
	SPI_Write_Reg(spifd,WRITE_REG+EN_RXADDR, 0x01);
	SPI_Write_Reg(spifd,WRITE_REG+SETUP_RETR, 0x3F);
	SPI_Write_Reg(spifd,WRITE_REG+RF_CH, 0x70);//频段为0x70
	SPI_Write_Reg(spifd,WRITE_REG+RF_SETUP, 0x0f);
	SPI_Write_Reg(spifd,WRITE_REG+SETUP_AW, 0x03);
	
	//CE_1;	 待机模式Ⅰ结束
    ioctl(gpiofd, XEINT12_B, HIGH);//启动发送 高电平保持时间>10us
}
 

void RX_Mode(int gpiofd,int spifd,uChar *addr)
{
	//CE_0;   进入待机Ⅰ模式
    ioctl(gpiofd, XEINT12_B, LOW);
	
	SPI_Write_Reg(spifd,WRITE_REG+CONFIG, 0x0F);
	SPI_Write_Reg(spifd,FLUSH_RX, 0xff);
	
	SPI_Write_Buf(spifd,WRITE_REG+RX_ADDR_P0, addr, RX_ADR_WIDTH); 
	
	SPI_Write_Reg(spifd,WRITE_REG+EN_AA, 0x01);
	SPI_Write_Reg(spifd,WRITE_REG+EN_RXADDR, 0x01);
	SPI_Write_Reg(spifd,WRITE_REG+RF_CH, 0x70);
	SPI_Write_Reg(spifd,WRITE_REG+RX_PW_P0, RX_PLOAD_WIDTH);
	SPI_Write_Reg(spifd,WRITE_REG+RF_SETUP, 0x0f);
	SPI_Write_Reg(spifd,WRITE_REG+SETUP_AW, 0x03);
	
	//CE_1;
    ioctl(gpiofd,XEINT12_B, HIGH);//启动接收模式
	//usleep(160);  //>130us,from rf datasheet 
}


int SPI_Write_Reg(int spifd,uChar reg,uChar value)
{
	int status;
	struct spi_ioc_transfer transfer_data[1];
	uint8_t	W_buf[2], R_buf[2];
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
	
	W_buf[0] = reg;
	W_buf[1] = value;
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = 2;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SPI_Write_Reg():SPI_IOC_MESSAGE\n");
		return -1;
	}
	
	return 0;
}


int SPI_Read_Reg(int spifd,uChar reg,uChar *buf)
{
	int status;
	struct spi_ioc_transfer transfer_data[1];
	uint8_t	W_buf[2], R_buf[2];
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
	
	W_buf[0] = reg;
	W_buf[1] = 0xff;
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = 2;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SPI_Read_Reg():SPI_IOC_MESSAGE\n");
		return -1;
	}
	memcpy(buf, R_buf, sizeof(R_buf));
	return 0;
}


int SPI_Write_Buf(int spifd,uChar reg, uChar *pBuf, uChar len)
{
	int status;
	uChar i, j;
	struct spi_ioc_transfer transfer_data[1];
	uChar	W_buf[32], R_buf[32];
	
	
	if (len > ((sizeof(W_buf)) - 1))
    {
        len = (sizeof(W_buf)) - 1;
    }
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
 
	W_buf[0] = reg;
	
	for(i=1,j=0; j<len; i++,j++) {
		W_buf[i] = pBuf[j];
	}
	
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = len + 1;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SPI_Write_Buf():SPI_IOC_MESSAGE\n");
		return -1;
	}
	
	return 0;
}


int SPI_Read_Buf(int spifd,uChar reg, uChar *pBuf, uChar len)
{
	int status, i = 0;
	struct spi_ioc_transfer transfer_data[1];
	uint8_t	W_buf[32], R_buf[32];
	
	if (len > ((sizeof(W_buf)) - 1))
    {
        len = (sizeof(W_buf)) - 1;
    }
	
	memset(transfer_data, 0, sizeof transfer_data);
	memset(W_buf, 0, sizeof W_buf);
	memset(R_buf, 0, sizeof R_buf);
	
	W_buf[0] = reg;
	for(i=1; i<len+1; i++)
	{
		W_buf[i] = 0xff;
	}
	
	transfer_data[0].tx_buf = (unsigned long)W_buf;
	transfer_data[0].rx_buf = (unsigned long)R_buf;
	transfer_data[0].len = len + 1;
	
    status = ioctl(spifd, SPI_IOC_MESSAGE(1), transfer_data);
	if (status < 0) 
	{
		perror("SPI_Read_Buf():SPI_IOC_MESSAGE\n");
		return -1;
	}
	
	for(i=0; i<(len+1); i++)
	{
		pBuf[i] = R_buf[i+1];  //R_buf[0] is the return flag
	}
	return 0;
}

int RF_Send_to_MSub(int spifd)
{	
	int loop = 0;
	uChar TxStatBuf[2]={0,0};
	do {
		usleep(1000);//这个时间的确定:(1)主机和子机开机,然后用1ms延时,看串口打印终端loop的值,如果是loop=5,表示5ms后收到接收方的回应帧,表示发送成功,并且每次轮询都是5ms,那么就可以把这里延时改为5ms,这样能减少do...while循环里面函数的调用次数,减少无用的开销。(2)实际考虑时,要考虑循环里面函数执行时间的开销
		SPI_Read_Reg(spifd,READ_REG+STATUS,TxStatBuf);
        //printf("RF24L01_transmit():TxStatBuf[0] = 0x%02x,TxStatBuf[1] = 0x%02x,send_loop=%d\n", TxStatBuf[0], TxStatBuf[1],loop);
		loop++; 
	} while ( (TxStatBuf[1] == 0x0e) && (loop < 333));
	
	SPI_Write_Reg(spifd,WRITE_REG+STATUS,TxStatBuf[1]);//clear STATUS
	
	if( (TxStatBuf[1]) & TX_OK) 
	{
		SPI_Write_Reg(spifd,FLUSH_TX, 0xff);//如果收到应答信号,则认为数据成功发送到接收端,此时状态寄存器TX_DS位置高,并把数据冲TX FIFO中清掉(马上清理缓冲区)
		//printf("\nRF_Send_to_MSub(): TxStatBuf[0]=%#x,TxStatBuf[1]=%#x,send_loop=%d, rf  send successful\n",TxStatBuf[0],TxStatBuf[1],loop);
		return 1;
	}
	else if( (TxStatBuf[1]) & MAX_TX )
	{
		SPI_Write_Reg(spifd,FLUSH_TX, 0xff);
		printf("\nRF_Send_to_MSub():send_loop=%d,rf send Times Out\n",loop);
		return 0;
	}
	else
	{	
		printf("\nRF_Send_to_MSub(): rf send failed!\n");
		return -1;
	}
}


void RF_Revc_from_MSub(int spifd,uChar *rxBuf)
{
	int loop = 0;
	uChar RxStatBuf[2]={0,0};
	do { 
		 usleep(6000);
		 
		 //usleep(1000); 这种情况会出现频繁超时现象,改成50ms后超时偶尔发生
		 SPI_Read_Reg(spifd,READ_REG+STATUS,RxStatBuf);
		 
		 SPI_Write_Reg(spifd,WRITE_REG+STATUS, RxStatBuf[1]);
		
		 if( RxStatBuf[1] == 0x4e )
			 printf("RF_Revc_from_MSub():RxStatBuf[0]=%#x,RxStatBuf[1]=%#x,loop-rev=%d,rf rev 0x4E\n",RxStatBuf[0],RxStatBuf[1],loop);
		
		 if((RxStatBuf[1] != 0x4e) && (RxStatBuf[1] & RX_OK))
		 {
			SPI_Read_Buf(spifd,RD_RX_PLOAD, rxBuf, RX_PLOAD_WIDTH);
			SPI_Write_Reg(spifd,FLUSH_RX, 0xff); // 接收有效数据完成后,马上清理缓冲区
			//printf("RF_Revc_from_MSub():rxBuf[0]=%#x,rxBuf[1]=%#x,loop-rev=%d,rf rev successful\n",rxBuf[0],rxBuf[1],loop);
			//printf("\n");
			break;
		 }
		 else 
		 { 
			//printf("RF_Revc_from_MSub():loop-rev=%d,rf rev failed\n",loop);
			//SPI_Write_Reg(spifd,FLUSH_RX, 0xff);  //如果调用这一句  会出现0x4e
		 }
		 loop++;
	} while(loop < 25);//while(loop < 1000);
	
	//SPI_Write_Reg(spifd,WRITE_REG+CONFIG, 0x0D);  //这里注释掉,表示不进入掉电模式
}

头文件:

#ifndef SPIRF2401_H
#define SPIRF2401_H

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>//memset
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>


#define SCREAD_REG        0x00
#define SCWRITE_REG       0x20
#define SCTX_ADDR         0x10

/************* nRF24L01 register command *************/
#define READ_REG        0x00
#define WRITE_REG       0x20
#define RD_RX_PLOAD     0x61
#define WR_TX_PLOAD     0xA0
#define FLUSH_TX        0xE1
#define FLUSH_RX        0xE2
#define REUSE_TX_PL     0xE3
#define NOP             0xFF


/************* nRF24L01 register address *************/
#define CONFIG          0x00
#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
#define RX_ADDR_P1      0x0B
#define RX_ADDR_P2      0x0C
#define RX_ADDR_P3      0x0D
#define RX_ADDR_P4      0x0E
#define RX_ADDR_P5      0x0F
#define TX_ADDR         0x10
#define RX_PW_P0        0x11
#define RX_PW_P1        0x12
#define RX_PW_P2        0x13
#define RX_PW_P3        0x14
#define RX_PW_P4        0x15
#define RX_PW_P5        0x16
#define FIFO_STATUS     0x17


/************* send and receive data width *************/
#define TX_ADR_WIDTH    5	//send address width
#define RX_ADR_WIDTH    5	//rcve address width
#define TX_PLOAD_WIDTH  2	//send data width
#define RX_PLOAD_WIDTH  2	//rcve data width


/************* send and receive status *************/
#define MAX_TX  0x10
#define TX_OK   0x20
#define RX_OK   0x40


/******************** the others ******************/

//ioctl(fd,IOCTL_LED_1, LED_ON);//
#define IOCTL_LED_1 1
#define IOCTL_LED_2 2
#define IOCTL_LED_3 3
#define IOCTL_LED_4 4
#define LED_ON 0
#define LED_OFF 1


#define XEINT12_B  12
#define XEINT13_B  13

#define LOW 0
#define HIGH 1

typedef unsigned char uChar;

int spiOpen(void);
int gpioOpen(void);
void spiClose(int spifd);
void gpioClose(int gpiofd);
int spiSet(int fd);
void nRF24L01Init(int gpiofd);
int SCSPI_Write_TX_ADDR_reg(int spifd,uChar reg, uChar *pBuf, uChar len);
int SCSPI_Read_TX_ADDR_reg(int spifd,uChar reg, uChar *pBuf, uChar len);
int rfBeginTransfer(int spifd,uChar value,uChar *pBuf1);
int  nRF2401SelfCheckExist(int spifd);
void TX_Mode(int gpiofd,int spifd,uChar *addr,uChar * txBuf);
void RX_Mode(int gpiofd,int spifd,uChar *addr);
int SPI_Write_Reg(int spifd,uChar reg,uChar value);
int SPI_Read_Reg(int spifd,uChar reg,uChar *buf);
int SPI_Write_Buf(int spifd,uChar reg, uChar *pBuf, uChar len);
int SPI_Read_Buf(int spifd,uChar reg, uChar *pBuf, uChar len);
int RF_Send_to_MSub(int spifd);
void RF_Revc_from_MSub(int spifd,uChar *rxBuf);


#endif

上一篇:【OpenCV】访问Mat图像中每个像素的值


下一篇:单片机:数码管显示计时,LED0 1 1秒一闪 LED2 3 1分一闪 LED5 LED6 1小时一闪 K1 K2调整时 K3 K4调整分钟