Copyright ©

Mongoose OS Forum


Analog interrupt handling possible?


I'm working on a smart electricity power meter monitor, and have an LDR hooked up to the ADC pin on my ESP8266. Using mgos_adc_read() I'm able to get reasonable values from the LDR (1024 when dark, ~60 when lit with a bright source). I've read that doing pulse counting via interrupts is the way to go here, so I've tried that out but have had no success.

Very simple example (started with demo_c and borrowed a bit from this post):

#define ADC_PIN 0
volatile uint32_t pulses = 0;

enum mgos_app_init_result mgos_app_init(void) {
  mgos_gpio_set_int_handler(ADC_PIN, MGOS_GPIO_INT_EDGE_ANY, interrupt_cb, NULL);

  /* Blink built-in LED every second */
  mgos_gpio_set_mode(mgos_sys_config_get_pins_led(), MGOS_GPIO_MODE_OUTPUT);
  mgos_set_timer(1000, MGOS_TIMER_REPEAT, led_timer_cb, NULL);


static void interrupt_cb(int pin, void *arg) {
  pulses += 1;
  LOG(LL_INFO, ("*pulse*")); // allowed?
  (void) pin;
  (void) arg;

static void led_timer_cb(void *arg) {
  bool val = mgos_gpio_toggle(mgos_sys_config_get_pins_led());
  LOG(LL_INFO, (raw=%d, pulses=%lu", mgos_adc_read(ADC_PIN), (unsigned long)pulses));
  (void) arg;

In the led cb output, I can see the raw value from the ADC pin moving around, but pulses always stays 0 and the log message there is never shown (although I'm not sure if it should be, since I'm using the _isr variant). I've tried with the standard mgos_gpio_set_int_handler() call too, and got the same result.

Am I on the right track here? I'm not entirely sure that you can use an analog source for this, since the interrupt stuff is part of gpio, but would appreciate if anyone could shed some light on it.

Thanks a lot!


  • scaprilescaprile Argentina

    I don't see an EOC interrupt callback function in Mongoose-OS's API, so you are left alone in Espressif SDK world.
    There is no such thing as an "analog interrupt". The equivalent is an analog comparator with interrupt capability (sort of an LM339 with its output tied to an interrupt capable pin). There are ADC interrupts, as the end-of-conversion (EOC) interrupt of the ADC peripheral.
    You start the ADC conversion process and either busy wait for it to finish or resume when the ADC EOC interrupt callback is called. Not the GPIO, no pulse here, the ADC EOC, and you get a number from 0 to the ADC max value.
    In most microcontrollers, when you set a pin for the ADC it is disconnected from the GPIO (he reason is more off-topic than this whole response...), so you most likely can read ADC_PIN as a digital pin once you've set it up for the ADC.
    You can periodically read the ADC and decide whether it is light/not-light and so decide it is "a pulse" and count them. Bear in mind you are sampling the pulses, your check period needs to be < 1/2 the fastest pulse period and < pulse width to guarantee you see it.
    You can redesign your circuit so a photodiode (or the LDR, a photodiode is faster but I guess the electricity meter pulse is ~100ms) lit is a 0 and unlit is a 1, and then you can count interrupts. Depending on how you do your filtering, you might need to debounce.
    PM me if you need off-topic subject ellaboration.

    Thanked by 1Sergey
  • simpsorasimpsora Australia

    Hi @scaprile,

    Thanks for the details! I was thinking that analog interrupt didn't make a whole lot of sense. I just now tried swapping the LDR from the ADC pin to a GPIO pin, and it mostly works! With a very bright light source, the voltage on the LDR is low enough that it reads low, and the interrupt fires. My intended light source is a bit dimmer, so I'll have to experiment with different resistor values for the voltage divider.

    Thanks again for the help,

  • simpsorasimpsora Australia

    By the way, the following page was extremely helpful in clarifying the conditions where a digital IO pin can be used:

    tl;dr: for a 3.3v supply:
    Low: -0.3 to 0.825v
    High: 2.475 to 3.6v

Sign In or Register to comment.