基于STM32的无线通信模块使用—A7130
2.4G Hz的无线通信芯片A7130。本文简单介绍A7130的使用。
注:相关资源在这里
- A7130简介
- A7130 SPI接口
- A7130寄存器配置及初始化
- A7130数据传输
- A7130扩展
- A7130总结
一、A7130简介
A7130 is a high performance and low cost 2.4GHz ISM band wireless transceiver.user can configure on-air data rates to either 3Mbps or 4Mbps.
A7130 supports fast settling time (100 us) for frequency hopping system. For packet handling, A7130 has built-in separated.64-bytes TX/RX FIFO (could be logically extended to 4K bytes) for data buffering and burst transmission, auto-ack and auto-resend, CRC for error packet filtering
A7130’s control registers are accessed via 3-wire or 4-wire SPI interface such as TX/RF FIFO, ID register, RSSI value.
Another one, via SPI as well, is the unique Strobe command, A7130 can be controlled from power saving mode (deep sleep, sleep, idle, standby), TX mode, RX mode. In addition to the SPI, other connections between A7130 and MCU are GIO1 and GIO2, multi-function GPIO, to output A7130’s status so that MCU could use either polling or interrupt scheme for radio control.
从datasheet上面的信息可以得知A7130的几个特性:
1、A7130的传输速度有3Mbps和4Mbps两种,可见这速度传输图片数据完全是没问题的。
2、A7130有64Bytes的TX/RX FIFO,可扩展到4KBytes,这么大的FIFO,说明读写效率蛮可观的。支持自动应答自动重传,CRC校验,这在一定程度上保证了数据传输的可靠性。
3、A7130的控制寄存器支持3线或者4线的SPI方式的读写,也就是说无论是读写寄存器还是读写FIFO,都是通过SPI方式实现的。
4、A7130支持多种模式,可保证低功耗。
上面的这些信息将有助于我们接下来程序的编写。
二、A7130 SPI接口
1、接口说明
A7130 only supports one SPI interface with maximum data rate up to 10Mbps. MCU should assert SCS pin low (SPI chip select) to active accessing of A7130. Via SPI interface, user can access control registers and issue Strobe command.
3-wire SPI (SCS, SCK and SDIO) or 4-wire SPI (SCS, SCK, SDIO and GIO1/GIO2) configuration is provided. For 3-wire SPI, SDIO pin is configured as bi-direction to be data input and output. For 4-wire SPI, SDIO pin is data input and GIO1 (or GIO2) pin is data output. In such case, GIO1S (0bh) or GIO2S (0ch) should be set to [0110].
手册上说了需将SCS引脚拉低以选中芯片。3线SPI方式,SDIO引脚要配置成双向输入输出引脚。对于4线的SPI,SDIO作为输入引脚,GIO1和GIO2配置成输出引脚。配置GIO1和GIO2需要将控制寄存器Reg0b的GIO1S置为0110或Reg0c的GIO2S置为0110.
A7130支持8中模式(Sleep,Idle,STBY,PLL,RX,TX,FIFO Write Reset,FIFO Read Reset)。在实际的编程中,后四种模式直接的状态切换需要特别的注意。
2、SPI接口配置
在程序中,我们使用的是4线的SPI方式,使用到GIO2作为输出。
STM32引脚 | A7130引脚 |
---|---|
SPI_CS | SCS |
SPI_CLK | SCK |
SPI_MISO | GIO2 |
SPI_MOSI | SDIO |
GPIOA_P1 | GIO1 |
至于为什么要把GIO1接到PA1上面。因为在手册中提到无论是数据从FIFO发出去完成还是从FIFO中接收完成,都将要有一个标记来进行判断,此处我们把GIO1配置成发送接收完成的标记。
在Reg0c中,我们将GIO1配置成WTR(Wait until TX or RX Finished)。
在发送模式下,进入TX Mode,然后在RF Port中经过一小段时间(PDL+TDL,这段时间可通过寄存器控制),芯片自动在数据前面加上Premable等数据然后发送出去,此时WTR(GIO1)为高电平,当数据传输结束之后,WTR置为低电平,芯片自动进去PLL Mode。这样我们就可以通过判断GIO1的引脚变化来判断数据发送或者接收是否完成。
配置相关的SPI引脚之后,我们调用
A7130_SPI_Init()
函数,且之后调用
A7130_CS_HIGH()
把A7130的SCS引脚拉高,只有当我们对A7130进行操作时才拉低该引脚。当然,上面那两个函数要自己去封装实现。
三、A7130寄存器配置及初始化
1、A7130配置代码生成器
当SPI配置完成后我们就要检验SPI是否通。最简单的方式就是去读写它的芯片ID,看返回值是否是正确的,但是这步还不能实现。因为要读写芯片的ID之前要对A7130进行初始化操作,具体怎么初始化,在手册上面并没有说。那么怎么验证呢?首先尝试着去读写某个寄存器,通过示波器看看时钟是否正确,SPI写入是否正确以及时序是否正确。当这些都确认无误后,我们再去初始化A7130。
笙科公司为开发人员提供了一个工具RC_A7130_ReferenceCodeGenerator.exe可生成A7130的寄存器配置代码,不过生成的代码是仿SPI时序的,不是我们用的STM32固件的SPI接口,所以还需要修改部分代码。
注意红色的区域要根据自己的配置进行选择。其中的RF IO Setting中除WTR外都可不用配置。
生成三个文件A7130reg.h(定义寄存器的名称),define.h(数据类型的相关定义),main.c(主程序)。
2、main.c
2.1、各个寄存器的值
这里面包含A7130所有寄存器的配置信息以及数据发送接收的示例程序。这里只贴出配置信息。
//-----------------------------------------------------------------------------
// RF ID code
//-----------------------------------------------------------------------------
const Uint8 code ID_Tab[] =
{
0x54, 0x75, 0xC5, 0x2A
};
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE !!
// !! THIS CONFIG TABLE ONLY USE ON RF CRYSTAL = 16MHz !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
const Uint16 code A7130Config[] =
{
// address name Descript
// ------- ---- ---------
0x00, //0x00 ; MODE_REG only reset, not use on config
0x62, //0x01 ; MODE_CONTROL_REG FIFO mode, Enable ARSSI, Enable AIF
0x00, //0x02 ; CALIBRATION_REG
0x3F, //0x03 ; FIFO1_REG
0x00, //0x04 ; FIFO2_REG
0x00, //0x05 ; FIFO_REG
0x00, //0x06 ; IDCODE_REG
0x00, //0x07 ; RCOSC1_REG
0x00, //0x08 ; RCOSC2_REG
0x00, //0x09 ; RCOSC3_REG
0x00, //0x0A ; CKO_REG
0x01, //0x0B ; GIO1 register, WTR
0x19, //0x0C ; GIO2 register, SDO
0x9F, //0x0D ; DATARATE_REG
0x00, //0x0E ; PLL1_REG
0x0E, //0x0F ; PLL2_REG RFbase 2400.001MHz
0x96, //0x10 ; PLL3_REG
0x00, //0x11 ; PLL4_REG
0x04, //0x12 ; PLL5_REG
0x3C, //0x13 ; ChannelGroup1 register
0x78, //0x14 ; ChannelGroup2 register
0xAF, //0x15 ; TX1_REG
0x40, //0x16 ; TX2_REG
0x10, //0x17 ; DELAY1_REG
0x60, //0x18 ; DELAY2_REG
0x70, //0x19 ; RX_REG
0x6F, //0x1A ; RXGAIN1
0xC2, //0x1B ; RXGAIN2
0x3D, //0x1C ; RXGAIN3
0xE7, //0x1D ; RXGAIN4
0x00, //0x1E ; RSSI_REG
0xF1, //0x1F ; ADC_REG
0x07, //0x20 ; CODE1_REG
0x06, //0x21 ; CODE2_REG
0x2A, //0x22 ; CODE3_REG
0x60, //0x23 ; IFCAL1_REG
0xFF, //0x24 ; IFCAL2_REG
0x80, //0x25 ; VCOCCAL_REG
0xD0, //0x26 ; VCOCAL1_REG
0x00, //0x27 ; VCOCAL2_REG
0x70, //0x28 ; VCO deviation 1 register
0x00, //0x29 ; VCO deviation 2 register
0x00, //0x2A ; DSA register
0xDC, //0x2B ; VCO Modulation delay register
0xF0, //0x2C ; BATTERY_REG
0x37, //0x2D ; TXTEST_REG
0x47, //0x2E ; RXDEM1_REG
0xF7, //0x2F ; RXDEM2_REG
0xF0, //0x30 ; CPC1_REG
0x37, //0x31 ; CPC2_REG
0x55, //0x32 ; CRYSTALTEST_REG
0x15, //0x33 ; PLLTEST_REG
0x15, //0x34 ; VCOTEST1_REG
0x00, //0x35 ; RF Analog register
0x00, //0x36 ; Key data register
0x77, //0x37 ; Channel select register
0x00, //0x38 ; ROM register
0x00, //0x39 ; DataRate register
0x00, //0x3A ; FCR register
0x00, //0x3B ; ARD register
0x00, //0x3C ; AFEP register
0x00, //0x3D ; FCB register
0x00, //0x3E ; KEYC register
0x00, //0x3F ; USID register
};
const Uint8 code A7130_Addr2A_Config[]=
{
0x34, //page0,
0x49, //page1,
0x00, //Page2,
0x80, //page3,
0x80, //page4,
0x00, //page5,
0x0A, //page6,
0x00, //page7,
};
const Uint8 code A7130_Addr38_Config[]=
{
0x00, //page0,
0x10, //page1,
0x20, //page2,
0x24, //page3,
0x20, //page4,
};
2.2、初始化
void initRF(void)
{
//init io pin
SCS = 1;
SCK = 0;
SDIO = 1;
GIO1 = 1;
GIO2 = 1;
A7130_Reset(); //reset A7105 RF chip
A7130_WriteID(); //write ID code
A7130_Config(); //config A7105 chip
A7130_Cal(); //calibration IF,VCO,VCOC
}
initRF();
StrobeCmd(CMD_STBY);
A7130_WriteReg( IFCAL2_REG, 0xFF ); //
A7130_WriteReg( TXTEST_REG, 0x37 ); // TX power = 5dBm
A7130_WriteReg( MODECTRL_REG, 0x62 ); // FIFO mode
A7130_WriteReg( PLL1_REG, 100 ); // set radio channel
A7130_WriteReg( CODE1_REG, 0x0F); // enable CRC check function
初始化A7130要Reset芯片,写ID,配置,Cal校准,然后进入STBY Mode,接下来设置发射功率等。上述的这些操作无非就是写寄存器,最关键的一个函数当然是A7130_WriteReg(Uint8 addr, Uint8 dataByte)。
void A7130_WriteReg(Uint8 addr, Uint8 dataByte)
{
Uint8 i;
SCS = 0;
addr |= 0x00; //bit cmd=0,r/w=0
for(i = 0; i < 8; i++)
{
if(addr & 0x80)
SDIO = 1;
else
SDIO = 0;
SCK = 1;
_nop_();
SCK = 0;
addr = addr << 1;
}
_nop_();
//send data byte
for(i = 0; i < 8; i++)
{
if(dataByte & 0x80)
SDIO = 1;
else
SDIO = 0;
SCK = 1;
_nop_();
SCK = 0;
dataByte = dataByte << 1;
}
SCS = 1;
}
这里使用的是仿SPI的时序来写寄存器,我们需要转换为STM32库的形式,变成如下:
uint8_t SPI_SendByte(SPI_TypeDef *SPIx, uint8_t byte)
{
/*!< Loop while DR register in not empty */
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
/*!< Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPIx, byte);
/*!< Wait to receive a byte */
while (SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_RXNE) == RESET);
/*!< Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPIx);
}
void A7130_WriteReg(uint8_t addr, uint8_t dataByte)
{
A7130_CS_LOW();
addr |= 0x00; // bit6 write
SPI_SendByte(SPI1, addr); // locate register address for write
SPI_SendByte(SPI1, dataByte); // write data
A7130_CS_HIGH();
}
当然,还有个读寄存器的函数
uint8_t A7130_ReadReg(uint8_t addr)
{
uint8_t data;
A7130_CS_LOW();
addr |= 0x40; // bit6 read
SPI_SendByte(SPI1, addr);
data= SPI_SendByte(SPI1, 0xff); // 0xff is dummy bytes
A7130_CS_HIGH();
return data;
}
注意读写寄存器的时候,要遵循数据包的格式进行书写
最终,我们将A7130的初始化和配置集成到一个函数A7130_Init(),然后我们调用A7130_ReadID()读取ID,看读出来的数据是不是与我们之前在RC_A7130_ReferenceCodeGenerator.exe中设置的一样。
四、A7130数据传输
1、发送数据
1、设置FIFO大小;
2、重置FIFO指针;
3、选中芯片
4、定位到TX FIFO寄存器;
5、写入数据到TX FIFO中;
6、取消选中;
7、发送数据;
8、等待发送完毕。
按照这六个步骤,把数据写入到TX FIFO中,A7130就会自动把FIFO中的数据发送出去。
void A7130_WriteData(uint8_t data)
{
A7130_WriteReg(FIFO1_REG, 64); // setting FIFO length
A7130_StrobeCmd(CMD_TFR); // reset TX FIFO pointer
A7130_CS_LOW(); // select chip
SPI_SendByte(SPI1, FIFO_REG); // locate TX FIFO
SPI_SendByte(SPI1, data); // write data into TX FIFO
A7130_CS_HIGH();
A7130_StrobeCmd( CMD_TX ); // transmit data from RF port
while( A7130_isTxRxFinish() ); // wait until TX finished
}
2、接收数据
uint8_t A7130_ReadData(void)
{
uint8_t data = 0;
A7130_StrobeCmd(CMD_RX); // in RX Mode
while( A7130_isTxRxFinish() ); // wait until receieve finished
A7130_CS_LOW();
SPI_SendByte(SPI1, FIFO_REG | 0x40); // locate RX FIFO
data = ARC_SPI_SendByte(SPI1, 0xff); // read data
A7130_CS_HIGH();
return data;
}
五、A7130扩展
上述只是A7130的一些基本的操作,最终还是要根据项目来使用。为了保证数据的可靠传输,我们可以把发射功率设大,采用自动应答自动重传的机制进行数据传输。为了读写速率,我们可以扩展FIFO。当然这些都要配置相关的寄存器来实现。A7130还提供了诸多功能,用户可根据需要配置寄存器。
六、A7130总结
A7130在传输速度上已经很快了,但是有点遗憾的是数据传输的可靠性不高。经过验证,当数据量大时或距离稍远时或者干扰较大,A7130的自动应答和自动重传并不如意。如果要保证数据的可靠性传输,需要用户自己定义一种简单的通信协议。但是如果数据量较小的情况下,可对该数据进行编码,然后再接收端进行解码。至于采用哪种编码方式,需用户根据自己的情况做出取舍。