0001-drivers-lora-sx126x-add-one-shot-IRQ-timestamp-peek.patch 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. From 4a7e9a77611d7a85a660e826c1dad97f355b0414 Mon Sep 17 00:00:00 2001
  2. From: ZiB <zib@zi3.xyz>
  3. Date: Mon, 2 Nov 2026 00:00:11 -0800
  4. Subject: [PATCH 1/3] drivers: lora: sx126x: add one-shot IRQ timestamp peek
  5. Expose higher-precision IRQ timestamp via sx126x_irq_timestamp_get()
  6. by capturing a free-running cycle count at the DIO1 GPIO ISR, before
  7. any SPI/workqueue latency, and resolving it in the IRQ handler to an
  8. absolute timestamp directly comparable to k_uptime_get()/k_uptime_ticks().
  9. Gated by CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP (default y): the
  10. cycle-counter/uptime reads, the conversions, and the extra struct
  11. fields all compile out when disabled, and sx126x_irq_timestamp_get()
  12. still links as a trivial false-returning stub so no caller needs its
  13. own #ifdef. The added work (one more cycle-counter read in the ISR,
  14. one k_uptime_ticks() read, two 64-bit fixed-point conversions) runs
  15. per IRQ, reducing timestamp latency by about 450us in testing.
  16. Signed-off-by: ZiB <zib@zi3.xyz>
  17. ---
  18. drivers/lora/native/sx126x/Kconfig | 10 +++++
  19. drivers/lora/native/sx126x/sx126x.c | 38 +++++++++++++++++
  20. drivers/lora/native/sx126x/sx126x.h | 7 ++++
  21. drivers/lora/native/sx126x/sx126x_hal.c | 4 ++
  22. drivers/lora/native/sx126x/sx126x_hal.h | 3 ++
  23. include/zephyr/drivers/lora/sx126x.h | 55 +++++++++++++++++++++++++
  24. 6 files changed, 117 insertions(+)
  25. create mode 100644 include/zephyr/drivers/lora/sx126x.h
  26. diff --git a/drivers/lora/native/sx126x/Kconfig b/drivers/lora/native/sx126x/Kconfig
  27. index 2e59112419a..14d955302b3 100644
  28. --- a/drivers/lora/native/sx126x/Kconfig
  29. +++ b/drivers/lora/native/sx126x/Kconfig
  30. @@ -39,3 +39,13 @@ config LORA_SX126X_NATIVE_STANDALONE
  31. depends on DT_HAS_SEMTECH_SX1262_ENABLED || DT_HAS_SEMTECH_SX1261_ENABLED
  32. help
  33. Standalone SX1261/SX1262 support for the native SX126x driver.
  34. +
  35. +config LORA_SX126X_NATIVE_IRQ_TIMESTAMP
  36. + bool "Radio-IRQ timestamp peek"
  37. + default y
  38. + depends on LORA_SX126X_NATIVE
  39. + help
  40. + Expose higher-precision IRQ timestamp via sx126x_irq_timestamp_get()
  41. + by capturing a free-running cycle count at the DIO1 GPIO ISR, before
  42. + any SPI/workqueue latency, and resolve it in the IRQ handler to an
  43. + absolute timestamp directly comparable to k_uptime_get()/k_uptime_ticks().
  44. diff --git a/drivers/lora/native/sx126x/sx126x.c b/drivers/lora/native/sx126x/sx126x.c
  45. index d3a7313e964..c3f9d63f3f5 100644
  46. --- a/drivers/lora/native/sx126x/sx126x.c
  47. +++ b/drivers/lora/native/sx126x/sx126x.c
  48. @@ -6,6 +6,7 @@
  49. #include <zephyr/kernel.h>
  50. #include <zephyr/device.h>
  51. #include <zephyr/drivers/lora.h>
  52. +#include <zephyr/drivers/lora/sx126x.h>
  53. #include <zephyr/pm/device.h>
  54. #include <zephyr/sys/byteorder.h>
  55. @@ -847,6 +848,15 @@ static void sx126x_irq_work_handler(struct k_work *work)
  56. return;
  57. }
  58. +#if IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP)
  59. + uint32_t delta_cycles = k_cycle_get_32() - data->hal.dio1_raw_cycles;
  60. + uint64_t delta_ns = k_cyc_to_ns_floor64(delta_cycles);
  61. + uint64_t now_ns = k_ticks_to_ns_floor64(k_uptime_ticks());
  62. +
  63. + data->irq_ts.event_uptime_ns = now_ns - delta_ns;
  64. + data->irq_ts.irq_status = irq_status;
  65. +#endif
  66. +
  67. LOG_DBG("IRQ status: 0x%04x", irq_status);
  68. /* Clear handled IRQs */
  69. @@ -870,6 +880,34 @@ static void sx126x_irq_work_handler(struct k_work *work)
  70. }
  71. }
  72. +bool sx126x_irq_timestamp_get(const struct device *dev, uint16_t irq_bit, uint64_t *ns_out)
  73. +{
  74. +#if IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP)
  75. + struct sx126x_data *data = dev->data;
  76. + unsigned int key;
  77. + uint64_t event_uptime_ns;
  78. + uint16_t irq_status;
  79. +
  80. + key = irq_lock();
  81. + event_uptime_ns = data->irq_ts.event_uptime_ns;
  82. + irq_status = data->irq_ts.irq_status;
  83. + irq_unlock(key);
  84. +
  85. + if (!(irq_status & irq_bit)) {
  86. + return false;
  87. + }
  88. +
  89. + *ns_out = event_uptime_ns;
  90. +
  91. + return true;
  92. +#else
  93. + ARG_UNUSED(dev);
  94. + ARG_UNUSED(irq_bit);
  95. + ARG_UNUSED(ns_out);
  96. + return false;
  97. +#endif
  98. +}
  99. +
  100. static int sx126x_set_configured_packet_params(const struct device *dev, uint8_t payload_len)
  101. {
  102. struct sx126x_data *data = dev->data;
  103. diff --git a/drivers/lora/native/sx126x/sx126x.h b/drivers/lora/native/sx126x/sx126x.h
  104. index 07c50f0044d..0ea5154e901 100644
  105. --- a/drivers/lora/native/sx126x/sx126x.h
  106. +++ b/drivers/lora/native/sx126x/sx126x.h
  107. @@ -75,6 +75,13 @@ struct sx126x_data {
  108. /* Deferred work for interrupt handling */
  109. struct k_work irq_work;
  110. const struct device *dev;
  111. +
  112. +#if IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP)
  113. + struct {
  114. + uint64_t event_uptime_ns;
  115. + uint16_t irq_status;
  116. + } irq_ts;
  117. +#endif
  118. };
  119. int sx126x_set_packet_type(const struct device *dev, uint8_t type);
  120. diff --git a/drivers/lora/native/sx126x/sx126x_hal.c b/drivers/lora/native/sx126x/sx126x_hal.c
  121. index 34f7089584f..2bc86251fc0 100644
  122. --- a/drivers/lora/native/sx126x/sx126x_hal.c
  123. +++ b/drivers/lora/native/sx126x/sx126x_hal.c
  124. @@ -76,6 +76,10 @@ static void dio1_isr(const struct device *gpio, struct gpio_callback *cb,
  125. {
  126. struct sx126x_hal_data *data = CONTAINER_OF(cb, struct sx126x_hal_data, dio1_cb);
  127. +#if IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP)
  128. + data->dio1_raw_cycles = k_cycle_get_32();
  129. +#endif
  130. +
  131. if (data->dio1_callback != NULL) {
  132. data->dio1_callback(data->dev);
  133. }
  134. diff --git a/drivers/lora/native/sx126x/sx126x_hal.h b/drivers/lora/native/sx126x/sx126x_hal.h
  135. index e4b26ba60bd..b7d8d30922e 100644
  136. --- a/drivers/lora/native/sx126x/sx126x_hal.h
  137. +++ b/drivers/lora/native/sx126x/sx126x_hal.h
  138. @@ -42,6 +42,9 @@ struct sx126x_hal_data {
  139. struct gpio_callback dio1_cb;
  140. void (*dio1_callback)(const struct device *dev);
  141. const struct device *dev;
  142. +#if IS_ENABLED(CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP)
  143. + uint32_t dio1_raw_cycles;
  144. +#endif
  145. };
  146. int sx126x_hal_init(const struct device *dev);
  147. diff --git a/include/zephyr/drivers/lora/sx126x.h b/include/zephyr/drivers/lora/sx126x.h
  148. new file mode 100644
  149. index 00000000000..7e134f434af
  150. --- /dev/null
  151. +++ b/include/zephyr/drivers/lora/sx126x.h
  152. @@ -0,0 +1,55 @@
  153. +/**
  154. + * @file
  155. + * @brief SX126x-specific extensions to the LoRa driver API.
  156. + *
  157. + * Not part of the generic @ref lora_interface API: these expose a hardware
  158. + * capability (radio-internal IRQ timing) specific to the SX126x family.
  159. + */
  160. +#ifndef ZEPHYR_INCLUDE_DRIVERS_LORA_SX126X_H_
  161. +#define ZEPHYR_INCLUDE_DRIVERS_LORA_SX126X_H_
  162. +
  163. +#include <zephyr/device.h>
  164. +#include <zephyr/sys/util.h>
  165. +#include <stdint.h>
  166. +#include <stdbool.h>
  167. +
  168. +#ifdef __cplusplus
  169. +extern "C" {
  170. +#endif
  171. +
  172. +/**
  173. + * @name SX126x IRQ source bits
  174. + *
  175. + * Mirror the chip's GetIrqStatus bit positions (DS.SX1261-2.W.APP,
  176. + * 13.3.1), for use with @ref sx126x_irq_timestamp_get.
  177. + * @{
  178. + */
  179. +#define SX126X_IRQ_TS_TX_DONE BIT(0)
  180. +#define SX126X_IRQ_TS_RX_DONE BIT(1)
  181. +#define SX126X_IRQ_TS_PREAMBLE_DETECTED BIT(2)
  182. +#define SX126X_IRQ_TS_SYNC_WORD_VALID BIT(3)
  183. +#define SX126X_IRQ_TS_HEADER_VALID BIT(4)
  184. +#define SX126X_IRQ_TS_HEADER_ERR BIT(5)
  185. +#define SX126X_IRQ_TS_CRC_ERR BIT(6)
  186. +#define SX126X_IRQ_TS_RX_TX_TIMEOUT BIT(9)
  187. +/** @} */
  188. +
  189. +/**
  190. + * @brief Get a precise timestamp for the most recent occurrence of one
  191. + * SX126x radio IRQ.
  192. + *
  193. + * @param dev SX126x LoRa device
  194. + * @param irq_bit Single @c SX126X_IRQ_TS_* bit to query
  195. + * @param ns_out Set to the absolute event timestamp, in nanoseconds,
  196. + * on the same timebase as @ref k_uptime_ticks
  197. + * @return true if @p irq_bit was set in the most recent IRQ status read,
  198. + * and @p ns_out was written; false otherwise (including when
  199. + * @kconfig{CONFIG_LORA_SX126X_NATIVE_IRQ_TIMESTAMP} is disabled)
  200. + */
  201. +bool sx126x_irq_timestamp_get(const struct device *dev, uint16_t irq_bit, uint64_t *ns_out);
  202. +
  203. +#ifdef __cplusplus
  204. +}
  205. +#endif
  206. +
  207. +#endif /* ZEPHYR_INCLUDE_DRIVERS_LORA_SX126X_H_ */
  208. --
  209. 2.54.0 (Apple Git-157)