If I call a void function loop2() containing a for(; declaration from the main void loop(), will loop() continue to run in parallel since it isn't waiting for a value to be returned?
No.
You could have tested this in the time it took to post. But, no. In the case you mention, loop() is waiting for the function to return. Whether or not it returns a value is immaterial.
Well, I was at a social function, so, no, I couldn't have. I was trying to get a leg-up so I could conceptualize prior to diving into it.
But thanks for the info so far.
How about this, if one process (as described, for(; {do stuff;} is running on one core of an esp32-c3, updating global variables, and loop() or some other function is performing operations on those variables, would that give me the result I'm looking for? I grasp your notion of "just do it and see", and normally I do, but I'm pretty sure I just fried one trying to run on dual cores, so I'd rather have something intelligent in mind before throwing the ones I just ordered into a toaster.
Thanks in advance.
Yes fundamentally, as the ESP32 has dual cores, so you can do 2 things at once. You need to manage accessing the same data concurrently but this is possible.
What exactly are you trying to do?
It is often possible to do what appears to be parallel processing with a single core processor. Like checking inputs and displaying to a screen at the same time (or at close to the same time that no one would notice).
could your for loop be implemented within a conditional timer? is a 2nd processor (core) really needed?
Given what I perceive your coding experience level to be (based on your questions), coming up to speed on multi-thread / muti-processor programing techniques will be a very steep learning curve indeed. I suggest you at least start out with the standard Arduino "Several Things at a Time" methods.
I seriously doubt that. It's not really possible with most MCU's. There was one CPU a long time ago, had a "suicide OP code" that would incinerate the board if it was executed. It became a legend, I doubt that any designer would let something like that happen again on their watch.
On the other hand, when you have I/O ports connected, you can burn them with incorrect configuration or usage in software.
An ESP32 can run 2 or even 3 things at the same time.
Putting 1 thing on one core and another thing on another core is done through the use of the ESp32's OS, freeRTOS.
Here is a simple ESP32 freeRTOS task running 2 things at the same time on different cores.
#include "esp_system.h"
#include "freertos/FreeRTOS.h" //freeRTOS items to be used
#include "freertos/task.h"
void setup()
{
//
gpio_config_t io_cfg = {}; // initialize the gpio configuration structure
io_cfg.mode = GPIO_MODE_OUTPUT;
io_cfg.pin_bit_mask = ( (1ULL << GPIO_NUM_2) | (1ULL << GPIO_NUM_19) ); //bit mask of the pins to set, assign gpio number to be configured
gpio_config(&io_cfg);
gpio_set_level( GPIO_NUM_19, LOW );
gpio_set_level( GPIO_NUM_2,LOW );
//
xTaskCreatePinnedToCore( Blink19, "Blink19", 10000, NULL, 3, NULL, 1 ); //assigned to core1
xTaskCreatePinnedToCore( Blink2, "Blink2", 10000, NULL, 3, NULL, 0 ); //assigned to core0
}
void Blink19( void * pvParameters )
{
for(;;)
{
gpio_set_level( GPIO_NUM_19, HIGH );
vTaskDelay( 1000 );
gpio_set_level( GPIO_NUM_19, LOW );
vTaskDelay( 1000 );
}
}
////
void Blink2( void * pvParameters )
{
for(;;)
{
gpio_set_level( GPIO_NUM_2, HIGH );
vTaskDelay ( 700 );
gpio_set_level( GPIO_NUM_2, LOW );
vTaskDelay( 500 );
}
}
void loop() {}
To make it even more complex to the TO ... if you use RTOS you don't need to distribute your tasks on several cores. One core can run several tasks. But tasks will need some more measures if you access variables and/or hardware (e.g. serial) in several tasks.
If you were on a slow single core Arduino UNO you would migrate the for loop into a separate function with some static variables and just call your function in loop if necessary. And still the same can be done on the ESP32.
@Hossifer : Can you come up with an example sketch which shows what you want to do, and define what MUST be done "in parallel" or what could be done "near parallel"?
doesn't it depend on what kinds of "things" need to be done.
surely an esp32 can do 10s of things not requiring a short response time at the "same time"
For some definition of "at the same time".
Yes! The op code was
HCF ; halt and catch fire
a7
a)
Assume you have a for loop with blocking delays:
// example with a blocking for loop
void blockingSequenceA()
{
for (int i = 0; i < 8; i++)
{
digitalWrite(ledA, HIGH);
delay(interval); // dirty delay
digitalWrite(ledA, LOW);
delay(interval); // dirty delay
}
}
b)
you could replace these blocking for loop with a function:
void sequenceBupdate()
{
static uint32_t previousMillis = 0;
if (sequenceBForLoopCounter < sequenceBForLoopEndvalue)
{
if (millis() - previousMillis > interval)
{
previousMillis = millis();
if (digitalRead(ledB) == LOW)
{
digitalWrite(ledB, HIGH);
}
else
{
digitalWrite(ledB, LOW);
sequenceBForLoopCounter++;
}
}
}
}
c)
if you have already a function, you could create a class and let the class handle the object.
d)
Big advantage of a class/OOP is that it can be easily reused for similar objects.
Here comes a working code with example LEDs A to D:
/*
https://forum.arduino.cc/t/looped-void-function-and-continuity/1039262/
to be deleted 2022-11
*/
constexpr uint8_t ledA {13};
constexpr uint8_t ledB {12};
constexpr uint8_t ledC {14};
constexpr uint8_t ledD {27};
constexpr uint8_t button {23};
constexpr uint16_t interval {500};
// example with a blocking for loop
void blockingSequenceA()
{
for (int i = 0; i < 8; i++)
{
digitalWrite(ledA, HIGH);
delay(interval); // dirty delay
digitalWrite(ledA, LOW);
delay(interval); // dirty delay
}
}
// example nonblocking
byte sequenceBForLoopCounter = 255;
constexpr byte sequenceBForLoopEndvalue = 8;
void sequenceBupdate()
{
static uint32_t previousMillis = 0;
if (sequenceBForLoopCounter < sequenceBForLoopEndvalue)
{
if (millis() - previousMillis > interval)
{
previousMillis = millis();
if (digitalRead(ledB) == LOW)
{
digitalWrite(ledB, HIGH);
}
else
{
digitalWrite(ledB, LOW);
sequenceBForLoopCounter++;
}
}
}
}
void sequenceBstart()
{
sequenceBForLoopCounter = 0;
}
//example in OOP
class Sequence {
protected:
const byte led;
const byte forLoopEndvalue;
byte forLoopCounter = 255;
uint32_t previousMillis = 0;
public:
Sequence (byte led, byte forLoopEndvalue = 8) :
led{led},
forLoopEndvalue{forLoopEndvalue}
{}
void begin()
{
pinMode(led, OUTPUT);
}
void start()
{
forLoopCounter = 0;
}
void update()
{
if (forLoopCounter < forLoopEndvalue)
{
if (millis() - previousMillis > interval)
{
previousMillis = millis();
if (digitalRead(led) == LOW)
{
digitalWrite(led, HIGH);
}
else
{
digitalWrite(led, LOW);
forLoopCounter++;
}
}
}
}
};
Sequence objectLedC(ledC); // create a LED object
Sequence objectLedD(ledD, 5); // blinks only n times
void setup()
{
pinMode(ledA, OUTPUT);
pinMode(ledB, OUTPUT);
pinMode(button, INPUT_PULLUP);
objectLedC.begin();
objectLedD.begin();
}
void loop() {
if (digitalRead(button) == LOW)
{
//blockingSequenceA();
sequenceBstart();
objectLedC.start();
objectLedD.start();
}
sequenceBupdate(); // call unblocked in loop
objectLedC.update();
objectLedD.update();
}
for limited time on wokwi:
Crikey. So that was what the IMF were using! Lol
Yes, BUT... NEITHER thread can monopolize its core 100% of the time! They MUST surrender control to the OS on a regular basis, or the watchdog kicks in. The end result is, it is little different from simply running using "millis-based" "multi-tasking" on a single core for most applications.
I'd bet whatever OP is wanting to do can be done perfectly well using the standard Arduino "multi-tasking" methods. And, as already pointed out, true multi-tasking/multi-threading/multi-processing opens up all kinds of ugly cans of worms that WILL bite the uneducated user in the butt again, and again, and again. It is NOT as simple as simply kicking off multiple threads, or multiple processors and all your prblems are solved. It creates a whole lot of new, different MUCH more complicated problems.
I've not found multi-threading or multi-processing all that scary, myself.
I see what you mean, but none of the people talking now are beginners... it wouldn't be SO bad if there was no need for inter-process communication. That isn't fundamentally complicated, but usually the interfaces are a bit complex in order to be flexible and be capable of handling a lot of different needs. I've never seen RTOS code that didn't look really "techy".
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.