-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
Add accurate interrupt counter #3775
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This sounds like it's very specific to each port i.e. each microcontroller because, as you noticed, everything is done using C (and maybe assembly) + interrupts. Almost all the work would be done setting up the counter peripheral and interrupts in C/assembly; the actual code to create the uPy module and update the counter for uPy to read is trivial. NOTE that I said each MICROCONTROLLER not each core ISA i.e. ARM, ST, Freescale, NXP. A big complication is that for the more complicated micros, sometimes external pins (or even internal resources) are shared and you might get into a situation where you can have, for example, (edge counting enabled) or . . . (something else) but not both. Or even more complicated: (edge counting at max rate (like 10KHz)) or (edge counting at a slower rate AND some other peripheral enabled). I haven't done low-level drivers in a long time but I did JUST talk to a guy who is doing it daily and he gave an example: certain micro has 2 CAN-FD bus channels and a SD-CARD channel. If you activate the second CAN-FD bus channel, the SD-CARD max data transfer rate is drastically reduced because the 2nd CAN-FD channel takes away pins from the SD-CARD and those are the pins that enable faster SD-CARD data transmission. The same thing could happen with internal multiplexing: maybe peripheral A takes up timers/special RAM area/etc and activating peripheral B, which also needs some of those resources, causes peripheral A to run slower. So, if you want to do this the user-friendly way, you'd have to implement all those dependencies - they're in the manual - and if someone tries to instantiate two peripherals with competing internal (or external) resources . . . I assume you'd want to warn the user. Or take the easy way out: you expect the user to read the 2,000 page manual to figure out all the cross-dependencies and if instantiating the 2nd CAN-FD channel reduces their SD-CARD write speed, too bad for the user; they should've read the manual. |
Hi, I am well aware of such caveats when it comes to the microcontrollers in general. I am saying the interrupt handling is already there in MicroPython, see https://micropython.org/resources/docs/en/latest/wipy/reference/isr_rules.html What I really need is just have the the interrupt handler written in C and just have it counting the events (blah++) and timestamp of last poll - and when polled return the count of events and reset both variables. My experience using MicroPython ESP32 shows that externally triggered interrupts and timers have pretty terrible jitter, but having a simple C probably yields near real-time response. |
I'm looking at this
You're saying that instead of the ISR calling |
Hi, yes something like that. I am saying the overhead of the Python interpreter in the callback machinery is probably the source of jitter/lag, having it do the counting in C and occasionally report it to the Python code probably gets the job done way better |
In order to completely avoid
you would have to create your own custom uPy firmware and flash it. Besides compiling to bytecode - which results in Python VM interpreter getting involved - you can choose to compile, at the granualarity of a uPy function, to 3 other binary formats: Native, Viper, assembly. NOTE: frozen Native or Viper code emitter. The explanation is here. Of course it's entirely possible that even the Native/Viper formats will be too slow; I have no experience with it. If those two formats are not fast enough, you can actually write native assembly. I haven't personally used any of these but based on this I'd guess it does avoid the virtual machine (after maybe a header is processed) because there are no bytecodes; it's all assembly instructions. But if writing assembly is too hard or Native/Viper is too slow, your only other option is creating custom firmware. ISR overhead ftm0_isr() -> ftm_irq_handler() -> ftm_handle_irq_callback() ->mp_call_function_1() So, the majority of overhead is definitely, as you stated, after you call |
The real issue on the ESP32 and ESP8266 is that there is essentially an underlying OS running under micropython and micropython isn't really running completely bare metal. The underlying OS will wind up disabling interrupts and/or perform other activities which you have no control over. These activities are what cause the jitter. This really has nothing to do with micropython itself. You'd notice the same behavior if you were coding in C. If you're running on a pyboard, there is no other OS. Interrupt latency is much more deterministic, and consequently you get much less jitter. There are techniques that can be used to reduce the jitter, but these typically require intimate knowledge of the microcontroller and OS that you're running on. |
Can't you configure the underlying OS? |
@adritium Have you seen this? http://esp-idf.readt 8000 hedocs.io/en/latest/api-guides/freertos-smp.html |
@WayneKeenan that should be for @laurivosandi; my question was rhetorical i.e. "you can configure the OS so the OS shouldn't be an issue" |
@laurivosandi thanks for the input on the addition of such a counter. There is an existing function IMO this is a good thing to try and add, precisely because it is 1) timing sensitive so best written in C; 2) different to implement on each MCU so helps the user if they don't need to remember/know details of all controllers. The hard part is to define a good, general API for such a functionality, that can be implemented on a broad range of devices. As I see it, the main concepts/building-blocks here is a counter object which can be incremented by an external event, in this case a pin change event. Note that such a thing already exists on pyboard/stm32. |
Use nina-fw root certs
Uh oh!
There was an error while loading. Please reload this page.
The microcontrollers support counting rising/falling edges at rather fast pace (1-10kHz), eg to measure RPM of a motor with hall sensor or disc encoder. It would be nice to have the interrupt handling implemented in C code and export something easier to use into Python:
In this pseudo-code instantiating a counter object sets up interrupt handlers and an integer for storing the count of events and another integer for storing current timestamp. When poll() function is executed, count and timestamp delta are returned and variables are reset.
The main benefit of such approach is accuracy and this probably hogs the Python runtime less as well especially at higher frequecies (1kHz and above)
The text was updated successfully, but these errors were encountered: