Missing Pin interrupts with HTTP GET

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
Post Reply
ljweko
Posts: 2
Joined: Fri Jun 25, 2021 9:23 pm

Missing Pin interrupts with HTTP GET

Post by ljweko » Fri Jun 25, 2021 9:58 pm

I have to detect/count frequency of 30Hz on digital input pin and occasionally send results to HTTP server.
Test code to count 30Hz is standard:

Code: Select all

ctr = 0
def cbInt(p):
	global ctr
	ctr = ctr + 1
def xstart(lock):
	pin = Pin(27, Pin.IN)
	pin.irq(trigger = Pin.IRQ_RISING, handler = cbInt)
Then I have loop with async.sleep to get ctr value every 10 seconds.

Code: Select all

async def loop():
	global ctr
	while True:
		irqs = machine.disable_irq()
		tmp = ctr
		ctr = 0
		machine.enable_irq(irqs)
		print(tmp)
		await asyncio.sleep(10)
So far so good, with 30Hz signal on Pin I get 300 interrupts every 10 seconds. Now I include simple HTTP PUT every 25 secs on separate async loop. Now some interrupts are missing, not always. Some HTTP requests pass OK, but occasionally it only counts 260 or even less interrupts in 10 seconds.

I know getaddrinfo is blocking, so I put interrupt routine in separate thread, with no improvement. I assume the problem lies in mp_sched_schedule still waiting for getaddrinfo to finish.

1. Is this assumption correct?
2. Does the same problem exist e.g. with 1wire driver in combination with MQTT?
3. Besides using static IP (nope), is there a way to instruct DNS resolver to use cached value for longer time?
4. Is there other solution besides writing external C module?

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: Missing Pin interrupts with HTTP GET

Post by marcidy » Sat Jun 26, 2021 6:32 am

Depending on what exactly you mean, I don't think dropping to C will help if you have to use getaddrinfo with every request.

The blocking is happening in the lwip call to netconn_gethostbyname, not in any micropython code. The call itself will block until the IP address is resolved or timesout even if you call it directly from C.

I don't understand why the interrupts aren't working during this call, though, but I haven't dug through the whole call graph to see if they are disabled somewhere.

You can cache the result of getaddrinfo yourself, you really don't need to call it every request, but that doesn't help you for the times when you do need to call it.

Personally, I'm lazy, so I would solve this with an intermediate server with a static IP which bounces the info to the destination. An external pulse counter circuit is also an option rather than relying on ESP32's interrupts. That would give you plenty of time to complete the getaddrinfo call.

ljweko
Posts: 2
Joined: Fri Jun 25, 2021 9:23 pm

Re: Missing Pin interrupts with HTTP GET

Post by ljweko » Fri Jul 09, 2021 3:52 pm

I tried with static IP (thanks), getaddrinfo now doesn't skip interrupts. However, when I break transmission (no internet connection to server) the problem arises again. Each line in next table shows: utime.time, digital input 1 count, digital input 2 count (unused), time diff from previous line.

Code: Select all

679154084 300 0 10
679154094 300 0 10
11.22.33.44 9889
***** [Errno 113] ECONNABORTED
679154117 158 0 23
679154127 300 0 10
679154137 300 0 10
11.22.33.44 9889
***** [Errno 113] ECONNABORTED
679154161 159 0 24
679154171 300 0 10
679154181 300 0 10
11.22.33.44 9889
***** [Errno 113] ECONNABORTED
679154204 160 0 23
When doing GET from IP not only pin interrupts are missing, the asyncio.sleep(10) loop is executed after ~24 seconds instead of expected 10 seconds.

Code for HTTP GET (from requests.py):

Code: Select all

print(host, port)
ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM)
ai = ai[0]
s = usocket.socket(ai[0], ai[1], ai[2])
try:
	s.connect(ai[-1])
except Exception as e:
	print('*****', e)
I am using MicroPython v1.15-212-g0db4d296d on TinyPico.

Is there any workaround available?

My appli has to detect that there is at least one state change on digital input every 40ms. Missing change means system problem.

marcidy
Posts: 133
Joined: Sat Dec 12, 2020 11:07 pm

Re: Missing Pin interrupts with HTTP GET

Post by marcidy » Fri Jul 09, 2021 11:29 pm

Sorry, I'm not clear. Are you suspecting the getaddrinfo in requests.py is the problem? If so, rewrite it passing it the static IP instead of host.

requests.py is adequate for some needs, and depending where you got it, really not adequate for others. For example I had to rewrite it to manage chunked encoding so I could receive large files without running out of memory.

I'm not sure if you are able to use a static IP 100% of the time now, or if you still need to rely on getaddinfo occasionally. If you have access to a static IP, use it instead of getaddrinfo everywhere that getaddrinfo appears

Post Reply