Interrupt Queueing #1397
-
Hi, I'm using I am sure there is a way to disable such a behavior, right? I already tried wrapping my ISR in |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 22 replies
-
Can you give a minimal example of what's going and what's expected? A button ISR triggers an ADC reading, but if during reading the interrupt is triggered another time it pre-empts the running execution or still queues the next ISR call? Disabling interrupts should avoid pre-emption / nesting per https://stackoverflow.com/a/45807834. |
Beta Was this translation helpful? Give feedback.
-
Overclocking will do nothing for you.
The SDK function adc_read() will wait for each analog sample until it is
available. Also not really something you want to do in interrupt context.
That's why see such a dramatic difference when changing the number of
samples you take.
…On April 25, 2023 13:03:36 NuclearPhoenix ***@***.***> wrote:
Thanks a lot for your time! I just checked it and it definitely seems to
help a bit, although, it still doesn't seem to get rid of the effect (I can
go to about 550 ints/sec instead of 500). If I change the number of ADC
measurements to take inside the function, it still changes a lot. (L605).
If I do 5 vs 1 analogRead(), for example, I can go from 550 ints/sec to
about 2k ints/sec without much of an issue, so something's clearly still
happening here.
Now, I could do only one, of course, and it also helps a lot to overclock
the Pico, but now I'm very much interested what's really going on here 🤔
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message
ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
@Phoenix1747 There are no doubt better ways to use the ADC, by going a bit more direct to the hardware, but I think you would still run into the problem of the fundamental bandwidth of the internal ADC being too low - if you needed a sample within, say, 1 microsecond of an event / detection, you would need at least a 1MHz bandwidth ADC, or more realistically, a faster one than that. I've just had an idea, which might work better. You can make a simple sample and hold circuit with an analog switch, a suitable capacitor and a FET input op amp. Your ISR could simply grab and hold the sample, then set a flag to say to read it. The held value will decay, but potentially quite slowly. If you can read it with the ADC within a reliable interval, that may be good enough, or perhaps you could also use a timer to measure how long it's been since the flag was set by the ISR - make the ISR store the time in clock cycles, for example. You can then use a lookup table or just an exponential floating point calculation, to compensate for the time taken, to give you a more accurate reading. Coping with more arriving before the ADC reading can be taken, could be done by just adding more sample and hold circuits, e.g. a quad op amp chip could provide two or maybe four, with a four channel analog switch. Since there will definitely be a limit, set by your hardware design, to how many events you can handle in a few microseconds, the code doesn't need to be very complicated - just an ISR that can set flags allocated from a small pool, held in an array, and some code in a loop that polls for the flags being set and acts on them, freeing up a flag for re-use as it deals with one. The ISR can just read through the array of flags to find a free one, since there can only be a very limited number of them - there's no need for anything more complicated like lists or dynamic allocation. Also, the ISR code linked to, used a calculation as part of disabling the interrupt for the pin, but that just produces a constant value from another constant. Maybe you could be passing the pre-calculated values instead, or have the ISR pull them out of an array, if it can only be passed a pin number. I always wondered with things like Z80 ISRs if it was possible for another interrupt to happen before the single instruction that was used to disable them. In this case, there are quite a lot of clock cycles where the ISR is calculating values to use to disable them, which seems like asking for trouble. |
Beta Was this translation helpful? Give feedback.
-
@Phoenix1747 It needs to get to the point where it's setting control bits as soon as possible after the start of the ISR, to reduce the chances of another interrupt happening first. I'm guessing that for any given pin number, there is only one possible value for &(iobank0_hw->proc0_irq_ctrl.inte[INT_PIN / 8]), 0b1111 << (INT_PIN % 8 )*4u, so those values could presumably be calculated in advance, e.g. in setup(), then stored in an array. If so, retrieving them from the array might be quicker, even though that's a simple looking calculation. The fewer clock cycles you can do it in, the better. |
Beta Was this translation helpful? Give feedback.
-
@Phoenix1747 I haven't looked at the code, but if INT_PIN is a constant, isn't &(iobank0_hw->proc0_irq_ctrl.inte[INT_PIN / 8]), 0b1111 << (INT_PIN % 8 )*4u the same every time? If so, just evaluate it once, during setup() and store it in a global or static variable. But, yes, avoiding the possibility of another interrupt happening before interrupts are disabled, would be much better. A simple SR latch, made from two NAND or NOR gates could do it - the detection circuit would set the latch, then the ISR would clear it as the last step before it exits. There would still be the small possibility of another interrupt before the ISR actually does return, so ideally, it should have a monostable circuit to add a small delay to the reset - two more gates and a capacitor + resistor, so a quad NAND or NOR gate chip would do it. Maybe the PIO could be programmed to simulate that sort of circuit? You'd need a state variable that can be set by the external detector circuit, then a delayed reset that can be initiated by the CPU, counting enough clock cycles to allow for the ISR to finish up. If it doesn't need to respond immediately, and in a set amount of time, maybe it would be better to just not use interrupts at all, and poll the detector in a tight loop. You could potentially have one core doing other things, provided you can prioritise the one doing the polling. |
Beta Was this translation helpful? Give feedback.
-
@Phoenix1747 Here, there's an example of a simple logic circuit which detects pulses with a lock out period (retriggerable one-shot monostable multivibrator). More pulses arriving within the lockout period get ignored: https://www.allaboutcircuits.com/textbook/digital/chpt-10/monostable-multivibrators/ The sort of hardware that's needed just takes one 74HC series 14 pin chip (e.g. 74HC00 quad NAND gate or 74HC02 quad NOR gate), or similar, and a couple of discrete components. It can be built on the smallest sized breadboard, e.g. https://www.pololu.com/product/1490 (47 × 35 mm (1.84 × 1.37") and there are prototyping PCBs you can buy very cheaply, to make a soldered version. Add a 0.1uF (100nF) capacitor between the Vcc and GND pins, as close as possible to the Vcc pin, to decouple (smooth) the power supply to avoid glitches. You'd just need to place that circuit between your detector and the CPU pin. |
Beta Was this translation helpful? Give feedback.
-
I don't get it. What is the actual answer ? No example code included. How should the code look when I want to disable the interrupt and assign for example a new.
|
Beta Was this translation helpful? Give feedback.
Another idea, have you tried explicitly clearing the GPIO IRQ at the end of your ISR, right before returning? That would throw out anything that happened during your ISR cleanly w/o you keeping track of anything.
There should be an NVIC function and maybe an Pico-SDK wrapper call you could use. One note, though, is that there is only one IRQ for all GPIO pins, so if you have other GPIO-based IRQs you'll lose those, too.