How to improve interrupt handler function pick up?

General discussions and questions abound development of code with MicroPython that is not hardware specific.
Target audience: MicroPython Users.
Post Reply
Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

How to improve interrupt handler function pick up?

Post by Divergentti » Thu Jan 21, 2021 10:37 am

I am strugling with a touch screen interrupt handler in this code https://github.com/divergentti/airquali ... en/main.py

Idea is to replace interrupt handler for each setup screen, which seems to work fine, but initial interrupt handler:

Code: Select all

self.xpt.int_handler = self.first_press
goes to:

Code: Select all

    def first_press(self, x, y):
        """ If touchscreen is pressed, change status """
        gc.collect()
        # self.display.clear()
        self.touchscreen_pressed = True
and then in the asynchronous loop, which as default loops through display show (co2, particles etc):

Code: Select all

    async def run_display_loop(self):
        # TODO: Initial welcome screen?

        # await self.show_welcome_screen()

        # NOTE: Loop is started in the main()

        while True:
            if self.touchscreen_pressed is True:
                if self.setup_screen_active is False:
                    # First setup screen
                    self.draw_setup_screen()
                else:
                    # Draw setup screen just once
                    # TODO: screen timeout
                    pass
            elif self.touchscreen_pressed is False:
                rows, rowcolours = await self.show_time_co2_temp_screen()
                await self.show_screen(rows, rowcolours)
                rows, rowcolours = await self.show_particle_screen()
                await self.show_screen(rows, rowcolours)
                rows, rowcolours = await self.show_status_monitor_screen()
                await self.show_screen(rows, rowcolours)
            await asyncio.sleep_ms(1)
Loop practically check if touchscreen is pressed once per millisecond and if condition is true, activate setup screen(s). This logic generally works, but I have hard time to get interrupt handler working first time, meaning, that somehow interrupt is not activated promptly. I may need to press touchscreen a few seconds before interrupt handler activates.

I tried to change screen update so that instead of using await asyncio.sleep I had a counter for each millisecond, which checked is touchscreen pressed (= interrupt handler), but behavior was same.

Documentation https://docs.micropython.org/en/latest/ ... rules.html explains "As mentioned above, ISR’s should be designed to be as simple as possible. They should always return in a short, predictable period of time. This is important because when the ISR is running, the main loop is not: inevitably the main loop experiences pauses in its execution at random points in the code." and this is true, because if I long press touch screen digitizer, screen update slows down, but the interrupt handler function is not activated.

Is there better ways to implement interrupt handlers or is my logic wrong?

User avatar
pythoncoder
Posts: 4929
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: How to improve interrupt handler function pick up?

Post by pythoncoder » Thu Jan 21, 2021 11:58 am

I have developed GUI's for three different touchscreens, using the same general approach. Hardware interrupts are not used. The touch controller is polled by a uasyncio task which runs continuously. An example may be seen here. The responsiveness is fine. In my view interrupts are only necessary when you need a response measured in μs. The human response required from a touch panel is in the 10-100ms range which uasyncio can provide.

Incidentally uasyncio.sleep_ms(1) is wishful thinking. The time taken to switch tasks is the time used by each task between yields to the scheduler multiplied by the number of concurrent tasks. So uasyncio.sleep_ms(0) will yield delays measured in many milliseconds - the number being entirely dependent on your code.
Peter Hinch

User avatar
jimmo
Posts: 2235
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: How to improve interrupt handler function pick up?

Post by jimmo » Thu Jan 21, 2021 12:53 pm

Calling gc.collect() from an interrupt handler is going to be problematic as collection takes a (relatively) long time.

I suspect part of the problem here might be that on ESP32, all IRQs run in scheduler context, which means that they will be blocked by operations like updating the display (e.g. while the SPI transfer is in progress).

Another thing to take a look at is in the Touch driver, the int_press method does a sleep(0.1) which will block all execution. Rather than sleeping for debouncing, record the time the last event occurred (using time.ticks_ms) and then use time.ticks_diff to decide whether a future event should be ignored or not.

User avatar
pythoncoder
Posts: 4929
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: How to improve interrupt handler function pick up?

Post by pythoncoder » Thu Jan 21, 2021 4:28 pm

Debouncing? Unless the touch controller datasheet says otherwise it shouldn't be needed: contact bounce is a feature of mechanical switches.
Peter Hinch

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: How to improve interrupt handler function pick up?

Post by Divergentti » Thu Jan 21, 2021 5:20 pm

Thank you @jimmo and @pythoncoder! I am getting there. At least I know what is wrong.

For testing I added to the toucscreen driver https://github.com/divergentti/airquali ... XPT2046.py simple self.pressed status flag, what I continuously monitor in the main code in the asynchronous loop. Now touchscreen press is recognized immediatly, but I have to figure out how to do that int_handler part so that it returns proper x and y coordinates.

main.py code https://github.com/divergentti/airquali ... en/main.py

Divergentti
Posts: 67
Joined: Fri Sep 04, 2020 9:27 am
Location: Hanko, Finland
Contact:

Re: How to improve interrupt handler function pick up?

Post by Divergentti » Fri Jan 22, 2021 10:23 am

Update:

Problem was bad DUPONT patch cable connectors! You can use them once, then throw them away!

Touchscreen with the interrupt works just fine. If you need to debug, check behavior by adding print just after "def int_press" and then print just after "if buss is not None:". Normal operations shows pin.value() 0 in the beginning and then 1 as long as touchscreen is pressed, and x,y values are read if interrupt is locked. If you have bad cables, you may see pin.value 1 or 0, but x, y values are not read.

Code: Select all

 def int_press(self, pin):
        """Send X,Y values to passed interrupt handler. Interrupt activates when pressed and once interrupt is
         active, coordinates can be read."""

        if not pin.value() and not self.int_locked:
            self.int_locked = True  # Lock Interrupt
            buff = self.raw_touch()

            if buff is not None:
                x, y = self.normalize(*buff)
                self.int_handler(x, y)
            sleep(.1)  # Debounce falling edge
        elif pin.value() and self.int_locked:
            sleep(.1)  # Debounce rising edge
            self.int_locked = False  # Unlock interrupt

Post Reply