text:
Using ESP32CAM board but no face is enrolled
I was working on a project to use the ESP32CAM board to detect faces and open some sort of lock. The program can detect the face using the yellow box that shows up as you can see from the following image:

But after clicking "Enroll Face", nothing changes. I'm currently using the default CameraWebServer application located in the ESP32CAM board examples. Any advice to solve these issues would be greatly appreciated

The short version is you need an ESP32-S3 (which the ESP32CAM isn't) if you want practical face recognition from this example. But you may be able to make face recognition work on the ESP32CAM with this example very slowly if you really want to try it.

A comment the example code explains:

You must select partition scheme from the board menu that has at least 3MB APP space.
Face Recognition is DISABLED for ESP32 and ESP32-S2, because it takes up from 15
seconds to process single frame. Face Detection is ENABLED if PSRAM is enabled as well

My understanding is "detection" refers to just what you're seeing in the image you've included, that it can find faces (any face) and draw a box around it. This makes sense because the board has PSRAM.
"Recognition" is detection of the specific face you "enroll", which "is DISABLED for ESP32". And the ESP32CAM uses an ESP32 (importantly not more powerful ESP32-S3)
You can see this again in the form of code rather than a comment in the web server code.
The web page served is not configured to show anything different when those features are disabled. It it just passes events back to the web server code. However, if you're looking at the serial output you should see messages saying "Unknown command: face_enroll" and "Unknown command: face_recognize" if you have the Core Debug Level setting at Info level or higher.

They say it takes 15 seconds on an plain ESP32, which apparently means it is possible if a bit useless. So, if you really want to try it you may be able to modify this line in app_httpd.cpp to read:
#define CONFIG_ESP_FACE_RECOGNITION_ENABLED 1

I may try it later if I find my ESP32CAM. But the expectation is that it will "work" but have horrible performance. Well, I found my ESP32CAM and edited that line and yes, it barely functions, but you can see that does technically work, at least for a little while. I may be crashing it during the enroll process or it might just be picking up what it thinks are extra faces and it's so bogged down that it stops responding, which may have motivated why they just disabled it outright. Either way, yeah, it behaves more or less as explained by the comment.


text:
Do I connect multiple I2C units to the microcontroler in series or parallel?
I have a project (still planning) with three I2C sensors: GPS, 3-axis gyro+accelerometer, and OLED. Do I connect SDA/SCL in series, or do I connect them in parallel?

Use the Wikipedia page on the protocol as an introduction to your learning curve on I2C. I may cite:

At the physical layer, both SCL and SDA lines are [a ...] bus design, [...]

This means that all devices connect in parallel (image from the same page, public domain):

Rp are pull-up resistors, Rs are optional series resistors. (Emphasis by me)

Connect the three I2C devices in parallel.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Feather M0 RFM69 serial over radio IP over serial works for UDP packets but fails for TCP sessions
I'm trying to build a serial over radio transmitter module using two Feather M0 boards with RFM69HCW chips on board. As a test I'm trying to run a slip IP over serial session. This seems to work consistantly for UDP sessions (in my case ICMP ping requests) but fails for TCP sessions (in my case a simple HTTP request).
Here is the code:
#include <RFM69.h>
#include <RFM69_ATC.h>
#include <SPI.h>
#include <string>
// a simple off the shelf CRC8 implementation
#include <crc.h>

// defined for one of the two boards
// #define B

#ifdef B
#define NODEID 1
#define RECEIVER 2
#endif
#ifndef B
#define NODEID 2
#define RECEIVER 1
#endif

#define MAX_BYTES 56

#define NETWORKID 100
#define FREQUENCY RF69_433MHZ
#define IS_RFM69HW_HCW

RFM69_ATC radio(8, 3, true);

char buf[512];

void setup()
{
  // initialize random using receiver address
  // this guarantees that both nodes have different initial random values
  randomSeed(RECEIVER);

  Serial.begin(115200);

  radio.initialize(FREQUENCY, NODEID, NETWORKID);
  radio.setPowerLevel(0);
  radio.setFrequency(446000000);
}

int8_t receiver_last_id = -1;

bool read_packet(bool override = false)
{
  if (radio.receiveDone() || override)
  {
    int cnt = radio.DATALEN - 2;
    int crc = radio.DATA[0];
    int8_t packet_id = radio.DATA[1];

    memcpy(buf, radio.DATA + 2, cnt);

    uint8_t crc_data = crc8(0, (uint8_t*)buf, cnt);

    if (radio.ACKRequested())
    {
      if (crc == crc_data)
      {
        radio.sendACK();

        // sometimes duplicates seem to occure
        // in case this happens just ignore the packet
        if (packet_id != receiver_last_id)
        {
          Serial.write(buf, cnt);
          receiver_last_id = packet_id;
          return true;
        }
        return false;
      }
      else
      {
        radio.ACK_REQUESTED = 0;
        return false;
      }
    }

    return false;
  }
  return false;
}

int8_t sender_packet_id = 0;

bool send_packet()
{
  int serial_cnt = Serial.available();

  if (serial_cnt > 0 && radio.canSend())
  {
    // packet structure:
    // 1. byte: CRC8 of DATA
    // 2. byte: ID of packet (to prevent duplicates)
    // variable length: DATA

    int payload_size = min(MAX_BYTES, serial_cnt);
    int total_size = payload_size + 2;

    Serial.readBytes((char *)buf + 2, payload_size);
    buf[0] = crc8(0, (uint8_t*)(buf + 2), payload_size);
    buf[1] = sender_packet_id++;

    while (!radio.sendWithRetry(RECEIVER, buf, total_size, 1, 5U))
    {
      // radio.receiveDone() switches the
      // radio into receive mode
      if (radio.receiveDone())
      {
        // if receive is done instantly
        // process the packet and move on
        read_packet(true);
        continue;
      }

      // wait random time in case
      // a collision happened
      delay(random(5, 30));

      read_packet();

      // wait for radio to be ready to send
      while (!radio.canSend()) ;
    }

    return true;
  }

  return false;
}

void loop()
{
  read_packet();

  send_packet();
}

I also have a network capture of both sides.
Here is the capture for the Client: https://ufile.io/v945jl8i
Here is the capture for the Server: https://ufile.io/yn36rjw4
I've figured out that it happens somewhere in the while (!radio.sendWithRetry(RECEIVER, buf, total_size, 1, 5U)) loop but I can't figure out what exactly goes wrong and how I can fix it.
Any help would be greatly appreciated!
Edit: I'm running a simple python HTTP server (python 3 -m http.server 8080). And as client i'm using curl (curl <server address>:8080)
Here are the Commands I use for starting slip:
modprobe slip
slattach -vL -s 115200 -p slip /dev/ttyACM0
ifconfig sl0 192.168.2.1 pointtopoint 192.168.2.2 up

I switched the two IP addresses for the other side.
Also interestingly it sometimes seems to randomly work for one or two requests, so i'm guessing some kind of race condition.
I also made sure that i'm connecting to the correct serial ports.
PS: i'm kind of new to C++ so any recommendations on best practices are also appreciated

Are you running an actual server on the receiver?

edited the question to add the info. TLDR: yes, I have a server running

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
GPS module Serial.begin value
I've disassembled a drone and found a GPS module. I want to use it. I haven't found any information about the architecture and the Serial.begin value I have to use. Could I break it if I tried different values of Serial.begin as 4800, 9600 and different types of architecture like NMEA with TinyGPS?
The module: https://www.aliexpress.us/item/3256805691773977.html
I've tried this sketch and ss.available() is constantly false, why aren't any chars available?
#include <SoftwareSerial.h>

#include <TinyGPS.h>

/* This sample code demonstrates the normal use of a TinyGPS object.
   It requires the use of SoftwareSerial, and assumes that you have a
   4800-baud serial GPS device hooked up on pins 4(rx) and 3(tx).
*/

TinyGPS gps;
SoftwareSerial ss(4, 3);

void setup()
{
  Serial.begin(115200);
  ss.begin(4800);

  Serial.print("Simple TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
}

void loop()
{
  bool newData = false;
  unsigned long chars;
  unsigned short sentences, failed;

  // For one second we parse GPS data and report some key values
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (ss.available())
    {
      char c = ss.read();
      // Serial.write(c); // uncomment this line if you want to see the GPS data flowing
      if (gps.encode(c)) // Did a new valid sentence come in?
        newData = true;
    }
  }

  if (newData)
  {
    float flat, flon;
    unsigned long age;
    gps.f_get_position(&flat, &flon, &age);
    Serial.print("LAT=");
    Serial.print(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flat, 6);
    Serial.print(" LON=");
    Serial.print(flon == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : flon, 6);
    Serial.print(" SAT=");
    Serial.print(gps.satellites() == TinyGPS::GPS_INVALID_SATELLITES ? 0 : gps.satellites());
    Serial.print(" PREC=");
    Serial.print(gps.hdop() == TinyGPS::GPS_INVALID_HDOP ? 0 : gps.hdop());
  }

  gps.stats(&chars, &sentences, &failed);
  Serial.print(" CHARS=");
  Serial.print(chars);
  Serial.print(" SENTENCES=");
  Serial.print(sentences);
  Serial.print(" CSUM ERR=");
  Serial.println(failed);
  if (chars == 0)
    Serial.println("** No characters received from GPS: check wiring **");
}

No, the module will not break because of an incorrect baudrate.

thanks, what about the protocol ?

What do you mean? Do you want an explanation of the modules protocol? We also can only google for the datasheet of the module. Without a part number that is also impossible. Though such modules often send human readable data (in ASCII format) over serial. So you can look at the data in the Serial Monitor and check, how to read it. Thats something, that you need to test yourself (we don't have your module)

Probably a nice clear picture of this GPS module would help. FWIW, the GPS modules I have worked with start out running at either 9600 or 15200. If you want to learn about GPS it may be better to get a known good GPS module from the likes of sparkfun or adafruit.  Either supplier/manufacturer have good web presence, support and community.  All good assets for people w/lots of questions.

BTW, serial protocols such as RS232 have been around likely before you were born (no offense). Back when a few things had to be everything to everybody.  It's been called "the standard that isn't". That said, the major knobs are speed, number of data bits, number of stop bits and parity. You should be able to fiddle w/all that w/little concern about damaging what is connected. The thing you need to worry about: True RS232 swings from -12 Volts to 12 Volts. That will certainly be cause for alarm. But most Arduinos will pump out RS232 like pulses that swing from 0 to 5 Volts or 0 to 3 Volts.

ok thanks, last thing, the gps module is connected correctly but no data is available with the SoftwareSerial library, i've modified the question why that happens, should i pass some data to the tx pin of the module before receiving data at the rx?

How did you connect the module? Usually for serial connections, you would connect the Arduino's RX pin to the module's TX pin and vice versa.

i've done so and it didn't worked it is possible that i have to pass some data at the module before he can start

The GPS module you link to is UART-I2C dual mode. You switch between these 2 modes by (de)soldering resistors. Check first which mode the module is in.
Most GPS these days are in 9600 baud, when in UART mode. Try that too.


text:
LCD Wiki screen (ILI9341) works on Mega. How to get it working on the Due?
I have this exact LCD shield: http://www.lcdwiki.com/2.8inch_Arduino_Display
SKU: MAR2808
Driver IC: ILI9341

It works on an Arduino Mega 2560 using the old libraries the manufacturer (I assume) provides on the wiki page. I was sending data to show on the screen through USB serial. Quickly realizing that was very limited, I heard that the Arduino Due would have a faster USB connection as it is "native".
So now I'm trying to get the shield to work on the Due.
The Due has a different operating voltage but the wiki said that the shield has an automatic level shifter, I decided to take a chance and put it on and see if anything broke. It seems it is fine as I can put the shield back on the Mega and it still works.
Back on the Due, I managed to find the original libraries that the Lcd Wiki guys copied and modified as I wanted to get a later version that supported the Due. They have not made that available so it seems it's up to me (and maybe you).
It seems they used this library (an older version): https://github.com/adafruit/TFTLCD-Library
So since the library had some updates since their hacks, I tried out the latest version (1.0.3 at the time of writing). Then I re-applied their changes to the pin_magic.h file. That got the latest library to work with the Mega.
It also allowed me to use the latest versions of other dependent libraries which is nice as I can now keep these all up to date.
adafruit/Adafruit TouchScreen@^1.1.3
adafruit/Adafruit GFX Library@^1.11.9

The issue comes in with their changes. I don't quite know how to translate them into Due related code as it seems you need to have a deep knowledge of the Due and the Mega hardware to understand what they did.
So they changed the following Mega code in the original library (pin_magic.h) from:
#define write8inline(d)                                                        \
{                                                                            \
    PORTH =                                                                    \
        (PORTH & B10000111) | (((d)&B11000000) >> 3) | (((d)&B00000011) << 5); \
    PORTB = (PORTB & B01001111) | (((d)&B00101100) << 2);                      \
    PORTG = (PORTG & B11011111) | (((d)&B00010000) << 1);                      \
    WR_STROBE;                                                                 \
}

to:
#define write8inline(d)                                                        \
{                                                                            \
    PORTE = (PORTE & B11001111) | ((d << 2) & B00110000); \
    PORTE = (PORTE & B11110111) | ((d >> 2) & B00001000); \
    PORTG = (PORTG & B11011111) | ((d << 1) & B00100000); \
    PORTH = (PORTH & B11100111) | ((d >> 3) & B00011000); \
    PORTH = (PORTH & B10011111) | ((d << 5) & B01100000); \
    WR_STROBE;                                                                 \
}

That's a lot of binary and ports that I don't understand. I feel like an important part is they change the ports(?) that it uses.
So the problem lies in how to change the original Due code to work in the same way the new code worked with the Mega?
This is the current Due code in the library:
#define write8inline(d)                                                        \
{                                                                            \
    PIO_Set(PIOD, (((d)&0x08) << (7 - 3)));                                    \
    PIO_Clear(PIOD, (((~d) & 0x08) << (7 - 3)));                               \
    PIO_Set(PIOC, (((d)&0x01) << (22 - 0)) | (((d)&0x02) << (21 - 1)) |        \
                      (((d)&0x04) << (29 - 2)) | (((d)&0x10) << (26 - 4)) |    \
                      (((d)&0x40) << (24 - 6)) | (((d)&0x80) << (23 - 7)));    \
    PIO_Clear(PIOC,                                                            \
              (((~d) & 0x01) << (22 - 0)) | (((~d) & 0x02) << (21 - 1)) |      \
                  (((~d) & 0x04) << (29 - 2)) | (((~d) & 0x10) << (26 - 4)) |  \
                  (((~d) & 0x40) << (24 - 6)) | (((~d) & 0x80) << (23 - 7)));  \
    PIO_Set(PIOB, (((d)&0x20) << (27 - 5)));                                   \
    PIO_Clear(PIOB, (((~d) & 0x20) << (27 - 5)));                              \
    WR_STROBE;                                                                 \
}

How do I change this code for the Due to do the same thing that the new Mega code does on the Mega?
I also don't understand why the Mega code uses binary and the Due code uses hex code all over. I'm hoping someone knows these things off-hand before I spend years researching how all this works.
An extra thing to note is that there is an option in the library to let it know the LCD is on a shield:
// **** IF USING THE LCD BREAKOUT BOARD, COMMENT OUT THIS NEXT LINE. ****
// **** IF USING THE LCD SHIELD, LEAVE THE LINE ENABLED:             ****

//#define USE_ADAFRUIT_SHIELD_PINOUT 1

That option must NOT be un-commented. It seems this LCD only works as if it was not a shield. Doesn't make sense to me but it continues what feels like not a thought in the world for maintainability/upgradability from the manufacturer.
The following is my current full pin_magic.h file with the modified Mega code and unmodified Due code. I may have removed some original library code in there while testing to narrow down the issue. The Mega code works correctly in this file.
#ifndef PIN_MAGIC
#define PIN_MAGIC

// This header file serves two purposes:
//
// 1) Isolate non-portable MCU port- and pin-specific identifiers and
//    operations so the library code itself remains somewhat agnostic
//    (PORTs and pin numbers are always referenced through macros).
//
// 2) GCC doesn't always respect the "inline" keyword, so this is a
//    ham-fisted manner of forcing the issue to minimize function calls.
//    This sometimes makes the library a bit bigger than before, but fast++.
//    However, because they're macros, we need to be SUPER CAREFUL about
//    parameters -- for example, write8(x) may expand to multiple PORT
//    writes that all refer to x, so it needs to be a constant or fixed
//    variable and not something like *ptr++ (which, after macro
//    expansion, may increment the pointer repeatedly and run off into
//    la-la land).  Macros also give us fine-grained control over which
//    operations are inlined on which boards (balancing speed against
//    available program space).

// When using the TFT shield, control and data pins exist in set physical
// locations, but the ports and bitmasks corresponding to each vary among
// boards.  A separate set of pin definitions is given for each supported
// board type.
// When using the TFT breakout board, control pins are configurable but
// the data pins are still fixed -- making every data pin configurable
// would be much too slow.  The data pin layouts are not the same between
// the shield and breakout configurations -- for the latter, pins were
// chosen to keep the tutorial wiring manageable more than making optimal
// use of ports and bitmasks.  So there's a second set of pin definitions
// given for each supported board.

// Shield pin usage:
// LCD Data Bit :    7    6    5    4    3    2    1    0
// Digital pin #:    7    6   13    4   11   10    9    8
// Uno port/pin :  PD7  PD6  PB5  PD4  PB3  PB2  PB1  PB0
// Mega port/pin:  PH4  PH3  PB7  PG5  PB5  PB4  PH6  PH5
// Leo port/pin :  PE6  PD7  PC7  PD4  PB7  PB6  PB5  PB4
// Due port/pin : PC23 PC24 PB27 PC26  PD7 PC29 PC21 PC22
// Breakout pin usage:
// LCD Data Bit :   7   6   5   4   3   2   1   0
// Uno dig. pin :   7   6   5   4   3   2   9   8
// Uno port/pin : PD7 PD6 PD5 PD4 PD3 PD2 PB1 PB0
// Mega dig. pin:  29  28  27  26  25  24  23  22
// Mega port/pin: PA7 PA6 PA5 PA4 PA3 PA2 PA1 PA0 (one contiguous PORT)
// Leo dig. pin :   7   6   5   4   3   2   9   8
// Leo port/pin : PE6 PD7 PC6 PD4 PD0 PD1 PB5 PB4
// Due dig. pin :  40  39  38  37  36  35  34  33
// Due port/pin : PC8 PC7 PC6 PC5 PC4 PC3 PC2 PC1 (one contiguous PORT. -ish…)

// Pixel read operations require a minimum 400 nS delay from RD_ACTIVE
// to polling the input pins.  At 16 MHz, one machine cycle is 62.5 nS.
// This code burns 7 cycles (437.5 nS) doing nothing; the RJMPs are
// equivalent to two NOPs each, final NOP burns the 7th cycle, and the
// last line is a radioactive mutant emoticon.
#define DELAY7                                                                 \
  asm volatile("rjmp .+0"                                                      \
               "\n\t"                                                          \
               "rjmp .+0"                                                      \
               "\n\t"                                                          \
               "rjmp .+0"                                                      \
               "\n\t"                                                          \
               "nop"                                                           \
               "\n" ::);

#if defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2561__) ||            \
    defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__)

// Arduino Mega, ADK, etc.

// #define write8inline(d)                                                        \
// {                                                                            \
//     PORTH = (PORTH & B10000111) | (((d)&B11000000) >> 3) | (((d)&B00000011) << 5); \
//     PORTB = (PORTB & B01001111) | (((d)&B00101100) << 2);                      \
//     PORTG = (PORTG & B11011111) | (((d)&B00010000) << 1);                      \
//     WR_STROBE;                                                                 \
// }

#define write8inline(d)                                                        \
{                                                                            \
    PORTE = (PORTE & B11001111) | ((d << 2) & B00110000); \
    PORTE = (PORTE & B11110111) | ((d >> 2) & B00001000); \
    PORTG = (PORTG & B11011111) | ((d << 1) & B00100000); \
    PORTH = (PORTH & B11100111) | ((d >> 3) & B00011000); \
    PORTH = (PORTH & B10011111) | ((d << 5) & B01100000); \
    WR_STROBE;                                                                 \
}

#define read8inline(result)                                                    \
{                                                                            \
    RD_ACTIVE;                                        \
    DELAY7;                                           \
    result = ((PINH & B00011000) << 3) | ((PINE & B00001000) << 2) | ((PING & B00100000) >> 1) |((PINE & B00110000) >> 2) | ((PINH & B01100000) >> 5); \
    RD_IDLE;                                                             \
}

#define setWriteDirInline() { DDRE |=  B00111000; DDRG |=  B00100000; DDRH |= B01111000;}
#define setReadDirInline() { DDRE &=  ~B00111000; DDRG &=  ~B00100000; DDRH &= ~B01111000;}

// All of the functions are inlined on the Arduino Mega.  When using the
// breakout board, the macro versions aren't appreciably larger than the
// function equivalents, and they're super simple and fast.  When using
// the shield, the macros become pretty complicated...but this board has
// so much code space, the macros are used anyway.  If you need to free
// up program space, some macros can be removed, at a minor cost in speed.
#define write8 write8inline
#define read8 read8inline
#define setWriteDir setWriteDirInline
#define setReadDir setReadDirInline
#define writeRegister8 writeRegister8inline
#define writeRegister16 writeRegister16inline
#define writeRegisterPair writeRegisterPairInline

#elif defined(__SAM3X8E__)

// Arduino Due

#define RD_PORT PIOA /*pin A0 */
#define WR_PORT PIOA /*pin A1 */
#define CD_PORT PIOA /*pin A2 */
#define CS_PORT PIOA /*pin A3 */
#define RD_MASK 0x00010000
#define WR_MASK 0x01000000
#define CD_MASK 0x00800000
#define CS_MASK 0x00400000

#define write8inline(d)                                                        \
  {                                                                            \
    PIO_Set(PIOD, (((d)&0x08) << (7 - 3)));                                    \
    PIO_Clear(PIOD, (((~d) & 0x08) << (7 - 3)));                               \
    PIO_Set(PIOC, (((d)&0x01) << (22 - 0)) | (((d)&0x02) << (21 - 1)) |        \
                      (((d)&0x04) << (29 - 2)) | (((d)&0x10) << (26 - 4)) |    \
                      (((d)&0x40) << (24 - 6)) | (((d)&0x80) << (23 - 7)));    \
    PIO_Clear(PIOC,                                                            \
              (((~d) & 0x01) << (22 - 0)) | (((~d) & 0x02) << (21 - 1)) |      \
                  (((~d) & 0x04) << (29 - 2)) | (((~d) & 0x10) << (26 - 4)) |  \
                  (((~d) & 0x40) << (24 - 6)) | (((~d) & 0x80) << (23 - 7)));  \
    PIO_Set(PIOB, (((d)&0x20) << (27 - 5)));                                   \
    PIO_Clear(PIOB, (((~d) & 0x20) << (27 - 5)));                              \
    WR_STROBE;                                                                 \
  }

#define read8inline(result)                                                    \
  {                                                                            \
                                                                               \
    RD_ACTIVE;                                                                 \
    delayMicroseconds(1);                                                      \
    result = (((PIOC->PIO_PDSR & (1 << 23)) >> (23 - 7)) |                     \
              ((PIOC->PIO_PDSR & (1 << 24)) >> (24 - 6)) |                     \
              ((PIOB->PIO_PDSR & (1 << 27)) >> (27 - 5)) |                     \
              ((PIOC->PIO_PDSR & (1 << 26)) >> (26 - 4)) |                     \
              ((PIOD->PIO_PDSR & (1 << 7)) >> (7 - 3)) |                       \
              ((PIOC->PIO_PDSR & (1 << 29)) >> (29 - 2)) |                     \
              ((PIOC->PIO_PDSR & (1 << 21)) >> (21 - 1)) |                     \
              ((PIOC->PIO_PDSR & (1 << 22)) >> (22 - 0)));                     \
    RD_IDLE;                                                                   \
  }

#define setWriteDirInline()                                                    \
  {                                                                            \
    PIOD->PIO_MDDR |= 0x00000080; /*PIOD->PIO_SODR =  0x00000080;*/            \
    PIOD->PIO_OER |= 0x00000080;                                               \
    PIOD->PIO_PER |= 0x00000080;                                               \
    PIOC->PIO_MDDR |= 0x25E00000; /*PIOC->PIO_SODR =  0x25E00000;*/            \
    PIOC->PIO_OER |= 0x25E00000;                                               \
    PIOC->PIO_PER |= 0x25E00000;                                               \
    PIOB->PIO_MDDR |= 0x08000000; /*PIOB->PIO_SODR =  0x08000000;*/            \
    PIOB->PIO_OER |= 0x08000000;                                               \
    PIOB->PIO_PER |= 0x08000000;                                               \
  }

#define setReadDirInline()                                                     \
  {                                                                            \
    pmc_enable_periph_clk(ID_PIOD);                                            \
    pmc_enable_periph_clk(ID_PIOC);                                            \
    pmc_enable_periph_clk(ID_PIOB);                                            \
    PIOD->PIO_PUDR |= 0x00000080;                                              \
    PIOD->PIO_IFDR |= 0x00000080;                                              \
    PIOD->PIO_ODR |= 0x00000080;                                               \
    PIOD->PIO_PER |= 0x00000080;                                               \
    PIOC->PIO_PUDR |= 0x25E00000;                                              \
    PIOC->PIO_IFDR |= 0x25E00000;                                              \
    PIOC->PIO_ODR |= 0x25E00000;                                               \
    PIOC->PIO_PER |= 0x25E00000;                                               \
    PIOB->PIO_PUDR |= 0x08000000;                                              \
    PIOB->PIO_IFDR |= 0x08000000;                                              \
    PIOB->PIO_ODR |= 0x08000000;                                               \
    PIOB->PIO_PER |= 0x08000000;                                               \
  }

// Control signals are ACTIVE LOW (idle is HIGH)
// Command/Data: LOW = command, HIGH = data
// These are single-instruction operations and always inline
#define RD_ACTIVE RD_PORT->PIO_CODR |= RD_MASK
#define RD_IDLE RD_PORT->PIO_SODR |= RD_MASK
#define WR_ACTIVE WR_PORT->PIO_CODR |= WR_MASK
#define WR_IDLE WR_PORT->PIO_SODR |= WR_MASK
#define CD_COMMAND CD_PORT->PIO_CODR |= CD_MASK
#define CD_DATA CD_PORT->PIO_SODR |= CD_MASK
#define CS_ACTIVE CS_PORT->PIO_CODR |= CS_MASK
#define CS_IDLE CS_PORT->PIO_SODR |= CS_MASK

#else

#error "Board type unsupported / not recognized"

#endif

#if !defined(__SAM3X8E__)
// Stuff common to all Arduino AVR board types:

// When using the TFT breakout board, control pins are configurable.
#define RD_ACTIVE *rdPort &= rdPinUnset
#define RD_IDLE *rdPort |= rdPinSet
#define WR_ACTIVE *wrPort &= wrPinUnset
#define WR_IDLE *wrPort |= wrPinSet
#define CD_COMMAND *cdPort &= cdPinUnset
#define CD_DATA *cdPort |= cdPinSet
#define CS_ACTIVE *csPort &= csPinUnset
#define CS_IDLE *csPort |= csPinSet

#endif

// Data write strobe, ~2 instructions and always inline
#define WR_STROBE                                                              \
{                                                                              \
    WR_ACTIVE;                                                                 \
    WR_IDLE;                                                                   \
}

// These higher-level operations are usually functionalized,
// except on Mega where's there's gobs and gobs of program space.

// Set value of TFT register: 8-bit address, 8-bit value
#define writeRegister8inline(a, d)                                             \
  {                                                                            \
    CD_COMMAND;                                                                \
    write8(a);                                                                 \
    CD_DATA;                                                                   \
    write8(d);                                                                 \
  }

// Set value of TFT register: 16-bit address, 16-bit value
// See notes at top about macro expansion, hence hi & lo temp vars
#define writeRegister16inline(a, d)                                            \
  {                                                                            \
    uint8_t hi, lo;                                                            \
    hi = (a) >> 8;                                                             \
    lo = (a);                                                                  \
    CD_COMMAND;                                                                \
    write8(hi);                                                                \
    write8(lo);                                                                \
    hi = (d) >> 8;                                                             \
    lo = (d);                                                                  \
    CD_DATA;                                                                   \
    write8(hi);                                                                \
    write8(lo);                                                                \
  }

// Set value of 2 TFT registers: Two 8-bit addresses (hi & lo), 16-bit value
#define writeRegisterPairInline(aH, aL, d)                                     \
  {                                                                            \
    uint8_t hi = (d) >> 8, lo = (d);                                           \
    CD_COMMAND;                                                                \
    write8(aH);                                                                \
    CD_DATA;                                                                   \
    write8(hi);                                                                \
    CD_COMMAND;                                                                \
    write8(aL);                                                                \
    CD_DATA;                                                                   \
    write8(lo);                                                                \
  }

#endif /* PIN_MAGIC */


text:
I need help for applying a logic to this code
Here's the code:
int softStart = A0;
int enable = A1;
int powerBTN = A2, powerState = HIGH, lastPowerState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 25;
unsigned long powerTimer = 0;
unsigned long powerHoldTimer = 0;
bool softStartENB = 0;

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);
  pinMode(powerBTN, INPUT_PULLUP);
}

void loop() {
  int powerReading = digitalRead(powerBTN);

  if (powerReading != lastPowerState) {
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay && !softStartENB) {
    if (powerReading != powerState) {
      powerState = powerReading;
      if (powerState == HIGH) {
        digitalWrite(enable, !digitalRead(enable));
        Serial.print("Normal start: ");
        Serial.println(digitalRead(enable));
      }
    }
  }

  if (powerReading == LOW) {
    powerTimer = millis() - lastDebounceTime;
  } else {
    powerTimer = 0;
  }

  if (powerTimer >= 1000 && millis() - powerHoldTimer >= 2000) {
    softStartENB = 1;
    digitalWrite(enable, LOW);
    digitalWrite(softStart, HIGH);
    Serial.print("Soft start started: ");
    Serial.println(digitalRead(softStart));
    powerHoldTimer = millis();
  }

  if (softStartENB && lastPowerState == HIGH && powerReading == LOW) {
    digitalWrite(enable, HIGH);
    delay(2000);
    digitalWrite(softStart, LOW);
    Serial.print("Soft start ended: ");
    Serial.println(digitalRead(softStart));
    softStartENB = 0;
  }

  lastPowerState = powerReading;

}

So the logic is as this:

By pressing powerBTN the enable pin toggles.
By holding powerBTN for 1 seconds softStartENB condition becomes true.
When softStartENB is true, if I press powerBTN again it sets enable pin to high and after 2 seconds softStart to low.

The problem is that after setting softStartENB to 0, lastPowerState = powerReading toggles enable pin to low but I want enable pin to stay high until I press powerBTN again to toggle it.

How can I apply the described logic?

should enable toggle when powerBTN is pressed for 1 second?

@jsotola It can't, because after holding it for a sec the 'softStartENB' flag becomes true and 'enable' can only toggle when 'softStartENB' is flase.

point 1. says nothing about softStartENB ... also, the softStartENB could be false at the beginning of the button press ... should enable be toggled when the button is released?

Your problem statement seems very incomplete. Once softStartENB becomes true, does it stay true forever? If not, which events toggle it back to false? Same question for softStart: can it ever change from LOW to HIGH? What happens if the button is pressed during the 2 second delay? Please, try to give a complete description of the desired behavior, preferably in the form of a state diagram.

@jsotola see the edit.

@EdgarBonet see the edit.

The device you are controlling has 3 states, OFF,  ON, and IN_SOFT_START. A short press of the button causes the device to toggle between ON and OFF.  A long press initiates IN_SOFT_START. A second press of the button in this state  then puts the device in state ON after waiting 2 seconds. Simple but you should draw it as a conventional state diagram. What about adding a timeout if, after entering state IN_SOFT_START, the user does not press the button again within a reasonable amount of time?

@6v6gt I can do all these later, right now the problem is that enable pin goes low after softStartENB flag becomes false.

I solved the problem by using JC_button library:
#include <JC_Button.h>

const byte softStart(A0), enable(A1);
int powerStates = 0;
bool enableState;

Button powerBTN(A2);

void setup() {
  Serial.begin(115200);
  powerBTN.begin();
  pinMode(enable, OUTPUT);
  pinMode(softStart, OUTPUT);
}

void loop() {
  powerBTN.read();
  Serial.println(powerStates);

  switch (powerStates) {
    case 0:
      if (powerBTN.wasReleased())
        switchEnable();
      else if (powerBTN.pressedFor(1000))
        powerStates = 1;
      break;

    case 1:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, LOW);
        digitalWrite(softStart, HIGH);
        enableState = false;
        powerStates = 2;
      }
      break;

    case 2:
      if (powerBTN.wasReleased()){
        digitalWrite(enable, HIGH);
        delay(2000);
        digitalWrite(softStart, LOW);
        enableState = true;
        powerStates = 0;
      }
      break;
  }
}

void switchEnable() {
  enableState = !enableState;
  digitalWrite(enable, enableState);
}

I restructured your code as a finite state machine. There is a minimal number of "foreign" flags and almost a 1:1 relationship between the code and the state diagram.
You can test a simulation of it here: https://wokwi.com/projects/383445446722551809

int softStart = A0;
int enable = A1;
int powerBTN = A2;

enum State { OFF = 0, ON = 1, WAIT_ON = 2 , WAIT_OFF = 3, IN_SOFT_START = 4, SOFT_START_CONFIRM = 5 } ;
State state  ;
State oldState ;
bool stateChange = true ;

uint32_t inCurrentStateAtMs = 0 ;

void setState ( State newState ) {
  // forces change to new state
  inCurrentStateAtMs = millis() ;
  oldState = state ;
  state = newState ;
  stateChange = true ;
}

void setup() {
  Serial.begin(115200);
  pinMode(softStart, OUTPUT);
  pinMode(enable, OUTPUT);
  pinMode(powerBTN, INPUT_PULLUP) ;
  digitalWrite(enable, LOW);
  digitalWrite(softStart, LOW);

  setState( State::OFF ) ;

}

void loop() {

  if ( stateChange ) {
    //debug
    stateChange = false ;
    Serial.print("state changes to: ");
    Serial.println( state ) ;
  }

  switch ( state ) {

    case State::OFF : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_ON ) ;
        }
        break ;
      }

    case State::WAIT_ON : {

          if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs < 500 ) {
            digitalWrite( enable, HIGH ) ;
            setState( State::ON );
          }
          else if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs >= 500 ) {
            digitalWrite( enable, LOW ) ;
            digitalWrite( softStart, HIGH ) ;
            setState( State::IN_SOFT_START );
          }

        break ;
      }

    case State::ON : {
        if ( ! digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          setState( State::WAIT_OFF );
        }
        break ;
      }

    case State::WAIT_OFF : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 100 ) {
          digitalWrite( enable, LOW ) ;
          setState( State::OFF ) ;
        }
        break;
      }

    case State::IN_SOFT_START : {
        if ( ! digitalRead( powerBTN )  ) {
          digitalWrite( enable, HIGH ) ;
          state = State::SOFT_START_CONFIRM ;
        }
        else if ( millis() - inCurrentStateAtMs > 3000 ) {
          // timeout
          digitalWrite( softStart, LOW ) ;
          setState( State::OFF );
        }
        break ;
      }

    case State::SOFT_START_CONFIRM  : {
        if ( digitalRead( powerBTN ) && millis() - inCurrentStateAtMs > 2000  ) {
          digitalWrite( softStart, LOW ) ;
          setState( State::ON ) ;
        }
        break ;
      }

  } // switch

}  // loop

Please don't change the code behavior, in my code even if the enable pin is high and powerBTN held for 1 second, enable pin goes low. in any case the problem persist, the enable pin doesn't stay/goes high before and after softStart goes high and then low.


text:
ESPAsyncDNSServer cannot find AsyncUDP anymore
I'm using this ESP32AsyncDNSServer library on my ESP32 application.
Suddenly (I'm not sure what I did) it does not compile anymore:

.pio/libdeps/Aphrodite/ESPAsyncDNSServer/src/ESPAsyncDNSServer.h:8:10: fatal error: AsyncUDP.h: No such file or directory

Here the related code of the library:
#ifdef ARDUINO_ARCH_ESP32
#ifndef Stream_h
#include <Stream.h>
#endif
#include <AsyncUDP.h>
#else
#include <ESPAsyncUDP.h>
#endif

but of course AsyncUDP.h does exist:

/home/mark/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src/AsyncUDP.h

What could prevent the compiler to find it?

for whatever reason, adding this to your platformio.ini env section helps:
[env]
lib_compat_mode = strict # default is "soft"

I guess the more clean version would be to add this to your lib_deps
lib_deps =
    ESP32 Async UDP # important! otherwise "AsyncUDP.h" blabla is missing..
    <your libs following>


text:
WiFi.scanNetworks() sometimes triggers wdt reset
In my sketch for ESP32, I call the network scanning function:
WiFi.scanNetworks(true);

but sometimes it trigger a wdt reset:
E (372741) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (372741) task_wdt:  - async_tcp (CPU 0/1)
E (372741) task_wdt: Tasks currently running:
E (372741) task_wdt: CPU 0: IDLE
E (372741) task_wdt: CPU 1: IDLE
E (372741) task_wdt: Aborting.

abort() was called at PC 0x40113f64 on core 0

Backtrace: 0x40083db5:0x3ffbf1ac |<-CORRUPTED

I added these lines in the setup() with no changes in the behavior:
disableCore0WDT();
disableCore1WDT();
disableLoopWDT();

EDIT:
My questions are:

"Why it triggers a WDT reset even if I disabled the WDT?"
"Why a scan network triggers a WDT reset? It should be a stock function"

what is your question? ... please add a clear, answerable question to your post

@jsotola done. Please tell me if now the questions are clear and answerable, or how to improve them further

WiFi.scanNetworks(true); means async WiFi scan, it is non-blocking, so anything that causing the WDT trigger is in your code and we don't know how you setup the task and handing the state transitions. Do you have any problem running WiFi scan with sync mode WiFi.scanNetworks();?

@hcheung I'm fairly certain that it might be something inside Espressif's proprietary RF driver code. All of the task's setup and everything is hidden away as well from most Arduino users, so I don't think we'll be able to answer #2. For #1, it's because there is also a WDT for tasks, while the disabled WDTs are the "loop WDTs".


text:
How to bypass any on board circuitry when using an external LDO
I am using an ESP8266 NodeMCU (Amica) module.  I am powering it with a 3.7v rechargeable Li-Lion battery (18650).  I am regulating the voltage using a LDO circuit. https://randomnerdtutorials.com/esp8266-voltage-regulator-lipo-and-li-ion-batteries/
I want to avoid as much on board circuitry as possible.  For example I notice that there is a non-LDO regulator (AMS1117 chip) on board.
What pin on the module should I connect the regulator output to?
Thanks.


text:
How to output two PWM signals, one of 50% duty cycle, the other 25% duty cycle, from an Arduino Uno?
I need to output two PWM signals, one of 50% duty cycle, the other 25% duty cycle, from an Arduino. Feed both signals into the 2 channels of a PicoScope and measure:
a) the time difference between the rising pulse of the traces and
b) the time it takes for the signal to settle for the 50% trace.
I understand that I may not get help with the Picoscope part of the question, however I do need help with the other part.
I'm very new to Arduino and don't really know what I'm doing. Any help will be appreciated!

examine the blinkWithoutDelay example sketch in the Arduimo IDE ... use that for timing the rising and falling edges of the two signals

The function analogWrite generates PWM signals. See its documentation for details.
You use analogWrite(pin_for_25_percent, 64); for 25% and analogWrite(pin_for_50_percent, 128); for 50%.
const int pin_for_25_percent = /* your choice */;
const int pin_for_50_percent = /* your choice */;

void setup() {
    analogWrite(pin_for_25_percent, 64);
    analogWrite(pin_for_50_percent, 128);
}

void loop() {
}

On an AVR-Arduino, each hardware timer controls two PWM pins. Results regarding timing/synchronization of the PWM signals may vary depending on the chosen pins.

@DataFiddler There are no requirements in the question concerning synchronous signals. ;-) I assume this is just an introductory experiment of a homework or laboratory assignment. But granted, with more and clear requirements, you could have a point.

@busybee I understand the time difference between the rising pulse of the traces as a question about the synchronization  of the two PWM signals. But you're right, the task rather seems to aim at manual triggering of digital pins.


text:
Recursive listing of sd card files
I'm working on a MP3 player and I want to list all files on the SD card.
I have found this code on internet :
void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print('\t');
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

It lists all the files but I can display only the first level directory. Here is my full code.
#define pushButton_pin   32
// Include required libraries
#include "Audio.h"
#include "SD.h"
#include "FS.h"
#include <Wire.h>
#include <TFT_eSPI.h>
#include <SPI.h>

// microSD Card Reader connections
#define SD_CS          5
#define SPI_MOSI      21
#define SPI_MISO      19
#define SPI_SCK       18

// I2S Connections
#define I2S_DOUT      22
#define I2S_BCLK      26
#define I2S_LRC       25

 // Create Audio object
Audio audio;

TFT_eSPI tft = TFT_eSPI();
//digitalWrite(TFT_BL, 1);

int maxIndex;
uint32_t Freq = 0;
int Val;
String Btn, SongName;
String Status = "Idle";
bool state = true;
bool Current_State = state;
int Current_Millis;
int Previous_Millis;
int Debounce = 175;
int Xindex = 0;
int Yindex = 0;

const uint8_t maxFileNameSize = 50;
struct FileItem {
  bool isDir;
  char name[maxFileNameSize + 1];
  FileItem* upDir;
  std::vector<FileItem> elements;
};

File dir;
String CurrDir;
String NextDir;
String Song;
String Liste[50];

void setup() {
  pinMode(pushButton_pin, INPUT);
  setCpuFrequencyMhz(160);
  tft.init();
  tft.setRotation(3);
  tft.fillScreen(TFT_BLACK);
  tft.setTextWrap(false);

  // Set microSD Card CS as OUTPUT and set HIGH
  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);

  // Initialize SPI bus for microSD Card
  SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);

  // Start Serial Port
  Serial.begin(115200);

  // Start microSD Card
  if (!SD.begin(SD_CS))
  {
    Serial.println("Error accessing microSD card!");
    while(true);
  }
  Serial.println("initialization done.");
  Serial.println("Creating structure of files");
  File root = SD.open("/");
  FileItem rootItem;
  if (strlen(root.name()) != 0)
    strncpy(rootItem.name, root.name(), maxFileNameSize);
  else
    strncpy(rootItem.name, "/", maxFileNameSize);
  rootItem.name[maxFileNameSize] = '\0';
  rootItem.isDir = true;
  readSdCard(root, rootItem);
  //Fin du listing

  Serial.println ("----Disp----");
  displaySdCardContent(rootItem, 0);
}

void readSdCard(File dir, FileItem& parentItem) {
  while (true) {
    File entry = dir.openNextFile();
    if (!entry) {
      break;  // no more files
    }
    FileItem item;
    item.isDir = entry.isDirectory();
    strncpy(item.name,  entry.name(), maxFileNameSize); // https://cplusplus.com/reference/cstring/strncpy/
    item.name[maxFileNameSize] = '\0';
    parentItem.elements.push_back(item);
    Serial.printf("Add %s to %s\n", item.name, parentItem.name);
    if (entry.isDirectory()) {
      readSdCard(entry, item);
    }
  }
}

void displaySdCardContent(FileItem& item, int numTabs) {
  for (int i = 0; i < numTabs; i++) {
    Serial.print("...");
  }
  if (item.isDir) {
    Serial.println(item.name);
    for (FileItem& fileElement : item.elements) {
      displaySdCardContent(fileElement, numTabs + 1);
    }
  } else {
    Serial.println(item.name);
  }
}

I have tried this to access the second level directories :
  FileItem* subFolder = &rootItem.elements.at(0);
  Serial.println ("----Disp----");
  FileItem _subFolder= *subFolder;

  displaySdCardContent(_subFolder, 0);

But it doesn't work ...
Here is what I get with the serial monitor :
23:36:23.419 -> Add 11-Avalanche.mp3 to War Eternal
23:36:23.419 -> Add 12-Down To Nothing.mp3 to War Eternal
23:36:23.419 -> Add 13-Not Long For This World.mp3 to War Eternal
23:36:23.451 -> Add folder.jpg to War Eternal
23:36:23.451 -> Add Will To Power to Arch Enemy
23:36:23.483 -> Add 01-Set Flame To The Night.mp3 to Will To Power
23:36:23.483 -> Add 02-The Race.mp3 to Will To Power
23:36:23.515 -> Add 03-Blood In The Water.mp3 to Will To Power
23:36:23.515 -> Add 04-The World Is Yours.mp3 to Will To Power
23:36:23.515 -> Add 05-The Eagle Flies Alone.mp3 to Will To Power
23:36:23.547 -> Add 06-Reason To Believe.mp3 to Will To Power
23:36:23.547 -> Add 07-Murder Scene.mp3 to Will To Power
23:36:23.579 -> Add 08-First Day In Hell.mp3 to Will To Power
23:36:23.579 -> Add 09-Saturnine.mp3 to Will To Power
23:36:23.612 -> Add 10-Dreams Of Retribution.mp3 to Will To Power
23:36:23.643 -> Add 11-My Shadow And I.mp3 to Will To Power
23:36:23.643 -> Add 12-A Fight I Must Win.mp3 to Will To Power
23:36:23.675 -> Add folder.jpg to Will To Power
23:36:23.675 -> ----Disp----
23:36:23.675 -> Arch Enemy

Edit :
Attributes item i can print  in displaySdCardContent()
14:58:54.763 -> ----Disp----
14:58:54.763 -> name : Arch Enemy
14:58:54.763 -> IsDir : 1

Debug in ReadsdCard
⸮⸮item name : 07. [Through The Eyes Of A Raven].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :7
Add 07. [Through The Eyes Of A Raven].mp3 to CD1 - Khaos Legions
item name : 08. [Cruelty Without Beauty].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :8
Add 08. [Cruelty Without Beauty].mp3 to CD1 - Khaos Legions
item name : 09. [We Are A Godless Entity].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :9
Add 09. [We Are A Godless Entity].mp3 to CD1 - Khaos Legions
item name : 10. [Cult Of Chaos].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :10
Add 10. [Cult Of Chaos].mp3 to CD1 - Khaos Legions
item name : 11. [Thorns In My Flesh].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :11
Add 11. [Thorns In My Flesh].mp3 to CD1 - Khaos Legions
item name : 12. [Turn To Dust].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :12
Add 12. [Turn To Dust].mp3 to CD1 - Khaos Legions
item name : 13. [Vengeance Is Mine].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :13
Add 13. [Vengeance Is Mine].mp3 to CD1 - Khaos Legions
item name : 14. [Secrets].mp3
item IsDir : 0
item size :0
parent item name : CD1 - Khaos Legions
parent item IsDir : 1
Parent item size :14
Add 14. [Secrets].mp3 to CD1 - Khaos Legions
item name : CD2 - Kovered In Khaos
item IsDir : 1
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :2
Add CD2 - Kovered In Khaos to 2011 - Khaos Legions (2xCD, Ltd)
item name : 01. [Warning].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :1
Add 01. [Warning].mp3 to CD2 - Kovered In Khaos
item name : 02. [Wings Of Tomorrow].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :2
Add 02. [Wings Of Tomorrow].mp3 to CD2 - Kovered In Khaos
item name : 03. [The Oath].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :3
Add 03. [The Oath].mp3 to CD2 - Kovered In Khaos
item name : 04. [The Book Of Heavy Metal].mp3
item IsDir : 0
item size :0
parent item name : CD2 - Kovered In Khaos
parent item IsDir : 1
Parent item size :4
Add 04. [The Book Of Heavy Metal].mp3 to CD2 - Kovered In Khaos
item name : Folder.jpg
item IsDir : 0
item size :0
parent item name : 2011 - Khaos Legions (2xCD, Ltd)
parent item IsDir : 1
Parent item size :3
Add Folder.jpg to 2011 - Khaos Legions (2xCD, Ltd)
item name : War Eternal
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :4
Add War Eternal to Arch Enemy
item name : 01-Tempore Nihil Sanat (Prelude in F minor).mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :1
Add 01-Tempore Nihil Sanat (Prelude in F minor).mp3 to War Eternal
item name : 02-Never Forgive, Never Forget.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :2
Add 02-Never Forgive, Never Forget.mp3 to War Eternal
item name : 03-War Eternal.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :3
Add 03-War Eternal.mp3 to War Eternal
item name : 04-As The Pages Burn.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :4
Add 04-As The Pages Burn.mp3 to War Eternal
item name : 05-No More Regrets.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :5
Add 05-No More Regrets.mp3 to War Eternal
item name : 06-You Will Know My Name.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :6
Add 06-You Will Know My Name.mp3 to War Eternal
item name : 07-Graveyard Of Dreams.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :7
Add 07-Graveyard Of Dreams.mp3 to War Eternal
item name : 08-Stolen Life.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :8
Add 08-Stolen Life.mp3 to War Eternal
item name : 09-Time Is Black.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :9
Add 09-Time Is Black.mp3 to War Eternal
item name : 10-On And On.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :10
Add 10-On And On.mp3 to War Eternal
item name : 11-Avalanche.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :11
Add 11-Avalanche.mp3 to War Eternal
item name : 12-Down To Nothing.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :12
Add 12-Down To Nothing.mp3 to War Eternal
item name : 13-Not Long For This World.mp3
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :13
Add 13-Not Long For This World.mp3 to War Eternal
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : War Eternal
parent item IsDir : 1
Parent item size :14
Add folder.jpg to War Eternal
item name : Will To Power
item IsDir : 1
item size :0
parent item name : Arch Enemy
parent item IsDir : 1
Parent item size :5
Add Will To Power to Arch Enemy
item name : 01-Set Flame To The Night.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :1
Add 01-Set Flame To The Night.mp3 to Will To Power
item name : 02-The Race.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :2
Add 02-The Race.mp3 to Will To Power
item name : 03-Blood In The Water.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :3
Add 03-Blood In The Water.mp3 to Will To Power
item name : 04-The World Is Yours.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :4
Add 04-The World Is Yours.mp3 to Will To Power
item name : 05-The Eagle Flies Alone.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :5
Add 05-The Eagle Flies Alone.mp3 to Will To Power
item name : 06-Reason To Believe.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :6
Add 06-Reason To Believe.mp3 to Will To Power
item name : 07-Murder Scene.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :7
Add 07-Murder Scene.mp3 to Will To Power
item name : 08-First Day In Hell.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :8
Add 08-First Day In Hell.mp3 to Will To Power
item name : 09-Saturnine.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :9
Add 09-Saturnine.mp3 to Will To Power
item name : 10-Dreams Of Retribution.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :10
Add 10-Dreams Of Retribution.mp3 to Will To Power
item name : 11-My Shadow And I.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :11
Add 11-My Shadow And I.mp3 to Will To Power
item name : 12-A Fight I Must Win.mp3
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :12
Add 12-A Fight I Must Win.mp3 to Will To Power
item name : folder.jpg
item IsDir : 0
item size :0
parent item name : Will To Power
parent item IsDir : 1
Parent item size :13
Add folder.jpg to Will To Power
----end of listing ----
rootItem.element[0] name : Arch Enemy
rootItem.element[0] IsDir : 1
rootItem.element[0] size :0

i am trying to access sub directories, but "it doesn't work". The original code with displaySdCardContent(rootItem,0); display the first level, and my test also display the only first level

OT: You set no upDir value in your items. However, you don't use it.

I see no apparent error on a first glance, and I don't have the hardware to reproduce. Please [edit] your question with the results of debugging output of item's attributes in displaySdCardContent(). If this looks fishy, do the same while building the tree of items in readSdCard().

the debugging output is already in my question . Before the "23:36:23.675 -> ----Disp----" it's the output while building the tree, and after is the output of '''displaySdCardContent().

Please read closer: I'd like to see all attributes of each item given to displaySdCardContent().

i can only acces items in root, and there is one folder. I can just print name and isDir. upDir is an item and Elements a vector items, i can't print  it.

Thanks. As isDir is 1, item.elements should be iterated. Apparently it is not, so please print item.elements.size(). And so on, you will want to "single-step" through the data with multiple prints.

item.elements.size return 0  ... o_O?
20:20:47.622 -> name : Arch Enemy 20:20:47.622 -> IsDir : 1 20:20:47.622 -> size :0

The next step is logical: Add debug prints to readSdCard() for each completed item before appending it, and to setup() for rootItem.elements[0].

i have edited the question with readSdCard() debug. I don't know why i can't get the begining but what i understand, each item have a size equal to 0, but each time it's add to the parent directory, parentdirectory size rise by 1 and when it change the directory, parent item size restart to 0.

Thanks for the debug log! It looks as if the readSdCard() works like expected and populates your tree. There must be something else. Unfortunately I need some sleep now, I'll get back in some hours.

I think I see what you are trying to do; you appear to be building a tree structure on the stack by recursively navigating the SD file structure. You are clearly expecting that tree structure to still exist intact after the recursively called function's final invocation returns so you can then navigate that tree structure with another recursive function. Are you sure that the tree will exist at the you try to navigate it ?

In the meantime you've got an answer and maybe that solves it but I set up a quick Wokwi ESP32 simulation including a sample file structure but using the LittleFS instead of the SD filesystem so that it can be experimented with online. The core is similar to your original simple recursive scan rather that your two pass solution. It based on a general "randomnerd" tutorial and that appears to work. https://wokwi.com/projects/383917656227391489

thank you, yes the answer solve my problem, but i keep your code, just in case ^^

The error is hard to see, but it is essentially in this original sequence (irrelevant statements omitted):
    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, item);
    }

The method push_back() copies the item to elements. Since at that moment item has no elements, the copy also has none. Later modifications of item do not change the copy.
There are multiple alternatives to correct.
1. Recurse first, then push:
    FileItem item;
    // ...
      readSdCard(entry, item);
    }
    // ...
    parentItem.elements.push_back(item);

This way item's elements vector collect its entries before the push_back().
However, the order of debug messages changes.
2. Recurse with the copy:
    FileItem item;
    // ...
    parentItem.elements.push_back(item);
    // ...
      readSdCard(entry, parentItem.elements.back());
    }

In this case readSdCard() uses the copy of item in parentItem's elements to collect the entries.

Thank you so much !! it seems to work, i have quickly try to navigate in tree and Serial.println(rootItem.elements[0].elements.at(1).elements[1].name); return an mp3 file ! Now i have to deal with this tree to print it on my screen but the hardest thing is done :) thank you again !


text:
Diecimila with firmata standard not working
Hi would like to use an old Diecimila with home-assistant, and that seems to imply installing firmata-standard.
That fails since there is not enough space on the board.
Is there a workaround (I only need inputs, maybe even only digital)?
What would be a good way forward otherwise? Is there an alternative to firmata for homeassistant?  Or should I just buy a newer board?

You could try ConfigurableFirmata instead. I haven't tried it with such old boards, but when you only need digital I/O, it could even be smaller than StandardFirmata.

The error message was:
Sketch uses 13172 bytes (91%) of program storage space. Maximum is 14336 bytes.
Global variables use 1113 bytes (108%) of dynamic memory, leaving -89 bytes for local variables. Maximum is 1024 bytes.

Huh. I thought I got it compiling but I'm getting a similar message now, although with a different memory number, still not enough memory though.  So, I'm going vote up your comment and delete my own. You should edit that detail into your question because it's important. It may be good to mention which board core and firmata library versions are in use. And even though the error message kind of contains this information, you may want to be explicit about ATmega168. And, I'll see what I can do locally with what I have.

Is there a workaround (I only need inputs, maybe even only digital)?

OldStandardFirmata
I don't know enough about homeassistant to know what you need exactly. But it seems very likely that you can and probably should use OldStandardFirmata. And it is so similar to the modified StandardFirmata (below) that it will probably just work for you. It uses 505 (reported) bytes of RAM.
AllInputsFirmata may also work, but it's RAM usage is only a percent smaller.
Modifying StandardFirmata
That said, it looks like you can get StandardFirmata.ino from current version 2.5.9 to be within limits by removing everything associated with I2C and Servo. It is probably worth trying OldStandardFirmata first, because much of these changes are what makes the difference between the Old and not-Old examples.
Under AVR support version 1.8.7.
Sketch uses 7978 bytes (55%) of program storage space. Maximum is 14336 bytes.
Global variables use 522 bytes (50%) of dynamic memory, leaving 502 bytes for local variables. Maximum is 1024 bytes.

So, slightly larger than OldStandardFirmata.

Action
Reported Global variables

Nothing
1079 bytes

Removing only I2C
650 bytes

Removing servo
951 bytes

Removing both I2C and SERVO
522 bytes

Removing servo-related stuff doesn't lower the ram using
that much but it does remove some lines from this post.
Removing analogWrite, analogRead can remove nontrivial amounts of code, but doesn't affect the memory footprint much. The final size is similar to OldFirmataStandard's size.
The following may work for you. It's the example in entirety after removing I2C and Servo related parts. I would have changed the formatting a bit, but leaving it as is you should be able to diff it against the original to see the changes if you care to.
/*
  Firmata is a generic protocol for communicating with microcontrollers
  from software on a host computer. It is intended to work with
  any host computer software package.

  To download a host software package, please click on the following link
  to open the list of Firmata client libraries in your default browser.

  https://github.com/firmata/arduino#firmata-client-libraries

  Copyright (C) 2006-2008 Hans-Christoph Steiner.  All rights reserved.
  Copyright (C) 2010-2011 Paul Stoffregen.  All rights reserved.
  Copyright (C) 2009 Shigeru Kobayashi.  All rights reserved.
  Copyright (C) 2009-2016 Jeff Hoefs.  All rights reserved.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  See file LICENSE.txt for further informations on licensing terms.

  Last updated August 17th, 2017
*/

#include <Firmata.h>

// the minimum interval for sampling analog input
#define MINIMUM_SAMPLING_INTERVAL   1

/*==============================================================================
 * GLOBAL VARIABLES
 *============================================================================*/

#ifdef FIRMATA_SERIAL_FEATURE
SerialFirmata serialFeature;
#endif

/* analog inputs */
int analogInputsToReport = 0; // bitwise array to store pin reporting

/* digital input ports */
byte reportPINs[TOTAL_PORTS];       // 1 = report this port, 0 = silence
byte previousPINs[TOTAL_PORTS];     // previous 8 bits sent

/* pins configuration */
byte portConfigInputs[TOTAL_PORTS]; // each bit: 1 = pin in INPUT, 0 = anything else

/* timer variables */
unsigned long currentMillis;        // store the current value from millis()
unsigned long previousMillis;       // for comparison with currentMillis
unsigned int samplingInterval = 19; // how often to run the main loop (in ms)

/* i2c data */
struct i2c_device_info {
  byte addr;
  int reg;
  byte bytes;
  byte stopTX;
};

boolean isResetting = false;

// Forward declare a few functions to avoid compiler errors with older versions
// of the Arduino IDE.
void setPinModeCallback(byte, int);
void reportAnalogCallback(byte analogPin, int value);
void sysexCallback(byte, byte, byte*);

/*==============================================================================
 * FUNCTIONS
 *============================================================================*/

void outputPort(byte portNumber, byte portValue, byte forceSend)
{
  // pins not configured as INPUT are cleared to zeros
  portValue = portValue & portConfigInputs[portNumber];
  // only send if the value is different than previously sent
  if (forceSend || previousPINs[portNumber] != portValue) {
    Firmata.sendDigitalPort(portNumber, portValue);
    previousPINs[portNumber] = portValue;
  }
}

/* -----------------------------------------------------------------------------
 * check all the active digital inputs for change of state, then add any events
 * to the Serial output queue using Serial.print() */
void checkDigitalInputs(void)
{
  /* Using non-looping code allows constants to be given to readPort().
   * The compiler will apply substantial optimizations if the inputs
   * to readPort() are compile-time constants. */
  if (TOTAL_PORTS > 0 && reportPINs[0]) outputPort(0, readPort(0, portConfigInputs[0]), false);
  if (TOTAL_PORTS > 1 && reportPINs[1]) outputPort(1, readPort(1, portConfigInputs[1]), false);
  if (TOTAL_PORTS > 2 && reportPINs[2]) outputPort(2, readPort(2, portConfigInputs[2]), false);
  if (TOTAL_PORTS > 3 && reportPINs[3]) outputPort(3, readPort(3, portConfigInputs[3]), false);
  if (TOTAL_PORTS > 4 && reportPINs[4]) outputPort(4, readPort(4, portConfigInputs[4]), false);
  if (TOTAL_PORTS > 5 && reportPINs[5]) outputPort(5, readPort(5, portConfigInputs[5]), false);
  if (TOTAL_PORTS > 6 && reportPINs[6]) outputPort(6, readPort(6, portConfigInputs[6]), false);
  if (TOTAL_PORTS > 7 && reportPINs[7]) outputPort(7, readPort(7, portConfigInputs[7]), false);
  if (TOTAL_PORTS > 8 && reportPINs[8]) outputPort(8, readPort(8, portConfigInputs[8]), false);
  if (TOTAL_PORTS > 9 && reportPINs[9]) outputPort(9, readPort(9, portConfigInputs[9]), false);
  if (TOTAL_PORTS > 10 && reportPINs[10]) outputPort(10, readPort(10, portConfigInputs[10]), false);
  if (TOTAL_PORTS > 11 && reportPINs[11]) outputPort(11, readPort(11, portConfigInputs[11]), false);
  if (TOTAL_PORTS > 12 && reportPINs[12]) outputPort(12, readPort(12, portConfigInputs[12]), false);
  if (TOTAL_PORTS > 13 && reportPINs[13]) outputPort(13, readPort(13, portConfigInputs[13]), false);
  if (TOTAL_PORTS > 14 && reportPINs[14]) outputPort(14, readPort(14, portConfigInputs[14]), false);
  if (TOTAL_PORTS > 15 && reportPINs[15]) outputPort(15, readPort(15, portConfigInputs[15]), false);
}

// -----------------------------------------------------------------------------
/* sets the pin mode to the correct state and sets the relevant bits in the
 * two bit-arrays that track Digital I/O and PWM status
 */
void setPinModeCallback(byte pin, int mode)
{
  if (Firmata.getPinMode(pin) == PIN_MODE_IGNORE)
    return;

  if (IS_PIN_ANALOG(pin)) {
    reportAnalogCallback(PIN_TO_ANALOG(pin), mode == PIN_MODE_ANALOG ? 1 : 0); // turn on/off reporting
  }
  if (IS_PIN_DIGITAL(pin)) {
    if (mode == INPUT || mode == PIN_MODE_PULLUP) {
      portConfigInputs[pin / 8] |= (1 << (pin & 7));
    } else {
      portConfigInputs[pin / 8] &= ~(1 << (pin & 7));
    }
  }
  Firmata.setPinState(pin, 0);
  switch (mode) {
    case PIN_MODE_ANALOG:
      if (IS_PIN_ANALOG(pin)) {
        if (IS_PIN_DIGITAL(pin)) {
          pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
          // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
          digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        }
        Firmata.setPinMode(pin, PIN_MODE_ANALOG);
      }
      break;
    case INPUT:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT);    // disable output driver
#if ARDUINO <= 100
        // deprecated since Arduino 1.0.1 - TODO: drop support in Firmata 2.6
        digitalWrite(PIN_TO_DIGITAL(pin), LOW); // disable internal pull-ups
#endif
        Firmata.setPinMode(pin, INPUT);
      }
      break;
    case PIN_MODE_PULLUP:
      if (IS_PIN_DIGITAL(pin)) {
        pinMode(PIN_TO_DIGITAL(pin), INPUT_PULLUP);
        Firmata.setPinMode(pin, PIN_MODE_PULLUP);
        Firmata.setPinState(pin, 1);
      }
      break;
    case OUTPUT:
      if (IS_PIN_DIGITAL(pin)) {
        if (Firmata.getPinMode(pin) == PIN_MODE_PWM) {
          // Disable PWM if pin mode was previously set to PWM.
          digitalWrite(PIN_TO_DIGITAL(pin), LOW);
        }
        pinMode(PIN_TO_DIGITAL(pin), OUTPUT);
        Firmata.setPinMode(pin, OUTPUT);
      }
      break;
    case PIN_MODE_PWM:
      if (IS_PIN_PWM(pin)) {
        pinMode(PIN_TO_PWM(pin), OUTPUT);
        analogWrite(PIN_TO_PWM(pin), 0);
        Firmata.setPinMode(pin, PIN_MODE_PWM);
      }
      break;
    case PIN_MODE_I2C:
      if (IS_PIN_I2C(pin)) {
        // mark the pin as i2c
        // the user must call I2C_CONFIG to enable I2C for a device
        Firmata.setPinMode(pin, PIN_MODE_I2C);
      }
      break;
    case PIN_MODE_SERIAL:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handlePinMode(pin, PIN_MODE_SERIAL);
#endif
      break;
    default:
      Firmata.sendString("Unknown pin mode"); // TODO: put error msgs in EEPROM
  }
  // TODO: save status to EEPROM here, if changed
}

/*
 * Sets the value of an individual pin. Useful if you want to set a pin value but
 * are not tracking the digital port state.
 * Can only be used on pins configured as OUTPUT.
 * Cannot be used to enable pull-ups on Digital INPUT pins.
 */
void setPinValueCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS && IS_PIN_DIGITAL(pin)) {
    if (Firmata.getPinMode(pin) == OUTPUT) {
      Firmata.setPinState(pin, value);
      digitalWrite(PIN_TO_DIGITAL(pin), value);
    }
  }
}

void analogWriteCallback(byte pin, int value)
{
  if (pin < TOTAL_PINS) {
    switch (Firmata.getPinMode(pin)) {
      case PIN_MODE_PWM:
        if (IS_PIN_PWM(pin))
          analogWrite(PIN_TO_PWM(pin), value);
        Firmata.setPinState(pin, value);
        break;
    }
  }
}

void digitalWriteCallback(byte port, int value)
{
  byte pin, lastPin, pinValue, mask = 1, pinWriteMask = 0;

  if (port < TOTAL_PORTS) {
    // create a mask of the pins on this port that are writable.
    lastPin = port * 8 + 8;
    if (lastPin > TOTAL_PINS) lastPin = TOTAL_PINS;
    for (pin = port * 8; pin < lastPin; pin++) {
      // do not disturb non-digital pins (eg, Rx & Tx)
      if (IS_PIN_DIGITAL(pin)) {
        // do not touch pins in PWM, ANALOG, SERVO or other modes
        if (Firmata.getPinMode(pin) == OUTPUT || Firmata.getPinMode(pin) == INPUT) {
          pinValue = ((byte)value & mask) ? 1 : 0;
          if (Firmata.getPinMode(pin) == OUTPUT) {
            pinWriteMask |= mask;
          } else if (Firmata.getPinMode(pin) == INPUT && pinValue == 1 && Firmata.getPinState(pin) != 1) {
            // only handle INPUT here for backwards compatibility
#if ARDUINO > 100
            pinMode(pin, INPUT_PULLUP);
#else
            // only write to the INPUT pin to enable pullups if Arduino v1.0.0 or earlier
            pinWriteMask |= mask;
#endif
          }
          Firmata.setPinState(pin, pinValue);
        }
      }
      mask = mask << 1;
    }
    writePort(port, (byte)value, pinWriteMask);
  }
}

// -----------------------------------------------------------------------------
/* sets bits in a bit array (int) to toggle the reporting of the analogIns
 */
//void FirmataClass::setAnalogPinReporting(byte pin, byte state) {
//}
void reportAnalogCallback(byte analogPin, int value)
{
  if (analogPin < TOTAL_ANALOG_PINS) {
    if (value == 0) {
      analogInputsToReport = analogInputsToReport & ~ (1 << analogPin);
    } else {
      analogInputsToReport = analogInputsToReport | (1 << analogPin);
      // prevent during system reset or all analog pin values will be reported
      // which may report noise for unconnected analog pins
      if (!isResetting) {
        // Send pin value immediately. This is helpful when connected via
        // ethernet, wi-fi or bluetooth so pin states can be known upon
        // reconnecting.
        Firmata.sendAnalog(analogPin, analogRead(analogPin));
      }
    }
  }
  // TODO: save status to EEPROM here, if changed
}

void reportDigitalCallback(byte port, int value)
{
  if (port < TOTAL_PORTS) {
    reportPINs[port] = (byte)value;
    // Send port value immediately. This is helpful when connected via
    // ethernet, wi-fi or bluetooth so pin states can be known upon
    // reconnecting.
    if (value) outputPort(port, readPort(port, portConfigInputs[port]), true);
  }
  // do not disable analog reporting on these 8 pins, to allow some
  // pins used for digital, others analog.  Instead, allow both types
  // of reporting to be enabled, but check if the pin is configured
  // as analog when sampling the analog inputs.  Likewise, while
  // scanning digital pins, portConfigInputs will mask off values from any
  // pins configured as analog
}

/*==============================================================================
 * SYSEX-BASED commands
 *============================================================================*/

void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte stopTX;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  switch (command) {
    case SAMPLING_INTERVAL:
      if (argc > 1) {
        samplingInterval = argv[0] + (argv[1] << 7);
        if (samplingInterval < MINIMUM_SAMPLING_INTERVAL) {
          samplingInterval = MINIMUM_SAMPLING_INTERVAL;
        }
      } else {
        //Firmata.sendString("Not enough data");
      }
      break;
    case EXTENDED_ANALOG:
      if (argc > 1) {
        int val = argv[1];
        if (argc > 2) val |= (argv[2] << 7);
        if (argc > 3) val |= (argv[3] << 14);
        analogWriteCallback(argv[0], val);
      }
      break;
    case CAPABILITY_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(CAPABILITY_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write((byte)INPUT);
          Firmata.write(1);
          Firmata.write((byte)PIN_MODE_PULLUP);
          Firmata.write(1);
          Firmata.write((byte)OUTPUT);
          Firmata.write(1);
        }
        if (IS_PIN_ANALOG(pin)) {
          Firmata.write(PIN_MODE_ANALOG);
          Firmata.write(10); // 10 = 10-bit resolution
        }
        if (IS_PIN_PWM(pin)) {
          Firmata.write(PIN_MODE_PWM);
          Firmata.write(DEFAULT_PWM_RESOLUTION);
        }
        if (IS_PIN_DIGITAL(pin)) {
          Firmata.write(PIN_MODE_SERVO);
          Firmata.write(14);
        }
        if (IS_PIN_I2C(pin)) {
          Firmata.write(PIN_MODE_I2C);
          Firmata.write(1);  // TODO: could assign a number to map to SCL or SDA
        }
#ifdef FIRMATA_SERIAL_FEATURE
        serialFeature.handleCapability(pin);
#endif
        Firmata.write(127);
      }
      Firmata.write(END_SYSEX);
      break;
    case PIN_STATE_QUERY:
      if (argc > 0) {
        byte pin = argv[0];
        Firmata.write(START_SYSEX);
        Firmata.write(PIN_STATE_RESPONSE);
        Firmata.write(pin);
        if (pin < TOTAL_PINS) {
          Firmata.write(Firmata.getPinMode(pin));
          Firmata.write((byte)Firmata.getPinState(pin) & 0x7F);
          if (Firmata.getPinState(pin) & 0xFF80) Firmata.write((byte)(Firmata.getPinState(pin) >> 7) & 0x7F);
          if (Firmata.getPinState(pin) & 0xC000) Firmata.write((byte)(Firmata.getPinState(pin) >> 14) & 0x7F);
        }
        Firmata.write(END_SYSEX);
      }
      break;
    case ANALOG_MAPPING_QUERY:
      Firmata.write(START_SYSEX);
      Firmata.write(ANALOG_MAPPING_RESPONSE);
      for (byte pin = 0; pin < TOTAL_PINS; pin++) {
        Firmata.write(IS_PIN_ANALOG(pin) ? PIN_TO_ANALOG(pin) : 127);
      }
      Firmata.write(END_SYSEX);
      break;

    case SERIAL_MESSAGE:
#ifdef FIRMATA_SERIAL_FEATURE
      serialFeature.handleSysex(command, argc, argv);
#endif
      break;
  }
}

/*==============================================================================
 * SETUP()
 *============================================================================*/

void systemResetCallback()
{
  isResetting = true;

  // initialize a defalt state
  // TODO: option to load config from EEPROM instead of default

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.reset();
#endif

  for (byte i = 0; i < TOTAL_PORTS; i++) {
    reportPINs[i] = false;    // by default, reporting off
    portConfigInputs[i] = 0;  // until activated
    previousPINs[i] = 0;
  }

  for (byte i = 0; i < TOTAL_PINS; i++) {
    // pins with analog capability default to analog input
    // otherwise, pins default to digital output
    if (IS_PIN_ANALOG(i)) {
      // turns off pullup, configures everything
      setPinModeCallback(i, PIN_MODE_ANALOG);
    } else if (IS_PIN_DIGITAL(i)) {
      // sets the output to 0, configures portConfigInputs
      setPinModeCallback(i, OUTPUT);
    }
  }
  // by default, do not report any analog inputs
  analogInputsToReport = 0;

  /* send digital inputs to set the initial state on the host computer,
   * since once in the loop(), this firmware will only send on change */
  /*
  TODO: this can never execute, since no pins default to digital input
        but it will be needed when/if we support EEPROM stored config
  for (byte i=0; i < TOTAL_PORTS; i++) {
    outputPort(i, readPort(i, portConfigInputs[i]), true);
  }
  */
  isResetting = false;
}

void setup()
{
  Firmata.setFirmwareVersion(FIRMATA_FIRMWARE_MAJOR_VERSION, FIRMATA_FIRMWARE_MINOR_VERSION);

  Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);
  Firmata.attach(DIGITAL_MESSAGE, digitalWriteCallback);
  Firmata.attach(REPORT_ANALOG, reportAnalogCallback);
  Firmata.attach(REPORT_DIGITAL, reportDigitalCallback);
  Firmata.attach(SET_PIN_MODE, setPinModeCallback);
  Firmata.attach(SET_DIGITAL_PIN_VALUE, setPinValueCallback);
  Firmata.attach(START_SYSEX, sysexCallback);
  Firmata.attach(SYSTEM_RESET, systemResetCallback);

  // to use a port other than Serial, such as Serial1 on an Arduino Leonardo or Mega,
  // Call begin(baud) on the alternate serial port and pass it to Firmata to begin like this:
  // Serial1.begin(57600);
  // Firmata.begin(Serial1);
  // However do not do this if you are using SERIAL_MESSAGE

  Firmata.begin(57600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for ATmega32u4-based boards and Arduino 101
  }

  systemResetCallback();  // reset to default config
}

/*==============================================================================
 * LOOP()
 *============================================================================*/
void loop()
{
  byte pin, analogPin;

  /* DIGITALREAD - as fast as possible, check for changes and output them to the
   * FTDI buffer using Serial.print()  */
  checkDigitalInputs();

  /* STREAMREAD - processing incoming messagse as soon as possible, while still
   * checking digital inputs.  */
  while (Firmata.available())
    Firmata.processInput();

  // TODO - ensure that Stream buffer doesn't go over 60 bytes

  currentMillis = millis();
  if (currentMillis - previousMillis > samplingInterval) {
    previousMillis += samplingInterval;
    /* ANALOGREAD - do all analogReads() at the configured sampling interval */
    for (pin = 0; pin < TOTAL_PINS; pin++) {
      if (IS_PIN_ANALOG(pin) && Firmata.getPinMode(pin) == PIN_MODE_ANALOG) {
        analogPin = PIN_TO_ANALOG(pin);
        if (analogInputsToReport & (1 << analogPin)) {
          Firmata.sendAnalog(analogPin, analogRead(analogPin));
        }
      }
    }
  }

#ifdef FIRMATA_SERIAL_FEATURE
  serialFeature.update();
#endif
}

Upgrading the board

Or should I just buy a newer board?

You probably don't need to because of the above. But you also have the option of upgrading it to an ATmega328P version with just the chip and burning the bootloader or having that done for you. Some hobby places will sell them burned with optiboot.


text:
Matter protocol with Arduino Mega/Giga
I would like to try matter protocol with Arduino mega or Arduino giga.
But I don't find any sample or library. I have only found libraries compatibles with ESP32.
Do you know how I can work with matter protocol on an Arduino Mega or Giga ?
Thanks

What kind of answer do you expect? "Why" something is the way it is usually cannot be answered, and the probable reason will not help you, I'm afraid. It might be as simple as "Because the authors did not make it for those Arduino models." So please [edit] your question and ask what you really want to know.

Sorry, i have edit my question. Thanks

If this is the source code repository for the ESP32 Matter project, then this statement from the README file found there:

Make sure that ESP32 board version is 2.0.14. This is crucial, because
this library contains pre-compiled files.

...would infer that not all the source code is available. It follows that the application can not be ported to a different processor.

Apparently it is an 'open' standard per wikipedia https://en.wikipedia.org/wiki/Matter_(standard) so theoretically one could write their own source with enough effort... Not that there aren't 'open' standards where just about every implementation is proprietary and fails to be compatible with items of other (or even the same) proprietor(s).


text:
Why I always see while(serial.available() > 0) as the standard way of reading serial data?
Examples online always show this code to read bytes from the serial interface:
while(serial.available() > 0)
{
      char receivedByte = serial.read();
}

But I don't understand why it works.
The read() operation "removes" a single byte from the queue, so the while loop should consume all the bytes from the queue.
However, what guarantees that the incoming bytes are being pushed into the queue faster than the consuming process? I would imagine that any Arduino board is order of magnitude faster than a standard serial transmission, so it would starve the queue and effectively exit the while loop even though there are more incoming bytes to process.
What am I missing here?

You're right. It depends on what else is done in the while block.
BTW: byte is a data type in the Arduino environment, better don't use it as a variable name.

@DataFiddler fixed

an if block would make more sense than a while block

what guarantees that the incoming bytes are being pushed into the queue faster than the consuming process?

Nothing. In the code handling the transmitted data you need to account for that. The fact, that serial transmission is not as fast as the code runs, doesn't matter, when you regularly check execute that while loop again (on each iteration of a non-blocking loop() for example). The code shouldn't rely on a full message being received inside that while loop. The data is normally saved into its own buffer and only processed, when a full valid message is in there (which can be checked by using a delimiter byte at the end of each message). So this makes more sense in the context of the rest of the corresponding serial code.
Though you should always keep in mind, that there are many many codes for Arduino online and that many of them are not that good.

That's the answer I was hoping for. Some sloppy implementations use a small delay(x); inside the loop to guarantee that at least 1 new byte is present when re-checking the while condition. The x depends on the baud rate. Reading piece by piece over the main loop() makes sense, but then one has to guarantee that the overall loop() execution time does not exceed the time required to fill up the serial queue, otherwise bytes would be lost. Isn't it ?

Yes, in that case loop() should be non-blocking. Though this is recommended either way, because it enables you to do multiple things simultaneously, basically multitasking, and keeping everything responsive.

Examples online always show this code ...

 while(serial.available() > 0)
 {
       char receivedByte = serial.read();
 }

You wouldn't have seen this "always" because it is Serial and not serial.
Also the code you posted would be useless because it would repeatedly read into the same byte and do nothing with it.
Assuming you are taking a bit of a licence with what you actually saw, it would be better for the code to gradually fill a buffer (and check for overflow) and then when a newline or other delimiter arrives, do something with it.
You are right that you would, generally speaking, read faster than data arrives. You are also right that putting delays in is a silly way of trying to allow for that.
I have an answer on this site plus a page with suggested code which goes into more detail.
Those posts might help.


text:
Converting raw data of IIS2MDC into angle
I do not know that this is a good place for asking question but I have a 3 axis magnetometer IIS2MDC. I used this with Arduino. I downloaded the library IIS2MDC.h in Arduino IDE. I used example code of IIS2MDC.h library for reading magnetometer data.  I have 3 axis raw data.
My question is that how to convert magnetometer data into degrees?
Is there any reference or solution for this?

Welcome to SE/Arduino! The device and its library should have documentation, and I would expect example code to show such conversions. Please [edit] your question to provide links to that, and add why it does not help you. -- OT: A library consists in C++ projects commonly of two parts, the header file and the library file. The former is "just" for convenience, the important file is the second one. Apparently the IDE does everything automagically correct, but please be aware of such details.

@EDExpert, do edit your question to make it better. Just so you know:  In the many stackexchange web sites, it is better to edit your question and for others to edit their answer to resolve the unexpected. In other words: Ask your question as if in front of an audience any of whom may have the same problem that needs resolving.

It is likely the magnetometer needs to be calibrated before it can be used. Before calibration is applied to the magnetometer's output values, comparing any 2 of the 3 orthogonal sensors will be difficult.
Search and learn the terms hard iron and soft iron distortion / calibration with respect to magnetometers. Hard iron distortion is an offset error.  Find the maximum (point a particular magnetometer toward magnetic north) and the minimum (point the same magnetometer away from magnetic north) values of one of the magnetometers. Calculate an offset value such that when applied the maximum and minimum magnitudes are the same. Soft iron distortion is a magnitude error. Find the maximum and minimum values for all 3 sensors. From this find the total range of all 3 sensors. Arbitrarily pick one of the sensors ranges and calculate magnitude adjustment values for the remaining sensor ranges such that after applying them all 3 sensors have the same range.
At this point let us narrow the scope of the electronic compass to simplify the project.  Let us constrain the compass to only be used on a table which is parallel to the surface of the earth. At which point we only need to use 2 of the sensors (the two that lie in the plane of the table).
To calculate the angle the magnetometer is pointing with respect to magnetic north we take the arctangent of the ratio of the 2 magnetic sensor which lie in the plane of the table. However, this math function only gives us angles for half the desired angles. Fortunately, the C programming math library contains a special function atan2() which can return a full circle of angles (from here):

Synopsis. The atan2() function divides the first argument by the second and returns the arc tangent of the result, or arctan( y / x ) . The return value is given in radians, and is in the range -π ≤ atan2( y , x ) ≤ π.

I try hard iron and soft iron distortion / calibration but i am unable to get correct values. I convert heading values of magnetometer into degrees using atan2(y/x) * 180/ PI equation but i got few random values i did not get 0 to 360 degree values. So how can i work my IIS2MDC chip as compass IC and get accurate degrees according to direction?

Take it one step at a time. Before finding the arc tan, make sure the way your sensor is held that you are using the 2 sensors that are always parallel (not tilted) with respect to the earth's surface.  Then, after adding or subtracting the calibrated offset and multiplying with the calibrated magnitude that the 2 values raise when that sensor is pointed to north and lowers when pointed away by the same or nearly the same amount. That the negative of the maximum for a particular sensor is the same or nearly the same as the minimum. After that works, then take the arc tan.


text:
Modifying the alert-like popup in ESPAsyncWebServer authenticate() function
So, ESPAsyncWebServer library is using the Digest MD5 Authentication by default, and I want to use this feature in my webserver, but there is a problem, I don't like the ugly prompt box, and I don't want to write a form for authentication, because is sends the password in clear text. I have searched all files in the Src folder of the ESPAsyncWebServer library, Yet I had no luck up to my beginner programming knowledge. So, how can I do this? it is something totally browser side and I cannot change it?
Update: I was able to get the following from the Wireshark.
Hypertext Transfer Protocol
    GET /openthefdoor HTTP/1.1\r\n
        [Expert Info (Chat/Sequence): GET /openthefdoor HTTP/1.1\r\n]
            [GET /openthefdoor HTTP/1.1\r\n]
            [Severity level: Chat]
            [Group: Sequence]
        Request Method: GET
        Request URI: /openthefdoor
        Request Version: HTTP/1.1
    Host: 192.168.1.3\r\n
    Connection: keep-alive\r\n
    Cache-Control: max-age=0\r\n
     [truncated]Authorization: Digest username="admin", realm="asyncesp", nonce="d13ba3040a4ed5c661a47d28c08554f4", uri="/openthefdoor", response="ca8806aa058dda66838784e784e67f8b", opaque="90ba2cd8a2870065f4daa582fd57105a", qop=auth, nc=0000
         username="admin"
         realm="asyncesp"
         nonce="d13ba3040a4ed5c661a47d28c08554f4"
         uri="/openthefdoor"
         response="ca8806aa058dda66838784e784e67f8b"
         opaque="90ba2cd8a2870065f4daa582fd57105a"
         qop=auth
         nc=00000002

2nd update: based on this question I guess the popup is coming up from the browser and I was looking in a wrong place!

searched all files in the Src folder ... what did you search for?

If you write a nice webpage to login, why can't you do the login exactly the same way, with a webrequest from the browser through javascript? Why would that be any less encrypted than doing it directly?

@chrisl Can I implement Digest MD5 Authentication? also I don't have enough memory on my esp8266.

@jsotola for theauthenticate() and requestDigestAuthentication() and WWW-Authenticate and to my knowledge I couldn't find anything useful to me.

try searching for HTML tags ... if you can determine the HTML code for the login popup, it may help to search for the tags in the popup

@jsotola based on this question I guess it's coming up from the browser and I was looking in a wrong place!

I don't know about a specific authentication method. I wanted to point out, that there is no functional difference if you make the web request by typing the address in your browser and hitting enter, or by writing a web request in the javascript code of a website.

@chrisl the form that I wrote is a login form, so I has to use an authentication method.,or the username and password will be sent in clear text form!

The authentication dialog, that you get, is provided by the browser. You cannot change this, since it is part of the browser software.

I don't want to write a form for authentication, because is sends the password in clear text.

That is false. How exactly the data is send depends on how you implement your login/action site. You can also tap into the forms submit event and use javascript with something other than Basic Authentication, like the Digest Authentication, that you mentioned. So your webpage, that gets served from the ESP, would contain the nice looking HTML form and javascript code, that uses the submit event of the form and does a webrequest to the ESP for the /openthefdoor endpoint, providing the credentials as digest (hashes).
From the ESPs (aka webservers) perspective, it is functionally irrelevant, if the login webrequest is done by typing in the login address in the address bar, or by javascript code embedded inside the served website. Both are just simple webrequests. You don't need to submit data from a form directly (unencrypted)
I cannot give you a ready made example of such javascript code and this is off topic for this Arduino site. Though you should be able to find example code online. Maybe by searching for something like "javascript digest authentication" or similar.
Note: Digest authentication transmits hashes of the credentials. That is not the same as encryption, especially with an easy hash standard like MD5. Better than plain text, but with a hash table an attacker would still be able to read the credentials. For encryption you would need TLS (https).