本文介绍了基于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