目录
一、前言
对于lora_pkt_fwd.c主函数实现功能的流程不熟悉的话,可以看上一篇文章。本篇文章就集中器开始进行整理。
二、主函数逻辑
i = lgw_start();
if (i == LGW_HAL_SUCCESS)
{
MSG("INFO: [main] concentrator started, packet can now be received\n");
}
else
{
MSG("ERROR: [main] failed to start the concentrator\n");
exit(EXIT_FAILURE);
}
首先,调用 lgw_start()
函数启动集中器,并将返回值赋给变量 i
。然后检查 lgw_start()
的返回值,以确定集中器是否成功启动:
成功---调用 MSG
宏输出信息:“INFO: [main] concentrator started, packet can now be received”,通知用户集中器已经成功启动,并且可以接收数据包。
失败---调用 MSG
宏输出错误信息:“ERROR: [main] failed to start the concentrator”,通知用户启动集中器失败。然后调用 exit(EXIT_FAILURE)
退出程序,表示程序因错误退出。
三、lgw_start函数
该函数用于初始化和启动一个 LoRa 集中器设备。接下来我们来看看该函数是如何实现功能的吧!
1、检查设备是否已经启动
if (lgw_is_started == true)
{
DEBUG_MSG("Note: LoRa concentrator already started, restarting it now\n");
}
2、连接到设备(lgw_connect函数下面已经整理了)
reg_stat = lgw_connect(false, rf_tx_notch_freq[rf_tx_enable[1]?1:0]);
if (reg_stat == LGW_REG_ERROR)
{
DEBUG_MSG("ERROR: FAIL TO CONNECT BOARD\n");
return LGW_HAL_ERROR;
}
3、重置寄存器(lgw_soft_reset函数下面已经整理了)
lgw_soft_reset();
lgw_reg_w(LGW_GLOBAL_EN, 0);
lgw_reg_w(LGW_CLK32M_EN, 0);
4、启动和重置射频电台
lgw_reg_w(LGW_RADIO_A_EN,1);
lgw_reg_w(LGW_RADIO_B_EN,1);
wait_ms(500);
lgw_reg_w(LGW_RADIO_RST,1);
wait_ms(5);
lgw_reg_w(LGW_RADIO_RST,0);
5、配置射频电台
err = lgw_setup_sx125x(0, rf_clkout, rf_enable[0], rf_radio_type[0], rf_rx_freq[0]);
if (err != 0)
{
DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
return LGW_HAL_ERROR;
}
err = lgw_setup_sx125x(1, rf_clkout, rf_enable[1], rf_radio_type[1], rf_rx_freq[1]);
if (err != 0)
{
DEBUG_MSG("ERROR: Failed to setup sx125x radio for RF chain 0\n");
return LGW_HAL_ERROR;
}
6、配置外部数字滤波器
lgw_reg_w(LGW_GPIO_MODE,31);
lgw_reg_w(LGW_GPIO_SELECT_OUTPUT,2);
7、配置LBT(Listen Before Talk)功能
if (lbt_is_enabled() == true)
{
lgw_reg_w(LGW_CLK32M_EN, 1);
i = lbt_setup();
if (i != LGW_LBT_SUCCESS)
{
DEBUG_MSG("ERROR: lbt_setup() did not return SUCCESS\n");
return LGW_HAL_ERROR;
}
lgw_reg_w(LGW_CLK32M_EN, 0);
i = lbt_start();
if (i != LGW_LBT_SUCCESS)
{
DEBUG_MSG("ERROR: lbt_start() did not return SUCCESS\n");
return LGW_HAL_ERROR;
}
}
8、启用时钟
lgw_reg_w(LGW_GLOBAL_EN, 1);
lgw_reg_w(LGW_CLK32M_EN, 1);
9、选择和发送校准命令
cal_cmd = 0;
cal_cmd |= rf_enable[0] ? 0x01 : 0x00;
cal_cmd |= rf_enable[1] ? 0x02 : 0x00;
cal_cmd |= (rf_enable[0] && rf_tx_enable[0]) ? 0x04 : 0x00;
cal_cmd |= (rf_enable[1] && rf_tx_enable[1]) ? 0x08 : 0x00;
cal_cmd |= 0x10;
switch (rf_radio_type[0]) {
case LGW_RADIO_TYPE_SX1255:
cal_cmd |= 0x20;
break;
case LGW_RADIO_TYPE_SX1257:
cal_cmd |= 0x00;
break;
default:
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d FOR RADIO TYPE\n", rf_radio_type[0]);
break;
}
cal_time = 2300;
10、加载校准固件并启动MCU
load_firmware(MCU_AGC, cal_firmware, MCU_AGC_FW_BYTE);
lgw_reg_w(LGW_FORCE_HOST_RADIO_CTRL, 0);
lgw_reg_w(LGW_RADIO_SELECT, cal_cmd);
lgw_reg_w(LGW_MCU_RST_1, 0);
11、检查固件版本
lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, FW_VERSION_ADDR);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
fw_version = (uint8_t)read_val;
if (fw_version != FW_VERSION_CAL)
{
printf("ERROR: Version of calibration firmware not expected, actual:%d expected:%d\n", fw_version, FW_VERSION_CAL);
return -1;
}
12、启动校准并检查校准状态
lgw_reg_w(LGW_PAGE_REG, 3);
lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 0);
DEBUG_PRINTF("Note: calibration started (time: %u ms)\n", cal_time);
wait_ms(cal_time);
lgw_reg_w(LGW_EMERGENCY_FORCE_HOST_CTRL, 1);
lgw_reg_r(LGW_MCU_AGC_STATUS, &read_val);
cal_status = (uint8_t)read_val;
if ((cal_status & 0x81) != 0x81)
{
DEBUG_PRINTF("ERROR: CALIBRATION FAILURE (STATUS = %u)\n", cal_status);
return LGW_HAL_ERROR;
}
13、获取和检查校准偏移值
for(i=0; i<=7; ++i)
{
lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA0+i);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
cal_offset_a_i[i] = (int8_t)read_val;
lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xA8+i);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
cal_offset_a_q[i] = (int8_t)read_val;
lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB0+i);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
cal_offset_b_i[i] = (int8_t)read_val;
lgw_reg_w(LGW_DBG_AGC_MCU_RAM_ADDR, 0xB8+i);
lgw_reg_r(LGW_DBG_AGC_MCU_RAM_DATA, &read_val);
cal_offset_b_q[i] = (int8_t)read_val;
}
14、调整常数并配置频率漂移
lgw_constant_adjust();
x = 4096000000 / (rf_rx_freq[0] >> 1);
x = ( x > 63 ) ? 63 : x;
lgw_reg_w(LGW_FREQ_TO_TIME_DRIFT, x);
x = 4096000000 / (rf_rx_freq[0] >> 3);
x = ( x > 63 ) ? 63 : x;
lgw_reg_w(LGW_MBWSSF_FREQ_TO_TIME_DRIFT, x);
15、配置LoRa多通道解调器
radio_select = 0;
for(i=0; i<LGW_MULTI_NB; ++i)
{
radio_select += (if_rf_chain[i] == 1 ? 1 << i : 0);
}
16、配置LoRa单独解调器
lgw_reg_w(LGW_IF_FREQ_8, IF_HZ_TO_REG(if_freq[8]));
if (if_enable[8] == true) {
lgw_reg_w(LGW_MBWSSF_RADIO_SELECT, if_rf_chain[8]);
switch(lora_rx_bw) {
case BW_125KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 0); break;
case BW_250KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 1); break;
case BW_500KHZ: lgw_reg_w(LGW_MBWSSF_MODEM_BW, 2); break;
default:
DEBUG_PRINTF("ERROR: UNEXPECTED VALUE %d IN SWITCH STATEMENT\n", lora_rx_bw);
return LGW_HAL_ERROR;
}
switch(lora_rx_sf) {
case DR_LORA_SF7: lgw_reg_w(LGW_MBWSSF_RATE_SF, 7); break;
case DR_LORA_SF8: lgw_reg_w(LGW_MBWSSF_RATE_SF, 8); break;
case DR_LORA_SF9: lgw_reg_w(LGW_MBWSSF_RATE_SF, 9); break;
四、lgw_connect函数
这段代码主要用于连接 LoRa 集中器,并且在连接成功后进行一些初始化操作。以下是代码的详细解释:
代码主干部分
int lgw_connect(bool spi_only, uint32_t tx_notch_freq)
{
int spi_stat = LGW_SPI_SUCCESS;
uint8_t u = 0;
int x;
/* check SPI link status */
if (lgw_spi_target != NULL)
{
DEBUG_MSG("WARNING: concentrator was already connected\n");
lgw_spi_close(lgw_spi_target);
}
/* open the SPI link */
spi_stat = lgw_spi_open(&lgw_spi_target);
if (spi_stat != LGW_SPI_SUCCESS)
{
DEBUG_MSG("ERROR CONNECTING CONCENTRATOR\n");
return LGW_REG_ERROR;
}
lgw_connect
函数接受两个参数:spi_only
表示是否仅使用 SPI,tx_notch_freq
是传输时的不可用频率。- 首先,代码检查当前的 SPI 链接状态,如果已经连接了集中器,则关闭当前连接。
- 然后,尝试打开 SPI 链接,如果打开失败,则输出错误信息并返回错误代码
LGW_REG_ERROR
。
if (spi_only == false ) {
/* Detect if the gateway has an FPGA with SPI mux header support */
/* First, we assume there is an FPGA, and try to read its version */
spi_stat = lgw_spi_r(lgw_spi_target, LGW_SPI_MUX_MODE1, LGW_SPI_MUX_TARGET_FPGA, loregs[LGW_VERSION].addr, &u);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR READING VERSION REGISTER\n");
return LGW_REG_ERROR;
}
if (check_fpga_version(u) != true) {
/* We failed to read expected FPGA version, so let's assume there is no FPGA */
DEBUG_PRINTF("INFO: no FPGA detected or version not supported (v%u)\n", u);
lgw_spi_mux_mode = LGW_SPI_MUX_MODE0;
} else {
DEBUG_PRINTF("INFO: detected FPGA with SPI mux header (v%u)\n", u);
lgw_spi_mux_mode = LGW_SPI_MUX_MODE1;
/* FPGA Soft Reset */
lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 1);
lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 0);
/* FPGA configure */
x = lgw_fpga_configure(tx_notch_freq);
if (x != LGW_REG_SUCCESS) {
DEBUG_MSG("ERROR CONFIGURING FPGA\n");
return LGW_REG_ERROR;
}
}
/* check SX1301 version */
spi_stat = lgw_spi_r(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_VERSION].addr, &u);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR READING CHIP VERSION REGISTER\n");
return LGW_REG_ERROR;
}
if (u != loregs[LGW_VERSION].dflt) {
DEBUG_PRINTF("ERROR: NOT EXPECTED CHIP VERSION (v%u)\n", u);
return LGW_REG_ERROR;
}
/* write 0 to the page/reset register */
spi_stat = lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, loregs[LGW_PAGE_REG].addr, 0);
if (spi_stat != LGW_SPI_SUCCESS) {
DEBUG_MSG("ERROR WRITING PAGE REGISTER\n");
return LGW_REG_ERROR;
} else {
lgw_regpage = 0;
}
}
如果 spi_only
参数为 false
,则执行以下操作:
- 检测网关是否具有带有 SPI 复用器头的 FPGA 支持。
- 尝试读取 FPGA 版本,如果成功读取到版本号则进行 FPGA 的软复位和配置。
- 检查 SX1301 芯片的版本号,并且确保版本号与期望的版本号相符。
- 将值 0 写入页/复位寄存器,以重置寄存器页为默认页。
DEBUG_MSG("Note: success connecting the concentrator\n");
return LGW_REG_SUCCESS;
}
最后,在成功连接集中器后输出成功信息,并返回 LGW_REG_SUCCESS
表示连接成功。
五、lgw_soft_reset函数
这个函数实现了软重置功能,用于重置集中器模块。
1、检查SPI连接
if ((lgw_spi_target == NULL) || (lgw_regpage < 0))
{
DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
return LGW_REG_ERROR;
}
这里首先检查了是否已经初始化了 SPI 连接,并且检查了是否已经设置了正确的寄存器页(lgw_regpage
)。如果 SPI 连接未初始化或者寄存器页设置不正确,就会打印错误消息并返回 LGW_REG_ERROR
。
2、发送软重置命令
lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_SX1301, 0, 0x80); /* 1 -> SOFT_RESET bit */
这行代码向 SX1301 芯片的指定目标(LGW_SPI_MUX_TARGET_SX1301
)发送一个特定的命令字节,其中第 7 位被设置为 1,表示软重置(SOFT_RESET)。这个命令将触发 SX1301 芯片执行软重置操作。
3、重置寄存器页
lgw_regpage = 0; /* reset the paging static variable */
4、返回执行结果