Skip to content

Commit a955619

Browse files
committed
v5.0.1
* HAL: Reworked the way the TX start delay is calculated, taking into account the delay introduced by TX notch filter (when enabled) and the delay linked to signal bandwidth separately.
1 parent a0d4607 commit a955619

File tree

9 files changed

+106
-76
lines changed

9 files changed

+106
-76
lines changed

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
5.0.0
1+
5.0.1

libloragw/inc/loragw_fpga.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ this file is autogenerated from registers description
8484
/* -------------------------------------------------------------------------- */
8585
/* --- PUBLIC FUNCTIONS PROTOTYPES ------------------------------------------ */
8686

87+
/**
88+
@brief LoRa concentrator TX notch filter delay
89+
@return delay in microseconds introduced by TX notch filter
90+
*/
91+
float lgw_fpga_get_tx_notch_delay(void);
92+
93+
/**
94+
@brief LoRa concentrator FPGA configuration
95+
@param tx_notch_freq TX notch filter frequency, in Hertz
96+
@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
97+
*/
8798
int lgw_fpga_configure(uint32_t tx_notch_freq);
8899

89100
/**

libloragw/inc/loragw_lbt.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ int lbt_start(void);
5858
@param tx_allowed pointer to receive permission for transmission
5959
@return LGW_LBT_ERROR id the operation failed, LGW_LBT_SUCCESS else
6060
*/
61-
int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed);
61+
int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed);
6262

6363
/**
6464
@brief Check if LBT is enabled

libloragw/inc/loragw_reg.h

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,6 @@ struct lgw_reg_s {
4141
int32_t dflt; /*!< register default value */
4242
};
4343

44-
enum lgw_brd_version_e {
45-
LGW_BRD_VERSION_1_0, /*!< Gateway v1.0 (no FPGA) */
46-
LGW_BRD_VERSION_1_5, /*!< Gateway v1.5 (with FPGA) */
47-
LGW_BRD_VERSION_UNKNOWN /*!< Unknown */
48-
};
49-
5044
/* -------------------------------------------------------------------------- */
5145
/* --- INTERNAL SHARED FUNCTIONS -------------------------------------------- */
5246

@@ -414,12 +408,6 @@ int lgw_connect(bool spi_only, uint32_t tx_notch_freq);
414408
*/
415409
int lgw_disconnect(void);
416410

417-
/**
418-
@brief Get LoRa concentrator board version
419-
@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)
420-
*/
421-
int lgw_brd_version(enum lgw_brd_version_e * brd_version);
422-
423411
/**
424412
@brief Use the soft-reset register to put the concentrator in initial state
425413
@return status of register operation (LGW_REG_SUCCESS/LGW_REG_ERROR)

libloragw/src/loragw_fpga.c

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ const struct lgw_reg_s fpga_regs[LGW_FPGA_TOTALREGS] = {
9999
extern void *lgw_spi_target; /*! generic pointer to the SPI device */
100100
extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */
101101

102+
/* -------------------------------------------------------------------------- */
103+
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
104+
static bool tx_notch_support = false;
105+
static uint8_t tx_notch_offset;
106+
102107
/* -------------------------------------------------------------------------- */
103108
/* --- PRIVATE FUNCTIONS ---------------------------------------------------- */
104109

@@ -108,10 +113,25 @@ extern uint8_t lgw_spi_mux_mode; /*! current SPI mux mode used */
108113
/* -------------------------------------------------------------------------- */
109114
/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
110115

116+
float lgw_fpga_get_tx_notch_delay(void) {
117+
float tx_notch_delay;
118+
119+
if (tx_notch_support == false) {
120+
return 0;
121+
}
122+
123+
/* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */
124+
tx_notch_delay = (31.25 * ((64 + tx_notch_offset) / 2)) / 1E3; /* 32MHz => 31.25ns */
125+
126+
return tx_notch_delay;
127+
}
128+
129+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
130+
111131
int lgw_fpga_configure(uint32_t tx_notch_freq) {
112132
int x;
113-
int32_t val, notch_offset_reg;
114-
bool tx_filter_support, spectral_scan_support, lbt_support;
133+
int32_t val;
134+
bool spectral_scan_support, lbt_support;
115135

116136
/* Check input parameters */
117137
if ((tx_notch_freq < LGW_MIN_NOTCH_FREQ) || (tx_notch_freq > LGW_MAX_NOTCH_FREQ)) {
@@ -122,16 +142,16 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) {
122142
/* Get supported FPGA features */
123143
printf("INFO: FPGA supported features:");
124144
lgw_fpga_reg_r(LGW_FPGA_FEATURE, &val);
125-
tx_filter_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1);
126-
if (tx_filter_support) {
145+
tx_notch_support = TAKE_N_BITS_FROM((uint8_t)val, 0, 1);
146+
if (tx_notch_support == true) {
127147
printf(" [TX filter] ");
128148
}
129149
spectral_scan_support = TAKE_N_BITS_FROM((uint8_t)val, 1, 1);
130-
if (spectral_scan_support) {
150+
if (spectral_scan_support == true) {
131151
printf(" [Spectral Scan] ");
132152
}
133153
lbt_support = TAKE_N_BITS_FROM((uint8_t)val, 2, 1);
134-
if (lbt_support) {
154+
if (lbt_support == true) {
135155
printf(" [LBT] ");
136156
}
137157
printf("\n");
@@ -152,9 +172,9 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) {
152172
}
153173

154174
/* Configure TX notch filter */
155-
if (tx_filter_support == true) {
156-
notch_offset_reg = (32E6 / (2*tx_notch_freq)) - 64;
157-
x = lgw_fpga_reg_w(LGW_FPGA_NOTCH_FREQ_OFFSET, notch_offset_reg);
175+
if (tx_notch_support == true) {
176+
tx_notch_offset = (32E6 / (2*tx_notch_freq)) - 64;
177+
x = lgw_fpga_reg_w(LGW_FPGA_NOTCH_FREQ_OFFSET, (int32_t)tx_notch_offset);
158178
if (x != LGW_REG_SUCCESS) {
159179
DEBUG_MSG("ERROR: Failed to configure FPGA TX notch filter\n");
160180
return LGW_REG_ERROR;
@@ -166,10 +186,10 @@ int lgw_fpga_configure(uint32_t tx_notch_freq) {
166186
DEBUG_MSG("ERROR: Failed to read FPGA TX notch frequency\n");
167187
return LGW_REG_ERROR;
168188
}
169-
if (val != notch_offset_reg) {
189+
if (val != tx_notch_offset) {
170190
DEBUG_MSG("WARNING: TX notch filter frequency is not programmable (check your FPGA image)\n");
171191
} else {
172-
DEBUG_PRINTF("INFO: TX notch filter frequency set to %u (%i)\n", tx_notch_freq, notch_offset_reg);
192+
DEBUG_PRINTF("INFO: TX notch filter frequency set to %u (%i)\n", tx_notch_freq, tx_notch_offset);
173193
}
174194
}
175195

libloragw/src/loragw_hal.c

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ Maintainer: Sylvain Miermont
8585
#define LGW_RF_RX_BANDWIDTH_250KHZ 1000000 /* for 250KHz channels */
8686
#define LGW_RF_RX_BANDWIDTH_500KHZ 1100000 /* for 500KHz channels */
8787

88+
#define TX_START_DELAY_DEFAULT 1497 /* Calibrated value for 500KHz BW and notch filter disabled */
89+
8890
/* constant arrays defining hardware capability */
8991
const uint8_t ifmod_config[LGW_IF_CHAIN_NB] = LGW_IFMODEM_CONFIG;
9092

@@ -157,12 +159,6 @@ static int8_t cal_offset_a_q[8]; /* TX Q offset for radio A */
157159
static int8_t cal_offset_b_i[8]; /* TX I offset for radio B */
158160
static int8_t cal_offset_b_q[8]; /* TX Q offset for radio B */
159161

160-
/* -------------------------------------------------------------------------- */
161-
/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
162-
163-
/* TX start delay adjusted for the concentrator board used */
164-
uint16_t lgw_i_tx_start_delay_us = 1500; /* shared with LBT module */
165-
166162
/* -------------------------------------------------------------------------- */
167163
/* --- PRIVATE FUNCTIONS DECLARATION ---------------------------------------- */
168164

@@ -332,7 +328,7 @@ void lgw_constant_adjust(void) {
332328
lgw_reg_w(LGW_FSK_PATTERN_TIMEOUT_CFG,128); /* sync timeout (allow 8 bytes preamble + 8 bytes sync word, default 0 */
333329

334330
/* TX general parameters */
335-
lgw_reg_w(LGW_TX_START_DELAY, (int32_t)lgw_i_tx_start_delay_us); /* default 0 */
331+
lgw_reg_w(LGW_TX_START_DELAY, TX_START_DELAY_DEFAULT); /* default 0 */
336332

337333
/* TX LoRa */
338334
// lgw_reg_w(LGW_TX_MODE,0); /* default 0 */
@@ -383,6 +379,36 @@ int32_t lgw_sf_getval(int x) {
383379
}
384380
}
385381

382+
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
383+
384+
uint16_t lgw_get_tx_start_delay(bool tx_notch_enable, uint8_t bw) {
385+
float notch_delay_us = 0.0;
386+
float bw_delay_us = 0.0;
387+
float tx_start_delay;
388+
389+
/* Notch filtering performed by FPGA adds a constant delay (group delay) that we need to compensate */
390+
if (tx_notch_enable) {
391+
notch_delay_us = lgw_fpga_get_tx_notch_delay();
392+
}
393+
394+
/* Calibrated delay brought by SX1301 depending on signal bandwidth */
395+
switch (bw) {
396+
case BW_125KHZ:
397+
bw_delay_us = 1.5;
398+
break;
399+
case BW_500KHZ:
400+
/* Intended fall-through: it is the calibrated reference */
401+
default:
402+
break;
403+
}
404+
405+
tx_start_delay = (float)TX_START_DELAY_DEFAULT - bw_delay_us - notch_delay_us;
406+
407+
printf("INFO: tx_start_delay=%u (%f) - (%u, bw_delay=%f, notch_delay=%f)\n", (uint16_t)tx_start_delay, tx_start_delay, TX_START_DELAY_DEFAULT, bw_delay_us, notch_delay_us);
408+
409+
return (uint16_t)tx_start_delay; /* keep truncating instead of rounding: better behaviour measured */
410+
}
411+
386412
/* -------------------------------------------------------------------------- */
387413
/* --- PUBLIC FUNCTIONS DEFINITION ------------------------------------------ */
388414

@@ -678,7 +704,6 @@ int lgw_start(void) {
678704
uint8_t cal_cmd;
679705
uint16_t cal_time;
680706
uint8_t cal_status;
681-
enum lgw_brd_version_e brd_version = LGW_BRD_VERSION_UNKNOWN;
682707

683708
uint64_t fsk_sync_word_reg;
684709

@@ -692,24 +717,6 @@ int lgw_start(void) {
692717
return LGW_HAL_ERROR;
693718
}
694719

695-
/* Adjust parameters which depends on the concentrator board version */
696-
reg_stat = lgw_brd_version(&brd_version);
697-
if ((reg_stat == LGW_REG_ERROR) || (brd_version == LGW_BRD_VERSION_UNKNOWN)) {
698-
DEBUG_MSG("ERROR: FAIL TO GET BOARD VERSION\n");
699-
return LGW_HAL_ERROR;
700-
}
701-
switch (brd_version) {
702-
case LGW_BRD_VERSION_1_0:
703-
lgw_i_tx_start_delay_us = 1495; /* adjusted to send Class-B beacons at 1500µs after PPS +/-1µs */
704-
break;
705-
case LGW_BRD_VERSION_1_5:
706-
lgw_i_tx_start_delay_us = 1494; /* adjusted to send Class-B beacons at 1500µs after PPS +/-1µs */
707-
break;
708-
default:
709-
/* nothing to do */
710-
break;
711-
}
712-
713720
/* reset the registers (also shuts the radios down) */
714721
lgw_soft_reset();
715722

@@ -1335,6 +1342,8 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
13351342
uint8_t target_mix_gain = 0; /* used to select the proper I/Q offset correction */
13361343
uint32_t count_trig = 0; /* timestamp value in trigger mode corrected for TX start delay */
13371344
bool tx_allowed = false;
1345+
uint16_t tx_start_delay;
1346+
bool tx_notch_enable = false;
13381347

13391348
/* check if the concentrator is running */
13401349
if (lgw_is_started == false) {
@@ -1396,6 +1405,14 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
13961405
return LGW_HAL_ERROR;
13971406
}
13981407

1408+
/* Enable notch filter for LoRa 125kHz */
1409+
if ((pkt_data.modulation == MOD_LORA) && (pkt_data.bandwidth == BW_125KHZ)) {
1410+
tx_notch_enable = true;
1411+
}
1412+
1413+
/* Get the TX start delay to be applied for this TX */
1414+
tx_start_delay = lgw_get_tx_start_delay(tx_notch_enable, pkt_data.bandwidth);
1415+
13991416
/* interpretation of TX power */
14001417
for (pow_index = txgain_lut.size-1; pow_index > 0; pow_index--) {
14011418
if (txgain_lut.lut[pow_index].rf_power <= pkt_data.rf_power) {
@@ -1443,7 +1460,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
14431460
/* TX state machine must be triggered at (T0 - lgw_i_tx_start_delay_us) for packet to start being emitted at T0 */
14441461
if (pkt_data.tx_mode == TIMESTAMPED)
14451462
{
1446-
count_trig = pkt_data.count_us - (uint32_t)lgw_i_tx_start_delay_us;
1463+
count_trig = pkt_data.count_us - (uint32_t)tx_start_delay;
14471464
buff[3] = 0xFF & (count_trig >> 24);
14481465
buff[4] = 0xFF & (count_trig >> 16);
14491466
buff[5] = 0xFF & (count_trig >> 8);
@@ -1519,10 +1536,12 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
15191536
if (pkt_data.bandwidth == BW_500KHZ) {
15201537
buff[0] |= 0x80; /* Set MSB bit to enlarge analog filter for 500kHz BW */
15211538
}
1522-
else if (pkt_data.bandwidth == BW_125KHZ){
1523-
buff[0] |= 0x40; /* Set MSB-1 bit to enable digital filter for 125kHz BW */
1524-
}
15251539

1540+
/* Set MSB-1 bit to enable digital filter if required */
1541+
if (tx_notch_enable == true) {
1542+
DEBUG_MSG("INFO: Enabling TX notch filter\n");
1543+
buff[0] |= 0x40;
1544+
}
15261545
} else if (pkt_data.modulation == MOD_FSK) {
15271546
/* metadata 7, modulation type, radio chain selection and TX power */
15281547
buff[7] = (0x20 & (pkt_data.rf_chain << 5)) | 0x10 | (0x0F & pow_index); /* bit 4 is 1 -> FSK modulation */
@@ -1567,6 +1586,9 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
15671586
return LGW_HAL_ERROR;
15681587
}
15691588

1589+
/* Configure TX start delay based on TX notch filter */
1590+
lgw_reg_w(LGW_TX_START_DELAY, tx_start_delay);
1591+
15701592
/* copy payload from user struct to buffer containing metadata */
15711593
memcpy((void *)(buff + payload_offset), (void *)(pkt_data.payload), pkt_data.size);
15721594

@@ -1578,7 +1600,7 @@ int lgw_send(struct lgw_pkt_tx_s pkt_data) {
15781600
lgw_reg_wb(LGW_TX_DATA_BUF_DATA, buff, transfer_size);
15791601
DEBUG_ARRAY(i, transfer_size, buff);
15801602

1581-
x = lbt_is_channel_free(&pkt_data, &tx_allowed);
1603+
x = lbt_is_channel_free(&pkt_data, tx_start_delay, &tx_allowed);
15821604
if (x != LGW_LBT_SUCCESS) {
15831605
DEBUG_MSG("ERROR: Failed to check channel availability for TX\n");
15841606
return LGW_HAL_ERROR;

libloragw/src/loragw_lbt.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ int lbt_start(void) {
215215

216216
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
217217

218-
int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) {
218+
int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, uint16_t tx_start_delay, bool * tx_allowed) {
219219
int i;
220220
int32_t val;
221221
uint32_t tx_start_time = 0;
@@ -255,7 +255,7 @@ int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) {
255255
break;
256256
case ON_GPS:
257257
DEBUG_MSG("tx_mode = ON_GPS\n");
258-
tx_start_time = (sx1301_time + (uint32_t)lgw_i_tx_start_delay_us + 1000000) & LBT_TIMESTAMP_MASK;
258+
tx_start_time = (sx1301_time + (uint32_t)tx_start_delay + 1000000) & LBT_TIMESTAMP_MASK;
259259
break;
260260
case IMMEDIATE:
261261
DEBUG_MSG("ERROR: tx_mode IMMEDIATE is not supported when LBT is enabled\n");
@@ -267,7 +267,7 @@ int lbt_is_channel_free(struct lgw_pkt_tx_s * pkt_data, bool * tx_allowed) {
267267
/* Select LBT Channel corresponding to required TX frequency */
268268
lbt_channel_decod_1 = -1;
269269
lbt_channel_decod_2 = -1;
270-
if (pkt_data->bandwidth == BW_125KHZ){
270+
if (pkt_data->bandwidth == BW_125KHZ) {
271271
for (i=0; i<lbt_nb_active_channel; i++) {
272272
if (is_equal_freq(pkt_data->freq_hz, lbt_channel_cfg[i].freq_hz) == true) {
273273
DEBUG_PRINTF("LBT: select channel %d (%u Hz)\n", i, lbt_channel_cfg[i].freq_hz);

libloragw/src/loragw_reg.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,6 @@ const struct lgw_reg_s loregs[LGW_TOTALREGS] = {
389389
/* --- PRIVATE VARIABLES ---------------------------------------------------- */
390390

391391
static int lgw_regpage = -1; /*! keep the value of the register page selected */
392-
static enum lgw_brd_version_e lgw_i_brd_version = LGW_BRD_VERSION_UNKNOWN; /*! detected concentrator board version */
393392

394393
/* -------------------------------------------------------------------------- */
395394
/* --- INTERNAL SHARED VARIABLES -------------------------------------------- */
@@ -532,11 +531,9 @@ int lgw_connect(bool spi_only, uint32_t tx_notch_freq) {
532531
/* We failed to read expected FPGA version, so let's assume there is no FPGA */
533532
DEBUG_PRINTF("INFO: no FPGA detected or version not supported (v%u)\n", u);
534533
lgw_spi_mux_mode = LGW_SPI_MUX_MODE0;
535-
lgw_i_brd_version = LGW_BRD_VERSION_1_0;
536534
} else {
537535
DEBUG_PRINTF("INFO: detected FPGA with SPI mux header (v%u)\n", u);
538536
lgw_spi_mux_mode = LGW_SPI_MUX_MODE1;
539-
lgw_i_brd_version = LGW_BRD_VERSION_1_5;
540537
/* FPGA Soft Reset */
541538
lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 1);
542539
lgw_spi_w(lgw_spi_target, lgw_spi_mux_mode, LGW_SPI_MUX_TARGET_FPGA, 0, 0);
@@ -590,20 +587,6 @@ int lgw_disconnect(void) {
590587

591588
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
592589

593-
/* Get concentrator board version */
594-
int lgw_brd_version(enum lgw_brd_version_e * brd_version) {
595-
if (lgw_spi_target == NULL) {
596-
DEBUG_MSG("ERROR: CONCENTRATOR UNCONNECTED\n");
597-
return LGW_REG_ERROR;
598-
}
599-
600-
*brd_version = lgw_i_brd_version;
601-
602-
return LGW_REG_SUCCESS;
603-
}
604-
605-
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
606-
607590
/* soft-reset function */
608591
int lgw_soft_reset(void) {
609592
/* check if SPI is initialised */

readme.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,12 @@ chip through GPIO, before starting any application using the concentrator.
7070
4. Changelog
7171
-------------
7272

73+
### v5.0.1 ###
74+
75+
* HAL: Reworked the way the TX start delay is calculated, taking into account
76+
the delay introduced by TX notch filter (when enabled) and the delay linked to
77+
signal bandwidth separately.
78+
7379
### v5.0.0 ###
7480

7581
* HAL: Changed GPS module to get native GPS time (monotonic, no leap second).

0 commit comments

Comments
 (0)