你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【STM32C0评测】4、驱动Lorasx126x,实现透传

[复制链接]
Teresa 发布时间:2024-4-3 17:59

前言

作为我心中报警器的首选,肯定是需要一个通信手段的,无线通信无疑是方便又愉快的选择,但是又要考虑低功耗,干扰,传输距离,信号强度等等因素。而LoRa专利调制技术无疑是一种较好的解决方案,拥有低功耗与长通信距离的优点。用在这类小电器上很是舒服。

关于LoRa

LoRa是一种线性调频扩频的物联网调制技术,也叫宽带现象调频(Chirp Modulation)技术。相对于传统的FSK技术,LoRa在相同的功耗下具有更长的传输距离,且抗干扰能力强。

1、LoRa SPI驱动

直接弄了个安信可的模块开整,安信可的模块是直接与LoRa的芯片通信,采用的是SPI接口

SPI我采用的是SPI1,具体IO如下:

image.png

SPI采用主从模式,CPOL:LOW,CPHA:1Edge,8位数据位,FirstBit:MSB,具体驱动代码如下:

void bsp_SPI_Init(void)
{
    hspi.Instance = SPIx;
    hspi.Init.Mode = SPI_MODE_MASTER;
    hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    hspi.Init.Direction = SPI_DIRECTION_2LINES;
    hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi.Init.CRCPolynomial = 7;
    hspi.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
    hspi.Init.NSS = SPI_NSS_SOFT;
    hspi.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;

    if (HAL_SPI_Init(&hspi) != HAL_OK)
    {
        Error_Handler();
    }
}

void HAL_SPI_MspInit(SPI_HandleTypeDef *_hspi)
{
    GPIO_InitTypeDef gpio_init;

    SPIx_SCK_CLK_ENABLE();
    SPIx_MISO_CLK_ENABLE();
    SPIx_MOSI_CLK_ENABLE();

    SPIx_CLK_ENABLE();

    gpio_init.Pin = SPIx_SCK_PIN;
    gpio_init.Mode = GPIO_MODE_AF_PP;
    gpio_init.Pull = GPIO_PULLUP;
    gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init.Alternate = SPIx_SCK_AF;
    HAL_GPIO_Init(SPIx_SCK_PORT, &gpio_init);

    gpio_init.Pin = SPIx_MISO_PIN;
    gpio_init.Alternate = SPIx_MISO_AF;
    HAL_GPIO_Init(SPIx_MISO_PORT, &gpio_init);

    gpio_init.Pin = SPIx_MOSI_PIN;
    gpio_init.Alternate = SPIx_MOSI_AF;
    HAL_GPIO_Init(SPIx_MOSI_PORT, &gpio_init);
}

关于SPI的时钟速率方面:

image.png

升特官方的文档也详细的写出最高为16Mhz,而我们的C0芯片最高频率为48Mhz,4分频随便跑

2 LoRa芯片驱动

升特官方给出了LoRa驱动的接口,安信可也有根据官方接口移植的驱动工程,为了方便快捷测试功能,直接就使用安信可的驱动文件进行移植,根据驱动工程分析,需要三个IO口RST,D1,D4来控制LoRa芯片的状态,定义为:

//LoRa的RST复位脚,PA8
#define RADIO_nRESET_PIN                GPIO_PIN_8
#define RADIO_nRESET_PORT               GPIOA
#define RADIO_nRESET_CLOCK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()

//LoRa的DIO1功能脚,PA15
#define RADIO_DIO1_PIN                  GPIO_PIN_15
#define RADIO_DIO1_PORT                 GPIOA
#define RADIO_DIO1_CLOCK_ENABLE()       __HAL_RCC_GPIOA_CLK_ENABLE()
#define RADIO_DIO1_EXINT_LINE           EXTI_LINE_15  

//LoRa的BUSY功能脚(对应sx127x的DIO4),PC7
#define RADIO_DIO4_BUSY_PIN             GPIO_PIN_7
#define RADIO_DIO4_BUSY_PORT            GPIOC
#define RADIO_DIO4_BUSY_CLOCK_ENABLE()  __HAL_RCC_GPIOC_CLK_ENABLE()

其中D1功能脚需要使用到外部中断模式,其他两个脚当成正常GPIO进行设置就行。

D1设置如下:

void SX126xIoIrqInit(DioIrqHandler dioIrq)
{
    GPIO_InitTypeDef gpio_init;

    dio1IrqCallback = dioIrq;

    /* 使能 DIO1 的时钟与外部中断时钟*/
    RADIO_DIO1_CLOCK_ENABLE();

    /* DIO1 */
    gpio_init.Pin = RADIO_DIO1_PIN;
    gpio_init.Mode = GPIO_MODE_IT_RISING;           //输入模式
    gpio_init.Pull = GPIO_PULLUP;          //上拉输入
    gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;        //强驱动模式
    HAL_GPIO_Init(RADIO_DIO1_PORT, &gpio_init);

    HAL_NVIC_SetPriority(EXTI4_15_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}

之前的标准库设置外部中断非常麻烦,直接只需要在GPIO_InitTypeDef结构体里面设置就行了,我这里设置的是上升边沿中断GPIO_MODE_IT_RISING,直接就搞定了。函数名称为升特提供的接口名称

D4与Nss设置如下:

void SX126xIoInit(void)
{
    GPIO_InitTypeDef gpio_init;

    /* 使能 BUSY 脚时钟*/
    RADIO_DIO4_BUSY_CLOCK_ENABLE();
    /* 使能 NSS 时钟 */
    RADIO_NSS_CLK_ENABLE();

    gpio_init.Pin = RADIO_DIO4_BUSY_PIN;
    gpio_init.Mode = GPIO_MODE_INPUT;
    gpio_init.Pull = GPIO_PULLUP;
    gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(RADIO_DIO4_BUSY_PORT, &gpio_init);

    gpio_init.Pin = RADIO_NSS_PIN;
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init.Pull = GPIO_PULLUP;
    gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(RADIO_NSS_PORT, &gpio_init);

    SPIx_NSS_Set();
}

因为SPI1上只有LoRa模块一个设备,所以在设置完成片选引脚的状态后,直接就选中LoRa芯片了

最后RST引脚设置:

void SX126xReset(void)
{
    GPIO_InitTypeDef gpio_init;

    SX126xDelayMs(10);

    /* 使能 nRESET 脚时钟*/
    RADIO_nRESET_CLOCK_ENABLE();

    gpio_init.Pin = RADIO_nRESET_PIN;
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init.Pull = GPIO_PULLUP;
    gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    HAL_GPIO_Init(RADIO_nRESET_PORT, &gpio_init);

    HAL_GPIO_WritePin(RADIO_nRESET_PORT, RADIO_nRESET_PIN, GPIO_PIN_RESET);

    SX126xDelayMs(20);

    HAL_GPIO_WritePin(RADIO_nRESET_PORT, RADIO_nRESET_PIN, GPIO_PIN_SET);

    SX126xDelayMs(10);
}

三个IO口简单轻松搞定,然后LoRa芯片还需要一个计时器用来统计收发时间,直接选TIM3作为计时器,具体如下:

void SX126xTimerInit(void)
{
    /* 使能 LoRaTMR */
    LoRa_TIM_CLOCK_ENABLE();

    TimHandle.Instance = LoRa_TIM;
    TimHandle.Init.Prescaler = 10;
    TimHandle.Init.Period = SystemCoreClock / 10000;
    TimHandle.Init.ClockDivision = 0;
    TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
    TimHandle.Init.RepetitionCounter = 0;
    TimHandle.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
    if (HAL_TIM_Base_Init(&TimHandle) != HAL_OK)
    {
        Error_Handler();
    }
    /* 两个软件定时器清零 */
    txTimerHandle.isRun = 0;  
    rxTimerHandle.isRun = 0;

    HAL_NVIC_SetPriority(TIM3_IRQn, 0, 2);
    HAL_NVIC_EnableIRQ(TIM3_IRQn);

    HAL_TIM_Base_Start_IT(&TimHandle);
}

最后再把外部中断与定时器的中断函数编写上,直接就能开始玩LoRa透传了。我直接使用了安信可提供的DEMO,核心函数如下:

void ExampleSX126xSendDemo(void){
    uint8_t OCP_Value = 0;

    printf("start %s() example\r\n",__func__);

    SX126xRadioEvents.TxDone = SX126xOnTxDone;
    SX126xRadioEvents.RxDone = SX126xOnRxDone;
    SX126xRadioEvents.TxTimeout = SX126xOnTxTimeout;
    SX126xRadioEvents.RxTimeout = SX126xOnRxTimeout;
    SX126xRadioEvents.RxError = SX126xOnRxError;

    Radio.Init( &SX126xRadioEvents );
    Radio.SetChannel(LORA_FRE);
    Radio.SetTxConfig( MODEM_LORA, LORA_TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
                     LORA_SPREADING_FACTOR, LORA_CODINGRATE,
                     LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
                     true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );//参数:lora模式,发射功率,fsk用的lora设置为0就可以,带宽,纠错编码率,前导码长度,固定长度数据包(一般是不固定的所以选false),crc校验,0表示关闭跳频,跳频之间的符号数(关闭跳频这个参数没有意义),这个应该是表示是否要翻转中断电平的,超时时间

    OCP_Value = Radio.Read(REG_OCP);
    printf("[%s()-%d]read OCP register value:0x%04X\r\n",__func__,__LINE__,OCP_Value);

    Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
                     LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
                     LORA_SX126X_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
                     0, true, 0, 0, LORA_IQ_INVERSION_ON, false );
    printf("freq: %d\r\n Tx power: %d\r\n band width: %d\r\n FS: %d\r\n CODINGRATE: %d\r\n PREAMBLE_LENGTH: %d\r\n",LORA_FRE,LORA_TX_OUTPUT_POWER,LORA_BANDWIDTH,LORA_SPREADING_FACTOR,LORA_CODINGRATE,LORA_PREAMBLE_LENGTH);
    while(1){
        Radio.IrqProcess( ); // Process Radio IRQ
        Radio.Send( (uint8_t *)MSG, strlen(MSG) );
        bsp_DelayMS( 3000 );
    }
}

安信可是把发送和接收分开了,我还是图方便,两个全部进行了初始化,然后在下面的while(1)大循环中调用了IrqProcess进程,最后发送一个MSG(aithinker888)。

要与这个芯片进行通信,必须括频率、扩频因子、带宽、编码率,前导码长度、跳频使能、同步字(syncword)、低速率优化这些选项全部相同,不过经过测试前导码长度这块,只需要接收方长度大于发送方就能让芯片解析收到的数据包了。总体设置如下:

#define LORA_FRE                            433000000       //收发频率
#define LORA_TX_OUTPUT_POWER                20              //发射功率,126x发射功率0~22dbm,127x发射功率2~20dbm
#define LORA_BANDWIDTH                      0               //带宽,sx126x:[0:125kHz, 1:250kHz, 2:500kHz, 3:Reserved]
#define LORA_SPREADING_FACTOR               7               //扩频因子,范围7~12
#define LORA_CODINGRATE                     1               //纠错编码率。[1:4/5, 2:4/6, 3:4/7, 4: 4/8]
#define LORA_PREAMBLE_LENGTH                8               //前导码长度,范围6~65536
#define LORA_SX126X_SYMBOL_TIMEOUT          0               //symbols(sx126x用到的是0,127x用到的是5)
#define LORA_FIX_LENGTH_PAYLOAD_ON          false           //是否为固定长度包(暂时只有sx126x用到了)
#define LORA_IQ_INVERSION_ON                false           //设置是否翻转中断电平(暂时只有sx126x用到了)
#define LORA_RX_TIMEOUT_VALUE               3000            //接收超时时间

全部设置完成之后,再弄一块接收板,参数设置相同就可以开始接收数据了。

上电信息如下:

image.png

芯片sx126x的OCP寄存器数值为0x38,安信可并没有更新,但是升特有说明

image.png

同步收发如下:

【LoRa透传测试视频】 https://www.bilibili.com/video/BV1Bq421w77b/?share_source=copy_web&vd_source=348ed027c500f7bd59a4eb77f3c8f510

简单的测试,使用视频方便看出同步收发

总结

STM32的库经过这么多年的积累,现在使用起来的感受,就初步使用来说,已经是非常舒服了。在我需要使用spi驱动lora芯片中,还加入了外部中断与定时器计时,还算是有点复杂,但是在使用Hal库,大部分只需要关注软件逻辑就行,还是那句话这是ST喊出替代8位芯片的底气之一。

接下来,我准备使用C0芯片的通信接口加上简单的协议制作一个Bootloader,完成物联网入门第一步

收藏 评论0 发布时间:2024-4-3 17:59

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版