Skip to content

Commit 4dc426c

Browse files
trantanenrlubos
authored andcommitted
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 07c4fac commit 4dc426c

File tree

1 file changed

+33
-22
lines changed
  • applications/serial_lte_modem/src

1 file changed

+33
-22
lines changed

applications/serial_lte_modem/src/main.c

+33-22
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,24 @@ 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 *dev,
166+
struct gpio_callback *gpio_callback, uint32_t)
163167
{
164-
configure_power_pin_interrupt(power_pin_callback_poweroff, GPIO_INT_EDGE_RISING);
168+
static K_WORK_DEFINE(work, slm_enter_sleep_work_fn);
169+
170+
LOG_INF("Power off triggered.");
171+
gpio_remove_callback(dev, gpio_callback);
172+
k_work_submit(&work);
165173
}
166174

167175
#endif /* POWER_PIN_IS_ENABLED */
@@ -237,28 +245,16 @@ static void indicate_stop(void)
237245
static void power_pin_callback_enable_poweroff(const struct device *dev,
238246
struct gpio_callback *gpio_callback, uint32_t)
239247
{
240-
static K_WORK_DELAYABLE_DEFINE(work, poweroff_interrupt_enabler);
241-
242248
LOG_DBG("Enabling the poweroff interrupt shortly...");
243249
gpio_remove_callback(dev, gpio_callback);
244250

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));
251+
configure_power_pin_interrupt(power_pin_callback_poweroff, GPIO_INT_EDGE_RISING);
249252
}
250253

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

257-
/* Prevent level triggered interrupt running this multiple times. */
258-
if (!atomic_cas(&callback_running, false, true)) {
259-
return;
260-
}
261-
262258
LOG_INF("Resuming from idle.");
263259
if (k_work_delayable_is_pending(&indicate_work)) {
264260
k_work_cancel_delayable(&indicate_work);
@@ -271,17 +267,32 @@ static void power_pin_callback_wakeup(const struct device *dev,
271267
}
272268
err = slm_at_host_power_on();
273269
if (err) {
274-
atomic_set(&callback_running, false);
275-
LOG_ERR("Failed to power on uart: %d", err);
270+
LOG_ERR("Failed to power on uart: %d. Resetting SLM.", err);
271+
gpio_remove_callback(gpio_dev, &gpio_cb);
272+
slm_reset();
273+
return;
274+
}
275+
276+
atomic_set(&callback_wakeup_running, false);
277+
}
278+
279+
static void power_pin_callback_wakeup(const struct device *dev,
280+
struct gpio_callback *gpio_callback, uint32_t)
281+
{
282+
static K_WORK_DEFINE(work, power_pin_callback_wakeup_work_fn);
283+
284+
/* Prevent level triggered interrupt running this multiple times. */
285+
if (!atomic_cas(&callback_wakeup_running, false, true)) {
276286
return;
277287
}
278288

289+
LOG_INF("Resuming from idle shortly...");
279290
gpio_remove_callback(dev, gpio_callback);
280291

281292
/* Enable the poweroff interrupt only when the pin will be back to a nonactive state. */
282293
configure_power_pin_interrupt(power_pin_callback_enable_poweroff, GPIO_INT_EDGE_RISING);
283294

284-
atomic_set(&callback_running, false);
295+
k_work_submit(&work);
285296
}
286297

287298
void slm_enter_idle(void)

0 commit comments

Comments
 (0)