简单记录下XN297L 四线SPI读写寄存器
前言
为避免吃灰,研究了下面买了很久的板子。因为便宜,照例只有发送板,没有接收板。配对不大可能,拆机比较现实。关于拆机价值最难利用的就是打磨过的MCU和其他IC。MCU是16p,12脚VCC,5脚GND,无从考证,放弃了。2.4g模块是本文重点。那个带天线独立于主板之外的红色小板就是2.4g模块,牛屎芯片,无管脚定义。主板上有丝印297,可以确认是XN297L无疑。剩下的就是确认管脚顺序了。
一、管脚确认
查了一下XN297L数据手册,XN297L有两种封装,QFN20 3x3 和SOP8。
开始认为SOP8小一点,牛屎糊起来更方便,可能是SOP8,于是找了SOP8的三线SPI程序编写了测试程序。管脚不知道,但先试吧,怎么试都不行。后来又研究了一下封装,感觉QFN20 3x3更为可能:
因为红色小板上引出了8个管脚,应该是VCC、GND、CE、CSN、SCK、MOSI、MISO、IRQ。sop8正好8个管脚,但XC1、XC2接的是晶振,ANT接天线,只剩5个需要引出。所以排除sop8封装。
下面就要确认管脚顺序。如果盲目试管脚,不考虑VCC、GND、IRG(悬空),会有5*4*3*2*1种可能,非人力可为。换一种思路猜管脚顺序其实也很简单,VCC、GND万用表可以确认。其他6个管脚可以看线路的走势辨别,因为为了布线方便,管脚之间的前后关系应该是不会变的。于是得到下图
二、XN297 四线SPI读写寄存器测试
通过读写寄存器可以确认XN297是XN297,并且管脚正确。main.c源码如下:
#include <STC89C5xRC.H>
#include <intrins.h>
sbit CE=P1^0;
sbit CS=P1^1;
sbit SCK=P1^2;
sbit MOSI=P1^3;
sbit MISO=P1^4;
const unsigned char TX_ADDRESS_DEF[5] = {0xcc,0xCC,0xCC,0xCC,0xCC}; //RF 地址:接收端和发送端需一致
#define HIGH (1)
#define LOW (0)
#define CSN_HIGH (CSN |= HIGH)
#define CSN_LOW (CSN &= LOW)
#define SCK_HIGH (SCK |= HIGH)
#define SCK_LOW (SCK &= LOW)
#define SPI_DATA_HIGH (DATA |= HIGH)
#define SPI_DATA_LOW (DATA &= LOW)
#define SPI_DATA_STATUS (DATA)
#define SPI_DATA_OUTPUT_MODE ;
#define SPI_DATA_INPUT_MODE ;
#define CE_HIGH RF_WriteReg(CE_FSPI_ON, 0)
#define CE_LOW RF_WriteReg(CE_FSPI_OFF, 0)
/********************SPI REGISTER ********************/
#define R_REGISTER 0x00 //SPI read RF data
#define W_REGISTER 0x20 //SPI write RF data
#define R_RX_PAYLOAD 0x61 //Read RX Payload
#define W_TX_PAYLOAD 0xA0 //Write TX Payload
#define FLUSH_TX 0xE1 //Flush RX FIFO
#define FLUSH_RX 0xE2 //Flush TX FIFO
#define REUSE_TX_PL 0xE3 //Reuse TX Payload
#define ACTIVATE 0x50 //ACTIVATE
#define DEACTIVATE 0x50 //DEACTIVATE
#define R_RX_PL_WID 0x60 //Read width of RX data
#define W_ACK_PAYLOAD 0xA8 //Data with ACK
#define W_TX_PAYLOAD_NOACK 0xB0 //TX Payload no ACK Request
#define CE_FSPI_ON 0xFD // CE HIGH
#define CE_FSPI_OFF 0xFC // CE LOW
#define RST_FSPI 0x53 // RESET
#define NOP_N 0xFF
/******************CONTROL REGISTER*******************/
#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 DATAOUT 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
#define DEM_CAL 0x19
#define RF_CAL2 0x1A
#define DEM_CAL2 0x1B
#define DYNPD 0x1C
#define FEATURE 0x1D
#define RF_CAL 0x1E
#define BB_CAL 0x1F
/
/*************************CONTROL CMD***********************************************/
#define RF13dBm 0x3F // 13dBm 发射档位功率设置
#define RF10dBm 0X0F // 10dBm
#define RF8dBm 0x15 // 8dbm
#define RF7dBm 0x07 // 7dbm
#define RF5dBm 0x2c // 5dbm
#define RF4dBm 0x06 // 4dbm
#define RF2dBm 0x05 // 2dbm
#define RF0dBm 0X0B // 0dBm
#define RF_3dBm 0x04 // -3dBm
#define RF_6dBm 0x0A // -6dBm
#define RF_10dBm 0x02 // -10dBm
#define RF_18dBm 0x01 // -18dBm
#define RF_30dBm 0x00 // -30dBm
#define DR_1M 0X00 //通信速率 1Mbps
#define DR_2M 0X40 //通信速率 2Mbps
#define DR_250K 0XC0 //通信速率 250Kbps
#define RX_DR_FLAG 0X40 // 接收中断标志位
#define TX_DS_FLAG 0X20 // 发送完成中断标志位
#define RX_TX_CMP_FLAG 0X60 // 发送接收完成中断标志位,ack_payload 模式下使用
#define MAX_RT_FLAG 0X10 // 发送重传超时中断标志位
#define TRANS_ENHANCE_MODE 1 //传输类型增强型
#define TRANS_BURST_MODE 2 //传输类型普通型
#define RxMode 1
#define RxMode_RTTE 2
#define DEFAULT_CHANNEL 78 //初始化时的频率: 2478 MHz
#define PAYLOAD_WIDTH 16 //Payload宽度: 8bytes
#define TRANSMIT_TYPE TRANS_BURST_MODE //使用普通型模式 TRANS_BURST_MODE TRANS_ENHANCE_MODE
#define DATA_RATE DR_1M //通信速率1Mbps DR_2M DR_1M DR_250K
#define RF_POWER (RF13dBm |DATA_RATE) //发射功率13dBm
#define RF_MODE RxMode_RTTE // RxMode_RTTE
typedef unsigned long Uint16;
typedef unsigned char Uint8;
void UART_int(Uint16 baud);
void Sentdata(Uint8 dat);
unsigned char XN297_Check(void);
Uint8 temp;
void SPI_init(void);
void RF_WriteReg( unsigned char reg, unsigned char wdata);
void RF_WriteBuf( unsigned char reg, unsigned char *pBuf, unsigned char length);
void Delay1000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 8;
j = 1;
k = 243;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay10ms() //@11.0592MHz
{
unsigned char i, j;
i = 18;
j = 235;
do
{
while (--j);
} while (--i);
}
void RF_Init(void)
{
#if(DATA_RATE == DR_1M)
unsigned char BB_cal_data[] = {0x0A,0x6D,0x67,0x9C,0x46}; //1M速率配置
unsigned char RF_cal_data[] = {0xF6,0x37,0x5D};
unsigned char RF_cal2_data[] = {0x45,0x21,0xef,0x2C,0x5A,0x50};
unsigned char Dem_cal_data[] = {0x01};
unsigned char Dem_cal2_data[] = {0x0b,0xDF,0x02};
#elif(DATA_RATE == DR_250K)
/*
// unsigned char BB_cal_data[] = {0x0A,0x6D,0x67,0x9C,0x46}; //250K速率配置
unsigned char BB_cal_data[] = {0x0A,0xeD,0x7F,0x9C,0x46};
unsigned char RF_cal_data[] = {0xF6,0x37,0x5D};
unsigned char RF_cal2_data[] = {0xD5,0x21,0xeb,0x2C,0x5A,0x40};
unsigned char Dem_cal_data[] = {0x1e};
unsigned char Dem_cal2_data[] = {0x0b,0xDF,0x02};
*/
unsigned char BB_cal_data[] = { 0x12,0xec,0x6f,0xa1,0x46};
unsigned char RF_cal_data[] = {0xF6,0x37,0x5d};
unsigned char RF_cal2_data[] = {0xd5,0x21,0xeb,0x2c,0x5a,0x40};
unsigned char Dem_cal_data[] = {0x1f};
unsigned char Dem_cal2_data[] = {0x0b,0xdf,0x02};
#endif
SPI_init();
RF_WriteReg(RST_FSPI, 0x5A); //Software Reset
RF_WriteReg(RST_FSPI, 0XA5);
// RF_WriteReg(W_REGISTER + FEATURE, 0x20); // enable Software control ce
if(PAYLOAD_WIDTH <33)
{
RF_WriteReg(W_REGISTER +FEATURE, 0x27); //切换到32byte模式 使能CE
}
else
{
RF_WriteReg(W_REGISTER +FEATURE, 0x38); //切换到64byte模式
}
//CE_LOW;
CE=0;//5.1
RF_WriteReg(FLUSH_TX, 0); // CLEAR TXFIFO
RF_WriteReg(FLUSH_RX, 0); // CLEAR RXFIFO
RF_WriteReg(W_REGISTER + STATUS, 0x70); // CLEAR STATUS
RF_WriteReg(W_REGISTER + EN_RXADDR, 0x01); // Enable Pipe0
RF_WriteReg(W_REGISTER + SETUP_AW, 0x03); // address witdth is 5 bytes
RF_WriteReg(W_REGISTER + RF_CH, DEFAULT_CHANNEL); // 2478M HZ
RF_WriteReg(W_REGISTER + RX_PW_P0, PAYLOAD_WIDTH); // 8 bytes
RF_WriteBuf(W_REGISTER + TX_ADDR, ( unsigned char*)TX_ADDRESS_DEF, sizeof(TX_ADDRESS_DEF)); // Writes TX_Address to PN006
RF_WriteBuf(W_REGISTER + RX_ADDR_P0,( unsigned char*)TX_ADDRESS_DEF, sizeof(TX_ADDRESS_DEF)); // RX_Addr0 same as TX_Adr for Auto.Ack
RF_WriteBuf(W_REGISTER + BB_CAL, BB_cal_data, sizeof(BB_cal_data));
RF_WriteBuf(W_REGISTER + RF_CAL2, RF_cal2_data, sizeof(RF_cal2_data));
RF_WriteBuf(W_REGISTER + DEM_CAL, Dem_cal_data, sizeof(Dem_cal_data));
RF_WriteBuf(W_REGISTER + RF_CAL, RF_cal_data, sizeof(RF_cal_data));
RF_WriteBuf(W_REGISTER + DEM_CAL2, Dem_cal2_data,sizeof(Dem_cal2_data));
RF_WriteReg(W_REGISTER + DYNPD, 0x00);
RF_WriteReg(W_REGISTER + RF_SETUP, RF_POWER); // 13DBM
#if(TRANSMIT_TYPE == TRANS_ENHANCE_MODE)
RF_WriteReg(W_REGISTER + SETUP_RETR,0x03); // 3 retrans...
RF_WriteReg(W_REGISTER + EN_AA, 0x01); // Enable Auto.Ack:Pipe0
#elif(TRANSMIT_TYPE == TRANS_BURST_MODE)
RF_WriteReg(W_REGISTER + SETUP_RETR,0x00); // Disable retrans...
RF_WriteReg(W_REGISTER + EN_AA, 0x00); // Disable AutoAck
#endif
}
void SPI_init(void)
{
CE =0;
CS = 1;
SCK = 0;
MOSI = 1;
}
void SPI_Write_Byte(unsigned char dat)
{
unsigned char i;
for (i = 0; i < 8; i++)
{
SCK = 0;
MOSI = dat & 0x80;
dat <<= 1;
SCK = 1;
}
SCK = 0;
}
unsigned char SPI_Read_Byte(void)
{
unsigned char i, dat = 0;
for (i = 0; i < 8; i++)
{
SCK = 0;
dat <<= 1;
SCK = 1;
if (MISO)
{
dat |= 0x01;
}
}
SCK = 0;
return dat;
}
unsigned char Read_Register(unsigned char reg_addr)
{
unsigned char dat;
CS = 0;
SPI_Write_Byte(reg_addr | 0x80);
dat = SPI_Read_Byte();
CS = 1;
return dat;
}
void RF_WriteReg( unsigned char reg, unsigned char wdata)
{
CS=0;
SPI_Write_Byte(reg);
SPI_Write_Byte(wdata);
CS=1;
}
void RF_WriteBuf( unsigned char reg, unsigned char *pBuf, unsigned char length)
{
unsigned char j;
CS=0;
j = 0;
SPI_Write_Byte(reg);
for(j = 0;j < length; j++)
{
SPI_Write_Byte(pBuf[j]);
}
j = 0;
CS=1;
}
/*
unsigned char ucRF_ReadReg( unsigned char reg)
{
unsigned char data1;
CS=0;
SPI_Write_Byte(reg);
data1 = SPI_Read_Byte();
//SPI_DATA_OUTPUT_MODE;
CS=1;
return data1;
}
*/
void RF_ReadBuf( unsigned char reg, unsigned char *pBuf, unsigned char length)
{
unsigned char byte_ctr;
CS=0;
SPI_Write_Byte(reg);
for(byte_ctr=0;byte_ctr<length;byte_ctr++)
pBuf[byte_ctr] = SPI_Read_Byte();
SPI_DATA_OUTPUT_MODE;
CS=1;
}
void RF_TxMode(void)
{
CE=0;
RF_WriteReg(W_REGISTER + CONFIG, 0X8E); // 将RF设置成TX模式
Delay10ms();
CE=1;//5.1
Delay10ms();
}
void main(void)
{
UART_int(9600);
EA =1;
RF_Init();
RF_TxMode();
Sentdata(0x33);
// 进一步处理读取结果
while(1){
XN297_Check();
Delay1000ms();
}
}
unsigned char XN297_Check(void)
{
unsigned char check_in_buf[5]={0x55,0xaa,0x55,0xaa,0x55};
unsigned char check_out_buf[5]={0x00};
unsigned char i;
//CE_HIGH;
RF_WriteBuf(W_REGISTER+TX_ADDR,check_in_buf,5);
RF_ReadBuf(R_REGISTER+TX_ADDR,check_out_buf,5);
for(i=0;i<5;i++)
{
Sentdata(check_out_buf[i]);
}
if((check_out_buf[0]==0x55)&&\
(check_out_buf[1]==0xaa)&&\
(check_out_buf[1]==0x55)&&\
(check_out_buf[1]==0xaa)&&\
(check_out_buf[1]==0x55))
return 0;
else
return 1;
}
void UART_int(Uint16 baud)
{
TMOD = (TMOD&0X0F)|0X20;
TH1 = 256-11059200/32/12/baud;
TL1 = TH1;
TR1 = 1;
ET1 = 0;
SCON = 0X50;
ES = 1;
}
void Sentdata(Uint8 dat)
{
SBUF =dat;
while(TI==0);
TI =0;
}
void UART() interrupt 4
{
if(RI==1)
{
RI=0;
temp =SBUF;
}
}
主要用于测试的函数是:
unsigned char XN297_Check(void)
{
unsigned char check_in_buf[5]={0x55,0xaa,0x55,0xaa,0x55};
unsigned char check_out_buf[5]={0x00};
unsigned char i;
//CE_HIGH;
RF_WriteBuf(W_REGISTER+TX_ADDR,check_in_buf,5);
RF_ReadBuf(R_REGISTER+TX_ADDR,check_out_buf,5);
for(i=0;i<5;i++)
{
Sentdata(check_out_buf[i]);
}
if((check_out_buf[0]==0x55)&&\
(check_out_buf[1]==0xaa)&&\
(check_out_buf[1]==0x55)&&\
(check_out_buf[1]==0xaa)&&\
(check_out_buf[1]==0x55))
return 0;
else
return 1;
}
就是向TX_ADDR寄存器写入0x55,0xaa,0x55,0xaa,0x55,然后通过RF_ReadBuf(R_REGISTER+TX_ADDR,check_out_buf,5)读出来保存到check_out_buf并发送给串口,通过串口助手得到:
收到“0x55,0xaa,0x55,0xaa,0x55”,说明假设成立。
三、总结
1、XN297L不同的封装,对应有三线或四线SPI。
2、猜管脚顺序最好看明白数据手册再来,事半功倍。