How can I clear any pending interrupts in the NodeMCU ESP32? - c++

I have built a simple coin sensor with two copper plates that detect when a coin hits them. Upon striking the two plates, I fire off an interrupt which looks like:
attachInterrupt( digitalPinToInterrupt(INPUT_PIN_COIN), Interrupt_CoinDeposit, FALLING );
This works fine and I am able to pick up when the coin strikes the two plates. In order to avoid the same coin being registered multiple times due to contact bounce, I detach the interrupt within the Interrupt_CoinDeposit() function as so:
void IRAM_ATTR Interrupt_CoinDeposit()
{
detachInterrupt(digitalPinToInterrupt(17));
g_crOSCore.EnqueueCoin();
}
EnqueueCoin simply increases a counter and returns back to where the interrupt left off. After which, I check if the counter has increased, and if it does, I reattach the interrupt. However, upon reattaching the interrupt, it fires off immediately. I learnt that reattaching the interrupt completes all the pending interrupts. I do not want this to happen. In the Arduino UNO R3, I believe you can solve this problem by resetting the EIFR. I'm wondering if there is something similar for the NodeMCU ESP32?

You could use a flag instead of disabling the interrupt. This way you also avoid the function call detachInterrupt() inside the ISR.
bool coinRegistered = false;
void IRAM_ATTR Interrupt_CoinDeposit()
{
if (!coinRegistered) {
coinRegistered = true;
g_crOSCore.EnqueueCoin();
}
}
/* ... somewhere else in the code ...*/
coinRegistered = false;
Either you can start a timer in the ISR, which resets the flag, or you reset it manually.

Related

Rising edge interrupt triggering multiple times on STM32 Nucleo

I am using the STM32 NUCLEO-F401RE microcontroller board.
I have a speaker programmed to change frequency by a set amount when the joystick is pushed up/down. My issue is that sometimes (more often than not) when the joystick is pushed up/down the frequency increases/decreases multiple times, implying that the ISR is executing multiple times. Also, the InterruptIn object is set to trigger on the rising edge however sometimes it also executes on the falling edge (when the joystick is returend to neutral after pushing up/down). Any help for getting over this?
void upISR()
{
if (greenLED.getStatus())
{
myTicker.detach();
frequency+=200;
myTicker.attach(callback(&spkr, &Speaker::toggle), 0.5/frequency);
}
}
'
int main()
{
InterruptIn up(A2);
InterruptIn down(A3);
InterruptIn fire(D4);
up.rise(&upISR);
down.rise(&downISR);
fire.rise(&toggleISR);
redLED.on();
while (1){}
}
Mechanical switch bounce is a feature of all mechanical switches to a lesser or greater extent. It is often necessary to implement "debouncing" in software especially if the switch is directly driving an interrupt as in this case.
A quick Google search for software denounce techniques yields some rather poor techniques IMO. I seen it done poorly more times than well unfortunately.
I suggest that in the switch ISR you start (or restart in the event of a "bounce") a hardware timer for a period of say 20ms or so (longer than the switch bounce time, but shorter than the time you could possibly to genuinely release the switch). Then in the timer ISR, you test the state of the switch and change the frequency accordingly:
Pseudocode:
void upISR()
{
debounceTimerRestart() ;
}
void downISR()
{
debounceTimerRestart() ;
}
void debounceTimerISR()
{
debounceTimerStop() ;
tDirection dir = getJoystickDir() ;
swithc( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
What this does is trigger a timer interrupt shortly ("debounce time") after the switch stops bouncing. Note the timer is "single-shot" not periodic.
Below I present an enhancement at #BenVoigt's suggestion (in comments). I am keeping it separate to make it clear it was his work. The above will generally work, but if you have a particularly poor switch the following would resolve issues, and at little cost, so you may as well:
void debounceTimerISR()
{
debounceTimerStop() ;
static tDirection previous_dir = CENTRE ;
tDirection dir = getJoystickDir() ;
// If the state changed...
if( previous_dir != dir )
{
previous_dir = dir ;
switch( dir )
{
case UP :
{
increaseFrquency() ;
}
break ;
case DN :
{
decreaseFrquency() ;
}
break ;
}
}
}
Simple do not use EXTI for mechanical yousticks and buttons.
Use regular interrupt (for example systick) to poll the status of the pins.
We clearly believe this is the normal and expected bouncing of the switch. Mechanically a switch is some piece of metal that when acted on moves that metal from one pole to another, even if they do not resemble a wiper and two poles. The metal that moves will collide and bounce, the electrical connection will show that. The bouncing is often slow enough for a processor to get multiple interrupts, although that may be an under-sampling of all the bounces possibly seen electrically. If you try to look at it on a scope the scope itself may not-intentionally be filtering some of it (but so will your chip).
One way to see the problem is as with anything, research first then write the application later. This is not a solution but a way to characterize the problem for your system
switch_isr ( void )
{
...
some_global_variable <<= 1;
some_global_variable |= (pin_state_register>>pin_number)&1;
...
}
main ( void )
{
...
some_local_variable = 0;
while(1)
{
if(some_local_variable != some_global_variable)
{
some_local_variable = some_global_variable;
primitive_hex_print(some_local_variable);
}
}
}
No reason to expect to see every state change in the shifted variable, but you should see some and get a feel for the problem. Another way is to just have a counter increment on every interrupt, print periodically in the foreground and you will see one button press may result in multiple counts. And from the time it takes for the printouts to stop changing roughly in human time the settling time.
Filtering is all about state changes per unit time though and you have to have some flavor of time, be it a loop in the foreground that polls some information set by the interrupt (up/down counters, etc), or state changes relative to a timer/clock.
I do not know what the complete rules are for your assignment, if you can only have an interrupt for each switch and not a timer, or preferably a timer instead, I do not see a clean solution that will actually work. You would have to filter in the foreground but all that is doing is polling a copy of the pin state collected by the interrupt and is that any different than not using the interrupt? You cannot use Clifford's answer if you cannot set a timer interrupt, if you could use a timer and an interrupt then you could just periodically sample the switch states with that interrupt or a copy of the pin state collected by the pin state change interrupts and filter in the timer interrupt. Not the same as Clifford's but in all cases you need state change history relative to time to see when the thing settles.
Without a time reference and states not changing with respect to time (which a pin interrupt cannot show since the state has not changed) you cannot filter out the bounces. Instead work on your dexterity and how you flick the joystick up and down.

Ending a while loop at any point when condition is not met

I am currently writing a program where I need to run a loop that can be interrupted at any time. In this case, a series of tones are playing over and over again but should stop when one of the values from a sensor comes back as HIGH.
At the moment, I've got this:
void loop() {
while(digitalRead(ctsPin) == LOW) {
// Some code here
}
}
However, the while loop will only break when the instructions inside it have finished running. Is there a way that I can run these over and over again but stop them at any time, even if it is part-way through?
Thanks in advance.
I take it that you are actually asking how to immediately break a loop which has many hard-coded delays (tones) in it, no matter what code inside that loop that is currently executing. That isn't possible.
Adding a lot of if statments all over the loop won't help, because that won't prevent delay-based code from playing out the current tone until it is done.
The alternative would be to create some sort of queue/ring buffer containing the items to be played. The PWM interrupt that plays the tones will go through this queue and play them one at a time.
When you wish to stop, you would then simply disable the interrupt and pull the port pin to a silent state. This will cause it to stop immediately, even if the program is playing the part between two edges of the tone signal.
The break statement will interrupt the current loop. So you should have a conditional statement for the condition you are monitoring, and if it evaluates to true, call break.
if (digitalRead(ctsPin) == HIGH){
break
}
Question is not clear. To stop running the loop you can use break as given below. Check if this is what you're looking for.
void loop() {
while(digitalRead(ctsPin) == LOW) {
// Some code here
if (digitalRead(ctsPin) == HIGH){
break;
}
// Some code here
}
}
There are two ways to break "instantly." One is to use an interrupt and the other is to check for the condition more often -- after each instruction if really necessary, and break out then:
void loop()
{
while(digitalRead(ctsPin) == LOW)
{
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// code block (or even a single statement)...
if (digitalRead(ctsPin) == HIGH) break;
// etc.
}
}
If you get too many of these, it may be advisable then to look into an interrupt instead. For an example of how to do that, and the various interrupts available for your target board, I suggest taking a look at Arduino Interrupt Documentation.
If you decide to go that way, give it a try and then if you run into issues, ask a different question and we'll help you out.

C++ multithreaded application using std::thread works fine on Windows but not Ubuntu

I have a somewhat simple multithreaded application written using the C++ std::thread library for both Ubuntu 14.04 and Windows 8.1. The code is nearly completely identical except that I'm using the operating system respective libraries windows.h and unistd.h to use Sleep/sleep to pause execution for a time. They both actually begin to run and the Ubuntu version does keep running for a short time but then hangs. I am using the proper arguments to the sleep/Sleep functions since I know Windows Sleep takes milliseconds, while Unix sleep takes seconds.
I've run the code multiple times and on Ubuntu it never makes it past two minutes whereas I've run it on windows twice for 20 minutes and then multiple times for roughly five minutes each to see if I was just lucky. Is this just an incompatibility with the thread library or does sleep not do what I think it does, or something else? The infinite loops are there because this is a school project and is expected to run without deadlocks or crashing.
The gist is that this is a modified 4-way stop where cars who arrive first don't have to slow down and stop. We only had to let one car through the intersection at a time which takes 3 seconds to cross, hence Sleep(3000), and don't have to worry about turns. Three threads run the spawnCars function and there are four other threads that each monitor one of the four directions N, E, S, and W. I hope that it's understandable why I can't post the entire code in the chance some other student stumbles upon this. These two functions are the only place where code is different aside from the operating system dependent library inclusion at the top. Thanks.
edit: Since I've just gone and posted all the code for the project, if the problem does end up being a deadlock, may I request that you only say so, and not post an in depth solution? I'm new here so if that's against the spirit of SO then fire away and I'll try to figure it out without reading the details.
/* function clearIntersection
Makes a car go through the intersection. The sleep comes before the removal from the queue
because my understanding is that the wait condition simulates the go signal for drivers.
It wouldn't make sense for the sensors to tell a car to go if the intersection isn't yet
clear even if the lock here would prevent that.
*/
void clearIntersection(int direction)
{
lock->lock();
Sleep(3000);
dequeue(direction);
lock->unlock();
}
/* function atFront(int direction)
Checks whether the car waiting at the intersection from a particular direction
has permission to pass, meaning it is at the front of the list of ALL waiting cars.
This is the waiting condition.
*/
bool isAtFront(int direction)
{
lock->lock();
bool isAtFront = cardinalDirections[direction].front() == list->front();
lock->unlock();
return isAtFront;
}
void waitInLine()
{
unique_lock<mutex> conditionLock(*lock);
waitForTurn->wait(conditionLock);
conditionLock.unlock();
}
//function broadcast(): Let all waiting threads know they can check whether or not their car can go.
void broadcast()
{
waitForTurn->notify_all();
}
};
/* function monitorDirection(intersectionQueue,int,int)
Threads will run this function. There are four threads that run this function
in total, one for each of the cardinal directions. The threads check to see
if the car at the front of the intersectionQueue, which contains the arrival order
of cars regardless of direction, is the car at the front of the queue for the
direction the thread is assigned to monitor. If not, it waits on a condition
variable until it is the case. It then calls the function to clear the intersection.
Broadcast is then used on the condition variable so all drivers will check if they
are allowed to pass, which one will unless there are 0 waiting cars, waiting again if not the case.
*/
void monitorDirection(intersectionQueue *intersection, int direction, int id)
{
while (true) //Do forever to see if crashes can occur.
{
//Do nothing if there are no cars coming from this direction.
//Possibly add more condition_variables for each direction?
if (!intersection->empty(direction))
{
while (!intersection->isAtFront(direction))
intersection->waitInLine();
intersection->clearIntersection(direction);
cout << "A car has gone " << numberToDirection(direction) << endl;
//All cars at the intersection will check the signal to see if it's time to go so broadcast is used.
intersection->broadcast();
}
}
}
Your culprit is likely your while (!isAtFront(...)) loop. If another thread gets scheduled between the check and the subsequent call to waitInLine(), the state of your queues could change, causing all of your consumer threads to end up waiting. At that point there's no thread to signal your condition_variable, so they will wait forever.

C++ Arduino, running two loops at once?

Okay so I have just recently dived into programming an Arduino, Currently I have the basic blink function along with a RGB LED program that changes an LED to blue, green and red in fading colors. I have 2 LEDS a simple and basic yellow LED that's supposed to function as an indicator for a "working status". And a LED that is RGB. Now I want the RGB one to transition through it's colors normally although I want to keep the Yellow LED constantly flashing.
How hould I make my code so that two processes can run at the same time?
Something like:
int timekeeper=0;
while (1)
{
do_fade(timekeeper);
if (timekeeper%100==0) {
do_blink_off();
}
if (timekeeper%100==50) {
do_blink_on();
}
delay(10);
timekeeper++;
}
This is done from memory, so your mileage may vary.
I've passed timekeeper to do_fade(), so you can figure out how far along the fade you are. do_fade() would update the fade, then immediately return. do_blink_on() and do_blink_off() would be similar - change what you need to change, then return. In this example, do_fade() would be called every 10 milliseconds, do_blink_off() once per second, with do_blink_on() 1/2 a second after (so on, 1/2 second, off, 1/2 second, on, 1/2 second...)
AMADANON's answer will work, however keep in mind the preferred way to do multiple tasks like this is with timer interrupts. For example, if you wanted your code to do something else after it fades, the timing of those other functions will interfere with your LED blinking. To solve this, you use timers that are built into the Arduino.
In the background, a timer is counting up, and when it hits a certain value, it resets it's counter and triggers the Interrupt Service Routine, which is where you would turn the LED on/off.
Here's a tutorial on blinking an LED with timer interrupts:
http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/
Try RTOS for Arduino.
You create tasks which are separate loops. I use it and it works fine.
https://create.arduino.cc/projecthub/feilipu/using-freertos-multi-tasking-in-arduino-ebc3cc
Also, I recommend using PlatformIO with the Arduino environment. Then you can also import RTOS via the library.
https://platformio.org/
Example code snippets:
In the setup:
void TaskMotion( void *pvParameters ); // Senses input from the motion sensor
and
xTaskCreate( // Create task
TaskMotion
, "Motion" // A name just for humans
, 12800 // Stack size
, NULL
, 1 // priority
, NULL );
... below the Arduino loop (having nothing but a delay(1000); in):
// ╔╦╗╔═╗╔╦╗╦╔═╗╔╗╔ ╔═╗╔═╗╔╗╔╔═╗╔═╗╦═╗
// ║║║║ ║ ║ ║║ ║║║║ ╚═╗║╣ ║║║╚═╗║ ║╠╦╝
// ╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝ ╚═╝╚═╝╝╚╝╚═╝╚═╝╩╚═
void TaskMotion(void *pvParameters) // This is a task.
{
(void) pvParameters;
// initialize stuff.
for (;;) // A Task shall never return or exit.
{
Serial.println("TEST MOTION");
delay(10000);
}
}
Copy paste and change "TaskMotion" to "LED something". You can create as many tasks as you want. The RTOS manages each task. Like if one task has a delay(10), then the next 10 ms are used for another task.

Multiple functions simultaneously in Arduino

I'm working on an Arduino sketch where I created two traffic lights, one for normal traffic and one for pedestrians. I created a function for each of these two lights, which loops it through it's cycle (for example: turn yellow, wait 20 seconds, then turn red and wait again). These are called aTrafficlight() and pTrafficlight, where a is the normal light and p the one for the pedestrians. In my loop() function I set a digitalRead for a button. When this button is pressed the traffic lights should cycle through their loops one at a time (so the normal light turns red, pTrafficlight waits a bit, then turns green, blinks a few times, turns red, waits and ends the loop, so it goes to it's original state.)
This all works. But now I want to add a buzzer. This buzzer must beep once a second while the pTrafficlight is red, once a tenth second while it's green and twice per two seconds while it's flashing green.
Here I encountered a few problems:
- When waiting in original state (button's not pressed) it seems I can sometimes press the button without reaction because the loop is still going. I need to figure out how to avoid waiting in the loop when buttonState == LOW. (There's a function wait(int sec))
- When the button is pressed, it loops through the cycles. I could just write some kind of loop implementing the traffic light being red and beeping at the same time, but I'd rather keep these seperated.
- Same for the double beeps. I do not want the beeping and flashing of the light to be in the same for loop, as it's confusing and difficult to read and understand the code.
Here's my loop():
int buttonState = 0;
void loop(){
buttonState = digitalRead(pButton);
if(buttonState == LOW){
vSet("red");
pSet("green");
// This is where I tried to create the sound.
digitalWrite(pSound, HIGH);
delay(10);
digitalWrite(pSound, LOW);
wait(1);
} else {
aTrafficlight();
pTrafficlight();
}
}
Is there a way to solve my problems with multithreading? I tried to look it up at arduino.cc and google, but I can't find a way I understand enough to use it in my existing code.
If not, do you have any better suggestions?
You don't need multi-threading. You need to use timers, whether via interrupts (as Pawel wrote) or via another mechanism, such as the Metro library, that lets the code continue to loop through while the timer is running. See this question and answer: How Can I Create Interrupts in C for Arduino
Coincidentally, I recently posted some material both on state machines and the Arduino, as Hans Passant mentioned, and on alternatives to delay(), both with additional references you might find useful.
You could use a time-slice design. Let me just outline this in very general terms.
First code loop so that it always issues a delay(1) and set a mod 10 counter as:
int stopWhen = -1; // at startup
// etc.
x = (x+1)%10; // every time loop execs
Then when buttonState == LOW
if (stopwWhen = -1)
{
stopWhen = x;
// beep etc.
}
But on every loop:
// always exec this:
if (stopWhen == x)
{
stopWhen = -1;
// stop beeping.
}