Skip to content

Commit ea8b6f8

Browse files
committed
applications: serial_lte_modem: Fix asserts when pressing power pin
Asserts were enabled with PR #20040. This has caused an assert to occur when pressing power pin, because GPIO callback (power_pin_callback_wakeup) called slm_at_host_power_on, which called k_sleep(), which has an assert that it's not called from interrupt context. Added most of the wake up operation into a worker. Jira: LRCS-70 Signed-off-by: Tommi Rantanen <tommi.rantanen@nordicsemi.no>
1 parent 52966b0 commit ea8b6f8

File tree

1 file changed

+35
-19
lines changed
  • applications/serial_lte_modem/src

1 file changed

+35
-19
lines changed

applications/serial_lte_modem/src/main.c

+35-19
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,12 @@ BUILD_ASSERT(!IS_ENABLED(CONFIG_SLM_START_SLEEP),
4343
static struct k_work_delayable indicate_work;
4444

4545
struct k_work_q slm_work_q;
46+
static atomic_t callback_wakeup_running;
4647

4748
/* Forward declarations */
4849
static void indicate_wk(struct k_work *work);
50+
static void power_pin_callback_wakeup(const struct device *dev,
51+
struct gpio_callback *gpio_callback, uint32_t);
4952

5053
NRF_MODEM_LIB_ON_INIT(lwm2m_init_hook, on_modem_lib_init, NULL);
5154
NRF_MODEM_LIB_ON_DFU_RES(main_dfu_hook, on_modem_dfu_res, NULL);
@@ -149,19 +152,22 @@ static int configure_power_pin_interrupt(gpio_callback_handler_t handler, gpio_f
149152
return err;
150153
}
151154

152-
LOG_DBG("Configured interrupt (0x%x) on power pin (%u).", flags, pin);
155+
LOG_DBG("Configured interrupt (0x%x) on power pin (%u) with handler (%p).",
156+
flags, pin, handler);
153157
return 0;
154158
}
155159

156-
static void power_pin_callback_poweroff(const struct device *, struct gpio_callback *, uint32_t)
160+
static void slm_enter_sleep_work_fn(struct k_work *)
157161
{
158-
LOG_INF("Power off triggered.");
159162
slm_enter_sleep();
160163
}
161164

162-
static void poweroff_interrupt_enabler(struct k_work *)
165+
static void power_pin_callback_poweroff(const struct device *, struct gpio_callback *, uint32_t)
163166
{
164-
configure_power_pin_interrupt(power_pin_callback_poweroff, GPIO_INT_EDGE_RISING);
167+
static K_WORK_DEFINE(work, slm_enter_sleep_work_fn);
168+
169+
LOG_INF("Power off triggered.");
170+
k_work_submit(&work);
165171
}
166172

167173
#endif /* POWER_PIN_IS_ENABLED */
@@ -237,25 +243,18 @@ static void indicate_stop(void)
237243
static void power_pin_callback_enable_poweroff(const struct device *dev,
238244
struct gpio_callback *gpio_callback, uint32_t)
239245
{
240-
static K_WORK_DELAYABLE_DEFINE(work, poweroff_interrupt_enabler);
241-
242246
LOG_DBG("Enabling the poweroff interrupt shortly...");
243247
gpio_remove_callback(dev, gpio_callback);
244248

245-
/* Enable the poweroff interrupt after a small delay
246-
* so that it doesn't fire right away (which it does if enabled here).
247-
*/
248-
k_work_schedule(&work, K_MSEC(1));
249+
configure_power_pin_interrupt(power_pin_callback_poweroff, GPIO_INT_EDGE_RISING);
249250
}
250251

251-
static void power_pin_callback_wakeup(const struct device *dev,
252-
struct gpio_callback *gpio_callback, uint32_t)
252+
static void power_pin_callback_wakeup_work_fn(struct k_work *)
253253
{
254-
static atomic_t callback_running;
255254
int err;
256255

257256
/* Prevent level triggered interrupt running this multiple times. */
258-
if (!atomic_cas(&callback_running, false, true)) {
257+
if (!atomic_cas(&callback_wakeup_running, false, true)) {
259258
return;
260259
}
261260

@@ -271,17 +270,34 @@ static void power_pin_callback_wakeup(const struct device *dev,
271270
}
272271
err = slm_at_host_power_on();
273272
if (err) {
274-
atomic_set(&callback_running, false);
273+
/* We couldn't wake up SLM device. Re-enable wakeup functionality. */
274+
configure_power_pin_interrupt(power_pin_callback_wakeup, GPIO_INT_LEVEL_LOW);
275+
atomic_set(&callback_wakeup_running, false);
275276
LOG_ERR("Failed to power on uart: %d", err);
276277
return;
277278
}
278279

279-
gpio_remove_callback(dev, gpio_callback);
280-
281280
/* Enable the poweroff interrupt only when the pin will be back to a nonactive state. */
282281
configure_power_pin_interrupt(power_pin_callback_enable_poweroff, GPIO_INT_EDGE_RISING);
283282

284-
atomic_set(&callback_running, false);
283+
atomic_set(&callback_wakeup_running, false);
284+
}
285+
286+
static void power_pin_callback_wakeup(const struct device *dev,
287+
struct gpio_callback *gpio_callback, uint32_t)
288+
{
289+
static K_WORK_DEFINE(work, power_pin_callback_wakeup_work_fn);
290+
291+
/* Prevent level triggered interrupt running this multiple times. */
292+
if (!atomic_cas(&callback_wakeup_running, false, true)) {
293+
LOG_WRN("power_pin_callback_wakeup_work_fn already running.");
294+
return;
295+
}
296+
297+
LOG_INF("Resuming from idle shortly...");
298+
gpio_remove_callback(dev, gpio_callback);
299+
300+
k_work_submit(&work);
285301
}
286302

287303
void slm_enter_idle(void)

0 commit comments

Comments
 (0)