using while loop in setup section for a system not using "delay" function

Hi,

Is it a good idea for a multitasking project that isn't using "delay()" function for initialization functions, is to lock setup section with a while loop until setup finish ? because some init functions requires some delay to process and since I don't want to use delay.

Of course with locking the setup section, the system is faster than when using delay function. As that functions requires delay, during delay, I can finish doing other stuff and hence, finishing setup faster.

I don't see a problem using delay() or other such mechanisms (e.g. blocking code) in setup(). You don't generally need to be doing more than one thing at a time in setup and it only runs once before loop().

I’m with blackfin here. delay() in setup() is typically exactly what you want.

-jim lee

Blackfin:
I don't see a problem using delay() or other such mechanisms (e.g. blocking code) in setup(). You don't generally need to be doing more than one thing at a time in setup and it only runs once before loop().

jimLee:
I'm with blackfin here. delay() in setup() is typically exactly what you want.

-jim lee

Thank you guys :slight_smile:
I just wanted to know what happens in a professional cases; like, booting up a complete device like a cellphone, drone, car infotainment system, any HMI system, a gopro camera, an advanced robot system.

also like a big printer, that when you switch it on, it takes time to be ready, what actually companies do for programming their commercial devices ? would they actually use blocking delays ? or use something that isn't blocking so they bootup the printer in a good time ?

The basic rule is use blocking delays only when necessary, or where using them won't make any real difference. If a device requires delays to initialize, and the rest of the system cannot function until that device is initialized, then it really doesn't make any difference. But most complex systems, like PCs, come up in stages, with the bare minimum of devices coming up first, and the rest coming up over a longer period of time. At the point where you get a login prompt, or the desktop appears, there are MANY systems and services that have not even been started yet.

Could be state machine. bootingHardware

-jim lee

If you’re in a section of code that can’t/won’t interfere with other code flow, it’s not impossible to use a for() or while() AND delay() to act out a specific role…

Of course a state-machine has advantages with added complexity, but during initialisation (setup) it makes little difference in most cases.

An example might be starting up your wifi connection…
You could enable and verify, or close the ‘failed’ connection within a loop, retesting every half second for ten seconds at most… then notify the user or retry with some different connection strategy when the connection has failed ‘n’ times.

In a large device, such as the large printer the OP mentions, you might not want to block too much during the initialization phase. It would be quite desirable, for example, for motors in various parts of the machine to home to their limit switches at the same time, in parallel with each other, in order to shorten the startup time. If those individual processes each take a "long" time (for some definition of "long") the users may find it very frustrating to wait while they finish in sequence.

So we might start all those motors off on their homing journey at the same time, and delay()-lessly check them in loop() not setup(), in say state_STARTUP and once they're all ok, move to the next state.

I'm pretty sure that when I've been near a printer with various hardware modules for paper input, output stacking and of course the actual copying / printing process, I've heard motors and other actuators all whirring at the same time during the fire-up stage.

Imagine something that needs to warm up, like heat elements in a glue binder for example. That might take 5 minutes: so turn it on, then start the motors homing, then check the temperature from time to time. It would be crazy to wait 5 minutes while nothing else happens during the warmup.

When I code a machine with lots of stuff in it, I let everything just run on their own idle loops independently. There is typically something in the background orchestrating the hardware. The foreground, loop(), is used to amuse the human.

-jim lee

The printer probably isn’t running an Arduino UNO
Most likely an ARM or similar ‘higher spec’ chip, maybe running Linux with multiple tasks or threads..

Chances are, while the LCD says ‘initialising’
None of the buttons will work anyway.... they were probably checked before the init process started, and will be tested again as part of the main() loop.

lastchancename:
If you’re in a section of code that can’t/won’t interfere with other code flow, it’s not impossible to use a for() or while() AND delay() to act out a specific role...

Yep, absolutely ! That's what I thought too :slight_smile:
My idea is that since all my code is done with millis() in task manager library, why not also to use a while loop with state-machine code to run the setup section.
My idea is to divide the stuff to be run the setup section in two groups:

  1. functions that are direct and require no delay
  2. functions that require some delay to setup
    my idea is like the floolowing:
#include "task_manager.h"
#include "lcd128x64_spi_fsm.h"
#include "sensors_modules.h"

// enumerations
typedef enum{TASK_START,TASK_FINISHED,TASK_NOT_FINISHED,
INIT_START,INIT_FINISHED}SYSTEM_STATES;
SYSTEM_STATES system_st_flag;

// system defines
#define SYSTEM_TASKS 2


void setup() {
  // put your setup code here, to run once:
  system_st_flag = INIT_START;
  
  // these functions don't require delay
  Serial.begin(9600);
  task_manager_init(SYSTEM_TASKS);
  sensors_modules_init();

  // these functions require delay
  while(system_st_flag != INIT_FINISHED){
    // init functions need delay in state-machine code
  }
}

Of course a state-machine has advantages with added complexity, but during initialisation (setup) it makes little difference in most cases.

Yes, that's the point I'm in, there's some complexity in the init section, I've done most of the system manager for loop functions. But init section should be fine with a while loop.

An example might be starting up your wifi connection...
You could enable and verify, or close the ‘failed’ connection within a loop, retesting every half second for ten seconds at most... then notify the user or retry with some different connection strategy when the connection has failed ‘n’ times.

Yes, I found these examples in ESP examples, so I learned a bit about securing system initialization before proceeding to actual project loop.

jimLee:
When I code a machine with lots of stuff in it, I let everything just run on their own idle loops independently. There is typically something in the background orchestrating the hardware. The foreground, loop(), is used to amuse the human.

-jim lee

Absolutely ! That's what I've thought about many times. The Arduino examples that are written in the IDE are OK and most the time serve one module but as you mentioned when you write a code to run a lot of stuff and need to manage the system calls, then probably %90 of code is written in libraries and I just put one "idle" or "run" function in Arduino IDE.

I guess the trick we’re all talking about is asynchronous operation, as long as there are ‘semaphores’ that inhibit a task starting until all the predecessors have completed to a known state.

Anything can happen at any time - as long as the dependencies have completed the ‘setup’ needed to continue.

This like a 3-dimensional state-machine !

The trick is when to know that its better to set a flag and let something else complete a task. This way you don't fall into weirdly obscure recursion. Leading to memory loss or thread-lock.

-jim lee

jimLee:
The trick is when to know that its better to set a flag and let something else complete a task. This way you don’t fall into weirdly obscure recursion. Leading to memory loss or thread-lock.

-jim lee

Do you mean the method I presented is good or not ?

If I understood you correctly and that you mean the example is a good one, then yes, I think II can debug the init part if anything goes wrong. But I haven’t done this part.

I have a question now, the enumeration in the example should be in the source code, I put it in Arduino sketch for demo.

But when the enumeration in the library, then how to check for this while statement?

while(system_st_flag != INIT_FINISHED)

I mean how to update the init state flag “INIT_FINISHED” from the library ?

In the library, add a line defining system_st_flag as extern

In whatever file defines system_st_flag, make sure it has global scope

Since it appears INIT_FINISHED is a const or enum, INIT_FINISHED must be defined in a file that is #include'd into BOTH files.

Yes, I learned that if I want to share a variable between source files then I have to use typedef and volatile:

Declaration:

// variables
typedef volatile uint8_t task_counter_t;
typedef volatile uint8_t task_counts_t;
typedef volatile uint8_t task_track_t;

Initialization and using it in the main source:

// system variables
task_counter_t task_counter;
task_counts_t task_counts;
task_track_t task_track;

Initialization and using it in the other source files:

// system variables
extern task_track_t task_track;
extern task_counter_t task_counter;
extern task_counts_t task_counts;

also I can use the variable in Arduino IDE and also get the value in the source file.

Now my struggle is the management of locks. I'm trying to balance them.

My method, is when any lcd function is called, other two callback functions are called which are:

  1. lcd_cmdt which manages the modes and flags
  2. delay which manages time elapse

I know it should be simple as possible, I don't want to use many locks and complicate the code more what it actually need.

wolfrose:
Yes, I learned that if I want to share a variable between source files then I have to use typedef and volatile:

Then you've learned wrong. typedef and volatile have their purposes, but NEITHER has anything whatsoever to do with sharing variables between source files.

RayLivingston:
Then you've learned wrong. typedef and volatile have their purposes, but NEITHER has anything whatsoever to do with sharing variables between source files.

But this is what worked with me in Arduino environment !
I wanted to use a variable from one library and provide it with a scope along all the source files in that library.
Well, I did that with typedef, I compiled the code and it compiled OK, then I used it in actual code and I'm able to use and display the value of that variable with this setting.
My goal now is to use C syntax.
What is the way you suggest ?

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.