Lora1278驱动V4.4.2讲解二:驱动多个SX1278芯片
Posted 无痕幽雨
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lora1278驱动V4.4.2讲解二:驱动多个SX1278芯片相关的知识,希望对你有一定的参考价值。
最近有个项目,要做微型网关,对于尺寸、体积、功耗、成本以及开发周期有要求,方案基于以前的Lora网关为基础进行快速研发,里面唯一的难点就是用一个MCU驱动多个SX1278,通过对比SX1278的sx12xxDrivers-V2.1.0和sx12xxDrivers-V4.4.2,发现V4.4.2驱动更好修改,于是决定在V4.4.2驱动基础之上增加支持多片SX1278功能。
sx12xxDrivers-V4.4.2驱动移植请看:Lora1278驱动V4.4.2讲解一:驱动移植
一、思路
增加多片SX1278的总体思路就是运用面向对象思想实现,举例:
SX1278Drivers RF1,RF2RF3;
RF1.init();
RF2.init();
RF3.init();
等等,实现起来很轻松,在嵌入式C开发中怎么实现呢,思路如下:
抽象出功能相同的一套函数,抽象出功能不通的函数并定义函数指针,把全局变量和函数指针定义成结构体,定义RF1/RF2/RF3实体,并把实体指针当做那套抽象出的函数的入参。类似如下:
net_work_rf_process(&s_tNetWorkRF1); //无线线程
net_work_protocol_analysis_process(&s_tNetWorkRF1); //协议解析
father_station_routing_table_maintenance(&s_tNetWorkRF1); //父节路由点维护
net_work_logic_process(&s_tNetWorkRF1); //组网逻辑
net_work_check_sx1278_process(&s_tNetWorkRF1); //SX1278维护线程
s_tNetWorkRF1.ptRadio->IrqProcess(&s_tNetWorkRF1.tSX1276); //DIO0处理函数
二、驱动修改
sx12xxDrivers-V4.4.2详细说明请看上篇博客(驱动讲解一),总体思路如下:
1、radio.h抽象出驱动接口;
/*!
* \\brief Radio driver definition
*/
struct Radio_s
/*!
* \\brief Initializes the radio
*
* \\param [IN] events Structure containing the driver callback functions
*/
void ( *Init )( RadioEvents_t *events );
/*!
* Return current radio status
*
* \\param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
Radiostate_t ( *GetStatus )( void );
/*!
* \\brief Configures the radio with the given modem
*
* \\param [IN] modem Modem to be used [0: FSK, 1: LoRa]
*/
void ( *SetModem )( RadioModems_t modem );
/*!
* \\brief Sets the channel frequency
*
* \\param [IN] freq Channel RF frequency
*/
void ( *SetChannel )( uint32_t freq );
/*!
* \\brief Checks if the channel is free for the given time
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] freq Channel RF frequency
* \\param [IN] rssiThresh RSSI threshold
* \\param [IN] maxCarrierSenseTime Max time while the RSSI is measured
*
* \\retval isFree [true: Channel is free, false: Channel is not free]
*/
bool ( *IsChannelFree )( RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \\brief Generates a 32 bits random value based on the RSSI readings
*
* \\remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \\retval randomValue 32 bits random value
*/
uint32_t ( *Random )( void );
/*!
* \\brief Sets the reception parameters
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \\param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \\param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \\param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \\param [IN] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \\param [IN] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \\param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \\param [IN] payloadLen Sets payload length when fixed length is used
* \\param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \\param [IN] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \\param [IN] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \\param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \\param [IN] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
void ( *SetRxConfig )( RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool freqHopOn, uint8_t hopPeriod,
bool iqInverted, bool rxContinuous );
/*!
* \\brief Sets the transmission parameters
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] power Sets the output power [dBm]
* \\param [IN] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \\param [IN] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \\param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \\param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \\param [IN] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \\param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \\param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \\param [IN] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \\param [IN] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \\param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \\param [IN] timeout Transmission timeout [ms]
*/
void ( *SetTxConfig )( RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool freqHopOn,
uint8_t hopPeriod, bool iqInverted, uint32_t timeout );
/*!
* \\brief Checks if the given RF frequency is supported by the hardware
*
* \\param [IN] frequency RF frequency to be checked
* \\retval isSupported [true: supported, false: unsupported]
*/
bool ( *CheckRfFrequency )( uint32_t frequency );
/*!
* \\brief Computes the packet time on air in ms for the given payload
*
* \\Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] pktLen Packet payload length
*
* \\retval airTime Computed airTime (ms) for the given packet payload length
*/
uint32_t ( *TimeOnAir )( RadioModems_t modem, uint8_t pktLen );
/*!
* \\brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \\param [IN]: buffer Buffer pointer
* \\param [IN]: size Buffer size
*/
void ( *Send )( uint8_t *buffer, uint8_t size );
/*!
* \\brief Sets the radio in sleep mode
*/
void ( *Sleep )( void );
/*!
* \\brief Sets the radio in standby mode
*/
void ( *Standby )( void );
/*!
* \\brief Sets the radio in reception mode for the given time
* \\param [IN] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *Rx )( uint32_t timeout );
/*!
* \\brief Start a Channel Activity Detection
*/
void ( *StartCad )( void );
/*!
* \\brief Sets the radio in continuous wave transmission mode
*
* \\param [IN]: freq Channel RF frequency
* \\param [IN]: power Sets the output power [dBm]
* \\param [IN]: time Transmission mode timeout [s]
*/
void ( *SetTxContinuousWave )( uint32_t freq, int8_t power, uint16_t time );
/*!
* \\brief Reads the current RSSI value
*
* \\retval rssiValue Current RSSI value in [dBm]
*/
int16_t ( *Rssi )( RadioModems_t modem );
/*!
* \\brief Writes the radio register at the specified address
*
* \\param [IN]: addr Register address
* \\param [IN]: data New register value
*/
void ( *Write )( uint16_t addr, uint8_t data );
/*!
* \\brief Reads the radio register at the specified address
*
* \\param [IN]: addr Register address
* \\retval data Register value
*/
uint8_t ( *Read )( uint16_t addr );
/*!
* \\brief Writes multiple radio registers starting at address
*
* \\param [IN] addr First Radio register address
* \\param [IN] buffer Buffer containing the new register's values
* \\param [IN] size Number of registers to be written
*/
void ( *WriteBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \\brief Reads multiple radio registers starting at address
*
* \\param [IN] addr First Radio register address
* \\param [OUT] buffer Buffer where to copy the registers data
* \\param [IN] size Number of registers to be read
*/
void ( *ReadBuffer )( uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \\brief Sets the maximum payload length.
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] max Maximum payload length in bytes
*/
void ( *SetMaxPayloadLength )( RadioModems_t modem, uint8_t max );
/*!
* \\brief Sets the network to public or private. Updates the sync byte.
*
* \\remark Applies to LoRa modem only
*
* \\param [IN] enable if true, it enables a public network
*/
void ( *SetPublicNetwork )( bool enable );
/*!
* \\brief Gets the time required for the board plus radio to get out of sleep.[ms]
*
* \\retval time Radio plus board wakeup time in ms.
*/
uint32_t ( *GetWakeupTime )( void );
/*!
* \\brief Process radio irq
*/
void ( *IrqProcess )( void );
/*
* The next functions are available only on SX126x radios.
*/
/*!
* \\brief Sets the radio in reception mode with Max LNA gain for the given time
*
* \\remark Available on SX126x radios only.
*
* \\param [IN] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *RxBoosted )( uint32_t timeout );
/*!
* \\brief Sets the Rx duty cycle management parameters
*
* \\remark Available on SX126x radios only.
*
* \\param [in] rxTime Structure describing reception timeout value
* \\param [in] sleepTime Structure describing sleep timeout value
*/
void ( *SetRxDutyCycle ) ( uint32_t rxTime, uint32_t sleepTime );
;
2、sx1276.c实现接口;
3、用户和底层打交道是通过5个事件,用户实现,底层驱动调用;
/*!
* \\brief Radio driver callback functions
*/
typedef struct
/*!
* \\brief Tx Done callback prototype.
*/
void ( *TxDone )( void );
/*!
* \\brief Tx Timeout callback prototype.
*/
void ( *TxTimeout )( void );
/*!
* \\brief Rx Done callback prototype.
*
* \\param [IN] payload Received buffer pointer
* \\param [IN] size Received buffer size
* \\param [IN] rssi RSSI value computed while receiving the frame [dBm]
* \\param [IN] snr SNR value computed while receiving the frame [dB]
* FSK : N/A ( set to 0 )
* LoRa: SNR value in dB
*/
void ( *RxDone )(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
/*!
* \\brief Rx Timeout callback prototype.
*/
void ( *RxTimeout )( void );
/*!
* \\brief Rx Error callback prototype.
*/
void ( *RxError )( void );
/*!
* \\brief FHSS Change Channel callback prototype.
*
* \\param [IN] currentChannel Index number of the current channel
*/
void ( *FhssChangeChannel )( uint8_t currentChannel );
/*!
* \\brief CAD Done callback prototype.
*
* \\param [IN] channelDetected Channel Activity detected during the CAD
*/
void ( *CadDone ) ( bool channelActivityDetected );
RadioEvents_t;
4、DIO中断处理
Lora有DIO0-DIO5,通过它们来指示目前芯片状态(比用SPI查询,快),底层驱动有对应的处理函数:
SX1276OnDio0Irq,
SX1276OnDio1Irq,
SX1276OnDio2Irq,
SX1276OnDio3Irq,
SX1276OnDio4Irq
DIO5没有,
这5个DIO处理函数在驱动里面是放到一个数组中,
/*!
* Hardware DIO IRQ callback initialization
*/
static DioIrqHandler *DioIrq[] = SX1276OnDio0Irq, SX1276OnDio1Irq,
SX1276OnDio2Irq, SX1276OnDio3Irq,
SX1276OnDio4Irq, NULL ;
然后需要外部实现:void SX1276IoIrqInit(DioIrqHandler **irqHandlers )
查看例子:
void SX1276IoIrqInit( DioIrqHandler **irqHandlers )
GpioSetInterrupt( &SX1276.DIO0, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[0] );
GpioSetInterrupt( &SX1276.DIO1, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[1] );
GpioSetInterrupt( &SX1276.DIO2, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[2] );
GpioSetInterrupt( &SX1276.DIO3, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[3] );
GpioSetInterrupt( &SX1276.DIO4, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[4] );
GpioSetInterrupt( &SX1276.DIO5, LL_EXTI_MODE_IT, LL_EXTI_TRIGGER_RISING, IRQ_HIGH_PRIORITY, irqHandlers[5] );
功能就是把中断处理函数放到对应的IO口中断处理函数里面,官方例程实现有点复杂,因为他写的是通用架构(我个人感觉没必要,总之记住一句话:把IO口中断放到对应的IO口中断处理函数里面)。以上是历程思路,也可以用驱动V2.1.0的查询思路,很简单:就是查询IO口状态,如果有效,则调用对应的函数,实现如下:
实现函数IrqProcess(入参void* ptRFStruct是为了支持多芯片,你可以直接在函数里面用实体实现):
#if (0 == LORA_IRQ_IS_ENABLE)
void IrqProcess( void* ptRFStruct )
SX1276_t* ptSX1276 = (SX1276_t*)ptRFStruct;
DioIrqHandler* ptIrqHandler = NULL;
if(NULL == ptSX1276)
return;
if(GpioRead(&ptSX1276->DIO0))
ptIrqHandler=ptSX1276->DioIrq[0];
if(NULL != ptIrqHandler)
ptIrqHandler(ptSX1276,NULL);
// if(GpioRead(&ptSX1276->DIO1))
// ptIrqHandler=ptSX1276->DioIrq[1];
// if(NULL != ptIrqHandler)
// ptIrqHandler(ptSX1276,NULL);
//
//
// if(GpioRead(&ptSX1276->DIO2))
// ptIrqHandler=ptSX1276->DioIrq[2];
// if(NULL != ptIrqHandler)
// ptIrqHandler(ptSX1276,NULL);
//
//
// if(GpioRead(&ptSX1276->DIO3))
// ptIrqHandler=ptSX1276->DioIrq[3];
// if(NULL != ptIrqHandler)
// ptIrqHandler(ptSX1276,NULL);
//
//
// if(GpioRead(&ptSX1276->DIO4))
// ptIrqHandler=ptSX1276->DioIrq[4];
// if(NULL != ptIrqHandler)
// ptIrqHandler(ptSX1276,NULL);
//
//
// if(GpioRead(&ptSX1276->DIO5))
// ptIrqHandler=ptSX1276->DioIrq[5];
// if(NULL != ptIrqHandler)
// ptIrqHandler(ptSX1276,NULL);
//
//
#endif
由于我测试驱动,只用到了DIO0,因此其他处理函数屏蔽掉。
5、超时处理函数
驱动提供了超时处理函数SX1276OnTimeoutIrq,驱动里面定义的三个超时事件:
/*!
* Tx and Rx timers
*/
TimerEvent_t TxTimeoutTimer;
TimerEvent_t RxTimeoutTimer;
TimerEvent_t RxTimeoutSyncWord;
驱动初始化:
// Initialize driver timeout timers
TimerInit( &TxTimeoutTimer, SX1276OnTimeoutIrq );
TimerInit( &RxTimeoutTimer, SX1276OnTimeoutIrq );
TimerInit( &RxTimeoutSyncWord, SX1276OnTimeoutIrq );
主要在收、发、接收同步字超时时候处理,这里如果不用低功耗模式(MCU休眠),则可以直接忽略,同时在应用层自己做对应逻辑,或者在应用层超时时候直接调用这个超时处理函数即可。
三、实现驱动支持多芯片
1、查看sx1276.c的全局变量:
/*
* Private global variables
*/
/*!
* Radio callbacks variable
*/
static RadioEvents_t *RadioEvents;
/*!
* Reception buffer
*/
static uint8_t RxTxBuffer[RX_BUFFER_SIZE];
/*
* Public global variables
*/
/*!
* Radio hardware and global parameters
*/
SX1276_t SX1276;
/*!
* Hardware DIO IRQ callback initialization
*/
DioIrqHandler *DioIrq[] = SX1276OnDio0Irq, SX1276OnDio1Irq,
SX1276OnDio2Irq, SX1276OnDio3Irq,
SX1276OnDio4Irq, NULL ;
/*!
* Tx and Rx timers
*/
TimerEvent_t TxTimeoutTimer;
TimerEvent_t RxTimeoutTimer;
TimerEvent_t RxTimeoutSyncWord;
分析如下:
1、RadioEvents变量指针为事件处理,需要用户实现,然后传入进来,由底层驱动调用,每个芯片的事件处理肯定不同,因此RadioEvents放到struct SX1276_s结构体中;
2、static uint8_t RxTxBuffer[RX_BUFFER_SIZE];接收发送缓存,放到struct SX1276_s结构体中;
3、SX1276_t SX1276;去掉,由用户层定义,当做驱动层API的入参;
4、DioIrq不变,修改DIO中断处理的,增加SX1276_t*指针入参;
5、三个超时处理事件变量,放到struct SX1276_s结构体中;
6、struct SX1276_s结构体中增加电源控制脚、射频开关控制脚,修改后如下:
/*!
* Radio hardware and global parameters
*/
typedef struct SX1276_s
//GPIO
Gpio_t Reset;
Gpio_t Power;
Gpio_t RFswitch;
Gpio_t DIO0;
Gpio_t DIO1;
Gpio_t DIO2;
Gpio_t DIO3;
Gpio_t DIO4;
Gpio_t DIO5;
Spi_t Spi;
RadioSettings_t Settings;
//事件
RadioEvents_t *RadioEvents;
//缓存
uint8_t RxTxBuffer[RX_BUFFER_SIZE];
//超时事件
TimerEvent_t TxTimeoutTimer;
TimerEvent_t RxTimeoutTimer;
TimerEvent_t RxTimeoutSyncWord;
//IO中断
#if (0 == LORA_IRQ_IS_ENABLE)
DioIrqHandler **DioIrq;
#endif
SX1276_t;
7、Spi_t里面增加SpiId变量,修改如下;
/*!
* SPI object type definition
*/
typedef struct Spi_s
SPI_TypeDef* SpiId;
Gpio_t Mosi;
Gpio_t Miso;
Gpio_t Sclk;
Gpio_t Nss;
Spi_t;
8、接口修改
对应的接口增加void*入参,因为radio.h为对外接口文件,sx1276.h包含radio.h,因此struct SX1276_s类型对radio.h是不可见的,
修改后的radio.h抽象接口:
/*!
* \\brief Radio driver definition
*/
struct Radio_s
/*!
* \\brief Initializes the radio
*
* \\param [IN] events Structure containing the driver callback functions
*/
void ( *Init )(void* ptSX1276, RadioEvents_t *events );
/*!
* Return current radio status
*
* \\param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING]
*/
RadioState_t ( *GetStatus )( void* ptSX1276 );
/*!
* \\brief Configures the radio with the given modem
*
* \\param [IN] modem Modem to be used [0: FSK, 1: LoRa]
*/
void ( *SetModem )(void* ptSX1276, RadioModems_t modem );
/*!
* \\brief Sets the channel frequency
*
* \\param [IN] freq Channel RF frequency
*/
void ( *SetChannel )(void* ptSX1276, uint32_t freq );
/*!
* \\brief Checks if the channel is free for the given time
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] freq Channel RF frequency
* \\param [IN] rssiThresh RSSI threshold
* \\param [IN] maxCarrierSenseTime Max time while the RSSI is measured
*
* \\retval isFree [true: Channel is free, false: Channel is not free]
*/
bool ( *IsChannelFree )(void* ptSX1276, RadioModems_t modem, uint32_t freq, int16_t rssiThresh, uint32_t maxCarrierSenseTime );
/*!
* \\brief Generates a 32 bits random value based on the RSSI readings
*
* \\remark This function sets the radio in LoRa modem mode and disables
* all interrupts.
* After calling this function either Radio.SetRxConfig or
* Radio.SetTxConfig functions must be called.
*
* \\retval randomValue 32 bits random value
*/
uint32_t ( *Random )( void* ptSX1276 );
/*!
* \\brief Sets the reception parameters
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] bandwidth Sets the bandwidth
* FSK : >= 2600 and <= 250000 Hz
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \\param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \\param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \\param [IN] bandwidthAfc Sets the AFC Bandwidth (FSK only)
* FSK : >= 2600 and <= 250000 Hz
* LoRa: N/A ( set to 0 )
* \\param [IN] preambleLen Sets the Preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \\param [IN] symbTimeout Sets the RxSingle timeout value
* FSK : timeout in number of bytes
* LoRa: timeout in symbols
* \\param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \\param [IN] payloadLen Sets payload length when fixed length is used
* \\param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON]
* \\param [IN] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \\param [IN] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \\param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \\param [IN] rxContinuous Sets the reception in continuous mode
* [false: single mode, true: continuous mode]
*/
void ( *SetRxConfig )(void* ptSX1276, RadioModems_t modem, uint32_t bandwidth,
uint32_t datarate, uint8_t coderate,
uint32_t bandwidthAfc, uint16_t preambleLen,
uint16_t symbTimeout, bool fixLen,
uint8_t payloadLen,
bool crcOn, bool freqHopOn, uint8_t hopPeriod,
bool iqInverted, bool rxContinuous );
/*!
* \\brief Sets the transmission parameters
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] power Sets the output power [dBm]
* \\param [IN] fdev Sets the frequency deviation (FSK only)
* FSK : [Hz]
* LoRa: 0
* \\param [IN] bandwidth Sets the bandwidth (LoRa only)
* FSK : 0
* LoRa: [0: 125 kHz, 1: 250 kHz,
* 2: 500 kHz, 3: Reserved]
* \\param [IN] datarate Sets the Datarate
* FSK : 600..300000 bits/s
* LoRa: [6: 64, 7: 128, 8: 256, 9: 512,
* 10: 1024, 11: 2048, 12: 4096 chips]
* \\param [IN] coderate Sets the coding rate (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]
* \\param [IN] preambleLen Sets the preamble length
* FSK : Number of bytes
* LoRa: Length in symbols (the hardware adds 4 more symbols)
* \\param [IN] fixLen Fixed length packets [0: variable, 1: fixed]
* \\param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON]
* \\param [IN] freqHopOn Enables disables the intra-packet frequency hopping
* FSK : N/A ( set to 0 )
* LoRa: [0: OFF, 1: ON]
* \\param [IN] hopPeriod Number of symbols between each hop
* FSK : N/A ( set to 0 )
* LoRa: Number of symbols
* \\param [IN] iqInverted Inverts IQ signals (LoRa only)
* FSK : N/A ( set to 0 )
* LoRa: [0: not inverted, 1: inverted]
* \\param [IN] timeout Transmission timeout [ms]
*/
void ( *SetTxConfig )(void* ptSX1276, RadioModems_t modem, int8_t power, uint32_t fdev,
uint32_t bandwidth, uint32_t datarate,
uint8_t coderate, uint16_t preambleLen,
bool fixLen, bool crcOn, bool freqHopOn,
uint8_t hopPeriod, bool iqInverted, uint32_t timeout );
/*!
* \\brief Checks if the given RF frequency is supported by the hardware
*
* \\param [IN] frequency RF frequency to be checked
* \\retval isSupported [true: supported, false: unsupported]
*/
bool ( *CheckRfFrequency )(void* ptSX1276, uint32_t frequency );
/*!
* \\brief Computes the packet time on air in ms for the given payload
*
* \\Remark Can only be called once SetRxConfig or SetTxConfig have been called
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] pktLen Packet payload length
*
* \\retval airTime Computed airTime (ms) for the given packet payload length
*/
uint32_t ( *TimeOnAir )(void* ptSX1276, RadioModems_t modem, uint8_t pktLen );
/*!
* \\brief Sends the buffer of size. Prepares the packet to be sent and sets
* the radio in transmission
*
* \\param [IN]: buffer Buffer pointer
* \\param [IN]: size Buffer size
*/
void ( *Send )(void* ptSX1276, uint8_t *buffer, uint8_t size );
/*!
* \\brief Sets the radio in sleep mode
*/
void ( *Sleep )( void* ptSX1276 );
/*!
* \\brief Sets the radio in standby mode
*/
void ( *Standby )( void* ptSX1276 );
/*!
* \\brief Sets the radio in reception mode for the given time
* \\param [IN] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *Rx )(void* ptSX1276, uint32_t timeout );
/*!
* \\brief Start a Channel Activity Detection
*/
void ( *StartCad )( void* ptSX1276 );
/*!
* \\brief Sets the radio in continuous wave transmission mode
*
* \\param [IN]: freq Channel RF frequency
* \\param [IN]: power Sets the output power [dBm]
* \\param [IN]: time Transmission mode timeout [s]
*/
void ( *SetTxContinuousWave )(void* ptSX1276, uint32_t freq, int8_t power, uint16_t time );
/*!
* \\brief Reads the current RSSI value
*
* \\retval rssiValue Current RSSI value in [dBm]
*/
int16_t ( *Rssi )(void* ptSX1276, RadioModems_t modem );
/*!
* \\brief Writes the radio register at the specified address
*
* \\param [IN]: addr Register address
* \\param [IN]: data New register value
*/
void ( *Write )(void* ptSX1276, uint16_t addr, uint8_t data );
/*!
* \\brief Reads the radio register at the specified address
*
* \\param [IN]: addr Register address
* \\retval data Register value
*/
uint8_t ( *Read )(void* ptSX1276, uint16_t addr );
/*!
* \\brief Writes multiple radio registers starting at address
*
* \\param [IN] addr First Radio register address
* \\param [IN] buffer Buffer containing the new register's values
* \\param [IN] size Number of registers to be written
*/
void ( *WriteBuffer )(void* ptSX1276, uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \\brief Reads multiple radio registers starting at address
*
* \\param [IN] addr First Radio register address
* \\param [OUT] buffer Buffer where to copy the registers data
* \\param [IN] size Number of registers to be read
*/
void ( *ReadBuffer )(void* ptSX1276, uint16_t addr, uint8_t *buffer, uint8_t size );
/*!
* \\brief Sets the maximum payload length.
*
* \\param [IN] modem Radio modem to be used [0: FSK, 1: LoRa]
* \\param [IN] max Maximum payload length in bytes
*/
void ( *SetMaxPayloadLength )(void* ptSX1276, RadioModems_t modem, uint8_t max );
/*!
* \\brief Sets the network to public or private. Updates the sync byte.
*
* \\remark Applies to LoRa modem only
*
* \\param [IN] enable if true, it enables a public network
*/
void ( *SetPublicNetwork )(void* ptSX1276, bool enable );
/*!
* \\brief Gets the time required for the board plus radio to get out of sleep.[ms]
*
* \\retval time Radio plus board wakeup time in ms.
*/
uint32_t ( *GetWakeupTime )(void* ptSX1276 );
/*!
* \\brief Process radio irq
*/
void ( *IrqProcess )( void* ptSX1276 );
/*
* The next functions are available only on SX126x radios.
*/
/*!
* \\brief Sets the radio in reception mode with Max LNA gain for the given time
*
* \\remark Available on SX126x radios only.
*
* \\param [IN] timeout Reception timeout [ms]
* [0: continuous, others timeout]
*/
void ( *RxBoosted )(void* ptSX1276, uint32_t timeout );
/*!
* \\brief Sets the Rx duty cycle management parameters
*
* \\remark Available on SX126x radios only.
*
* \\param [in] rxTime Structure describing reception timeout value
* \\param [in] sleepTime Structure describing sleep timeout value
*/
void ( *SetRxDutyCycle ) (void* ptSX1276, uint32_t rxTime, uint32_t sleepTime );
;
定义在sx1276-board.c:
/*!
* Radio driver structure initialization
*/
const struct Radio_s Radio =
SX1276Init,
SX1276GetStatus,
SX1276SetModem,
SX1276SetChannel,
SX1276IsChannelFree,
SX1276Random,
SX1276SetRxConfig,
SX1276SetTxConfig,
SX1276CheckRfFrequency,
SX1276GetTimeOnAir,
SX1276Send,
SX1276SetSleep,
SX1276SetStby,
SX1276SetRx,
SX1276StartCad,
SX1276SetTxContinuousWave,
SX1276ReadRssi,
SX1276Write,
SX1276Read,
SX1276WriteBuffer,
SX1276ReadBuffer,
SX1276SetMaxPayloadLength,
SX1276SetPublicNetwork,
SX1276GetWakeupTime,
#if (0 == LORA_IRQ_IS_ENABLE)
IrqProcess,
#else
NULL, // void ( *IrqProcess )( void )
#endif
NULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x Only
NULL, // void ( *SetRxDutyCycle )( uint32_t rxTime, uint32_t sleepTime ) - SX126x Only
;
sx1276.c接口实现修改,以SX1276Init为例,其它函数修改类似:
void SX1276Init(void* ptRFStruct, RadioEvents_t *events )
uint8_t i;
SX1276_t* ptSX1276 = (SX1276_t*)ptRFStruct;
if(NULL == ptSX1276)
return;
ptSX1276->RadioEvents = events;
// Initialize driver timeout timers
TimerInit( &ptSX1276->TxTimeoutTimer, SX1276OnTimeoutIrq );
TimerInit( &ptSX1276->RxTimeoutTimer, SX1276OnTimeoutIrq );
TimerInit( &ptSX1276->RxTimeoutSyncWord, SX1276OnTimeoutIrq );
//TRACE_DEBUG("SX1276Init=%d\\r\\n",1);
SX1276Reset( ptSX1276 );
//TRACE_DEBUG("SX1276Init=%d\\r\\n",2);
while(0x6C != SX1276Read(ptSX1276,0x06))
TRACE_ERROR("Hard SPI Err!\\r\\n");
my_delay_ms(500);
//TRACE_DEBUG("SX1276Init=%d\\r\\n",3);
RxChainCalibration(ptSX1276 );
SX1276SetOpMode(ptSX1276, RF_OPMODE_SLEEP );
#if (LORA_IRQ_IS_ENABLE)
SX1276IoIrqInit(ptSX1276, DioIrq );
#else
ptSX1276->DioIrq = DioIrq;
#endif
for( i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ )
SX1276SetModem(ptSX1276, RadioRegsInit[i].Modem );
SX1276Write(ptSX1276, RadioRegsInit[i].Addr, RadioRegsInit[i].Value );
SX1276SetModem(ptSX1276, MODEM_FSK );
ptSX1276->Settings.State = RF_IDLE;
//TRACE_DEBUG("SX1276Init irq= %x\\r\\n",SX1276Read(REG_LR_IRQFLAGS));
四、应用层修改
1、首先定义不同实体:
static net_work_t s_tNetWorkRF1;
static net_work_t s_tNetWorkRF2;
static net_work_t s_tNetWorkRF3;
2、实现不同的事件处理函数:
static void OnTxDoneRF1( void )
SET_EVENT(&s_tNetWorkRF1.tRfTxDone);
static void OnRxDoneRF1(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
if(WAIT_EVENT(&s_tNetWorkRF1.tRfRxDone) || size > NET_WOEK_RF_BUFFER_SIZE || NULL == payload)
return;
memcpy(s_tNetWorkRF1.chRadioRxBuffer,payload,size);
s_tNetWorkRF1.hwRadioRxSize = size;
s_tNetWorkRF1.chPacketRssiValue = rssi;
s_tNetWorkRF1.chSnrValue = snr;
SET_EVENT(&s_tNetWorkRF1.tRfRxDone);
static void OnTxTimeoutRF1( void )
//Radio.Sleep( );
static void OnRxTimeoutRF1( void )
//Radio.Sleep( );
static void OnRxErrorRF1( void )
//Radio.Sleep( );
static void OnTxDoneRF2( void )
SET_EVENT(&s_tNetWorkRF2.tRfTxDone);
static void OnRxDoneRF2(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
if(WAIT_EVENT(&s_tNetWorkRF2.tRfRxDone) || size > NET_WOEK_RF_BUFFER_SIZE || NULL == payload)
return;
memcpy(s_tNetWorkRF2.chRadioRxBuffer,payload,size);
s_tNetWorkRF2.hwRadioRxSize = size;
s_tNetWorkRF2.chPacketRssiValue = rssi;
s_tNetWorkRF2.chSnrValue = snr;
SET_EVENT(&s_tNetWorkRF2.tRfRxDone);
static void OnTxTimeoutRF2( void )
//Radio.Sleep( );
static void OnRxTimeoutRF2( void )
//Radio.Sleep( );
static void OnRxErrorRF2( void )
//Radio.Sleep( );
static void OnTxDoneRF3( void )
SET_EVENT(&s_tNetWorkRF3.tRfTxDone);
static void OnRxDoneRF3(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
if(WAIT_EVENT(&s_tNetWorkRF3.tRfRxDone) || size > NET_WOEK_RF_BUFFER_SIZE || NULL == payload)
return;
memcpy(s_tNetWorkRF3.chRadioRxBuffer,payload,size);
s_tNetWorkRF3.hwRadioRxSize = size;
s_tNetWorkRF3.chPacketRssiValue = rssi;
s_tNetWorkRF3.chSnrValue = snr;
SET_EVENT(&s_tNetWorkRF3.tRfRxDone);
static void OnTxTimeoutRF3( void )
//Radio.Sleep( );
static void OnRxTimeoutRF3( void )
//Radio.Sleep( );
static void OnRxErrorRF3( void )
//Radio.Sleep( );
/*!
* Radio events function pointer
*/
static const RadioEvents_t s_RadioEventsRF1 =
.TxDone = OnTxDoneRF1,
.TxTimeout = OnTxTimeoutRF1,
.RxDone = OnRxDoneRF1,
.RxTimeout = OnRxTimeoutRF1,
.RxError = OnRxErrorRF1,
.FhssChangeChannel = NULL,
.CadDone = NULL,
;
static const RadioEvents_t s_RadioEventsRF2 =
.TxDone = OnTxDoneRF2,
.TxTimeout = OnTxTimeoutRF2,
.RxDone = OnRxDoneRF2,
.RxTimeout = OnRxTimeoutRF2,
.RxError = OnRxErrorRF2,
.FhssChangeChannel = NULL,
.CadDone = NULL,
;
static const RadioEvents_t s_RadioEventsRF3 =
.TxDone = OnTxDoneRF3,
.TxTimeout = OnTxTimeoutRF3,
.RxDone = OnRxDoneRF3,
.RxTimeout = OnRxTimeoutRF3,
.RxError = OnRxErrorRF3,
.FhssChangeChannel = NULL,
.CadDone = NULL,
;
3、初始化如下:
void user_net_work_init(net_work_app_api_t *ptAppApiRF1,net_work_app_api_t *ptAppApiRF2,net_work_app_api_t *ptAppApiRF3)
srand(s_chRandomNumber[0]%s_chRandomNumber[1]+s_chRandomNumber[2]%s_chRandomNumber[3]); //随机数种子
TRACE_DEBUG("srand=%d\\r\\n",(s_chRandomNumber[0]%s_chRandomNumber[1]+s_chRandomNumber[2]%s_chRandomNumber[3]));
memset((uint8_t*)&s_tNetWorkRF1,0x00,sizeof(net_work_t));
memset((uint8_t*)&s_tNetWorkRF2,0x00,sizeof(net_work_t));
memset((uint8_t*)&s_tNetWorkRF3,0x00,sizeof(net_work_t));
s_tNetWorkRF1.tChannel = RF_DATA_CHANNEL_BASE_STATION;
s_tNetWorkRF2.tChannel = RF_DATA_CHANNEL_HANDHELD_DEVICE;
s_tNetWorkRF3.tChannel = RF_DATA_CHANNEL_SENSOR_1;
SX1276IoInit(&s_tNetWorkRF1.tSX1276,s_tNetWorkRF1.tChannel);
SX1276IoInit(&s_tNetWorkRF2.tSX1276,s_tNetWorkRF2.tChannel);
SX1276IoInit(&s_tNetWorkRF3.tSX1276,s_tNetWorkRF3.tChannel);
SpiInit(&s_tNetWorkRF1.tSX1276.Spi,RF1_SPI);
SpiInit(&s_tNetWorkRF2.tSX1276.Spi,RF2_SPI);
SpiInit(&s_tNetWorkRF3.tSX1276.Spi,RF3_SPI);
net_work_init(&s_tNetWorkRF1,s_chRfBufferRF1,sizeof(s_chRfBufferRF1),(RadioEvents_t*)&s_RadioEventsRF1,ptAppApiRF1);
TRACE_DEBUG("RF1 init success\\r\\n");
net_work_init(&s_tNetWorkRF2,s_chRfBufferRF2,sizeof(s_chRfBufferRF2),(RadioEvents_t*)&s_RadioEventsRF2,ptAppApiRF2);
TRACE_DEBUG("RF2 init success\\r\\n");
net_work_init(&s_tNetWorkRF3,s_chRfBufferRF3,sizeof(s_chRfBufferRF3),(RadioEvents_t*)&s_RadioEventsRF3,ptAppApiRF3);
TRACE_DEBUG("RF3 init success\\r\\n");
4、应用接口思路同驱动一样
示例:
/************************************* APP **********************************/
bool net_work_service_process(void)
net_work_rf_process(&s_tNetWorkRF1); //无线线程
net_work_protocol_analysis_process(&s_tNetWorkRF1); //协议解析
father_station_routing_table_maintenance(&s_tNetWorkRF1); //父节路由点维护
net_work_logic_process(&s_tNetWorkRF1); //组网逻辑
net_work_check_sx1278_process(&s_tNetWorkRF1); //SX1278维护线程
s_tNetWorkRF1.ptRadio->IrqProcess(&s_tNetWorkRF1.tSX1276); //DIO0处理函数
net_work_rf_process(&s_tNetWorkRF2); //无线线程
net_work_protocol_analysis_process(&s_tNetWorkRF2); //协议解析
father_station_routing_table_maintenance(&s_tNetWorkRF2); //父节路由点维护
net_work_logic_process(&s_tNetWorkRF2); //组网逻辑
net_work_check_sx1278_process(&s_tNetWorkRF2); //SX1278维护线程
s_tNetWorkRF2.ptRadio->IrqProcess(&s_tNetWorkRF2.tSX1276); //DIO0处理函数
net_work_rf_process(&s_tNetWorkRF3); //无线线程
net_work_protocol_analysis_process(&s_tNetWorkRF3); //协议解析
father_station_routing_table_maintenance(&s_tNetWorkRF3); //父节路由点维护
net_work_logic_process(&s_tNetWorkRF3); //组网逻辑
net_work_check_sx1278_process(&s_tNetWorkRF3); //SX1278维护线程
s_tNetWorkRF3.ptRadio->IrqProcess(&s_tNetWorkRF3.tSX1276); //DIO0处理函数
return true;
读取RSSI应用层API:
/******************************** SX1278维护线程 ****************************/
static bool net_work_check_rf_chip_state(net_work_t *ptNetWork)
int16_t iTemp = 0;
static uint8_t chNum = 0;
if(RF_IDLE == ptNetWork->ptRadio->GetStatus(&ptNetWork->tSX1276))
chNum = 0;
return true;
iTemp = ptNetWork->ptRadio->Rssi(&ptNetWork->tSX1276,MODEM_LORA);
TRACE_DEBUG("RF rx rssi = %d\\r\\n",iTemp);
if(iTemp <= (-160))
chNum++;
TRACE_ERROR("RF rx rssi error = %d\\r\\n",iTemp);
if(chNum >= 5)
chNum = 0;
return false;
else
chNum=0;
return true;
读取RSSI驱动层API:
int16_t SX1276ReadRssi(void* ptRFStruct, RadioModems_t modem )
int16_t rssi = 0;
SX1276_t* ptSX1276 = (SX1276_t*)ptRFStruct;
if(NULL == ptSX1276)
return 0;
switch( modem )
case MODEM_FSK:
rssi = -( SX1276Read(ptSX1276, REG_RSSIVALUE ) >> 1 );
break;
case MODEM_LORA:
if( ptSX1276->Settings.Channel > RF_MID_BAND_THRESH )
rssi = RSSI_OFFSET_HF + SX1276Read(ptSX1276, REG_LR_RSSIVALUE );
else
rssi = RSSI_OFFSET_LF + SX1276Read(ptSX1276, REG_LR_RSSIVALUE );
break;
default:
rssi = -1;
break;
return rssi;
运行效果如下:
以上是关于Lora1278驱动V4.4.2讲解二:驱动多个SX1278芯片的主要内容,如果未能解决你的问题,请参考以下文章
LoRa笔记03 LoRa sx1276 sx1278空中唤醒研究