Multiple triggers on a single interruption on Arduino - c++

I am working on Arduinos and I would like to use interrupts to use a rotary encoder. But I would like to reduce the interrupt code to the minimum.
Can I use multiple triggers on a single interrupt?
I would like to replcace my actual code :
attachInterrupt(0, ChangeA, CHANGE);
To something like
attachInterrupt(0, FailingA, FAILING);
attachInterrupt(0, RisingA, RISING);
Is it possible?

No, not exactly possible. The external interrupt is configured to react only to one of the possibilities internally.
One thing you can do is to use a CHANGE interrupt service routine and test the value of the pin at the beginning of the ISR to do FallingA() or RisingA().
There is a potential problem here. The pin may have changed again before you test it, so the interrupt that triggered the interrupt could have been falling, say, and your test determines that it was rising. One way to guard against two quick interrupts is to check if the flag is still set. It should have been cleared if at the start of the interrupt, and if it is set then a change happened again. There is no practical way to guard against three quick changes.
If you really want to use two separate ISRs, do you have an extra pin available? If so, you could just wire the pins together and run a FALLING ISR on one and a RISING ISR on the other.

Related

Trigger stm32 timer on PWM

I'm new to stm32 timers and have a question concerning triggering.
I would like to generate four squarewaves two of each complements of each other. That is the trivial part.
Now I would like to introduce a variable phaseshift between each of the two complementary signalgroups. (Phaseshift PWM)
Now my question, can I trigger timer 2 on the falling or rising edge of a pwm signal produced by timer 1?
Or is there another way for me to generate a phaseshift between those signals that's changeable during runtime?
A single advanced control timer (TIM1 or TIM8) can do all of this for you.
See the reference manual section 17.3.11 "Complementary outputs and dead-time insertion".
Alternatively you can chain timers, see section 13.3.15 of the same manual.

Getting notified when an I2C-Value changes in C++

I recently started experimenting with I2C-Hardware on my raspberry pi. Following this tutorial Using the I2C interface I already know how to read and set values. However, the program I want to realize needs the current value on a specific address all the time. So, I made a thread and query the value constantly in a never ending loop, which seems primitive to me. Is it possible to get notified in an event-like manner when a value on an I2C-adress changes?
A platform independend solution would also be much welcomed.
I was able to get what I wanted.
I use the following repeater for the I2C-Bus: link and it turns out there is a soldering bridge (LB2) you can set that sets a signal on GPIO17 whenever a value on the I2C-Bus changes since it has last been changed. I can now listen on this events accordingly.
Generally speaking, the I2C bus has no interrupt capability. So with only I2C, all you can do is poll the chip for a certain event to happen or value to change.
Most chips do have an interrupt line (sometimes even more than one) that can be programmed to trigger on certain events. The behavior of this line depends on the chip. Usually it needs to be enabled (using I2C commands) and it needs to be linked to a GPIO input line. For these, interrupt support is available.

Could ticker interrupts interfere with hardware interrupts?

Background
I was wondering if using ticker interrupts could interfere with hardware interrupts triggered by a button press.
Example
Imagine I would like to use these two types of interrupts:
a ticker timer to update a progress bar on a small display every n second
a hardware interrupt that starts/stops the process whose progress is displayed if the user presses a button
Important: Both interrupts set shared global volatile flags.
Main question
Would it be possible for the ticker interrupt to occur during a button induced interrupt and as a result for the program to end up in a state where the global flags are set contradictorily?
More specific questions
Does a hardware and a software interrupt have the same 'rank'?
If they occured at the same time, would the interrupt request occurring slightly later (but still overlapping with the first one) be ignored, or just put into a queue and execute straight after the first interrupt has finished? In this case, the flags would be set in an unexpected manner.
Can I disable one type of the interrupts inside the other type's ISR - i.e. ignore it?
I hope the problem statement is clear enough even without a code example.
I'mm assuming you are using an AVR.
When an interrupt fires, other interrupts are disabled while the interrupt routine is running. So any interrupts that occur in this time simply get flagged. When the interrupt routine returns, the global interrupt flag is re-enabled and any polled interrupts can then fire one at a time.
You can manually enable the global interrupts inside the routine for critical things that must run, but are disabled by default.
EDIT:
Is there a way to disable this flag setting? I don't want the ticker timer to perform an interrupt once the button has been pressed. This is why I asked about ranks and the ability to disable on type of interrupt, if there is such a thing
You can clear the pending interrupt, however you'll have to read the datasheet for your Arduino's AVR. You need to find the register for the external interrupt.
For example, on an atmega328p, external interrupt 0 can be cleared by setting its flag bit to 1:
EIFR |= (1 << INTF2);
EIFR = External Interrupt Flag Register
INTF2 = Bit 0 – INTF0: External Interrupt Flag 0
However, it may be far simpler to poll the button in your loop() function. Or at best, simply set a flag for you to act upon back in the loop() function. There you would be able to decide if you want to react or ignore to the interrupt
There is the issue of having your interrupts far too large. If you use timing, or require accuracy, this could be affected by a large amount over time. As the interrupt queue length is only 1 deep some interrupts could be lost. And the interrupt which powers millis() & micros() runs multiple times per millisecond, so a bulky interrupt could end up slowing down time.
Also do you have any debouncing code or hardware?
If not, the interrupt handling the button could be run multiple times on a single press.

what happens if interrupt occurs while ISR running?

I am programming arduino, I attached an interrupt on pin2 falling edge. While I am in the ISR and the ISR has not executed all the lines. Before finishing all the lines if falling edge comes again what happens? Does interrupt start from begining or ignor it. Here I am talking about only interrupt on pin2.
The Atmel processor disables interrupts when an interrupt is taken:
(Section 4.4: Bit 7 – I: Global Interrupt Enable)
The Global Interrupt Enable bit must be set for the interrupts to be
enabled. The individual interrupt enable control is then performed
in separate control registers. If the Global Interrupt Enable Register
is cleared, none of the interrupts are enabled independent of the
individual interrupt enable settings. The I-bit is cleared by hardware
after an interrupt has occurred, and is set by the RETI instruction to
enable subsequent interrupts. The I-bit can also be set and cleared by
the application with the SEI and CLI instructions, as described in the
instruction set reference.
Further:
External Interrupt Flag Register – EIFR
• Bits 7..0 – INTF6, INTF3 - INTF0: External Interrupt Flags 6, 3 - 0
When an edge or logic change on the INT[6;3:0] pin triggers an
interrupt request, INTF7:0 becomes set (one). If the I-bit in SREG and
the corresponding interrupt enable bit, INT[6;3:0] in EIMSK, are set
(one), the MCU will jump to the interrupt vector. The flag is cleared
when the interrupt routine is executed. Alternatively, the flag can be
cleared by writing a logical one to it. These flags are always cleared
when INT[6;3:0] are configured as level interrupt. Note that when
entering sleep mode with the INT3:0 interrupts disabled, the input
buffers on these pins will be disabled. This may cause a logic change
in internal signals which will set the INTF3:0 flags.
In other words, when another interrupt is detected, the flag register will have that bit set, and that interrupt taken when interrupts are enabled again (at return from interrupts if no separate action is taken).
http://www.atmel.com/Images/Atmel-7766-8-bit-AVR-ATmega16U4-32U4_%20Datasheet.pdf
If you want to, you could implement code that enables interrupt during that interrupt service routine, but you have to make sure that the code after such a point is fully re-entrant, and/or mask the current interrupt (some interrupt service routines are pretty darn hard to handle when you don't get another interrupt soon after, and it gets almost impossible if you get another one when you are currently in that handler). However, it is often the case for proper operating systems to enable all other interrupts - which means writing to the EIMSK register.
As a general rule, it's best to simply collect the necessary information in the interrupt handler, store it away in "safe" place (circular buffers are good for this), and signal that new data is available to a regular task in the system, and process the data there.
[Additionally, as far as I can tell, there is nothing stopping function calls inside an interrupt - as long as you understand what you are doing and there is no problems for example from calling the function from both the interrupt and the regular code at the same time]

Arduino read pulse-width frequency and duty cycle from a single digital input

I'm new to Arduino and coding, but have done all the tutorials and think I'm getting a grasp on how it all works.
I have a real-world problem that I'd love to solve with the arduino.
I have a PWM signal from a fuel injector on a gasoline engine that I need to derive two separate logical functions from inside the arduino.
Determine the delay between each rising edge (to derive engine RPM)
range between 6ms - 120ms between rising edges
and
read pulse-width Duty Cycle (to determine the fuel injector's duty cycle)
Pulsewidth range from 0.02ms to over 10ms for the pulse lengths.
these need to be represented independently in the logic as "RPM" and "Pulse Width"
I have read this blog about "secrets of Arduino PWM" and find it informative on how to WRITE pulse-width outputs of varying frequency and duty cycle, but I am trying to READ pulse-widths of varying frequency and duty cycle to create a variable byte or int to use for each.
Correct there is not a lot on timing pulse inputs or alike. Where the Arduino's ATmega can capture the timing of each side of the duty cycle by the below methods. And it will be up to the code to put them together and consider them a PWM for your needs.
There are several methods with examples.
Tight loop polling of the timed events. Such as with PulseIn
A better method is to create a timer1 overflow interrupt and
during that ISR pull the pin. This is the original method that Ken
Shirriff's Infrared Library works - 50ms pull shirriff IR Library where its resolution is only as good as the overflow.
Use Pin Change Interrupts ISR to get the time. Where it will be slightly latent. Where microtherion's fork of Ken's IR library converted the overflow to PinChangeInt. Where MicroTherion's code did this discretely in the library. Where the PinChangeInt library makes it simpler.
Use the Timer Input capture. In short when the corresponding
input pin changes the system clock is captured and an interrupt is
issued. So the ISR can latently get the exact time it occurred. InputCapture.ino
I just wrote a library with an example that does exactly this. In my Timer2_Counter library, I've written an example currently titled "read_PWM_pulses_on_ANY_pin_via_pin_change_interrupt" which reads in pulses then outputs the pulse width in us, with a resolution of 0.5us, as well as the period between pulses, and the frequency of the pulses.
Download the library and check out the example. To test the example you can connect a wire from a PWM pin outputting a PWM signal to the input pin. The library with example is found here: http://www.electricrcaircraftguy.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
PS. this example code uses pin change interrupts and can be done on ANY Arduino pin, including the analog pins.