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 timersTimerInit( &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
{//GPIOGpio_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,
#elseNULL, // void ( *IrqProcess )( void )
#endifNULL, // void ( *RxBoosted )( uint32_t timeout ) - SX126x OnlyNULL, // 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 timersTimerInit( &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 );
#elseptSX1276->DioIrq = DioIrq;
#endiffor( 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;
}
运行效果如下:
2022.06.08
今天测试sx12xxDrivers-V4.4.2驱动,发现Lora最大接收64字节,而以前sx12xxDrivers-V2.1.0驱动则没有这个限制,什么问题呢?
查看旧驱动在void SX1276LoRaInit( void )有如下设置:
SX1276LoRaSetPayloadLength( LoRaSettings.PayloadLength );tLoRaSettings LoRaSettings =
{LoRa_FREQENCY , // RFFrequency20, // Power8, // SignalBw [0: 7.8kHz, 1: 10.4 kHz, 2: 15.6 kHz, 3: 20.8 kHz, 4: 31.2 kHz,// 5: 41.6 kHz, 6: 62.5 kHz, 7: 125 kHz, 8: 250 kHz, 9: 500 kHz, other: Reserved]11, // SpreadingFactor [6: 64, 7: 128, 8: 256, 9: 512, 10: 1024, 11: 2048, 12: 4096 chips]1, // ErrorCoding [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8]true, // CrcOn [0: OFF, 1: ON]false, // ImplicitHeaderOn [0: OFF, 1: ON]0, // RxSingleOn [0: Continuous, 1 Single]0, // FreqHopOn [0: OFF, 1: ON] //跳频技术4, // HopPeriod Hops every frequency hopping period symbols100, // TxPacketTimeout100, // RxPacketTimeout128, // PayloadLength (used for implicit header mode)
};
查看sx12xxDrivers-V4.4.2,有如下设置:
/*!* \brief Sets the reception parameters** \remark When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported** \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 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 SX1276SetRxConfig(void* ptRFStruct, 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 );
但是查看说明:payloadLen Sets payload length when fixed length is used,意思是只有使用固定长度模式,才设置磁参数,显然不对。
于是查看void SX1276Init(void* ptRFStruct, RadioEvents_t *events )函数,看到:
for( i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ ){SX1276SetModem(ptSX1276, RadioRegsInit[i].Modem );SX1276Write(ptSX1276, RadioRegsInit[i].Addr, RadioRegsInit[i].Value );}
再看:
/*!* Radio hardware registers initialization** \remark RADIO_INIT_REGISTERS_VALUE is defined in sx1276-board.h file*/
const RadioRegisters_t RadioRegsInit[] = RADIO_INIT_REGISTERS_VALUE;
再看:
/*!* \brief Radio hardware registers initialization definition** \remark Can be automatically generated by the SX1276 GUI (not yet implemented)*/
#define RADIO_INIT_REGISTERS_VALUE \
{ \{ MODEM_FSK , REG_LNA , 0x23 },\{ MODEM_FSK , REG_RXCONFIG , 0x1E },\{ MODEM_FSK , REG_RSSICONFIG , 0xD2 },\{ MODEM_FSK , REG_AFCFEI , 0x01 },\{ MODEM_FSK , REG_PREAMBLEDETECT , 0xAA },\{ MODEM_FSK , REG_OSC , 0x07 },\{ MODEM_FSK , REG_SYNCCONFIG , 0x12 },\{ MODEM_FSK , REG_SYNCVALUE1 , 0xC1 },\{ MODEM_FSK , REG_SYNCVALUE2 , 0x94 },\{ MODEM_FSK , REG_SYNCVALUE3 , 0xC1 },\{ MODEM_FSK , REG_PACKETCONFIG1 , 0xD8 },\{ MODEM_FSK , REG_FIFOTHRESH , 0x8F },\{ MODEM_FSK , REG_IMAGECAL , 0x02 },\{ MODEM_FSK , REG_DIOMAPPING1 , 0x00 },\{ MODEM_FSK , REG_DIOMAPPING2 , 0x30 },\{ MODEM_LORA, REG_LR_PAYLOADMAXLENGTH, 0x40 },\
}
看到么有:MODEM_LORA, REG_LR_PAYLOADMAXLENGTH, 0x40
修改为255,测试OK。看手册这个值默认是0xFF,因此sx12xxDrivers-V2.1.0不设置,是没有问题的。而sx12xxDrivers-V4.4.2默认设置为64。
Lora1278驱动V4.4.2讲解二:驱动多个SX1278芯片相关推荐
- Lora1278驱动V4.4.2讲解一:驱动移植
注意,Lora1278驱动sx12xxDrivers-V2.1.0,原厂已经不更新和维护了,反馈的任何软件问题, 原厂就是一句话升级新的驱动,新驱动下载地址:https://github.com/Lo ...
- S3C2440上LCD驱动(FrameBuffer)实例开发讲解
一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--64MB Nand, Kernel:2.6.30.4 编译器:arm-linux-gcc-4.3.2 二.背景 ...
- Linux设备驱动开发详解【二】_设备驱动相关硬件基础知识
本文简介 本文讲解底层驱动工程师必备的硬件基础,给出了嵌入式系统硬件原理及分析方法的全景视图. 2.1 节讲解微控制器.微处理器.数字信号处理器以及应用于特定领域的处理器各自的特点. ...
- S3C2440上LCD驱动 (FrameBuffer)实例开发讲解
1.S3C2440上LCD驱动 (FrameBuffer)实例开发讲解 其中的代码也可直接参考:drivers/video/s3c2410fb.c 以下为转载文章,文章原地址:http://blog. ...
- Windows驱动开发学习笔记(二)—— 驱动调试内核编程基础
Windows驱动开发学习笔记(二)-- 驱动调试&内核编程基础 基础知识 驱动调试 PDB(Program Debug Database) WinDbg 加载 PDB 实验:调试 .sys ...
- 【Linux开发】linux设备驱动归纳总结(十二):简单的数码相框
linux设备驱动归纳总结(十二):简单的数码相框 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ...
- [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店...
原文:[.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店 一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Bytear ...
- windows10驱动 x64--- 3环代码加载驱动(二)
windows10驱动 x64--- 3环代码加载驱动 一:了解驱动加载工具 二:应用层--3环代码示例 一:了解驱动加载工具 平时调试.sys 我们都是用的驱动加载工具:open(打开驱动文件) - ...
- FS_S5PC100平台上Linux Camera驱动开发详解(二)
http://blog.csdn.net/wh_19910525/article/details/18091915 这个问题弄清楚了以后下面就来看获得Camera信息以后如何做后续的处理: 在fimc ...
最新文章
- 侧链,驱动链,和根链的双向锚定设计
- python爬百度翻译-Python爬取百度翻译(利用json提取数据)
- Linux下修改mysql root密码
- xcat 安装(liunx高性能刀片集群管理软件)
- Python对数列进行全排列
- live555源代码简介
- spark job运行参数优化
- Python编程 | 新手必会的 9 个 Python 技巧
- C++ 数据抽象 封装 接口
- java setter与getter方法
- 为什么可积不一定可导_本命年为什么要穿红?你一定不知道!
- vbs程序批量禁用域用户然后移动到指定OU
- 视频内容付费系统整站源码
- 基于jsp+mysql+java+ssm实验室设备管理系统——计算机毕业设计
- 13. 如何打破白天开会、晚上加班的节奏
- 元素出栈入栈顺序是否合法
- java去掉字符串的空格_如何去掉字符串中的空格?
- lammps教程:实例讲解npt、nvt系综的选择
- 银河麒麟系统部署.net core环境
- 示波器读取SCI串口数据
热门文章
- 计算机视觉注意力机制-Attention
- 必修三计算机选修三知识点总结,高一数学必修三知识点总结(超实用)
- 【DIY】手把手教你爆改一台手机制作掌上游戏机
- python声纹识别_【kaldi学习.4】Aishell V1(说话人识别、声纹识别)中的run.sh详解...
- Web前端之JavaScript基础
- 记一次feign调用报错:feign.codec.DecodeException: Error while extracting response for type [java...
- 怎么获得华为手机的产品sn号码imei号
- hazelcast java_Hazelcast入门教程
- IT项目经理应该做什么
- 南方cass简码识别大全_cass-简码识别详细分解.doc