1、多个从机和1个主机组成,通讯方式为lora。
2、主芯片stm32F1,RF芯片安信可Ra-02,SPI驱动。
3、多个主机可放到一起。(调整lora的相关参数,扩频因子,带宽,编码率,使主从机在一个空中速率。具体见如下说明)。
3、主从机采用一问一答方式通讯,lora全双工,延时20s。
实际项目已经应用,唯一不足就是延时长,RF驱动分享出来,希望可以完善代码。见附件。
/*
* THE FOLLOWING FIRMWARE IS PROVIDED: (1) "AS IS" WITH NO WARRANTY; AND
* (2)TO ENABLE ACCESS TO CODING INFORMATION TO GUIDE AND FACILITATE CUSTOMER.
* CONSEQUENTLY, SEMTECH SHALL NOT BE HELD LIABLE FOR ANY DIRECT, INDIRECT OR
* CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE CONTENT
* OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING INFORMATION
* CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* Copyright (C) SEMTECH S.A.
*/
/*!
* \file sx1276-LoRa.h
* \brief SX1276 RF chip driver mode LoRa
*
* \version 2.0.B2
* \date May 6 2013
* \author Gregory Cristian
*
* Last modified by Miguel Luis on Jun 19 2013
*/
#ifndef __SX1278_LORA_H__
#define __SX1278_LORA_H__
#include "spi.h"
#define RF_CS_Low GPIO_ResetBits(GPIOA, GPIO_Pin_4)//PD8 CS
#define RF_CS_High GPIO_SetBits(GPIOA, GPIO_Pin_4)//
#define RF_SDN_Low GPIO_ResetBits(GPIOB, GPIO_Pin_0)// PD10 SDN
#define RF_SDN_High GPIO_SetBits(GPIOB, GPIO_Pin_0)//
//#define RF_NIRQ GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_8)//NIRQ
#define RF_NIRQ GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11)//NIRQ
//-----------------------------------------------------------------------------
// 子程序声明
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// define MCU GPIO
//-----------------------------------------------------------------------------
u8 SPIRead(u8 adr);
void SPIBurstRead(u8 adr, u8 *ptr, u8 length);
void RFM96_LoRaEntryRx(void);
u8 RFM96_LoRaRxPacket(u8 *buf);
u8 RFM96_LoRaEntryTx(u8 packet_length);
u8 RFM96_LoRaTxPacket(u8 *buf,u8 len);
unsigned char RFM96_Config(u8 mode);
unsigned char SX1278_Init(void);
unsigned char SX1278_TXD(u8 *buf, u8 size);
unsigned char SX1278_RXD(unsigned char *Data);
/*!
* SX1276 Internal registers Address
*/
//RFM96 Internal registers Address
#define LR_RegFifo 0x0000//FIFO read/write access
// Common settings
#define LR_RegOpMode 0x0100//Operating mode & LoRaTM / FSK selection
#define LR_RegFrMsb 0x0600//RF Carrier Frequency, Most Significant Bits
#define LR_RegFrMid 0x0700//RF Carrier Frequency, Most Significant Bits
#define LR_RegFrLsb 0x0800//RF Carrier Frequency, Most Significant Bits
// Tx settings
#define LR_RegPaConfig 0x0900//PA selection and Output Power control
#define LR_RegPaRamp 0x0A00//Control of PA ramp time, low phase noise PLL
#define LR_RegOcp 0x0B00//Over Current Protection control
// Rx settings
#define LR_RegLna 0x0C00//LNA settings
// LoRa registers
#define LR_RegFifoAddrPtr 0x0D00//FIFO SPI pointer
#define LR_RegFifoTxBaseAddr 0x0E00//Start Tx data
#define LR_RegFifoRxBaseAddr 0x0F00//Start Rx data
#define LR_RegFifoRxCurrentaddr 0x1000//Start address of last packet received
#define LR_RegIrqFlagsMask 0x1100//Optional IRQ flag mask
#define LR_RegIrqFlags 0x1200//IRQ flags
#define LR_RegRxNbBytes 0x1300//Number of received bytes
#define LR_RegRxHeaderCntValueMsb 0x1400//Number of valid headers received
#define LR_RegRxHeaderCntValueLsb 0x1500//
#define LR_RegRxPacketCntValueMsb 0x1600//Number of valid packets received
#define LR_RegRxPacketCntValueLsb 0x1700
#define LR_RegModemStat 0x1800//Live LoRa TM modem status
#define LR_RegPktSnrValue 0x1900//Espimation of last packetSNR
#define LR_RegPktRssiValue 0x1A00//RSSI of last packet
#define LR_RegRssiValue 0x1B00//Current RSSI
#define LR_RegHopChannel 0x1C00//FHSS start channel
#define LR_RegModemConfig1 0x1D00//Modem PHY config 最重要的寄存器包括Signal bandwidth:Error coding rate,Explicit Header mode
#define LR_RegModemConfig2 0x1E00//SF rate,
#define LR_RegSymbTimeoutLsb 0x1F00//Receiver timeout value
#define LR_RegPreambleMsb 0x2000//Size of preamble
#define LR_RegPreambleLsb 0x2100//
#define LR_RegPayloadLength 0x2200//LoRa TM payload length
#define LR_RegMaxPayloadLength 0x2300//LoRaTM maximum pay-load length
#define LR_RegHopPeriod 0x2400//FHSS Hop period
#define LR_RegFifoRxByteAddr 0x2500//Address of last bytewritten in FIFO
#define LR_RegModemConfig3 0x2600//Modem PHY config 3
// I/O settings
#define REG_LR_DIOMAPPING1 0x4000
#define REG_LR_DIOMAPPING2 0x4100
// Version
#define REG_LR_VERSION 0x4200
// Additional settings
#define REG_LR_PLLHOP 0x4400
#define REG_LR_TCXO 0x4B00//TCXO or XTAL input setting
#define REG_LR_PADAC 0x4D00//Higher power settings of the PA
#define REG_LR_FORMERTEMP 0x5B00//Stored temperature during the former IQ Calibration
#define REG_LR_AGCREF 0x6100//Adjustment of the AGC thresholds
#define REG_LR_AGCTHRESH1 0x6200
#define REG_LR_AGCTHRESH2 0x6300
#define REG_LR_AGCTHRESH3 0x6400
#endif //__SX1276_LORA_H__
#include "sx1278_LoRa.h"
#include "stm32f10x_spi.h"
#include
#define u8 unsigned char
#define u16 unsigned short
#define gb_SF 3
#define gb_BW 6
#define CR 0x04
#define CRC_EN 0x00 //CRC Enable
/**********************************************************
**Parameter table define
**********************************************************/
static const u16 RFM96FreqTbl[3] = {0x066C, 0x0780, 0x0800}; //434MHz 32M晶振0x066C, 0x0780, 0x0800 30M:0x0673, 0x07BB, 0x08BB {0x85,0x89,0xd9},//26M-TCXO 434M
static const u16 RFM96PowerTbl[4] =
{
0x09FF, //20dbm
0x09FC, //17dbm
0x09F9, //14dbm
0x09F6, //11dbm
};
/*
const u8 RFM96SpreadFactorTbl[7] =
{
6,7,8,9,10,11,12
}; */
static const u8 RFM96SpreadFactorTbl[6] =
{
7,8,9,10,11,12
};//由于6扩频因子档位只能是固定数据包长所以去掉6扩频因子档位
static const u8 RFM96LoRaBwTbl[10] =
{// 0 1 2 3 4 5 6 7 8 9
//7.8KHz,10.4KHz,15.6KHz,20.8KHz,31.2KHz,41.7KHz,62.5KHz,125KHz,250KHz,500KHz
0,1,2,3,4,5,6,7,8,9
};
extern void bsp_DelayMS(uint32_t n);
extern void bsp_DelayUS(uint32_t n);
/**********************************************************
**Name: SPICmd8bit
**Function: SPI Write one byte
**Input: WrPara
**Output: none
**note: use for burst mode
**********************************************************/
u8 SPICmd8bit(u8 WrPara)
{
/* Loop while DR register in not emplty */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI1, WrPara);
/* Wait to receive a byte */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI1);
}
/**********************************************************
**Name: SPIRead8bit
**Function: SPI Read one byte
**Input: None
**Output: result byte
**Note: use for burst mode
**********************************************************/
//u8 SPIRead8bit(void)
//{
// return SPICmd8bit(0XFF);
//}
/**********************************************************
**Name: SPIRead
**Function: SPI Read CMD
**Input: adr -> address for read
**Output: None
**********************************************************/
u8 SPIRead(u8 adr)
{
static u8 tmp;
RF_CS_Low;//NSS_Low;
bsp_DelayUS(1);
SPICmd8bit(adr&0x7f); //Send address first
tmp = SPICmd8bit(0XFF);
// printf("读addr:%02x val:%02x\n",adr,tmp);
bsp_DelayUS(1);
RF_CS_High;//NSS_High;
return(tmp);
}
/**********************************************************
**Name: SPIWrite
**Function: SPI Write CMD
**Input: WrPara -> address & data
**Output: None
**********************************************************/
void SPIWrite(u16 WrPara)
{
WrPara |= 0x8000; //MSB must be "1" for write
// printf("写addr:%02x val:%02x\n",WrPara>>8,(u8)WrPara);
RF_CS_Low;//NSS_Low;
bsp_DelayUS(1);
SPICmd8bit(WrPara>>8);// 15->0
SPICmd8bit((u8)WrPara);
bsp_DelayUS(1);
RF_CS_High;//NSS_High;
}
/**********************************************************
**Name: SPIBurstRead
**Function: SPI burst read mode
**Input: adr-----address for read
** ptr-----data buffer point for read
** length--how many bytes for read
**Output: None
**********************************************************/
void SPIBurstRead(u8 adr, u8 *ptr, u8 length)
{
static u8 i;
if(length<=1) //length must more than one
return;
else
{
RF_CS_Low;
bsp_DelayUS(1);
SPICmd8bit(adr&0x7f);
for(i=0;i>8)); //获取SX1276 版本号 是0X11(V1A版本 工程版) 或者是 0X12(V1B 正式版)
//printf("\r\nsx1278(V12) v:%02X\r\n",Sx1276VerNO);
if(Sx1276VerNO!=0xff||Sx1276VerNO!=0)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
bsp_DelayUS(1000);
GPIO_SetBits(GPIOA, GPIO_Pin_5);
}
// SPIWrite(RFM96FreqTbl[0]);
// Sx1276VerNO=SPIRead((u8)(RFM96FreqTbl[0]>>8));
// printf("RFM96FreqTbl[0](0X06_6C) R:0x%02X",Sx1276VerNO);
for(i=0;i<3;i++) //setting frequency parameter
{
SPIWrite(RFM96FreqTbl[i]);
}
//setting base parameter
SPIWrite(RFM96PowerTbl[0]); //Setting output power parameter
SPIWrite(LR_RegOcp+0x0B); //RegOcp,Close Ocp
SPIWrite(LR_RegLna+0x23); //RegLNA,High & LNA Enable
if(RFM96SpreadFactorTbl[gb_SF]==6) //SFactor=6
{
SPIWrite(LR_RegModemConfig1+(RFM96LoRaBwTbl[gb_BW]<<4)+(CR<<1)+0x01);//带宽设置,包结构,Implicit Enable CRC Enable(0x02) & Error Coding rate 4/5(0x01), 4/6(0x02), 4/7(0x03), 4/8(0x04)
SPIWrite(LR_RegModemConfig2+(RFM96SpreadFactorTbl[gb_SF]<<4)+(CRC_EN<<2)+0x03);
tmp = SPIRead(0x31);
tmp &= 0xF8;
tmp |= 0x05;
SPIWrite(0x3100+tmp);
SPIWrite(0x3700+0x0C);
}
else
{
SPIWrite(LR_RegModemConfig1+(RFM96LoRaBwTbl[gb_BW]<<4)+(CR<<1)+0x00);//Explicit Enable CRC Enable(0x02) & Error Coding rate 4/5(0x01), 4/6(0x02), 4/7(0x03), 4/8(0x04)
SPIWrite(LR_RegModemConfig2+(RFM96SpreadFactorTbl[gb_SF]<<4)+(CRC_EN<<2)+0x03); //SFactor & LNA gain set by the internal AGC loop
}
// SPIWrite(LR_RegModemConfig1+0x36); //BW=3 20.8KHz , CR=3 4/7, explit
// SPIWrite(LR_RegModemConfig2+0x77); //SF=6, CRC on
SPIWrite(LR_RegSymbTimeoutLsb+0xFF); //RegSymbTimeoutLsb Timeout = 0x3FF(Max)
SPIWrite(LR_RegPreambleMsb + 0); //RegPreambleMsb
SPIWrite(LR_RegPreambleLsb + 12); //RegPreambleLsb 8+4=12byte Preamble
SPIWrite(REG_LR_DIOMAPPING2+0x01); //RegDioMapping2 DIO5=00, DIO4=01
SPIWrite(LR_RegOpMode+0x09); //Entry standby mode
return Sx1276VerNO;
}
/**********************************************************
**Name: RFM96_LoRaEntryRx
**Function: Entry Rx mode
**Input: None
**Output: None
**********************************************************/
void RFM96_LoRaEntryRx(void)
{
unsigned char addr;
RFM96_Config(0); //setting base parameter
SPIWrite(0x4D00+0x84); //Normal and Rx
SPIWrite(LR_RegHopPeriod+0xFF); //RegHopPeriod NO FHSS
SPIWrite(REG_LR_DIOMAPPING1+0x01); //DIO0=00, DIO1=00, DIO2=00, DIO3=01 DIO0=00--RXDONE
SPIWrite(LR_RegIrqFlagsMask+0x3F); //Open RxDone interrupt & Timeout
// RFM96_LoRaClearIrq(); 换成 SPIWrite(LR_RegIrqFlags+0xFF);
SPIWrite(LR_RegIrqFlags+0xFF);
//TODO
SPIWrite(LR_RegPayloadLength+21); //RegPayloadLength 21byte(this register must difine when the data long of one byte in SF is 6)
addr = SPIRead((u8)(LR_RegFifoRxBaseAddr>>8)); //Read RxBaseAddr
SPIWrite(LR_RegFifoAddrPtr+addr); //RxBaseAddr -> FiFoAddrPtr
SPIWrite(LR_RegOpMode+0x0D); //Continuous Rx Mode
}
/**********************************************************
**Name: RFM96_LoRaRxPacket
**Function: Receive data in LoRa mode
**Input: None
**Output: 1- Success
0- Fail
**********************************************************/
u8 RFM96_LoRaRxPacket(u8 *buf)
{
unsigned char packet_size,addr;
for(addr=0;addr<32;addr++) //清Buffer
buf[addr] = 0x00;
addr = SPIRead((u8)(LR_RegFifoRxCurrentaddr>>8)); //last packet addr 数据包的最后地址(数据的尾地址)
SPIWrite(LR_RegFifoAddrPtr+addr); //RxBaseAddr -> FiFoAddrPtr
bsp_DelayMS(1);
if(RFM96SpreadFactorTbl[gb_SF]==6) //When SpreadFactor is six,will used Implicit Header mode(Excluding internal packet length)
packet_size=21;
else
packet_size = SPIRead((u8)(LR_RegRxNbBytes>>8)); //Number for received bytes
SPIBurstRead(0x00, buf, packet_size);
SPIWrite(LR_RegIrqFlags+0xFF);
bsp_DelayUS(1);
return packet_size;
}
/**********************************************************
**Name: RFM96_LoRaEntryTx
**Function: Entry Tx mode
**Input: None
**Output: None
**********************************************************/
u8 RFM96_LoRaEntryTx(u8 packet_length)
{
unsigned char addr;
unsigned char SysTime = 0;
unsigned char temp;
RFM96_Config(0); //模块发射参数设置
bsp_DelayUS(10);
SPIWrite(0x4D00+0x87); //发射功率 for 20dBm
SPIWrite(LR_RegHopPeriod); //RegHopPeriod NO FHSS
SPIWrite(REG_LR_DIOMAPPING1+0x41); //DIO0=01, DIO1=00, DIO2=00, DIO3=01
SPIWrite(LR_RegIrqFlags+0xFF);
SPIWrite(LR_RegIrqFlagsMask+0xF7); //Open TxDone interrupt
SPIWrite(LR_RegPayloadLength+packet_length); //RegPayloadLength 21byte负载和fifo的字节数的关系是什么??
addr = SPIRead((u8)(LR_RegFifoTxBaseAddr>>8)); //RegFiFoTxBaseAddr
SPIWrite(LR_RegFifoAddrPtr+addr); //RegFifoAddrPtr
for(SysTime=0;SysTime<3;SysTime++)
{
temp=SPIRead((u8)(LR_RegPayloadLength>>8) );
if(temp==packet_length)
{
return packet_length;
}
bsp_DelayUS(100);
}
return 0;
}
/**********************************************************
**Name: RFM96_LoRaTxPacket
**Function: Send data in LoRa mode
**Input: None
**Output: 1- Send over
**********************************************************/
u8 RFM96_LoRaTxPacket(u8 *buf,u8 len)
{
u8 i=0;
BurstWrite(0x00, (u8 *)buf, len);
for(i=0;i>8));
SPIWrite(LR_RegIrqFlags+0xFF); //Clear irq
SPIWrite(LR_RegOpMode+0x09); //Entry Standby mode
return 1;
}
bsp_DelayMS(30);
}
// printf("\r\n RF发送失败.\r\n");
return 0;
}
unsigned char SX1278_Init(void)
{
unsigned char flag;
RF_SDN_Low;
bsp_DelayUS(600);
RF_SDN_High;
bsp_DelayUS(600);
flag = RFM96_Config(0); //初始化模块
RFM96_LoRaEntryRx(); //设置接收模式
return flag;
}
unsigned char SX1278_TXD(u8 *buf, u8 size)
{
unsigned char flag;
RFM96_LoRaEntryTx(size); //进入网络模式
flag = RFM96_LoRaTxPacket(buf,size); //在LoRa模式下发送
bsp_DelayUS(20);
RFM96_LoRaEntryRx(); //接收模式
return flag;
}
unsigned char SX1278_RXD(unsigned char *Data)
{
unsigned char length = 0;
if ( RF_NIRQ==1) //收到数据高电平中断
{
length=RFM96_LoRaRxPacket(Data); //在LoRa模式下接收数据
RFM96_LoRaEntryRx(); //接收模式
return(length);
}
return 0;
}