Interrupt attach/detatch functions called during ISR? (Piettetech DHT22)

Hello,

I have been using photons and DS18, DHT22 sensors for a long time now. Recently I have been having problems with DHT22 sensor, for it I am using the Piettetech library. Mainly what has changed on the firmware side before/after DHT22 started to disbehave is the enabling of system threading and utilization of an extra user thread. The communication is purely handled by the library software. Once the sensor has measured values, it triggers an interrupt on the photon, which is handled by a Piettetech library routine, during which attachInterrupt and detachInterrupt are called. However this pretty swiftly results in a deadlock.

Backtrace from the deadlocked state:

#0  0x08025072 in vListInsert (pxList=pxList@entry=0x2000d9c4, pxNewListItem=0x20010398) at WICED/RTOS    /FreeRTOS/ver7.5.2/Source/list.c:171
#1  0x08025c62 in vTaskPlaceOnEventList (pxEventList=pxEventList@entry=0x2000d9c4, xTicksToWait=4294967295) at WICED/RTOS/FreeRTOS/ver7.5.2/Source/tasks.c:1980
#2  0x080254c8 in xQueueGenericReceive (xQueue=xQueue@entry=0x2000d9a0, pvBuffer=pvBuffer@entry=0x0, xTicksToWait=xTicksToWait@entry=4294967295, xJustPeeking=xJustPeeking@entry=0) at WICED/RTOS/FreeRTOS/ver7.5.2/Source/queue.c:1164
#3  0x08025564 in xQueueTakeMutexRecursive (xMutex=0x2000d9a0, xBlockTime=xBlockTime@entry=4294967295) at WICED/RTOS/FreeRTOS/ver7.5.2/Source/queue.c:507
#4  0x0802d3c6 in __malloc_lock (ptr=ptr@entry=0x20000768 <impure_data>) at WICED/RTOS/FreeRTOS/WICED/wiced_rtos.c:475
#5  0x08031b3c in _free_r (reent_ptr=0x20000768 <impure_data>, free_p=<optimized out>) at src/mallocr.c:363
#6  0x0803e620 in std::_Function_base::_Base_manager<DHT22Sensor::DHT22Sensor(gr::PortID, gr::PortConfig)::<lambda()> >::_M_destroy (__victim=...) at /usr/include/newlib/c++/4.9.3/functional:1894
#7  std::_Function_base::_Base_manager<DHT22Sensor::DHT22Sensor(gr::PortID, gr::PortConfig)::<lambda()> >::_M_manager(std::_Any_data &, const std::_Any_data &, std::_Manager_operation) (__dest=..., __source=..., __op=<optimized out>)
    at /usr/include/newlib/c++/4.9.3/functional:1918
#8  0x080321be in std::_Function_base::~_Function_base (this=this@entry=0x20012870, __in_chrg=<optimized out>) at /usr/include/newlib/c++/4.9.3/functional:1998
#9  0x08040cb0 in std::function<void()>::~function (this=0x20012870, __in_chrg=<optimized out>) at /usr/include/newlib/c++/4.9.3/functional:2142
#10 detachInterrupt (pin=<optimized out>) at src/spark_wiring_interrupts.cpp:115
#11 0x08032f5a in PietteTech_DHT::isrCallback (this=0x20014cf0) at applications/kiwi/libraries/DHT22/src/PietteTech_DHT.cpp:185
#12 0x080203b4 in gpio_irq () at WICED/platform/MCU/STM32F2xx/peripherals/platform_gpio.c:479
#13 <signal handler called>
#14 0x080261fa in prvPortStartFirstTask () at WICED/RTOS/FreeRTOS/ver7.5.2/Source/portable/GCC/ARM_CM3/port.c:224
#15 0x08026320 in xPortStartScheduler () at WICED/RTOS/FreeRTOS/ver7.5.2/Source/portable/GCC/ARM_CM3/port.c:310
#16 0x08035954 in std::_Function_base::_Base_manager<int (*)(String)>::_M_manager (__dest=..., __source=..., __op=7) at /usr/include/newlib/c++/4.9.3/functional:1922

With my limited knowledge of what actually goes on ‘under the hood’ I figured the problem might lie in the interrupt functions doing memory alloc/deallocation, which would then cause the deadlock when performed during an ISR at the “correct” moment.
After adding some dirty methods to ‘pause/resume’ an interrupt ( into ‘wiring/src/spark_wiring_interrupts.cpp’ ) which only clears the interrupt, stores the callback object handle and does no memory allocation - the sensor began to work without problems.

/**
 ******************************************************************************
 * @file    spark_wiring_interrupts.cpp

/.../

static wiring_interrupt_handler_t *handlers[TOTAL_PINS], *_handlers[TOTAL_PINS];

/.../

bool free_stored_handler(uint16_t pin)
{
  if(_handlers[pin] == NULL) return false;
  delete _handlers[pin];
  return true;
}

bool store_handler(uint16_t pin)
{
  _handlers[pin] = handlers[pin];
  handlers[pin] = NULL;
  return _handlers[pin] != NULL;
}

bool fetch_handler(uint16_t pin)
{
  if(_handlers[pin] == NULL) return false;
  handlers[pin] = _handlers[pin];
  _handlers[pin] = NULL;
  return _handlers[pin] == NULL;
}

/.../

bool pauseInterrupt(uint16_t pin)
{
#if Wiring_Cellular == 1
    /* safety check that prevents users from detaching an interrupt from
     * BATT_INT_PC13 for power management which is shared with D7 */
    if (pin == D7) return;
#endif
    HAL_Interrupts_Detach(pin);
    return store_handler(pin);
}

bool resumeInterrupt(uint16_t pin, wiring_interrupt_handler_t fn, InterruptMode mode, int8_t priority, uint8_t subpriority)
{
#if Wiring_Cellular == 1
  /* safety check that prevents users from attaching an interrupt to D7
   * which is shared with BATT_INT_PC13 for power management */
  if (pin == D7) return false;
#endif
    HAL_Interrupts_Detach(pin);
    if(!fetch_handler(pin)) return attachInterrupt(pin, fn, mode, priority, subpriority);
    wiring_interrupt_handler_t* handler = handlers[pin];
    if (handler) {
        HAL_InterruptExtraConfiguration extra = {0};
        HAL_Interrupts_Attach(pin, call_wiring_interrupt_handler, handler, mode, configure_interrupt(extra, priority, subpriority));
    }
    return handler!=NULL;
}

Can anyone suggest what the proper way to handle this problem might look like? And is there another way to write the DHT22 software communication code without touching the system firmware and avoiding the deadlock?

I guess just masking the interrupt instead of detaching/reattaching might be the better solution.
A quick and dirty workaround might be to deactivate all interrupts or wrap the section in an ATOMIC_BLOCK.

I have tried the atomic block and the usual high-level interrupt disable ways, but if I remember correctly the lock still occurred. I will thoroughly retry the atomic block approach just to be sure.
Interrupt masking crossed my mind, but I figured since ‘pinMode’ and digital reads are performed on the input as well during the ISR it would probably screw up the system pin structures’ state somehow. I guess i’ll give this a go next.

I will get around to testing this soon.

Thank you :slight_smile: