mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-09-02 10:33:47 +00:00
sx1262 fixes
- calibrate_image: revert to datasheet band table. Narrow ±2 MHz window had truncation bug placing 433/869 MHz operating freq outside their own calibration windows. DS §9.2.1 confirms cal is range-validity, not point-precision - reset_agc: K_FOREVER mutex → K_MSEC(50). Was holding dispatcher thread up to ~3 s if a long TX/RX held the SPI lock. Now bails with WARN log; caller retries next maintenance interval.
This commit is contained in:
@@ -94,3 +94,4 @@ THINKNODE_M1_HANDOVER.md
|
||||
CLAUDE.md
|
||||
zephcore/apc_checklist.md
|
||||
zephcore/apc.md
|
||||
RADIO_AUDIT_INDEX.md
|
||||
|
||||
@@ -68,7 +68,7 @@ index 17689720dd2..09982dc2e70 100644
|
||||
return -EINVAL;
|
||||
}
|
||||
diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c
|
||||
index 30243ba5dc7..befb84797eb 100644
|
||||
index 30243ba5dc7..86c10f39fc3 100644
|
||||
--- a/drivers/lora/native/sx126x/sx126x.c
|
||||
+++ b/drivers/lora/native/sx126x/sx126x.c
|
||||
@@ -10,10 +10,16 @@
|
||||
@@ -88,34 +88,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
#define SX126X_REST_STATE \
|
||||
(IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_SLEEP) \
|
||||
? SX126X_STATE_SLEEP : SX126X_STATE_IDLE)
|
||||
@@ -177,22 +183,10 @@ static int sx126x_calibrate_image(const struct device *dev, uint32_t freq)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
|
||||
- if (freq > 900000000) {
|
||||
- buf[0] = 0xE1;
|
||||
- buf[1] = 0xE9;
|
||||
- } else if (freq > 850000000) {
|
||||
- buf[0] = 0xD7;
|
||||
- buf[1] = 0xDB;
|
||||
- } else if (freq > 770000000) {
|
||||
- buf[0] = 0xC1;
|
||||
- buf[1] = 0xC5;
|
||||
- } else if (freq > 460000000) {
|
||||
- buf[0] = 0x75;
|
||||
- buf[1] = 0x81;
|
||||
- } else {
|
||||
- buf[0] = 0x6B;
|
||||
- buf[1] = 0x6F;
|
||||
- }
|
||||
+ /* Calibrate ±2 MHz around the actual frequency.
|
||||
+ * CalibrateImage bytes are in 4 MHz steps (freq_Hz / 4000000). */
|
||||
+ buf[0] = (uint8_t)((freq - 2000000) / 4000000);
|
||||
+ buf[1] = (uint8_t)((freq + 2000000) / 4000000);
|
||||
|
||||
return sx126x_hal_write_cmd(dev, SX126X_CMD_CALIBRATE_IMAGE, buf, 2);
|
||||
}
|
||||
@@ -222,6 +216,7 @@ static int sx126x_set_packet_params(const struct device *dev,
|
||||
@@ -222,6 +228,7 @@ static int sx126x_set_packet_params(const struct device *dev,
|
||||
uint8_t invert_iq)
|
||||
{
|
||||
uint8_t buf[6];
|
||||
@@ -123,7 +96,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
|
||||
sys_put_be16(preamble_len, &buf[0]);
|
||||
buf[2] = header_type;
|
||||
@@ -229,7 +224,31 @@ static int sx126x_set_packet_params(const struct device *dev,
|
||||
@@ -229,7 +236,31 @@ static int sx126x_set_packet_params(const struct device *dev,
|
||||
buf[4] = crc_mode;
|
||||
buf[5] = invert_iq;
|
||||
|
||||
@@ -156,7 +129,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
}
|
||||
|
||||
static int sx126x_set_sync_word(const struct device *dev, bool public_network)
|
||||
@@ -247,6 +266,13 @@ static int sx126x_set_rx_gain(const struct device *dev, bool boosted)
|
||||
@@ -247,6 +278,13 @@ static int sx126x_set_rx_gain(const struct device *dev, bool boosted)
|
||||
{
|
||||
uint8_t val = boosted ? SX126X_RX_GAIN_BOOSTED : SX126X_RX_GAIN_POWER_SAVING;
|
||||
|
||||
@@ -170,7 +143,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
return sx126x_hal_write_regs(dev, SX126X_REG_RX_GAIN, &val, 1);
|
||||
}
|
||||
|
||||
@@ -296,7 +322,7 @@ static int sx126x_get_packet_status(const struct device *dev,
|
||||
@@ -296,7 +334,7 @@ static int sx126x_get_packet_status(const struct device *dev,
|
||||
uint8_t buf[3];
|
||||
int ret;
|
||||
|
||||
@@ -179,15 +152,20 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
if (ret == 0) {
|
||||
/* RSSI is -value/2 dBm */
|
||||
*rssi = -((int16_t)buf[0] >> 1);
|
||||
@@ -367,6 +393,21 @@ static int sx126x_chip_init(const struct device *dev)
|
||||
@@ -367,6 +405,26 @@ static int sx126x_chip_init(const struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ /* After TX/RX, fall back to STDBY_XOSC instead of STDBY_RC.
|
||||
+ * Keeps the crystal warm so the next SetRx skips the ~500 us
|
||||
+ * XOSC startup, reducing the deaf window between packets. */
|
||||
+ /* After TX/RX, fall back to FS mode instead of the default STDBY_RC.
|
||||
+ * FS keeps both XOSC and PLL active, so the next SetRx skips both the
|
||||
+ * ~500 us XOSC startup AND the ~50-100 us PLL settle — minimising the
|
||||
+ * deaf window between packets. Costs ~5-10 mA while in this state, but
|
||||
+ * we are typically only here for the brief ISR-to-handler window before
|
||||
+ * sleep or the next operation. Critical for duty-cycle restart where
|
||||
+ * every microsecond of deafness can mean a missed preamble.
|
||||
+ * (datasheet Table 13-23: 0x40=FS, 0x30=STDBY_XOSC, 0x20=STDBY_RC) */
|
||||
+ {
|
||||
+ uint8_t fallback = 0x40; /* STDBY_XOSC */
|
||||
+ uint8_t fallback = 0x40; /* FS mode */
|
||||
+
|
||||
+ ret = sx126x_hal_write_cmd(dev,
|
||||
+ SX126X_CMD_SET_RX_TX_FALLBACK_MODE,
|
||||
@@ -201,8 +179,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
/* Set packet type to LoRa */
|
||||
ret = sx126x_set_packet_type(dev, SX126X_PACKET_TYPE_LORA);
|
||||
if (ret < 0) {
|
||||
@@ -374,10 +415,16 @@ static int sx126x_chip_init(const struct device *dev)
|
||||
LOG_ERR("Set packet type failed: %d", ret);
|
||||
@@ -374,10 +432,16 @@ static int sx126x_chip_init(const struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -221,7 +198,8 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
+ ret = sx126x_set_dio_irq_params(dev, irq_mask, dio1_mask, 0, 0);
|
||||
if (ret < 0) {
|
||||
LOG_ERR("Set IRQ params failed: %d", ret);
|
||||
@@ -398,7 +445,7 @@ static void sx126x_dio1_callback(const struct device *dev)
|
||||
return ret;
|
||||
@@ -398,7 +462,7 @@ static void sx126x_dio1_callback(const struct device *dev)
|
||||
{
|
||||
struct sx126x_data *data = dev->data;
|
||||
|
||||
@@ -230,7 +208,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
}
|
||||
|
||||
static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
|
||||
@@ -406,7 +453,20 @@ static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
|
||||
@@ -406,7 +470,20 @@ static void sx126x_set_rf_path(const struct device *dev, bool enable, bool tx)
|
||||
const struct sx126x_hal_config *config = dev->config;
|
||||
|
||||
sx126x_hal_set_antenna_enable(dev, enable);
|
||||
@@ -252,7 +230,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
sx126x_hal_set_rf_switch(dev, enable, tx);
|
||||
}
|
||||
}
|
||||
@@ -455,6 +515,80 @@ static int sx126x_reconnect_rf_gpios(const struct device *dev)
|
||||
@@ -455,6 +532,80 @@ static int sx126x_reconnect_rf_gpios(const struct device *dev)
|
||||
}
|
||||
#endif /* CONFIG_PM_DEVICE */
|
||||
|
||||
@@ -333,7 +311,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
static int sx126x_set_sleep(const struct device *dev)
|
||||
{
|
||||
struct sx126x_data *data = dev->data;
|
||||
@@ -533,6 +667,9 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
@@ -533,6 +684,9 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
struct sx126x_data *data = dev->data;
|
||||
struct sx126x_rx_result result = { 0 };
|
||||
uint8_t payload_len = 0, offset = 0;
|
||||
@@ -343,7 +321,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
int ret;
|
||||
|
||||
/* Get received packet info */
|
||||
@@ -564,20 +701,34 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
@@ -564,20 +718,34 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,7 +368,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
}
|
||||
} else {
|
||||
/* Sync mode */
|
||||
@@ -589,8 +740,46 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
@@ -589,8 +757,46 @@ static void sx126x_handle_irq_rx_done(const struct device *dev, uint16_t irq_sta
|
||||
static void sx126x_handle_irq_timeout(const struct device *dev)
|
||||
{
|
||||
struct sx126x_data *data = dev->data;
|
||||
@@ -437,7 +415,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
sx126x_set_sleep(dev);
|
||||
|
||||
if (data->tx_async_signal != NULL) {
|
||||
@@ -637,6 +826,25 @@ static void sx126x_irq_work_handler(struct k_work *work)
|
||||
@@ -637,6 +843,25 @@ static void sx126x_irq_work_handler(struct k_work *work)
|
||||
sx126x_handle_irq_timeout(dev);
|
||||
}
|
||||
|
||||
@@ -463,7 +441,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
/* Re-enable the DIO1 interrupt for the next event (unless sleeping) */
|
||||
if (atomic_get(&data->state) != SX126X_REST_STATE) {
|
||||
sx126x_hal_dio1_irq_enable(dev);
|
||||
@@ -682,7 +890,7 @@ static int sx126x_lora_config(const struct device *dev,
|
||||
@@ -682,7 +907,7 @@ static int sx126x_lora_config(const struct device *dev,
|
||||
/* Configure PA and TX power based on chip variant and frequency */
|
||||
ret = sx126x_hal_configure_tx_params(dev, config->tx_power,
|
||||
config->frequency,
|
||||
@@ -472,7 +450,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
@@ -698,6 +906,29 @@ static int sx126x_lora_config(const struct device *dev,
|
||||
@@ -698,6 +923,29 @@ static int sx126x_lora_config(const struct device *dev,
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -502,7 +480,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
/* Set sync word */
|
||||
ret = sx126x_set_sync_word(dev, config->public_network);
|
||||
if (ret < 0) {
|
||||
@@ -721,6 +952,8 @@ out:
|
||||
@@ -721,6 +969,8 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -511,7 +489,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
static int sx126x_lora_send_async(const struct device *dev,
|
||||
uint8_t *data_buf, uint32_t data_len,
|
||||
struct k_poll_signal *async)
|
||||
@@ -752,6 +985,65 @@ static int sx126x_lora_send_async(const struct device *dev,
|
||||
@@ -752,6 +1002,65 @@ static int sx126x_lora_send_async(const struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -577,7 +555,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
data->tx_async_signal = async;
|
||||
k_msgq_purge(&data->tx_msgq);
|
||||
|
||||
@@ -777,6 +1069,29 @@ static int sx126x_lora_send_async(const struct device *dev,
|
||||
@@ -777,6 +1086,29 @@ static int sx126x_lora_send_async(const struct device *dev,
|
||||
/* Enable antenna and set TX path */
|
||||
sx126x_set_rf_path(dev, true, true);
|
||||
|
||||
@@ -607,7 +585,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
/* Start transmission with 10 second timeout */
|
||||
ret = sx126x_set_tx(dev, 10000);
|
||||
if (ret < 0) {
|
||||
@@ -847,6 +1162,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
|
||||
@@ -847,6 +1179,8 @@ static int sx126x_lora_recv(const struct device *dev, uint8_t *data_buf,
|
||||
}
|
||||
|
||||
data->rx_cb = NULL;
|
||||
@@ -616,7 +594,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
k_msgq_purge(&data->rx_msgq);
|
||||
|
||||
/* Set packet parameters for variable length reception */
|
||||
@@ -918,6 +1235,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
@@ -918,6 +1252,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
/* Stop async reception */
|
||||
data->rx_cb = NULL;
|
||||
data->rx_cb_user_data = NULL;
|
||||
@@ -624,7 +602,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
if (atomic_cas(&data->state, SX126X_STATE_RX, SX126X_STATE_IDLE)) {
|
||||
sx126x_set_standby(dev, SX126X_STANDBY_RC);
|
||||
sx126x_set_sleep(dev);
|
||||
@@ -947,6 +1265,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
@@ -947,6 +1282,8 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
|
||||
data->rx_cb = cb;
|
||||
data->rx_cb_user_data = user_data;
|
||||
@@ -633,7 +611,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
|
||||
/* Set packet parameters */
|
||||
ret = sx126x_set_packet_params(dev,
|
||||
@@ -959,6 +1279,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
@@ -959,6 +1296,7 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
SX126X_LORA_IQ_INVERTED : SX126X_LORA_IQ_STANDARD);
|
||||
if (ret < 0) {
|
||||
data->rx_cb = NULL;
|
||||
@@ -641,7 +619,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
sx126x_set_sleep(dev);
|
||||
k_mutex_unlock(&data->lock);
|
||||
return ret;
|
||||
@@ -971,11 +1292,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
@@ -971,11 +1309,21 @@ static int sx126x_lora_recv_async(const struct device *dev,
|
||||
ret = sx126x_set_rx(dev, 0);
|
||||
if (ret < 0) {
|
||||
data->rx_cb = NULL;
|
||||
@@ -663,7 +641,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
k_mutex_unlock(&data->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -1051,7 +1382,7 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
@@ -1051,7 +1399,7 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
|
||||
/* Set PA config and TX power */
|
||||
ret = sx126x_hal_configure_tx_params(dev, tx_power, frequency,
|
||||
@@ -672,7 +650,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
if (ret < 0) {
|
||||
sx126x_set_sleep(dev);
|
||||
k_mutex_unlock(&data->lock);
|
||||
@@ -1083,14 +1414,505 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
@@ -1083,14 +1431,513 @@ static int sx126x_lora_test_cw(const struct device *dev, uint32_t frequency,
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -753,7 +731,15 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
+ struct sx126x_data *data = dev->data;
|
||||
+ const struct sx126x_hal_config *config = dev->config;
|
||||
+
|
||||
+ k_mutex_lock(&data->lock, K_FOREVER);
|
||||
+ /* Bounded wait: a long TX/RX (e.g. SF12 packet ~3 s airtime) holds
|
||||
+ * data->lock for its full duration. K_FOREVER here would stall the
|
||||
+ * caller (typically the dispatcher main thread) for that whole time
|
||||
+ * and freeze packet routing. Instead, give up after 50 ms and let
|
||||
+ * the caller retry on the next maintenance interval. */
|
||||
+ if (k_mutex_lock(&data->lock, K_MSEC(50)) != 0) {
|
||||
+ LOG_WRN("reset_agc: mutex busy, skipping this cycle");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Warm sleep — powers down the analog frontend (resets AGC state)
|
||||
+ * but preserves register configuration. */
|
||||
@@ -1185,7 +1171,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_DEVICE
|
||||
@@ -1112,6 +1934,7 @@ static int sx126x_pm_action(const struct device *dev,
|
||||
@@ -1112,6 +1959,7 @@ static int sx126x_pm_action(const struct device *dev,
|
||||
static int sx126x_init(const struct device *dev)
|
||||
{
|
||||
struct sx126x_data *data = dev->data;
|
||||
@@ -1193,7 +1179,7 @@ index 30243ba5dc7..befb84797eb 100644
|
||||
int ret;
|
||||
|
||||
/* Initialize data structures */
|
||||
@@ -1121,9 +1944,25 @@ static int sx126x_init(const struct device *dev)
|
||||
@@ -1121,9 +1969,25 @@ static int sx126x_init(const struct device *dev)
|
||||
k_msgq_init(&data->rx_msgq, (char *)&data->rx_result,
|
||||
sizeof(struct sx126x_rx_result), 1);
|
||||
k_work_init(&data->irq_work, sx126x_irq_work_handler);
|
||||
|
||||
Reference in New Issue
Block a user