body:
Good Morning to everyone,
I am a PhD Student in experimental fluid mechanics at the University of Naples "Federico II", Italy. I am working on Arduino Due card and i am novel in applications using it. First, I need to generate a sine wave with variable frequency and amplitude. I tried to download several codes which are able to generate sine waves with a pre-defined frequency, but I would like to change this value of frequency at the beginning of the execution of the code. How could i do this ?
Second, I would like to change, in real-time, the output voltage of Arduino DAC0 or DAC1 at high speed to generate an arbitrary waveshape.. Is it possible?
Thank you in advance for your answers.

Dr. Alessandro Scala

title: Generate a sine wave with a predefined frequency and amplitude via DAC0 or DAC1 with Arduino Due

Answers: 1

body:
The formula commonly used to represent a sinusoidal signal is

  V = A cos(ωt)

where A is the amplitude and ω is the angular frequency. This formula
should cope well with a variable amplitude. It is, however, not suitable
for a signal with variable frequency, because a discontinuity of the
frequency is not supposed to create a discontinuity in the signal.

The correct formula for a signal where both the amplitude and the
frequency can vary is

  V = A(t) cos(φ(t))

where the phase is computed as

  φ(t) = ∫ ω(t)dt

In terms of code, this means you need a static variable to keep track of
the current phase, and you have to update it periodically in order to
perform the numerical integration.

Here is a tentative implementation. I have qualified some variables as
`extern` only to hint that you are responsible for managing them. You
can remove the qualifier if you integrate this into your own code:

```c++
// Defined and updated elsewhere.
extern const uint8_t output_channel;
extern float angular_frequency;  // in rad/us
extern float amplitude, offset;  // in ADC steps

// Call this as often as practical.
void update_output()
{
    // Compute the time delta.
    static uint32_t time_of_last_update;
    uint32_t now = micros();
    uint32_t dt = now - time_of_last_update;
    time_of_last_update = now;

    // Update the phase.
    static float phase;
    phase += angular_frequency * dt;
    while (phase >= 2 * M_PI) phase -= 2 * M_PI;  // unwrap

    // Output the signal.
    float output = offset + amplitude * cos(phase);
    analogWrite(output_channel, round(output));
}
```

Regarding the second part of the question (about arbitrary waveshapes),
it is, of course, feasible. You just have to pass arbitrary values to
`analogWrite()`.


body:
I have 2 IoT devices for measuring room temperature. Room does not have direct sunlight (it is north oriented and have tree in front of window). One is ESP8266 with DHT11 and next one is ESP8266 with DS18B20. DHT is on the table, away from PC. DS18B20 is on the top of bookshelf next to plant. Both of them shows temperature around 32-33 deg. celsius. It is not that hot in the room for sure. My home thermostat shows 23-24 deg. celsius. Outside temperature is about 15 deg. When I open the window and cool down the room, I can see temerature drop on both sensors, but still ony to around 26-28 celsius. I think, they are overheating themselves.

Code is almost same on both devices. Sampling every minute, so it should not be an issue of overloading sensors. Supply voltage is 3,3V. Not parasitic with 2k2 pull-up resistor.

What should I do to get correct temperature reading from these sensors?

EDIT: I have tired to get sensor out of PCB. First, I have just raised it for lengt of its legs (about 1cm) above board. It helped little, but it is visible, that sensor started cold, and slowly saturated heat from wires. So I took quite thick cables (0,25mm^2) and put sensor about 10cm away from board. And it helped! Temperature is about 23 degrees, what is somwhere in expected range. Most important is, that temperature curve was dropping before stabilizing. Spikes are just 85°C first reading. [![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/oKag6.png

title: Temperature sensors are heating themselves

Answers: 2

body:
It does not surprise me that a sensor needs a correction to calculate the correct value. I have had the same problems with a range of sensors.

Because linearity is not really important when you need to measure only a room temperature, it would be sufficient to measure room temperature with a reliable thermometer and see how much you need to subtract to correct the value from your sensor.
When still in doubt, you could cover the sensor with a plastic bag and measure the temperature dipped in a bowl of water with crushed ice cubes in it.

body: It seems, that problem is in heat transfer from ESP chip to thermometer via wires. Worst it was, when chip was on board itself, little bit better when it was raised about 1cm out of board. I have achieved correct readings only when I put sensor on longer and quite thick leads to avoid heat transfer as much as possible.


body:
I am new to C++ & I need to call functions of one class from another class. And so that the classes do not know anything about each other. How to do it in Arduino environment?

    class Encoder {
      using CallBack2 = void( * )(const int, const int);
      using CallBack0 = void( * )();
      private:
        CallBack2 callbackUpDown;
        CallBack0 callbackTab;
        CallBack0 callbackLongPress;
      public:
        Encoder() {}

      void Setup(CallBack2 updown, CallBack0 tab, CallBack0 cbLongPress) {
        callbackUpDown = updown;
        callbackTab = tab;
        callbackLongPress = cbLongPress;
      }

      void Loop() {
        if (true) {
          callbackUpDown(-1, 300);
          callbackTab();
          callbackLongPress();
        }
      }
    };

    class Menu {
      public:
        void UpDown(const int direction,
          const int count) {}
          void Tab() {}
    };

    class RTC {
      public:
        void Setup() {}
        void Toggle() {}
    };

    class Display {
      public:
        void Toggle() {}
    };

    Encoder encoder = Encoder();
    RTC rtc = RTC();
    Menu menu = Menu();
    Display display = Display();

    void setup() {
      rtc.Setup();
      encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});
    }

    void loop() {
      encoder.Loop();
    }

Output:

    In file included from sun.ino:47:0:
    callback.h: In function 'void setup()':
    callback.h:52:75: error: invalid use of non-static member function 'void Menu::UpDown(int, int)'
       encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle(); rtc.Toggle();});
                                                                               ^
    callback.h:28:7: note: declared here
      void UpDown(const int direction, const int count) {}
           ^~~~~~

Thank you!

title: Call functions of one class from another class - Callback

Answers: 2

body:
What you are doing here

```cpp
encoder.Setup(menu.UpDown, menu.Tab, []{display.Toggle();rtc.Toggle();});
```

is not only passing a function pointer. You are passing a member function pointer. This is 2 levels more difficult than function pointers on their own.

1. The syntax of declaring a member function pointer is different. You need to include the class name in the function pointer declaration. It would look like

    ```cpp
    using CallBack2 = void( Menu::* )(const int, const int);
    ```

2. When calling a member function pointer, you need an object to call the function on.

Unfortunately, this is so hard that I can't turn your code into a working example. If you want to be able to read your code in 3 months or if you want others to be able to read your code, stick to normal function pointers. They are hard enough.

Suggestion: implement free functions that do what you want:

```cpp
void menuUpDown(const int dir, const int count)
{
  menu.UpDown(dir, count);
}
void menuTab()
{
  menu.Tab();
}

void setup() {
  rtc.Setup();
  encoder.Setup(menuUpDown, menuTab, []{display.Toggle();rtc.Toggle();});
}
```

Or, since you're already using lambdas (are you aware of that?), you can also

```cpp
void setup() {
  rtc.Setup();
  encoder.Setup(
    [](const int dir, const int count){menu.UpDown(dir, count);},
    []{menu.Tab();},
    []{display.Toggle();rtc.Toggle();}
  );
}
```

Note that pupils and students might not have been introduced to the concept of lambdas. If you publish such code online, people might not be able to change it themselves because they don't understand it.

body:
Also, [Using Static Methods Or Non-Member Functions (C-Style)][1]

    class MyClass {
      public:
        static void onMsg(int num1, int num2) {
          // NOTE: Can't call any non-static method functions here!
        }
    };

    class LibraryClass {
      using CallBack = void( * )(int, int);
      private:
        CallBack callBack;
      public:
        void Setup(CallBack callBackFunc) {
          callBack = callBackFunc;
        }
        void Loop() {
          callBack(1, 2);
        }
    };

    MyClass myClass;
    LibraryClass libraryClass;

    void setup() {
      libraryClass.Setup(&myClass.onMsg); // Provide the instance and function to call
    }

    void loop() {
      libraryClass.Loop();
    }

  [1]: https://blog.mbedded.ninja/programming/languages/c-plus-plus/callbacks/


body:
New to arduino here, sorry for asking what may be a trivial question.

I need to simulate an industrial machine at home. It operates in a cyclic motion, creating an event for every rotation / cycle. Imagine a turntable or wheel with a marker in one place.

What I would like is:

  * Have a physical wheel which I turn one rotation every 300 msec. This is the length in time of a cycle.
  * Read a marker on this wheel using a sensor, such as Sick or Omron. I have this already. Sensor can be PNP or NPN, providing a closed or open connection. I can go via an optocoupler if needed.
  * Once a signal is seen, the arduino should send a (sequential) string using RS232 to a PC. Approximately 90 characters.  It is not needed to wait for response.

My question is: would be time for arduino to do this be relatively constant - ie, send out the data at approximately same point in the cycle. Example: signal read at "12" on the clock, data sent around "5".

If possible, what sort of Arduino would I be looking at ?

Or do I need something more real-time for such project, like a PLC ?

title: How real-time is an arduino (react to sensor)?

Answers: 2

body:
TLDR: any Arduino is probably sufficient for your purpose when done properly.

I'll assume a proper HIGH/LOW binary signal from the sensor, HIGH when it "sees" the marker, LOW when it doesn't.

What could go wrong?

1. You use `digitalRead()` to get the state of the digital input. Depending on the pulse width, you might not catch the high state. Use interrupts instead.
2. Sending the data over Serial port takes longer than a turn of the machine. 90 bytes at 9600 bit/s needs (90 bytes * 10 bits/byte / (9600 kbit/s) = 93ms. In 300ms, there's enough time to send the 90 bytes. And 9600 bit/s is quite slow: you can probably use 115200 bit/s on short or shielded wires.
3. "Approximately 90 characters": calculate everything for the maximum data that will eventually be sent
4. Getting the data on Arduino side takes too long. You didn't give details on where those 90 bytes come from. Asking 90 devices to each give you a byte of data might not be possible in 300ms.
5. Receiving the data on the PC side (or whatever) might be delayed, because it is buffered. Especially USB to Serial adapters have no guaranteed timing. Doing the math for USB devices is hard.
6. Threading on the PC side: due to the OS Thread scheduling, the application that shall receive the data might not get CPU time for several milliseconds, 16ms (1/64s) is quite common. Doing the math is impossible (try running 8 real time threads that do something else and your PC is basically frozen)
7. Processing on the PC side: unknown
8. Displaying: after processing until a signal is displayed on the screen, that may take another 16 ms (at 60 Hz refresh rate).

> would be time for Arduino to do this be relatively constant

Relatively: yes. It certainly depends on the implementation (the Arduino C++ code).

If the data to send is hard coded 90 characters, I would expect the complete signal has been sent at before the 4 o'clock mark (94ms /300ms * 12 hours ~ 3 hours) . I see the problem more on the receiving side (see points 5., 6., 7. and 8.).

> what sort of Arduino would I be looking at ?

I don't know all of them, but an Uno will certainly work. If you only have that one digital input, even smaller ones are probably ok. Just start with an Uno or what you have available and see how it goes.

> do I need something more real-time for such project, like a PLC?

I don't see a need for a PLC in your project.

body:
> one rotation every 300 msec.

300 ms is a _very long time_ for an Arduino, even for an AVR-based
one, like an Uno.

I did a little experiment. I generated (with an Arduino...) a periodic
signal consisting of a 96 µs-wide negative pulse repeating every
300 ms. I sent that signal to an Arduino Uno running the following
code:

```c++
const uint8_t sensor_pin = 3;

// 90-byte message.
const char message[] = "Korem ipsum dolor sit amet, consectetur "
        "adipiscing elit sed do eiusmod tempor incididunt\r\n";

void setup() {
    pinMode(sensor_pin, INPUT_PULLUP);
    Serial.begin(9600);
}

void loop() {
    if (digitalRead(sensor_pin) == LOW) {
        Serial.write(message);

        // Wait until the signal rises again.
        while (digitalRead(sensor_pin) == LOW)
            continue;
    }
}
```

This is not the nicest way to do edge detection, but for this simple
test it will do. You may notice that I am not using interrupts for
capturing the pulse: 96 µs is long enough to be captured with this
simple `digitalRead()`. I then captured the input and output signals
with a dual-channel pocket oscilloscope. Here is a screen capture:

[![Oscilloscope screen capture][1]][1]

The cyan trace at the top is the received pulse. The yellow trace below
is the output of the serial port. The negative pulse on this trace that
is almost coincident with the received pulse is the start bit. Then the
signal rises to transmit the first data bit, which is a 1 (that's
why I chose “K” rather than “L” as the first letter).

What you can see in this capture is that the latency of the Arduino is
tiny at this scale: a small fraction of the duration of the start bit.
What you cannot see is the jitter, which is quite large in _relative_
terms, but still small compared to the time scales relevant to you. In
short, the delay between the falling edge on the input and the falling
edge of the serial port start bit fluctuates roughly between 10 and
20 µs. Yes, those are **micro**seconds. This delay is roughly
20,000 times shorter than the rotation period. If the signal is read at
“12” on the clock, the start bit fires at 12 hours with
0 minutes and 2 seconds.

Note that, on the other hand, the time needed to send the message at
9600 b/s is 93.6 ms, a significant fraction of the rotation
period. And I didn't look at the behavior of the USB-to-serial converter
chip, which is another can of worms...

[1]: https://i.stack.imgur.com/6FXC2.png


body:
I designed a circuitboard and need to proof the function.Therefore i have to modify the code to read from Pins D1 instead of D2.
Unfourtunatly i am not that familar with the high level programming so im not sure if i got all changes.
Basically all PINS on the circuit are used.

Basecode foud here:
https://arduino.stackexchange.com/questions/85741/seeeduino-xiao-write-and-read-pwm-duration-period-using-timers

Reading short square waves with Seeeduino XIAO pin D2

```
// Setup TC4 to capture pulse-width and period on digital pin D2 on Seeeduino Xiao
volatile boolean periodComplete;
volatile uint32_t isrPeriod;
volatile uint32_t isrPulsewidth;
uint32_t period;
uint32_t pulsewidth;

void setup()   {
  SerialUSB.begin(115200);                         // Initialise the native serial port
  while(!SerialUSB);                               // Wait for the console to open

  PM->APBCMASK.reg |= PM_APBCMASK_EVSYS;           // Switch on the event system peripheral

  GCLK->GENDIV.reg = GCLK_GENDIV_DIV(1) |          // Divide the 48MHz system clock by 1 = 48MHz
                     GCLK_GENDIV_ID(4);            // Set division on Generic Clock Generator (GCLK) 4

  GCLK->GENCTRL.reg = GCLK_GENCTRL_IDC |           // Set the duty cycle to 50/50 HIGH/LOW
                      GCLK_GENCTRL_GENEN |         // Enable GCLK 4
                      GCLK_GENCTRL_SRC_DFLL48M |   // Set the clock source to 48MHz
                      GCLK_GENCTRL_ID(4);          // Set clock source on GCLK 4
  while (GCLK->STATUS.bit.SYNCBUSY);               // Wait for synchronization

  GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN |         // Route GCLK4 to TC4 and TC5
                      GCLK_CLKCTRL_GEN_GCLK4 |
                      GCLK_CLKCTRL_ID_TC4_TC5;

  // Enable the port multiplexer on port pin PA10
  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
  // Set-up the pin as an EIC (interrupt) on port pin PA10
  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;

  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Enable event output on external interrupt 10
  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Set event detecting a HIGH level
  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Disable interrupts on external interrupt 10
  EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Enable EIC peripheral
  while (EIC->STATUS.bit.SYNCBUSY);                                        // Wait for synchronization

  EVSYS->USER.reg = EVSYS_USER_CHANNEL(1) |                                // Attach the event user (receiver) to channel 0 (n + 1)
                    EVSYS_USER_USER(EVSYS_ID_USER_TC4_EVU);                // Set the event user (receiver) as timer TC4

  EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // No event edge detection
                       EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Set event path as asynchronous
                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Set event generator (sender) as external interrupt 10
                       EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0

  TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Enable the TC event input
                            //TC_EVCTRL_TCINV |              // Invert the event input
                            TC_EVCTRL_EVACT_PPW;           // Set up the timer for capture: CC0 period, CC1 pulsewidth

  TC4->COUNT32.CTRLC.reg = TC_CTRLC_CPTEN1 |               // Enable capture on CC1
                           TC_CTRLC_CPTEN0;                // Enable capture on CC0
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Wait for synchronization

  NVIC_SetPriority(TC4_IRQn, 0);      // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
  NVIC_EnableIRQ(TC4_IRQn);           // Connect the TC4 timer to the Nested Vector Interrupt Controller (NVIC)

  TC4->COUNT32.INTENSET.reg = TC_INTENSET_MC1 |            // Enable compare channel 1 (CC1) interrupts
                              TC_INTENSET_MC0;             // Enable compare channel 0 (CC0) interrupts

  TC4->COUNT32.CTRLA.reg = //TC_CTRLA_PRESCSYNC_PRESC |      // Overflow on precaler clock, (rather than the GCLK)
                           TC_CTRLA_PRESCALER_DIV1  |      // Set prescaler to 1, 48MHz/1 = 48MHz
                           TC_CTRLA_MODE_COUNT32;          // Set TC4/TC5 to 32-bit timer mode

  TC4->COUNT32.CTRLA.bit.ENABLE = 1;                       // Enable TC4
  while (TC4->COUNT32.STATUS.bit.SYNCBUSY);                // Wait for synchronization
}

void loop() {
  if (periodComplete)                             // Check if the period is complete
  {
    noInterrupts();                               // Read the new period and pulse-width
    period = isrPeriod;
    pulsewidth = isrPulsewidth;
    interrupts();
    SerialUSB.print("PW: ");
    SerialUSB.print(pulsewidth);
    SerialUSB.print(F("   "));
    SerialUSB.print("P: ");
    SerialUSB.println(period);
    periodComplete = false;                       // Start a new period
  }
}

void TC4_Handler()                                // Interrupt Service Routine (ISR) for timer TC4
{
  // Check for match counter 0 (MC0) interrupt
  if (TC4->COUNT32.INTFLAG.bit.MC0)
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Enable a read request
                               TC_READREQ_ADDR(0x18);      // Offset address of the CC0 register
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Wait for (read) synchronization
    isrPeriod = TC4->COUNT32.CC[0].reg;                    // Copy the period
    periodComplete = true;                                 // Indicate that the period is complete
  }

  // Check for match counter 1 (MC1) interrupt
  if (TC4->COUNT32.INTFLAG.bit.MC1)
  {
    TC4->COUNT32.READREQ.reg = TC_READREQ_RREQ |           // Enable a read request
                               TC_READREQ_ADDR(0x1A);      // Offset address of the CC1 register
    while (TC4->COUNT32.STATUS.bit.SYNCBUSY);              // Wait for (read) synchronization
    isrPulsewidth = TC4->COUNT32.CC[1].reg;                // Copy the pulse-width
  }
}
```

Do i only have to change the IOs:
from:
 PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
 PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
to:
 PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
 PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;

or do i need to mod more code?

Thanks for helping.

title: Seeeduino XIAO read PWM duration (period) using timers change Pins freom D2 to D1

Answers: 1

body:
In addition to the changes you mentioned, your `EIC_EVCTRL_EXTINTEO10`, `EIC_INTENCLR_EXTINT10`, and `EVSYS_ID_GEN_EIC_EXTINT_10` usages will need to be changed to `EIC_EVCTRL_EXTINTE4`, `EIC_INTENCLR_EXTINT4` and to `EVSYS_ID_GEN_EIC_EXTINT_4`, to re-target the event system source, because `PORT_PMUX_PMUXE_A` on both [these pins][1] routes the signal to the EIC, but not to the exact same interrupt number.  The `EIC->CONFIG` line needs to change to the first group of 8 (`[0]`) and fourth SENSE within that group (`EIC_CONFIG_SENSE4_HIGH`) to the change to D1 (PA04) uses EXTINT4.  This is something I'd left out of the first edit before I'd been able to test. I did eventually find a XIAO to test with and these modifications seem to make it work just fine on digital pin 1 now instead of digital pin 2.

```c++
EIC->EVCTRL.reg    |= EIC_EVCTRL_EXTINTE4;
EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;
EIC->INTENCLR.reg   = EIC_INTENCLR_EXTINT4;
EIC->CTRL.reg      |= EIC_CTRL_ENABLE;
while (EIC->STATUS.bit.SYNCBUSY);
```
   ...
```c++
EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |
                     EVSYS_CHANNEL_PATH_ASYNCHRONOUS |
                     EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |
                     EVSYS_CHANNEL_CHANNEL(0);
```

---

The changes you'd mentioned and those I've said above as diff:

```Diff
--- original.ino
+++ modified.ino
@@ -24,14 +24,14 @@
                       GCLK_CLKCTRL_GEN_GCLK4 |
                       GCLK_CLKCTRL_ID_TC4_TC5;

-  // Enable the port multiplexer on port pin PA10
-  PORT->Group[PORTA].PINCFG[10].bit.PMUXEN = 1;
-  // Set-up the pin as an EIC (interrupt) on port pin PA10
-  PORT->Group[PORTA].PMUX[10 >> 1].reg |= PORT_PMUX_PMUXE_A;
+  // Enable the port multiplexer on port pin PA04
+  PORT->Group[PORTA].PINCFG[4].bit.PMUXEN = 1;
+  // Set-up the pin as an EIC (interrupt) on port pin PA04
+  PORT->Group[PORTA].PMUX[4 >> 1].reg |= PORT_PMUX_PMUXE_A;

-  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO10;                                // Enable event output on external interrupt 10
-  EIC->CONFIG[1].reg |= EIC_CONFIG_SENSE2_HIGH;                            // Set event detecting a HIGH level
-  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT10;                               // Disable interrupts on external interrupt 10
+  EIC->EVCTRL.reg |= EIC_EVCTRL_EXTINTEO4;                                 // Enable event output on external interrupt 4
+  EIC->CONFIG[0].reg |= EIC_CONFIG_SENSE4_HIGH;                            // Set event detecting a HIGH level
+  EIC->INTENCLR.reg = EIC_INTENCLR_EXTINT4;                                // Disable interrupts on external interrupt 4
   EIC->CTRL.reg |= EIC_CTRL_ENABLE;                                        // Enable EIC peripheral
   while (EIC->STATUS.bit.SYNCBUSY);                                        // Wait for synchronization

@@ -40,7 +40,7 @@

   EVSYS->CHANNEL.reg = EVSYS_CHANNEL_EDGSEL_NO_EVT_OUTPUT |                // No event edge detection
                        EVSYS_CHANNEL_PATH_ASYNCHRONOUS |                   // Set event path as asynchronous
-                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_10) |   // Set event generator (sender) as external interrupt 10
+                       EVSYS_CHANNEL_EVGEN(EVSYS_ID_GEN_EIC_EXTINT_4) |    // Set event generator (sender) as external interrupt 4
                        EVSYS_CHANNEL_CHANNEL(0);                           // Attach the generator (sender) to channel 0

   TC4->COUNT32.EVCTRL.reg = TC_EVCTRL_TCEI |               // Enable the TC event input
```

  [1]: https://github.com/Seeed-Studio/ArduinoCore-samd/blob/v1.8.3/variants/XIAO_m0/variant.cpp#L28-L29


body: I have two different sensors which have SCL and SDA connections which I am trying to connect to an Arduino nano. From what I understand, connecting both of these sensor to the A5 and A4 pins doesn't make any sense, considering that I need to collect data continuously from both sensors. Moreover, there are no other pins with the same functionality as A5 and A4. I am a beginner learning about microcontrollers, but it seems to me like the best practice to follow here would be to use two Arduino nanos. Is this this the only way, or is there another method I am not aware of?

title: Best practice for wiring two sensors that have SCL and SDA connections

Answers: 1

body:
The whole point of the I2C bus is to allow multiple sensors or devices to be connected, as long as they have different I2C addresses. The addresses are usually built into the part, and often they have some provision for selecting an address from a range.

Whilst you can't *simultaneously* collect data from two sensors at once, you can certainly query them in quick succession. You need to connect SDA, SCL, Ground and +5V to each sensor, and the Arduino.

Your code would do something like:

* Query sensor at address 42
* Query sensor at address 43
* Do something with the data
* Wait a bit before doing it again

You could look at Wikipedia for some general information about I2C, and I also have [a page about I2c](http://gammon.com.au/i2c) that might help you.

Note that you also need a pull-up resistor on both SDA and SCL (that is, two resistors), a typical value would be 4.7k (connect the 4.7k resistors between SDA/SCL and your +5V line).


body: I would like to know is there a way of burning programs to microcontrollers like that on Arduino without using a computer? Like a pendrive or something? Suppose you want to update firmware on a utility end, must you carry the editable source code with you? How do the big companies do it?

title: How to upload code to Arduino without a laptop

Answers: 1

body:
One good way to update Uno/Nano/Mini without connecting it to a computer is to use SD bootloader. SD bootloader reads at boot the bin file with the update from the attached SD card and copies it to flash memory.

There are not many SD bootloader for ATmega. I use [avr_boot][2] by zevero. It works well. The downside is that it doesn't support upload over USB.

zevero doesn't offer built binaries of the bootloader so you have to compile it with the avr toolchain.

avr_boot requires a bin file, not a hex file, but it is simple to set Arduino IDE to create a bin file along with the hex file. You create platform.local.txt file next to platform.txt in the avr boards package, and put this line into the file:
```
## Create output (bin file)
recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" -O binary {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin"
```
Then you can use "Export compiled binary" from Sketch menu in Arduino IDE and you will find the binary file next to your ino file in the sketch folder.

----------

There are different ways how to update an Arduino without connecting it to computer. For small ATmega328p on Uno/Nano/Mini there is not enough flash space to do a self update. The code required to do the update takes more than half of the flash so there is no space left to store the update binary before applying it. (The updated sketch of course must have to have the code for the self update too.)

For illustration what is possible, [here is a sketch][1] for Arduino Mega which does a self update from SD card reading a hex file. It requires a modified Optiboot available in MegaCore.

  [1]: https://github.com/JAndrassy/ArduinoOTA/blob/master/examples/Advanced/SD2Flash2BootAVRHex/SD2Flash2BootAVRHex.ino
  [2]: https://github.com/zevero/avr_boot


body:
This was supposed to be the code for automatic pet feeder
Got it from here[1]

The problem is that I always got a "No matching function for call to'DS3231 (const uint8_t &, const uint8_t &)"

Here's the error code

```
Arduino: 1.8.19 (Windows 10), Board: "Arduino Uno"

ANA_FEEDER_PROJECT:53:18: error: no matching function for call to 'DS3231::DS3231(const uint8_t&, const uint8_t&)'

 DS3231 rtc(A4, A5);

                  ^

In file included from C:\Users\SERIES\Desktop\ANA_FEEDER_PROJECT\ANA_FEEDER_PROJECT.ino:1:0:

D:\Documents\Arduino\libraries\DS3231/DS3231.h:67:3: note: candidate: DS3231::DS3231(TwoWire&)

   DS3231(TwoWire & w);

   ^~~~~~

D:\Documents\Arduino\libraries\DS3231/DS3231.h:67:3: note:   candidate expects 1 argument, 2 provided

D:\Documents\Arduino\libraries\DS3231/DS3231.h:66:3: note: candidate: DS3231::DS3231()

   DS3231();

   ^~~~~~

D:\Documents\Arduino\libraries\DS3231/DS3231.h:66:3: note:   candidate expects 0 arguments, 2 provided

D:\Documents\Arduino\libraries\DS3231/DS3231.h:62:7: note: candidate: constexpr DS3231::DS3231(const DS3231&)

 class DS3231 {

       ^~~~~~

D:\Documents\Arduino\libraries\DS3231/DS3231.h:62:7: note:   candidate expects 1 argument, 2 provided

D:\Documents\Arduino\libraries\DS3231/DS3231.h:62:7: note: candidate: constexpr DS3231::DS3231(DS3231&&)

D:\Documents\Arduino\libraries\DS3231/DS3231.h:62:7: note:   candidate expects 1 argument, 2 provided

C:\Users\SERIES\Desktop\ANA_FEEDER_PROJECT\ANA_FEEDER_PROJECT.ino: In function 'void setup()':

ANA_FEEDER_PROJECT:84:7: error: 'class DS3231' has no member named 'begin'

   rtc.begin();

       ^~~~~

C:\Users\SERIES\Desktop\ANA_FEEDER_PROJECT\ANA_FEEDER_PROJECT.ino: In function 'void loop()':

ANA_FEEDER_PROJECT:130:10: error: 'class DS3231' has no member named 'getTimeStr'; did you mean 'getMinute'?

  t = rtc.getTimeStr();

          ^~~~~~~~~~

          getMinute

ANA_FEEDER_PROJECT:146:16: error: 'class DS3231' has no member named 'getTimeStr'; did you mean 'getMinute'?

  lcd.print(rtc.getTimeStr());

                ^~~~~~~~~~

                getMinute

ANA_FEEDER_PROJECT:152:16: error: 'class DS3231' has no member named 'getDateStr'; did you mean 'getDate'?

  lcd.print(rtc.getDateStr());

                ^~~~~~~~~~

                getDate

exit status 1

no matching function for call to 'DS3231::DS3231(const uint8_t&, const uint8_t&)'

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

```

The problem is that I always got a "No matching function for call to'DS3231 (const uint8_t &, const uint8_t &)"

Here's the error code

  [1]: https://circuitdigest.com/microcontroller-projects/automatic-pet-feeder-using-arduino

Answers: 1

body:
You are using the wrong DS3231 library. Unfortunately, you can often find incompatible libraries that share the same name. The sketch you downloaded has been written for a specific version of the DS3231 library. Thus your choices are:

 * either you use that specific version (linked to in the page you gave as reference)
 * or you adapt the code to work with the version you have installed.


body:
I'm trying to turn off line numbers on the Mac Arduino IDE but don't see the option for it after navigating to `Arduino IDE > Preferences`. Below is a screenshot of what I am seeing.

[![Arduino Preferences][1]][1]

I saw [this question][2] asked previously, but there is no `File > Preferences` path on Mac. I am using Version 2.0.0 on macOS (10.14 or newer).

  [1]: https://i.stack.imgur.com/7cIA5.jpg
  [2]: https://arduino.stackexchange.com/questions/52161/arduino-ide-display-code-line-numbers

title: How to turn off the display of line numbers on Mac Arduino IDE?

Answers: 1

body:
I don't see a proper place to do this in the 2.0.0 IDE preferences. However, modifying the .arduinoIDE/setting.json file to include `"editor.lineNumbers": "off",` seems to work.

```json
{
 "editor.lineNumbers": "off",
 "editor.fontSize": 14,
 ...
}
```

[![Shows IDE 2.0.0 with and without line numbers.][1]][1]

Edgar Bonet pointed out in a comment that there's still a bunch of empty space in that region. The image above doesn't do a good of showing why though. In the below screenshots I've told the IDE to set a breakout and hovered over where folding region so it displays the fold indicators to make somewhat easier to see that and compare what effect on width results from disabling these things.

If you want to save a bit more space you can add turn off the code folding feature, which removes the spaced that would be used for fold indicators with an additional `"editor.folding": "false",` in the settings.json file.

For comparison, here's everything enabled, numbers but no folding, folding but no numbers, no folding and no numbers:

[![Comparison of widths with different combinations of folding and line number settings.][2]][2]

I haven't yet found out how to turn off the display of break-point indicators. I assume that it is possible though.

  [1]: https://i.stack.imgur.com/qYfDd.png
  [2]: https://i.stack.imgur.com/Hf7hD.png


body:
[I'm following this tutorial on how to install FTDI drivers on macOS][1], but am facing some issues. After downloading the USB Serial Driver version 2.4.4 (for OS X 10.14) from [FTDI Chip's virtual COM port (VCP) driver page][2] (recommended by the tutorial), I still don't see any `usbserial` option listed under the Serial Port tab, shown below.

[![Missing USB Serial Port][3]][3]

Because I'm running macOS Monterrey (12.0.1), I also tried downloading the Beta driver release (version 1.5.0) for OS X 10.15 and macOS 11/12. After running the installer from my Applications folder (as recommended), I get the following result, indicating success, but the options list remains the same as shown above.

[![Successful Installation][4]][4]

Are there any workarounds? For reference, I am using Arduino IDE 2.0.0.

  [1]: https://learn.sparkfun.com/tutorials/how-to-install-ftdi-drivers/all#mac
  [2]: https://ftdichip.com/drivers/vcp-drivers/
  [3]: https://i.stack.imgur.com/xc9zp.png
  [4]: https://i.stack.imgur.com/Nd8IO.png

title: How to install FTDI Serial Drivers on Mac?

Answers: 1

body:
I have just managed to get the FTDI set up for my M1 mac using the Pro Mini. I think the issue is that newer macs automatically block the FTDI serial connection from being used as a com port. You need to install a program called **D2XXHelper** to prevent this behaviour.

I did the following, hopefully this will work for you too:

1. Install **FTDI VCP Driver**, found [here][1]: Scroll down to first table and find the latest Mac OS drivers. There are 2, the 2.4.4 version and the 1.5 version. I think you need to use the 1.5 version for the M1 but I’m not sure because I installed both before I did the next steps to get it working.
2. Install the **D2XXHelper** found [here][2]: Scroll down to first table and look in the comments column for the Mac OS row to find the download link.
 4. After installing the D2XXHelper, you should get a security prompt saying **system extension blocked**. Follow [this][3] guide which shows how to provide permission for the system extension to be applied – this requires going into recovery mode and requires several computer restarts.
 5. After following the steps in the guide, you should have enabled the D2XXHelper system extensions to be applied, in which case when you connect your Arduino to your computer via the FTDI connector, the Arduino IDE 2 should now recognise that a device has been connected via the FTDI virtual com port.
 6. **optional** – to check that your FTDI is connected correctly to your Arduino, connect it up, Open a Terminal window and type “ls /dev/tty.*” and run this command. If the FTDI is connected properly then a usb serial device should show up in the results to this command.

  [1]: https://ftdichip.com/drivers/vcp-drivers/
  [2]: https://ftdichip.com/drivers/d2xx-drivers/
  [3]: https://support.techsmith.com/hc/en-us/articles/360056384711-M1-M2-Chip-and-the-Snagit-System-Audio-Capture-Component#:~:text=To enable system extensions, you,from the Security Policy button.


body:
I'm working on a project to read data over CAN, display it on LCD and log data to SD card. LCD is on HSPI and SD card on VSPI. CAN and LCD code is working on core 1 and SD on core 0, there's no wifi. It's all working pretty well but now I'm looking for further improvements. I set the log to 20 Hz and took a sample of 117024 lines. Below is the "uniq -c" output of the seconds that weren't logged at 20 Hz (left column is the actual rate and right column is a specific second in the log). So only 21 out of 117024 lines. But why does this happen and how can I make sure that every line is logged at 20 Hz?

```     19 1632
     18 3195
     17 5393
     16 5401
     16 1622
     14 5397
     14 1628
     14 1625
     14 1624
     13 5400
     13 5398
     13 5396
     13 5395
     13 5394
     13 1626
     12 1631
     12 1630
     12 1627
     12 1623
      8 5399
      8 1629
```

```cpp
float timeStamp;
char filenameBuffer[23];
String filename;
bool logStarted = 0;
uint32_t lastSyncTime = 0, logStartTime = 0;

File file;

void initSD()
{
 if (SD.begin(5, SPI, 80000000))
 {
  Serial.println("Card Mount OK");
  updateFromFS(SD);
  generateFileName();
  sdInitialised = true;
 }
 else
 {
  Serial.println("Card Mount Failed");
  return;
 }
}

void logToSD()
{
 if (!sdInitialised) return;
 if (!EMUfresh) return;

 if (!logStarted)
 {
  file = SD.open(filenameBuffer, FILE_APPEND);
  if (file)
  {
   file.print("Time,RPM,MAP,TPS,IAT,CLT,Lambda,PulseWidth,EGT1,EGT2,Vbatt,Baro,IgnAngle,LambdaCorr,Gear,Pwm1,Vss,EmuTemp,CEL,FLAGS1,LambdaTarget,OilTemp,OilPress,CanState\r\n");
   logStartTime = millis();
   logStarted = true;
  }
 }

 uint32_t duration = millis() - logStartTime;
 uint32_t seconds = duration / 1000;
 uint32_t milliseconds = duration % 1000;
 String dataString = "";

 dataString += seconds;
 dataString += ".";
 if (milliseconds < 100) { dataString += "0"; }
 if (milliseconds < 10) { dataString += "0"; }
 dataString += milliseconds;
 dataString += ",";
 dataString += String(emu_data.RPM);
 dataString += ",";
 dataString += String(emu_data.MAP);
 dataString += ",";
 dataString += String(emu_data.TPS);
 dataString += ",";
 dataString += String(emu_data.IAT);
 dataString += ",";
 dataString += String(emu_data.CLT);
 dataString += ",";
 dataString += String(emu_data.lambda);
 dataString += ",";
 dataString += String(emu_data.pulseWidth);
 dataString += ",";
 dataString += String(emu_data.EGT1);
 dataString += ",";
 dataString += String(emu_data.EGT2);
 dataString += ",";
 dataString += String(emu_data.vBat);
 dataString += ",";
 dataString += String(emu_data.baro);
 dataString += ",";
 dataString += String(emu_data.ignAngle, 0);
 dataString += ",";
 dataString += String(emu_data.lambdaCorr, 0);
 dataString += ",";
 dataString += String(emu_data.gear);
 dataString += ",";
 dataString += String(emu_data.pwm1);
 dataString += ",";
 dataString += String(emu_data.vssSpeed);
 dataString += ",";
 dataString += String(emu_data.emuTemp);
 dataString += ",";
 dataString += String(emu_data.cel);
 dataString += ",";
 dataString += String(emu_data.flags1);
 dataString += ",";
 dataString += String(emu_data.lambdaTarget);
 dataString += ",";
 dataString += String(emu_data.oilTemperature);
 dataString += ",";
 dataString += String(emu_data.oilPressure);
 //dataString += ",";
 //dataString += String(can_error_data.state[1]); //Only first character
 dataString += "\r\n";

 file.print(dataString.c_str());

 if (millis() - lastSyncTime > 1000)
 {
  lastSyncTime = millis();
  file.flush();
 }
}

void generateFileName()
{
 char intBuffer[5];

 strcpy(filenameBuffer, "/");
 itoa(random(1000, 9999), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, "-");
 itoa(random(10), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, "-");
 itoa(random(10), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, "_");
 itoa(random(10), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, ".");
 itoa(random(10), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, ".");
 itoa(random(10), intBuffer, 10);
 strcat(filenameBuffer, intBuffer);
 strcat(filenameBuffer, ".csv");

 Serial.println(filenameBuffer);
}
```

title: Improve SD logger - 0.02% of data isn't logged at desired rate

Answers: 0


body:
In my code I want to send some float values from my phone to the Arduino's Bluetooth which I will then split using the substring function. it will then print that split value to the serial monitor.

I don't even know what is wrong but there is no error and it just spits out the ascii code of those numbers (not split). Please help if anyone has any idea.
Here is my code:

    #include <Wire.h>
    #include<SoftwareSerial.h>
    #define TxD 3
    #define RxD 2
    SoftwareSerial bluetoothSerial(TxD,RxD);

    String Sstring;
    String arrayOne;

    void setup()
    {
      bluetoothSerial.begin(9600);
      Serial.begin(9600);
    }

    void loop()
    {

     if(bluetoothSerial.available()>0)
     {

      arrayOne=bluetoothSerial.read();

      Sstring=arrayOne.substring(0);
      Serial.println(Sstring);
     }
    }

title: Bluetooth Arduino Data Type Error

Answers: 2

body:
I'm guessing the line `arrayOne=bluetoothSerial.read();`
is converting the received value to a string (character array of ASCII charachters terminated with the '\0' character).
Then, you copy that string to another string variable. If you want to split the string you should:
- define a starting character > 0
- and/or: define an ending character < the total string size.

See [this link][1] for more info.

You could try the following. I'm sure it's far from perfect but it might get you a bit further.
```
void setup()
{
    bluetoothSerial.begin(9600);
    Serial.begin(9600);
}

void loop()
{
    if (bluetoothSerial.available)
    {
        delay(100); // wait a little for the serial buffer to saturate. This value should be as short as possible

        // Save the buffer bytes as the float (Big Endian!)
        double received_float = (bluetoothSerial.read() << 24) | (bluetoothSerial.read() << 16) | (bluetoothSerial.read() << 8) | (bluetoothSerial.read());
        Serial.println(received_float);
    }
}
```
Some conciderations:
- The nr of bytes a float occupies may differ on your phone and your Arduino. The example above uses a 32-bit float
- If possible you'd want to start the transmission with a sequency of starting characters. That way, you can be sure to read the proper value.

  [1]: https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/substring/

body:
First thing, you have to decide what data format the phone application
will use for sending the data to the Arduino: define a “language” of
sorts. Then you have to program both the phone and the Arduino to speak
that same language.

Unless the data throughput is critical, I strongly advise you to use a
text-based format, where each “message” is followed by a dedicated
character that signals the end of the message. Popular choices for the
message terminator are `'\n'` (ASCII line feed, numeric value 0x0a =
10), `'\r'` (carriage return = 0x0d = 13) and `';'` (semicolon = 0x3b =
59). The semicolon is often used as a second-level separator, to split a
message into smaller fields.

Here is a simple example that reads one-line messages, using a line feed
as a delimiter:

```c++
void loop() {
    if (bluetoothSerial.available() > 0) {
        String message = bluetoothSerial.readStringUntil('\n');
        Serial.println(message);
    }
}
```

If you want to send the data as binary, then message framing becomes a
tricky problem. Since every possible byte value can legitimately appear
within the message (any byte can appear within a float), you cannot
simply reserve one byte to serve as a terminator. This is why, unless
you are an advanced programmer, I strongly encourage you to send
whatever data you want to send as text. Text also makes debugging much
easier.

Finally, I have to warn you that the `String` class is not friendly to
the memory of your Arduino, and can lead to instabilities if used
extensively. If you have time, I encourage you to study the robust way
to read text from the serial port: see the article [Reading Serial on
the Arduino][majenko], by Majenko.

[majenko]: https://majenko.co.uk/blog/our-blog-1/reading-serial-on-the-arduino-27


body:
FastLED web client, when clicked on, all RGB on in red color. Clicked off, all RGB off/black. but not work.
Here is the full code, i don't know why it's loop always and web client stuck when i clicked on button on webpage

I can not turn on all LED, or turn off all LED.

    #include <ESP8266WiFi.h>

    #include <FastLED.h>
    #define DATA_PIN 5
    #define NUM_LEDS 300
    CRGB leds[NUM_LEDS];
    #define COLOR_ORDER GRB
    #define BRIGHTNESS 254
    #define FRAMES_PER_SECOND 30

    // Enter your wifi network name and Wifi Password
    const char* ssid = "";
    const char* password = "";

    // Set web server port number to 80
    WiFiServer server(80);

    // Variable to store the HTTP request
    String header;

    // These variables store current output state of LED
    String outputRedState = "off";

    // Assign output variables to GPIO pins
    const int redLED = 5;

    // Current time
    unsigned long currentTime = millis();
    // Previous time
    unsigned long previousTime = 0;
    // Define timeout time in milliseconds (example: 2000ms = 2s)
    const long timeoutTime = 2000;

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

      //FastLED.addLeds<WS2812, DATA_PIN, GRB>(leds, NUM_LEDS);
      LEDS.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // 初始化光带
      FastLED.setBrightness(BRIGHTNESS);                     // 设置光带亮度
      set_max_power_in_volts_and_milliamps(5, 2000);         // 光带电源管理（设置光带5伏特，500mA）

      // Connect to Wi-Fi network with SSID and password
      Serial.print("Connecting to ");
      Serial.println(ssid);
      WiFi.begin(ssid, password);
      while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
      }
      // Print local IP address and start web server
      Serial.println("");
      Serial.println("WiFi connected.");
      Serial.println("IP address: ");
      Serial.println(WiFi.localIP());
      server.begin();
    }

    void loop() {
      WiFiClient client = server.available();  // Listen for incoming clients

      if (client) {                     // If a new client connects,
        Serial.println("New Client.");  // print a message out in the serial port
        String currentLine = "";        // make a String to hold incoming data from the client
        currentTime = millis();
        previousTime = currentTime;
        while (client.connected() && currentTime - previousTime <= timeoutTime) {  // loop while the client's connected
          currentTime = millis();
          if (client.available()) {  // if there's bytes to read from the client,
            char c = client.read();  // read a byte, then
            Serial.write(c);         // print it out the serial monitor
            header += c;
            if (c == '\n') {  // if the byte is a newline character
              // if the current line is blank, you got two newline characters in a row.
              // that's the end of the client HTTP request, so send a response:
              if (currentLine.length() == 0) {
                // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
                // and a content-type so the client knows what's coming, then a blank line:
                client.println("HTTP/1.1 200 OK");
                client.println("Content-type:text/html");
                client.println("Connection: close");
                client.println();

                // turns the GPIOs on and off
                if (header.indexOf("GET /2/on") >= 0) {
                  Serial.println("RED LED is on");
                  outputRedState = "on";

                  fill_solid(leds, 300, CRGB::Red);
                  FastLED.show();

                } else if (header.indexOf("GET /2/off") >= 0) {
                  Serial.println("RED LED is off");
                  outputRedState = "off";

                  fill_solid(leds, 300, 0);
                  FastLED.show();
                }

                // Display the HTML web page
                client.println("<!DOCTYPE html>");
                client.println("<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
                client.println("<link rel=\"icon\" href=\"data:,\">");
                // CSS to style the on/off buttons
                client.println("");

                // Web Page Heading
                client.println("
My LED Control Server
");

                // Display current state, and ON/OFF buttons for GPIO 2 Red LED
                client.println("
Red LED is " + outputRedState + "
");
                // If the outputRedState is off, it displays the OFF button
                if (outputRedState == "off") {
                  client.println("
<button class=\"button buttonOff\">OFF</button>
");
                } else {
                  client.println("
<button class=\"button buttonRed\">ON</button>
");
                }

                client.println("");

                // The HTTP response ends with another blank line
                client.println();
                // Break out of the while loop
                break;
              } else {  // if you got a newline, then clear currentLine
                currentLine = "";
              }
            } else if (c != '\r') {  // if you got anything else but a carriage return character,
              currentLine += c;      // add it to the end of the currentLine
            }
          }
        }
        // Clear the header variable
        header = "";
        // Close the connection
        client.stop();
        Serial.println("Client disconnected.");
        Serial.println("");
      }
    }

title: FastLED web client, clicked on page to control on and off for ws2812

Answers: 0


body:
I bought a bunch of Attiny12's from Digikey without checking if I can even program them with an Arduino. I've looked around a bunch, and I've only ever found ways to program Attiny13 and Attiny10.

Strangely, one of the board packages I downloaded had board information for the Attiny12 in the avrdude.conf file, but I can't select it in the Arduino IDE. I've tried to change the Attiny13 info in the config file to the Attin12 and just selecting the Attiny13, but I'm getting the following error:

```
         Using Port                    : COM3
         Using Programmer              : stk500v1
         Overriding Baud Rate          : 19200
         AVR Part                      : ATtiny13
         Chip Erase delay              : 20000 us
         PAGEL                         : P00
         BS2                           : P00
         RESET disposition             : dedicated
         RETRY pulse                   : SCK
         serial program mode           : yes
         parallel program mode         : yes
         Timeout                       : 200
         StabDelay                     : 100
         CmdexeDelay                   : 25
         SyncLoops                     : 32
         ByteDelay                     : 0
         PollIndex                     : 3
         PollValue                     : 0x53
         Memory Detail                 :

                                  Block Poll               Page                       Polled
           Memory Type Mode Delay Size  Indx Paged  Size   Size #Pages MinW  MaxW   ReadBack
           ----------- ---- ----- ----- ---- ------ ------ ---- ------ ----- ----- ---------
           eeprom         4     8    64    0 no         64    0      0  9000 20000 0xff 0xff
           flash          4     5   128    0 no       1024    0      0  4500 20000 0xff 0xff
           signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00
           lock           0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           calibration    0     0     0    0 no          1    0      0     0     0 0x00 0x00
           hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
           lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00

         Programmer Type : STK500
         Description     : Atmel STK500 Version 1.x firmware
         Hardware Version: 2
         Firmware Version: 1.18
         Topcard         : Unknown
         Vtarget         : 0.0 V
         Varef           : 0.0 V
         Oscillator      : Off
         SCK period      : 0.1 us

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.03s

avrdude: Device signature = 0x000000 (retrying)

Reading | ################################################## | 100% 0.02s

avrdude: Device signature = 0x000000 (retrying)

Error while burning bootloader.
Reading | ################################################## | 100% 0.03s

avrdude: Device signature = 0x000000
avrdude: Yikes!  Invalid device signature.
         Double check connections and try again, or use -F to override
         this check.

```

Anyway I can program the Attiny12 without resorting to a dedicated programmer?

title: How to program Attiny12 with Arduino?

Answers: 0


body:
I'm sure this is a super nooby question but,

what is the pinout of the Digispark ATTINY85 Development Board

The board looks like this:
[![Board][1]][1]

  [1]: https://i.stack.imgur.com/5vjVs.png

Now the reason why I'm asking this question, when I do ```digitalWrite(1, HIGH);```, the test light will come on. My question is then, what is the virtual number for PB1 (P1 in photo).

Also, does that arduino output + or -?

Any help is appreciated. Thank You!

title: Duinotech ATTINY85 Pinout

Answers: 1

body:
[This][1] seems to show an obvious pinout with an LED connected to p1 (digital pin 1).
With "virtual number" I guess you mean the Arduino pin nr. As your code shows you, it's Arduino pin 1.

  [1]: https://create.arduino.cc/projecthub/alaspuresujay/use-an-attiny85-with-arduino-ide-07740c


body:
I have an Arduino Pro Micro ATmega32U4 and I'm facing this error message on uploading:

```avrdude: Version 7.0
         Copyright (c) Brian Dean, http://www.bdmicro.com/
         Copyright (c) Joerg Wunsch

         System wide configuration file is "//etc/avrdude.conf"
         User configuration file is "/home/lucas/.avrduderc"
         User configuration file does not exist or is not a regular file, skipping

         Using Port                    : /dev/ttyACM0
         Using Programmer              : avr109
         Overriding Baud Rate          : 57600
avrdude: ser_open(): can't open device "/dev/ttyACM0": Permission denied
avrdude: opening programmer "avr109" on port "/dev/ttyACM0" failed

avrdude done.  Thank you.

Problem uploading to board.  See https://support.arduino.cc/hc/en-us/sections/360003198300 for suggestions.
```

I can upload code if I open Arduino IDE through terminal with `sudo`, but I don't know if there is any problem with this.

the stats for ttyACM0 shows up like this

```
~ >>> stat /dev/ttyACM0
    Arquivo: /dev/ttyACM0
    Tamanho: 0          Blocos: 0          bloco de E/S: 4096   arquivo especial de caractere
Dispositivo: 0,5        Inode: 1319        Ligações: 1     Tipo de dispositivo: 166,0
     Acesso: (0660/crw-rw----)  Uid: (    0/    root)   Gid: (  987/    uucp)
     Acesso: 2022-10-23 17:13:33.897457466 -0300
Modificação: 2022-10-23 17:13:33.897457466 -0300
  Alteração: 2022-10-23 17:13:33.897457466 -0300
    Criação: 2022-10-23 17:13:33.307457434 -0300

```

I've tried:

`sudo chmod a+rw /dev/ttyACM0`

`sudo usermod -a -G uucp myUser`

`sudo udevadm trigger`

And none of these worked, this error keeps showing when I use the IDE as my regular 'non root' user (Before someone ask, yes, I logged off and entered again, to make sure that the groups were updated).

So, is there any other step that I'm missing?

title: avrdude: ser_open(): can't open device "/dev/ttyACM0": Permission denied - can't get out of that

Answers: 0


body:
I'm making a stopwatch using an attiny85, the idea was to use the timer interrupts to count the seconds
my theory was: since I set the Attiny85 to run at 1Mhz, I can use a presale of 1024; 1000000 / 1024 = 976.5625 hz, 976.5625hz = 1.024ms, 125ms / 1.024ms = 122.07, so that I need to count to 122 to get a 125ms interrupt, then in the ISR function I can count to 8 to get around 1 second, ( 122 * 1.024 ) * 8 = 999.424ms

What is the problem? well, the problem is that I'm not getting something close to 999.424ms, I compere it with my phone's stopwatch and the attiny seems to start well, but then it gets about 2-3 slower than my phone's stopwatch

```cpp
#include <TM1637Display.h>

#define CLK 4
#define DIO 3
#define button 1

TM1637Display display (CLK, DIO);
int intr_count = 0;
byte dots = 0b01000000;

volatile int seg;
volatile int min;
volatile bool start = false;

void setup() {
  display.setBrightness(5);
  display.clear();
  pinMode(button, INPUT);

  cli();

  TCCR0A  = 0;
  TCCR0B  = 0;
  TCCR0B |= B00000101;
  TIMSK  |= B00010000;

  OCR0A   = 122;

  sei();
}

void start_counting(){
  if (digitalRead(button) == HIGH){
    start = !start;
    if(start == false){
//    display.clear();
      seg = 0;
      min = 0;
    }
    while(digitalRead(button) == HIGH);
  }
}

void loop() {
  start_counting();
  display.showNumberDecEx(min, dots, true, 2, 0);
  display.showNumberDec(seg, true, 2, 2);

}

ISR(TIMER0_COMPA_vect) {
  TCNT0 = 0;
  if(start == true){

    if (intr_count == 8) {

      seg++;

      if(seg == 60){
        min++;
        min = min % 60;
      }

      seg = seg % 60;

      intr_count = 0;
    } else {
      intr_count++;
    }
  }
}
```

title: Attiny timer interrupt does not make an interrupt every 1000ms

Answers: 1

body:
I see three issues with this approach.

The first is that you are using a very low quality, uncalibrated time
source. The frequency of the internal RC oscillator is good to within a
few percent only. It is also very unstable, and hugely dependent on
temperature. Using an external 16 Mhz ceramic oscillator should
give you a frequency that is no worse than 0.5% off, with a typical
error about 0.1%. It is still somewhat unstable though. If you instead
are using a _crystal_ oscillator, then you can expect an error about ten
times smaller (in the range of 100 ppm), and a very good stability.
Depending on you quality requirements, 100 ppm may still not be
good enough, in which case you still have the option to measure the
drift rate and calibrate it out (see below).

The second problem, which has already been raised by 6v6g, is that your
timer is counting from zero to 122 inclusive, which gives a period of
123 timer clock cycles. Take a look at the timing diagrams in the
datasheet if you need to convince yourself of this. If you want a period
of 122, you should set OCR0A to 121.

The third problem is that you are resetting the timer with the ISR. This
may work in this program, but it is a very fragile approach worth
avoiding. The problem is that everything the microcontroller does takes
time, and your ISR may even get delayed by another interrupt. If the
timer is incremented after rising the interrupt flag but before you
reset it, you are missing one count. If you want to have a continuous
time scale, _never_ reset your timer. You can either:

* let it run continuously, undisturbed (and do `OCR0A += 122` within the
  ISR),

* or let it reset itself by using the appropriate waveform generation
  mode (CTC or fast PWM).

Lastly, here is a trick you may use to calibrate your stop watch.
Instead of counting the interrupts until the counter reaches 8
(which assumes an interrupt period of exactly 1/8 s), increment a
nanosecond counter within the ISR, and count one second once you have
one billion nanoseconds:

```c++
const uint32_t nanoseconds_per_interrupt = 124928000;

ISR(TIMER0_COMPA_vect) {
    static uint32_t nanoseconds;
    nanoseconds += nanoseconds_per_interrupt;
    if (nanoseconds >= 1000000) {
        nanoseconds -= 1000000;
        seconds++;
        // then update minutes, hours... if needed
    }
}
```

This will increment the seconds every eight interrupts... most of the
time. From time to time, however, it will take nine interrupts. This
adds a little bit of jitter, but prevents the timing errors from
accumulating and making the clock drift. If the jitter is visible, you
can reduce it by shortening the interrupt period.

The value 124928000 I wrote above assumes the ISR is called every
122×1024 cycles of a 1 MHz clock. You can change it to fit a
different clock frequency or a different OCR0A setting. The trick is:
once you measure the drift rate of your stop watch, you can tweak this
number to remove that drift. For example, if you measure the stopwatch
and find it is running 0.04% too slow, then you increase that number by
0.04% (that would give 124977971) and the drift is gone.

**Edit**: In a comment, 6v6gt pointed out a fourth issue in your code,
which is likely the biggest issue. Your logic for counting interrupts
is:

```c++
if (intr_count == 8) {
    intr_count = 0;
} else {
    intr_count++;
}
```

This is counting from 0 to 8 _inclusive_, and looping with a period of
9 interrupts. A safer idiom for looping with a period of 8
would be:

```c++
if (++intr_count >= 8) {
    intr_count = 0;
}
```

Although I would still recommend counting nanoseconds if you want the
ability to calibrate your clock.


body:
I am using a project with an MQ138 sensor and want to push the real time sensor reads to firebase. Currently, the wifi/firebase part and sensor part work fine separately. The code connects to wifi and will update a temporary variable (just an int that gets 1 added to it every time the loop runs) and put that on firebase. On a separate arduino file, the code is also able to read the sensor, do math with it, and consistently update. However, when I put the two together and try to print the sensor output, the value does not change at all (both the raw analogRead AND the raw value after being put through some math)--even when it does change on the separate code I ran without any firebase/wifi involved.

Why is this? Could there be some sort of cache that saves the old sensor value? Something with the way the code loops? The only different between the firebase code and the sensor test code (without use of firebase) is that on the Arduino software the board has to be selected as ESP8266 for firebase/wifi connection to work, but the test code uses Arduino Uno as a board. Could there be something with this that is not letting `AnalogRead` (for the sensor) work properly?

The circuit is wired so that the ESP8266 and MQ138 sensor are both connected to an Arduino Uno.

My code is below (currently, the sensor output is only getting printed in serial, and the integer "n" is consistently getting updated and pushed on firebase, but even the serial output of the sensor won't change):

```cpp
#include <Firebase.h>
#include <FirebaseArduino.h>
#include <FirebaseCloudMessaging.h>
#include <FirebaseError.h>
#include <FirebaseHttpClient.h>
#include <FirebaseObject.h>
#include <dummy.h>

#include <ESP8266WiFi.h>
#include <FirebaseArduino.h>
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

//passwords have been removed, but are in the actual code
#define FIREBASE_HOST ""
#define FIREBASE_AUTH ""

#define WIFI_SSID ""
#define WIFI_PASSWORD ""

//Hardware Macros for sensor
#define MQ138 (5) //Analog 5 input
#define RL_VALUE (10000) //Load resistance in ohms
//Software macros
#define         CALIBRATION_SAMPLE_TIMES     (40)    //define how many samples you are going to take in the calibration phase
#define         CALIBRATION_SAMPLE_INTERVAL  (500)   //define the time interal(in milisecond) between each samples in the
//cablibration phase
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interal(in milisecond) between each samples in

//Globals for math with the sensor
float AcetoneCurve[2] = {3.720, -2.222}; //A, B
float R0 = 10000; //Initialized to 10k ohms
unsigned long SLEEP_TIME = 600; // Sleep time between reads (in seconds)
int val = 0;          // variable to store the value coming from the sensor
float calcVoltage = 0;
float dustDensity = 0;
boolean metric = true;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.print("help");
  WiFi.disconnect();
  Serial.setDebugOutput(true);
  /*IPAddress ip(192,168,3,34);
  IPAddress gateway(192,168,3,1);
  IPAddress subnet(255,255,255,0);*/
  WiFi.setAutoReconnect(true);

  //connect to Wifi
  WiFi.mode(WIFI_STA);
  WiFi.hostname("ESP-host");
  //WiFi.config(ip, gateway, subnet);
  WiFi.enableInsecureWEP(true);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    Serial.print("Wifi status: ");
    Serial.println(WiFi.status());
    delay(500);
  }
  Serial.println();
  Serial.print("connected: ");
  Serial.println(WiFi.localIP());
  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);

  //define pin
  pinMode(MQ138, INPUT);
}

int n = 0;

void loop() {
  // put your main code here, to run repeatedly:
  //MQ138 code
  int raw = analogRead(MQ138);
  static float Ro = MQCalibration(MQ138, 25, RL_VALUE, AcetoneCurve);    //Assuming 25ppm of acetone in clean air?
  float Rs = MQRead(MQ138, RL_VALUE);
  float ratio = Rs / Ro;
  int ppm = MQGetPercentage(ratio, Ro, AcetoneCurve);

 //This prints the same output every time, even when it shouldn't
  Serial.println(raw);
  Serial.print("PPM: ");
  Serial.println(ppm);

//Firebase code
  // set value
  Firebase.setFloat("PPM", n);
  //error catching
  if (Firebase.failed()) {
    Serial.print("setting /number failed:");
    Serial.println(Firebase.error());
    return;
  }
  delay(1000);
  // appending a new value to /logs, CHANGE INT
  String name = Firebase.pushInt("logs", n++);
  //handle error
  if (Firebase.failed()) {
    Serial.print("pushing /logs failed: ");
    Serial.println(Firebase.error());
    return;
  }
  Serial.print("pushed: /logs/");
  Serial.println(name);
  delay(1000);

  if (Firebase.failed()) {
    return;
  }

}

//Functions - for calculating the PPM from a raw sensor reading, can be ignored
/****************** MQResistanceCalculation ****************************************
  Input:   raw_adc - raw value read from adc, which represents the voltage
  Output:  the calculated sensor resistance
  Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage across the load resistor and its resistance, the resistance of the sensor could be derived.
************************************************************************************/
float MQResistanceCalculation(int raw_adc, float rl_value)
{
  return  (long)((long)(1024 * 1000 * (long)rl_value) / raw_adc - (long)rl_value);
  ;
}

/***************************** MQCalibration (R0) ****************************************
  Input:   mq_pin - analog channel
  Output:  Ro of the sensor
  Remarks: This function assumes that the sensor is in clean air. It use
         MQResistanceCalculation to calculates the sensor resistance in clean air.        .
************************************************************************************/
float MQCalibration(int mq_pin, double ppm, double rl_value, float *pcurve )
{
  int i;
  float val = 0;

  for (i = 0; i < CALIBRATION_SAMPLE_TIMES; i++) {      //take multiple samples
    val += MQResistanceCalculation(analogRead(mq_pin), rl_value);
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val / CALIBRATION_SAMPLE_TIMES;                 //calculate the average value
  //Ro = Rs * sqrt(a/ppm, b) = Rs * exp( ln(a/ppm) / b )

  return  (long)val * exp((log(pcurve[0] / ppm) / pcurve[1]));

}

/*****************************  MQRead (Rs) *********************************************
  Input:   mq_pin - analog channel
  Output:  Rs of the sensor
  Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
         The Rs changes as the sensor is in the different consentration of the target
         gas. The sample times and the time interval between samples could be configured
         by changing the definition of the macros.
************************************************************************************/
float MQRead(int mq_pin, float rl_value)
{
  int i;
  float rs = 0;

  for (i = 0; i < READ_SAMPLE_TIMES; i++) {
    rs += MQResistanceCalculation(analogRead(mq_pin), rl_value);
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs / READ_SAMPLE_TIMES;

  return rs;
}

/*****************************  MQGetPercentage **********************************
  Input:   rs_ro_ratio - Rs divided by Ro
         pcurve      - pointer to the curve of the target gas
  Output:  ppm of the target gas
  Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
         of the line could be derived if y(rs_ro_ratio) is provided. As it is a
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
         value.
************************************************************************************/
int  MQGetPercentage(float rs_ro_ratio, float ro, float *pcurve)
{
  return (double)(pcurve[0] * pow(((double)rs_ro_ratio), pcurve[1]));
}
```

The code to test the sensor, without integrating firebase and ESP8266, is as follows:
```cpp

//Source: https://github.com/empierre/arduino-mysensors-contribs/blob/master/AirQuality-Multiple_Gas_Sensor1_4.ino

// Libraries
#include <SPI.h>
#include <Wire.h>
#include <DHT.h>
#include <Adafruit_BMP085.h>

//Hardware Macros
#define MQ138 (5) //Analog 5 input
#define RL_VALUE (10000) //Load resistance in ohms
//Software macros
#define         CALIBRATION_SAMPLE_TIMES     (40)    //define how many samples you are going to take in the calibration phase
#define         CALIBRATION_SAMPLE_INTERVAL  (500)   //define the time interal(in milisecond) between each samples in the
                                                     //cablibration phase
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interal(in milisecond) between each samples in

//Globals
float AcetoneCurve[2] = {3.720, -2.222}; //A, B
float R0 = 10000; //Initialized to 10k ohms
unsigned long SLEEP_TIME = 600; // Sleep time between reads (in seconds)
int val = 0;          // variable to store the value coming from the sensor
//idfk what this is
float calcVoltage = 0;
float dustDensity = 0;
boolean metric = true;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(MQ138, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  int raw = analogRead(MQ138);
  static float Ro = MQCalibration(MQ138, 25, RL_VALUE, AcetoneCurve);    //Assuming 25ppm of acetone in clean air?
  //https://www.health.ny.gov/environmental/indoors/air/contaminants/acetone.htm#:~:text=Levels of acetone are typically,common ingredient in many products.
  float Rs = MQRead(MQ138, RL_VALUE);
  float ratio = Rs / Ro;
  int ppm = MQGetPercentage(ratio, Ro, AcetoneCurve);
  Serial.println(raw);
  Serial.print("PPM: ");
  Serial.println(ppm);
}

//Functions
/****************** MQResistanceCalculation ****************************************
Input:   raw_adc - raw value read from adc, which represents the voltage
Output:  the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage across the load resistor and its resistance, the resistance of the sensor could be derived.
************************************************************************************/
float MQResistanceCalculation(int raw_adc,float rl_value)
{
  return  (long)((long)(1024*1000*(long)rl_value)/raw_adc-(long)rl_value);
;
}

/***************************** MQCalibration (R0) ****************************************
Input:   mq_pin - analog channel
Output:  Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use
         MQResistanceCalculation to calculates the sensor resistance in clean air.        .
************************************************************************************/
float MQCalibration(int mq_pin, double ppm, double rl_value,float *pcurve )
{
  int i;
  float val=0;

  for (i=0;i<CALIBRATION_SAMPLE_TIMES;i++) {            //take multiple samples
    val += MQResistanceCalculation(analogRead(mq_pin),rl_value);
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBRATION_SAMPLE_TIMES;                   //calculate the average value
  //Ro = Rs * sqrt(a/ppm, b) = Rs * exp( ln(a/ppm) / b )

  return  (long)val*exp((log(pcurve[0]/ppm)/pcurve[1]));

}

/*****************************  MQRead (Rs) *********************************************
Input:   mq_pin - analog channel
Output:  Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
         The Rs changes as the sensor is in the different consentration of the target
         gas. The sample times and the time interval between samples could be configured
         by changing the definition of the macros.
************************************************************************************/
float MQRead(int mq_pin,float rl_value)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQResistanceCalculation(analogRead(mq_pin),rl_value);
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;
}

/*****************************  MQGetPercentage **********************************
Input:   rs_ro_ratio - Rs divided by Ro
         pcurve      - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm)
         of the line could be derived if y(rs_ro_ratio) is provided. As it is a
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic
         value.
************************************************************************************/
int  MQGetPercentage(float rs_ro_ratio, float ro, float *pcurve)
{
  return (double)(pcurve[0] * pow(((double)rs_ro_ratio), pcurve[1]));
}
```
Any help would be much appreciated!

title: Code not checking for updated sensor values after connecting to firebase?

Answers: 0


body:
I have ESP32-CAM that I plan to use as a simple security camera. I tested the software and it was working perfectly. I programmed it using FTDI programming board with 5V. After testing everything I decided to power it with an old adapter (5V 160mA) I had for some time but when I powered with adapter the power started flickering. When I noticed it I immediately unplugged the adapter but since then I started getting stuck in bootloop. Here is the output I get:

    12:56:10.663 -> ets Jul 29 2019 12:21:46
    12:56:10.667 ->
    12:56:10.667 -> rst:0x1 (POWERON_RESET),boot:0x3 (DOWNLOAD_BOOT(UART0/UART1/SDIO_REI_REO_V2))
    12:56:10.667 -> waiting for download
    12:56:49.327 -> ets Jul 29 2019 12:21:46
    12:56:49.327 ->
    12:56:49.327 -> rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:49.327 -> configsip: 0, SPIWP:0xee
    12:56:49.327 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:49.327 -> mode:DIO, clock div:2
    12:56:49.327 -> load:0x3fff0030,len:1344
    12:56:49.327 -> load:0x40078000,len:13836
    12:56:49.327 -> load:0x40080400,len:3608
    12:56:49.327 -> entry 0x400805f0
    12:56:50.707 -> ets Jul 29 2019 12:21:46
    12:56:50.707 ->
    12:56:50.707 -> rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:50.707 -> configsip: 0, SPIWP:0xee
    12:56:50.707 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:50.707 -> mode:DIO, clock div:2
    12:56:50.707 -> load:0x3fff0030,len:1344
    12:56:50.707 -> load:0x40078000,len:13836
    12:56:50.707 -> load:0x40080400,len:3608
    12:56:50.707 -> entry 0x400805f0
    12:56:52.086 -> ets Jul 29 2019 12:21:46
    12:56:52.086 ->
    12:56:52.086 -> rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
    12:56:52.086 -> configsip: 0, SPIWP:0xee
    12:56:52.086 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    12:56:52.086 -> mode:DIO, clock div:2
    12:56:52.086 -> load:0x3fff0030,len:1344
    12:56:52.086 -> load:0x40078000,len:13836
    12:56:52.086 -> load:0x40080400,len:3608
    12:56:52.086 -> entry 0x400805f0
It keeps going like this. I can upload new code without any problems but every code I upload gets stuck in this exact bootloop. Load and entry adresses does not change. I also tried programming with arduino nano instead of ftdi but nothing changed.

I am using Arduino IDE 2.0.0 on Linux Mint 21 OS. I also tried it on Windows 10 but the results didn't change. I am quite new to ESP32 so I don't know how to debug it either.

Thanks in advance.

##############

UPDATE 25/10/2022

After timemage's comment I tried a few more codes and one of arduino ide's example codes ran once with error. I couldn't get the error log but there was something like "PSRAM ID Read error 0xffffff" and another log pointing to a corrupted address.

After that I tried uploading another sketch without PSRAM with following settings:

 - Board: ESP32 Dev Module
 - CPU frequency: 240MHz(WiFi/BT)
 - Events run on: Core 1
 - Flash frequency: 80MHz
 - Flash mode: QIO
 - Flash size: 4MB(32Mb)
 - Arduino runs on: Core 1
 - PSRAM: Disabled
 - Partition scheme: Huge
   APP(3MB No OTA/1MB SPIFFS)
 - Upload speed: 115200

and it worked. But I need PSRAM for my project. So my question is: can it be a hardware problem ? If not, how can I fix it ?

Thanks again.

title: ESP32-CAM rst:0x8 TG1WDT_SYS_RESET bootloop

Answers: 4

body:
I had a similar problem when running test code for a data input module based on the NodeMCU-32s board. The board would reset about once per second with that same error. That turned out to be my error. I had confused the physical pin number of the board with the GPIO number. I am assuming that trying to read GPIO pins that are not routed to the chip pins was still accessing internal registers, and was enough to initialize the watchdog timer. Since I was otherwise doing nothing to the watchdog, (like resetting it frequently,) the watchdog was properly doing its job and resetting the part.
This wasn't obvious to me. In the Arduino environment, setting Tools->Core Debug Level to Verbose gave some clues. Turning off some of my use of GPIO inputs also got me to a point where the watchdog error stopped, and from there I was able to proceed. So long story shorter, I recommend checking your pin assignments for IO!

body:
1. Is your esp32_cam comes with PSRAM?  I had a program running on esp32 wrover with PSRAM, the same code could not run on esp32 wroom.  After checking, the esp32 wroom does not come with PSRAM.

2. Say that the esp32_cam does come with PSRAM, how do you initilize it?

3. My code has ISR to force shutdown after 15min of wakeup from deep sleep, I will get the same error with reset when there is a while loop or for loop, and i missed these 2 line of codes.
    vTaskDelay( 3 / portTICK_PERIOD_MS );
    esp_task_wdt_reset();

hopefully, this helps.

body:
I got the same "rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)" and crash when using the M5stack-Timer-Camera after doing a "SerialM.setDebugOutput(true);" then starting the camera with "camera_init()" and then doing an "EEPROM.commit".

When I remove the "SerialM.setDebugOutput(true);" the error/crash goes away and instead I just get a (Serial-Terminal) warning of "cam_hal: EV-EOF-OVF" when doing an "EEPROM.commit".

So in my case I suspect that the "SerialM.setDebugOutput(true)" was causing the "cam_hal: EV-EOF-OVF" error message to crash during the "EEPROM.commit".

body:
From my personal experience working with the ESP-CAM's ESP32-s3 chip, the particular error is the result of an invalid line of code.

The best way to address this is to look very closely at the code that you've written, for some of the errors you may introduce through the arduino ide may not be caught in the compilation process.

For example, I was building out a UART shell using the same processor.

My code was producing the same error because of this code here:

    private:
        size_t commandsLen = 1;
        string commands[1]{
            "lcdcam"
        };

I was able to fix the reset loop by correcting the syntax in my string array. Which was missing an equals sign.

The following modification fixed my particular issue, and odds are that your problem is syntax related like mine.

    private:
        size_t commandsLen = 1;
        string commands[1] = {
            "lcdcam"
        };

Edit:
Upon further inspection, there was an additional issue that also caused this error.

Take the following code into consideration:

    public:
        bool commandSwitch(Uart uart, BosCommand cmd){
            if(cmd.getCommandLength() <= 0){
                sendOutput(uart, "Failed to find commands.\n\r");
                return false;
            }
            string target = cmd.getCommandArg(0);

            if(target == "lcdcam"){
                BosCommandSwitch targetCmd;
                targetCmd.init(uart, cmd);
                return targetCmd.process();
            }else{
               // removed
            }
            return false;
        }

The issue is that the processor doesn't like it when I declare the BosCommandSwitch class inside the if logic. Not only did fixing the string array correct the reset bug, but moving the declaration of the class object up into the private section of my class allowed all my code to run without the automated reset.

    private:
        BosCommandSwitch targetCmd;
    public:
        bool commandSwitch(Uart uart, BosCommand cmd){
            if(cmd.getCommandLength() <= 0){
                sendOutput(uart, "Failed to find commands.\n\r");
                return false;
            }
            string target = cmd.getCommandArg(0);

            if(target == "lcdcam"){
                targetCmd.init(uart, cmd);
                return targetCmd.process();
            }else{
               // removed
            }
            return false;
        }

I believe that the issue is related to memory allocation. Once you get deep into logic, you reduce the amount of available memory in a particular region. Though this is just speculation on my part.


body: I want to use all SRAM of an Arduino by writing the code in assembly. But does the bootloader use some SRAM while the program is running, and if the answer is _yes_ would changing that data lead to failure or does the data stored there get corrupted? Thanks for reaching out.

title: Does the bootloader use some SRAM?

Answers: 1

body:
You did not specify what type of Arduino you are using. My answer is for
the AVR-based ones.

The bootloader does use RAM _while it is running_. However, once it
handles control to your program, the microcontroller is all yours: you
are free to use all the RAM.

Id did not check with optiboot but, it is possible that the bootloader
leaves some stuff in the stack. The C runtime of the avr-libc takes care
of this: one of the first things it does is to reset the stack pointer.
If you link with the avr-libc, you will find the stack empty. If you
don't, I suggest you set the stack pointer to RAMEND at the beginning of
your program, just in case.


body:
I'm new to C++. How to make a menu without `if() {} else {}` & `switch() case`?
I made a menu on an array, but for some reason it doesn't compile. How to correct it?

    typedef void (*cbd)(uint8_t, uint8_t);
    typedef void (*cbt)(uint8_t, uint8_t);
    typedef void (*cba)(uint8_t, uint8_t);
    typedef void (*MenuFunction) (int8_t);

    class Menu {
    public:
     Menu() {
            updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
        }

     static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
            cbDisplay = display;
      cbSetTime = setTime;
      cbSetAlarms = setAlarm;
            alarmHours = alarmHours;
            alarmMinutes = alarmMinutes;
            cbSetAlarms(alarmHours, alarmMinutes);
        }
        // Used for menu.UpDown(dir) callback
     static void UpDown(int8_t direction) {
            updownFn(direction);
     }
        // Used for menu.Tab() callback
        static void Tab() {
            updownFnNum++;
            updownFn = updownFns[updownFnNum % 5];
     }

    private:

        static void updownNone(int8_t direction) { }

        static void updownAlarmHours(int8_t direction) {
            alarmHours += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownAlarmMinutes(int8_t direction) {
            alarmMinutes += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownTimeHours(int8_t direction) {
            timeHours += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static void updownTimeMinutes(int8_t direction) {
            timeMinutes += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
        static uint8_t updownFnNum; // 0-None, 1-AlarmH, 2-AlarmM, 3-TimeH, 4-TimeM
        static cbd cbDisplay;
     static cbt cbSetTime;
     static cba cbSetAlarms;
     static MenuFunction updownFns[5];
     static MenuFunction updownFn;
    };

    uint8_t Menu::alarmHours = 0;
    uint8_t Menu::alarmMinutes = 0;
    uint8_t Menu::timeHours = 0;
    uint8_t Menu::timeMinutes = 0;
    uint8_t Menu::updownFnNum = 0;
    cbd Menu::cbDisplay = NULL;
    cbt Menu::cbSetTime = NULL;
    cba Menu::cbSetAlarms = NULL;
    MenuFunction Menu::updownFn = NULL;

Output:

    In file included from app.ino:7:0:
    menu.h: In constructor 'Menu::Menu()':
    menu.h:9:109: error: cannot convert '<brace-enclosed initializer list>' to 'MenuFunction {aka void (*)(signed char)}' in assignment
    updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes, updownTimeHours, updownTimeMinutes};

Thank you!

title: Array of Functions

Answers: 2

body:
First, your `updownFns[5]` can be contain 5 variable. And the last variable index can be 4 not 5 because of array index starts from 0.

Here is the code :

    typedef void (*cbd)(uint8_t, uint8_t);
    typedef void (*cbt)(uint8_t, uint8_t);
    typedef void (*cba)(uint8_t, uint8_t, uint8_t);
    typedef void (*MenuFunction) (int8_t);

    class Menu {
    public:
        Menu() {
            updownFns[0] = updownNone;
            updownFns[1] = updownAlarmHours;
            updownFns[2] = updownAlarmMinutes;
            updownFns[3] = updownTimeHours;
            updownFns[4] = updownTimeMinutes;
        }

        static void Setup(cbd display, cbt setTime, cba setAlarm, uint8_t alarmHours, uint8_t alarmMinutes) {
            cbDisplay = display;
            cbSetTime = setTime;
            cbSetAlarms = setAlarm;
            alarmHours = alarmHours;
            alarmMinutes = alarmMinutes;
            cbSetAlarms(alarmHours, alarmMinutes);
        }
        // Used for menu.UpDown(dir) callback
        static void UpDown(int8_t direction) {
            updownFn(direction);
        }
        // Used for menu.Tab() callback
        static void Tab() {
            updownFnNum++;
            updownFn = updownFns[updownFnNum % 5];
        }

    private:

        static void updownNone(int8_t direction) { }

        static void updownAlarmHours(int8_t direction) {
            alarmHours += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownAlarmMinutes(int8_t direction) {
            alarmMinutes += direction;
            cbDisplay(alarmHours, alarmMinutes);
            cbSetAlarms(alarmHours, alarmMinutes);
        }

        static void updownTimeHours(int8_t direction) {
            timeHours += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static void updownTimeMinutes(int8_t direction) {
            timeMinutes += direction;
            cbSetTime(timeHours, timeMinutes);
            cbDisplay(timeHours, timeMinutes);
        }

        static uint8_t alarmHours, alarmMinutes, timeHours, timeMinutes;
        static uint8_t updownFnNum; // 0-None, 1-AlarmH, 2-AlarmM, 3-TimeH, 4-TimeM
        static cbd cbDisplay;
        static cbt cbSetTime;
        static cba cbSetAlarms;
        static MenuFunction updownFns[5];
        static MenuFunction updownFn;
    };

    uint8_t Menu::alarmHours = 0;
    uint8_t Menu::alarmMinutes = 0;
    uint8_t Menu::timeHours = 0;
    uint8_t Menu::timeMinutes = 0;
    uint8_t Menu::updownFnNum = 0;
    cbd Menu::cbDisplay = NULL;
    cbt Menu::cbSetTime = NULL;
    cba Menu::cbSetAlarms = NULL;
    MenuFunction Menu::updownFn = NULL;
    // MenuFunction Menu::updownFns = {};

But still code is not correct. if you look at the signature of this definition

    typedef void (*cba)(uint8_t, uint8_t, uint8_t);
it takes 3 parameters. But inside the code, you give 2 parameter to the function

    cbSetAlarms(alarmHours, alarmMinutes)

body:
The C++ language makes a distinction between an _initialization_ and an
_assignment_. An initialization is the initial value you give to a
variable at the point where you are defining it. An assignment is the
use of the `=` operator anywhere else. Also, the language does not allow
assigning the contents of an array as a whole. You can initialize an
array though.

This:

```c++
Menu() {
    updownFns[5] = {updownNone, updownAlarmHours, updownAlarmMinutes,
        updownTimeHours, updownTimeMinutes};
}
```

is an attempt to assign a whole array. It cannot work. If you want to
initialize the array, do it at the point where it is being defined,
outside of the class definition:

```c++
MenuFunction Menu::updownFns[5] = {updownNone, updownAlarmHours,
    updownAlarmMinutes, updownTimeHours, updownTimeMinutes};
```