LoRa节点开发——SDK整体设计思路

时间:2022-07-25
本文章向大家介绍LoRa节点开发——SDK整体设计思路,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

LoRa节点SDK看着代码多、工程大,但是如果我们从宏观上把握了SDK的思路,那么很快就能拿下它。

1、硬件连接

从sx1276的参考设计https://os.mbed.com/media/uploads/GregCr/sx1276mb1las_e311v02a_sch.pdf中我们可以看出:

sx1276与mcu需要连接的io口,SPI(SCK、MISO、MOSI、NSS)、DIO0~DIO5;SPI口用于通讯,DIO~DIO5用于产生外部中断。实际上DIO0~DIO5可以根据软件设计取舍,查看datasheet可以看到DIO0~DIO5分别对应不同的功能:

2、外部中断

从上面的图,我们可以看出,DIOx Mapping被设置为不同的值,DIOx产生的中断(电平跳变)对应不同的状态。

基本的思路:将DIOx连接到MCU--->对应的mcu口设置为外部中断模式--->设置DIOx Mapping的模式--->事件发生(RxDone接受完成、TxDone发送完成)--->产生外部中断--->回调事件函数。

以DIO0为例说明:

DIO0连接到了PA10,我们知道PA10对应的外部中断函数是

void EXTI15_10_IRQHandler( void )

注册过程,依次调用如下函数:

SX1276IoInit( );
GpioInit( &SX1276.DIO0, RADIO_DIO_0, PIN_INPUT, PIN_PUSH_PULL, PIN_PULL_UP, 0 );
SX1276IoIrqInit( DioIrq );
//DioIrq是函数指针数组, SX1276OnDio0Irq、 SX1276OnDio1Irq等是成员,分别是DIO0、DIO1等的外部中断回调函数。
GpioSetInterrupt( &SX1276.DIO0, IRQ_RISING_EDGE, IRQ_HIGH_PRIORITY, irqHandlers[0] );
//设置DIO0为上升沿触发,高优先级,中断回调函数为irqHandlers[0];
GpioMcuSetInterrupt( obj, irqMode, irqPriority, irqHandler );
GpioIrq[( obj->pin ) & 0x0F] = obj; //注册回调函数

中断发生后,依次回调如下函数:

EXTI15_10_IRQHandler( );//外部中断的中断函数
HAL_GPIO_EXTI_Callback( uint16_t gpioPin ) //HAL库回调函数
GpioIrq[callbackIndex]->IrqHandler( GpioIrq[callbackIndex]->Context );//回调

3、定时器链表

SDK中用RTC作为定时器,调度整个系统的运行。

基本的思路:初始化RTC定时器,定义一个时间事件定时器、设置定时时长、启动时间事件定时器、设置RTC闹钟时间、RTC闹钟时间到、调用对应的事件回调函数。

看一下结构体时间事件定时器的结构体,其中struct TimerEvent_s *Next;指向下一个时间事件。

/*!
 * brief Timer object description
 */
typedef struct TimerEvent_s
{
    uint32_t Timestamp;                 //! Current timer value
    uint32_t ReloadValue;                //! Timer delay value
    bool IsStarted;                      //! Is the timer currently running
    bool IsNext2Expire;                  //! Is the next timer to expire
    void ( *Callback )( void* context );       //! Timer IRQ callback function
    void *Context;                      //! User defined data object pointer to pass back
    struct TimerEvent_s *Next;            //! Pointer to the next Timer object.
}TimerEvent_t;
 

时间事件定时器链表:SDK中以静态的方式创建了多个时间事件定时器,每个时间事件定时器作为链表的一个节点。

多个时间事件定时器处理:遍历定时器链表,设置定时时长最小的事件为当前RTC的闹钟时间,RTC闹钟时间到,处理当前事件,遍历定时器链表、再设置定时时长最小的事件为当前RTC的闹钟时间。

一个典型的时间事件定时器使用方法:

static TimerEvent_t LedRedTimer; //定义时间事件定时器节点
void LED_TipInit(void )  
{
   TimerInit( &LedRedTimer, LedRedTimerEvent ); //初始化时间事件
   TimerSetValue( &LedRedTimer, 4000);//设置定时时长
}
static void LedRedTimerEvent(void)
{
   TimerStop( &LedRedTimer );
   LED_RED_OFF();
}
void LedRedTipOn(void) //启动定时器
{
  TimerStart( &LedRedTipTimer );
  LED_RED_ON();
}

上面示例了一个简单的LED灯闪的时间事件定时器的用法。

4、休眠

SDK中使用的stop模式,只能通过外部中断,或者RTC闹钟唤醒。

外部中断:SX1276的DIOx、用户应用的外部中断;

RTC闹钟:进入休眠后射频是关闭的,因此进入休眠之前至少要确保有一个时间事件定时器在跑,负责进入休眠之后,将没法唤醒。通常情况下进入休眠之后,会有一个周期发送的时间事件定时器在跑的,SDK中的周期发送数据的时间事件定时器是TxNextPacketTimer。

总结:如果需要移植到其他的平台,主要的工作就是修改spi驱动、定时器、外部中断、休眠这几个部分。