text:
Bad Communication with Multiple I2C Devices
I have an Arduino Micro connected to two I2C devices. An MPU-6050 that is powered by 5V (though it has its own voltage regulator on it) and a Altimeter that is powered by 3.3V. They are both connected to the SDA and SCL.
I noticed that when I have the MPU powered on but don't power the 3.3V altimeter, the MPU does not communicate with the Arduino. I need to have the 3.3V power on to just communicate with the MPU through I2C. Why does this happen?
Then unfortunately, I believe I may have shorted the 3.3V rail and broke the altimeter. When I remove the MPU from the equation and try to just communicate with the Altimeter, I get nothing. Does this mean that I did short the device, or is there something else going on with I2C that I don't understand?
I have attached a schematic below of how the devices are connected.

so ... you connect the scl/sda on the "pressure sensor" to the MPU6050 using 1k resistors? why? and how are these two components connected to the arduino? as a schematic, that leaves a lot of unanswered questions

They are connected to the Arduino Micros SCL and SDA pins. I did have both devices working before I shorted the device. I would like to know why when one device is bad (or not powered) on I2C, it screws up the other devices.

because they're connected

Do all devices use 3.3 V or all 5V for I2C communication? You will get problems when connecting a 3.3V device to a 5V bus or vice versa. At that point you would need a level shifter.

I would like to know why when one device is bad (or not powered) on
  I2C, it screws up the other devices.

The I2C lines need to have a pull up resistor to provide the high. The master device, and the slave devices, ground the line to provide a low, but they release the line, and not drive it at all, in order to provide the high.

Consider switches a and b to be inside the I2C device. When the switch a is open point A will be at 5 volts. When switch a is closed, point A will be at 0 volts.
Now if you had a second set of R resistors on the same line, but powered from their own 5 volt power supply, the same voltages will be seen at A when switch a is open (5 volts) and switch a is closed (0 volts).
But now if we kill the supply feeding the second set of R resistors (sorry that I can't show them in a picture) instead of pulling up to 5 volts (because we killed the 5 volts) the resistors will be pulling down due to whatever other loads there are on the killed 5 volt supply. And just for argument sake, let's say the killed 5 volt supply was at 0 volts.
So if one set of resistors is pulling up to 5 volts (the still powered pair) and one pulling down (the killed pair) then the voltage at points A and B will not be as high as the 5 volts we would see when the switches are open.  If all the resistors R were the same value, and the killed supply was at 0 volts, then the highest voltage at A or B would be 2.5 volts. And that is not a good high.
So the additional device, that is not being powered, has disrupted the communitations, preventing true highs. Lows are not affected as the switch will pull the line low.
I don't know the values of all your pull up resistors, and don't know how low the dead supply goes, so I can't say what the new lower highest voltage is. But it seems that it is low enough to make the communications stop working.
And the resistor are not the only thing that can be disgusting the high. The unpowered chip can be providing unexpected current paths. Most port pins have an internal diode to Vcc. And since the chip has no power on Vcc the current on the I2C lines can follow that path to ground.
Also, I think you have drawn the resistors wrong. If they were in series with the SDA and the SCL pins there would be no communications because the 1k resistors doesn't allow the SDA line to be pulled low enough. I think those resistors are pull up resistors. Maybe you can take another look and confirm the connection.

Thanks for the reply!! So the pull up resistors for the I2C line are on the breakout board for the MPU. They are 4.7kohm resistors and are pulled high to 3.3V.

When a device is unpowered any voltage placed on an IO pin is leeched off and fed to the VCC pin through the internal ESD protection diodes.  On a bus like I2C this then cripples the bus. (Note: even if there are no intentional protection diodes the MOSFETs that drive the lines have diodes built into them and these act as protection diodes, but they are very weak and can be easily broken).
You cannot have an unpowered device on an I2C bus and doing so risks damaging the unpowered device (although the limited current provided by the pullup resistors should mitigate this).
If you want to have an unpowered device on the bus you must isolate it from the bus.  I use the PCA9306 as in this answer, but other devices are available.
Did you kill the device by shorting it out? Possibly. It depends what you shorted to where. 3.3V directly onto the SDA or SCL pin while the device is unpowered may well have killed that pin.


text:
Timer Accuracy Always off by 1uS
I am using the ATMega32u4 to generate a pulse at 1 kHz. I am using Timer 3, which is a 16-bit timer and using a prescaler of 1, so I have a 0.0625uS resolution. The good news is that this is working, I can control the frequency and pulse length of the square wave. The issue is that I noticed the pulse always seems to be 1uS off.
If I set a period of 1000uS, and a pulse of 500uS, the oscilloscope shows a period of 1001uS and a pulse of 501uS.
If I set a period of 100uS, and pulse of 10uS, the oscilloscope shows a period of 101uS, and a pulse of 11uS.

If the Timer had an error percentage, then both the period and pulse should be off by the same percentage, but there are always off by the same 1uS length. I assume I am doing something wrong, so I have posted my code below.
const int pin1 = 4;

void setup() {
  //Set pin to output
  pinMode(pin1, OUTPUT);

  // Reset Timer 3 Control Register to 0
  TCCR3A = 0;

  // Set prescaler to 1
  TCCR3B &= ~(1 << CS32); //0
  TCCR3B &= ~(1 << CS31); //0
  TCCR3B |= (1 << CS30);  //1

  //Reset Timer 3 and set compare value
  TCNT3 = 0;

  // Enable Timer 3 compare interrupt A and B
  TIMSK3 |= (1 << OCIE3B);
  TIMSK3 |= (1 << OCIE3A);

  //Enable global interrupts
  sei();

  //Set Refresh Rate
  OCR3A = 1000;
  OCR3B = 100 / 0.0625;
}

void loop() {
  delay(100);
}

ISR(TIMER3_COMPA_vect) {
  PORTD &= ~_BV(pin1); //LOW
  OCR3A = 160;
}

ISR(TIMER3_COMPB_vect) {
  TCNT3 = 0;
  PORTD |= _BV(pin1); //HIGH
}

Why doing a division with a float in 100 / 0.0625 instead of simply 1600?

@hcheung I just do this to make it easy to change. I will say "1600" when I lock down a frequency I want to use. Right now I am just testing, and it still works.

The thing is floating point calculation take time, your question is about timing.... Of course the compiler might optimised it for you during the compilation, but that's an assumption.

@hcheung, the floating-point operation is only in the setup, so it should only be crunching that number once and then putting it in the register. If I do change it to "1600", there is no change to the timing.

oh yes, you are right.

Not only that, but the compiler probably optimizes it to just a constant value, so there’s no crunching numbers at all (at least not by the ATMega).

The problem is here:
ISR(TIMER3_COMPB_vect) {
  TCNT3 = 0;
  ...

If you want to get anything that vaguely looks like accurate timings,
you should never reset the timer. The MCU needs time to process an
interrupt: it has to save the program counter to the stack, load the
address of the interrupt vector, execute it (it's typically a jump),
save all the registers it needs to the stack, and only then can it start
executing the code you wrote in the ISR. From your experiment, it looks
like all this process takes about 1 µs. But don't take this delay
for granted: from time to time the interrupt will fire while the MCU is
processing another interrupt, and this will increase the latency.
You have two options:

Update the compare registers in order to program the next interrupts
some time in the future. In this case, the COMPB ISR would do
OCR3A = OCR3B + 160; OCR3B += 1600;. Do not worry about the
overflows: they do the Right Thing.
Let the timer reset itself to zero: it will then do so without
loosing a single cycle. See the CTC and fast PWM modes of the timer.

For your specific use case, PWM seems like the obvious choice. Not only
will the timer handle the resetting itself, it can also generate the
output signal without requiring you to write any ISR. Beware that in
this case the period of the signal is whatever you load in corresponding
compare register plus one, and the duration of the pulse is another
compare register plus one.
As a side note:
  // Reset Timer 3 Control Register to 0
  TCCR3A = 0;

I would also reset TCCR3B. The Arduino core configures both registers
for it's own purposes, so it would be safer to clear them both.

source: Stack Exchange

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

sort: votes


text:
Arduino Timer Precision
I am using the ATMega32u4 to generate multiple pulses at 2.5 kHz. I am using Timer 3, which is a 16-bit timer and using a prescaler of 1, so I have a 0.0625uS resolution. I want to generate pulses with pretty high accuracy and consistency. I have my previous post here, which gave me accuracy. But when I look at the pulse with my oscilloscope it has some jitter. Youtube Video of Jitter.
My final goal is to create a pulse on multiple different pins in this configuration.

What I am assuming is that the reason there is jitter is that there are other interrupts going on in the background, that could be shifting when the pulse stops and starts by a few microseconds. Looking through the datasheet, I found this, which seems to show interrupt priority.

It seems that my TIMER3 COMPA and COMPB are very low down the list of priorities, is there a way to change this priority list? Or is there something else that is causing the jitter?
I have posted my code below:
#define pin2 12
#define pin3 6
#define pin4 8

#define REFRESH 6400

int PULSEIndex;

class Pulse {
  public:
    int pulseLength;
    void Begin(byte GPIO_PIN) {
      pinMode(GPIO_PIN, OUTPUT);
    }
    void writeMicro(double pulse) {
      pulseLength = (pulse * 16);
    }
};

Pulse PULSE1;
Pulse PULSE2;
Pulse PULSE3;
Pulse PULSE4;

void setup() {
  PULSE1.Begin(pin1);
  PULSE2.Begin(pin2);
  PULSE3.Begin(pin3);
  PULSE4.Begin(pin4);

  // Reset Timer 3 Control Register to 0
  TCCR3A = 0;
  TCCR3B = 0;

  // Set CTC Mode
  TCCR3B &= ~(1 << WGM33); //0
  TCCR3B |= (1 << WGM32);  //1

  // Set prescaler to 1
  TCCR3B &= ~(1 << CS32); //0
  TCCR3B &= ~(1 << CS31); //0
  TCCR3B |= (1 << CS30);  //1

  //Reset Timer 3 and set compare value
  TCNT3 = 0;

  // Enable Timer 3 compare interrupt A and B
  TIMSK3 |= (1 << OCIE3B);
  TIMSK3 |= (1 << OCIE3A);

  //Enable global interrupts
  sei();

  //Set Refresh Rate
  OCR3A = REFRESH;
  OCR3B = 1000;
}

void loop() {
  PULSE1.writeMicro(40);
  PULSE2.writeMicro(40);
  PULSE3.writeMicro(40);
  PULSE4.writeMicro(40);
  delay(2);
}

ISR(TIMER3_COMPA_vect) {
  digitalWrite(pin1, HIGH);
  OCR3B = PULSE1.pulseLength;
}

ISR(TIMER3_COMPB_vect) {

  if (PULSEIndex == 1) {
    digitalWrite(pin1, LOW);
    digitalWrite(pin2, HIGH);
    OCR3B += PULSE2.pulseLength;
  }

  if (PULSEIndex == 2) {
    digitalWrite(pin2, LOW);
    digitalWrite(pin3, HIGH);
    OCR3B += PULSE3.pulseLength;
  }

  if (PULSEIndex == 3) {
    digitalWrite(pin3, LOW);
    digitalWrite(pin4, HIGH);
    OCR3B += PULSE4.pulseLength;
  }

  if (PULSEIndex == 4) {
    digitalWrite(pin4, LOW);
  }

  PULSEIndex++;
  if (PULSEIndex > 4) PULSEIndex = 1;
} ```

Fist try to access pins directly. The digitalWrite is extremely slow, and at least for the first pulse it's no digitalWrite(pin4, LOW);, so there is few microseconds jitter. Just like that.
Maybe consider MCU with DMA

I'm not 100% sure, but I think the interrupt priorities are fixed in hardware.

What I am assuming is that the reason there is jitter is that
  there are other interrupts going on in the background

This seems like a reasonable assumption. Since you are not doing serial
communication, the Timer 0 interrupt is likely the only one triggering
in the background. You can disable it with:
TIMSK0 = 0;

but then all the Arduino timing functions will stop working. You will
have to #include <util/delay.h> and replace delay() with
_delay_ms(). Note that this avr-libc function only works with
compile-time constant delays. On the other hand, it is cycle-accurate
and accepts floating point delays.

is there a way to change this priority list?

There is not, and even if this was possible, it would not be that
useful. Interrupts in the Arduino are not interruptible: if a
low-priority interrupt is running when a high-priority one triggers, the
high-priority interrupt has to wait for the currently running one to
terminate. Priorities are only relevant when the processor is about to
serve an interrupt request but has to decide which one, among several
pending requests, it will serve first.
Now, a small remark about this:
void loop() {
  PULSE1.writeMicro(40);
  PULSE2.writeMicro(40);
  PULSE3.writeMicro(40);
  PULSE4.writeMicro(40);
  delay(2);
}

There is no point in rewriting those values over and over again. If you
plan to change the code in order to make those widths non-constant, then
you have to take care to:

make the pulseLength properties (or the whole Pulse objects)
volatile
within writeMicro(), disable interrupts while changing
pulseLength.

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


text:
I can't receive string that I have sent through nrf correctly
I'm using arduino uno and nrf24l01. to monitor sensor data.
But this is the message that master receives:

⸮

this is my slave code.
void monitoring() {
    delay(10);
    radio.stopListening();
    int soilMoisture = analogRead(A5);
    int light = analogRead(A4);
    float temp = analogRead(A3);
    temp = temp * 0.48828125;
    int ltemp = int(temp);
    String message = String(soilMoisture) + "," + String(light) + "," +    String(ltemp);
    Serial.println(message);
    delay(200);
    radio.write(&message, sizeof(message));
    delay(50);
    radio.startListening();
    delay(10);
}

and here is my master code.
while (1) {
    if (radio.available()) {
      char message[32] = "";
      radio.read(&message, sizeof(message));
      delay(500);
      Serial.println(message);
}

Remove the & in the master code line, change
 radio.read(message, sizeof(message));

to
radio.read(message, sizeof(message));

message is an array, so either you should pass the address of the first character (&message[0]), or simply pass message.
Another problem is sending a String in the slave code (using type String). It's better not to use this type anyway, but you probably have to convert it to a character array of the same type as in the master code.
You can use the function StringToCharArray for that, see StringToCharArray.

Thank you very much


text:
error 404 in HTTP GET request with Arduino Uno and ESP8266 using AT commands
when I try to send http get request I get error 404
AT+CIPMTX=1

OK
AT+CIPSTART=4,"TCP","alirezaabrhshami.ir",80
4,CONNECT
OK
AT⸮⸮R5U9⸮⸮b⸮⸮j
OK
>
Recv 47 qytes
SEND OK
+IPD,4,223;HTTP/1.1 404 Not Found
Cache-Contsol: public, max-age=0:a1n CeK⸮

this is my code:
#include <SoftwareSerial.h>

const byte rxPin = 2;
const byte txPin = 3;
SoftwareSerial ESP8266 (rxPin, txPin);

unsigned long lastTimeMillis = 0;

void setup() {
  Serial.begin(9600);
  ESP8266.begin(115200);
  delay(2000);
}

void printResponse() {
  while (ESP8266.available()) {
    Serial.println(ESP8266.readStringUntil('\n'));
  }
}

void loop() {

  if (millis() - lastTimeMillis > 30000) {
    lastTimeMillis = millis();

    ESP8266.println("AT+CIPMUX=1");
delay(1000);
printResponse();

ESP8266.println("AT+CIPSTART=4,\"TCP\",\"alirezaabrishami.ir\",80");
delay(1000);
printResponse();

String cmd = "GET /greencare/login.php?product_id=123456 ";
ESP8266.println("AT+CIPSEND=4," + String(cmd.length() + 4));
delay(1000);

ESP8266.println(cmd);
delay(1000);
ESP8266.println("");
  }

  if (ESP8266.available()) {
    Serial.write(ESP8266.read());
  }

}

there is no /greencare/login.php?product_id=123456 on the server

but there is : http://alirezaabrishami.ir/greencare/login.php?product_id=123456

your HTTP request is incomplete. it should be
String cmd = "GET /greencare/login.php?product_id=123456 HTTP/1.1\r\nHost:alirezaabrishami.ir\r\n\r\n"

if the wen server host has more hostnames for the same IP address, the Host header is used on HTTP server to direct the request to the right web application


text:
How can we use two devices at the same time with arduino?
I am using fingerprint module r307 and LCD together. In that, I am using 2,3 digital pins of arduino for data transfer to the fingerprint.(I tried other pin configurations for this but it didn't work) But as I am connecting LCD, it also requires same 2,3 digital pins of arduino and it is not possible for me to use 2 and 3 pins of Arduino for both lcd and fingerprint sensor for data transfer. Can you please suggest an alternative to this. Can we use analog pins of arduino as digital ones and if so the how?? PLEASE HELP... Thank you!!

Please add which libraries you are using. You could also add your sketch so far.

When you instantiate an instance of the LCD code, likely you will have a choice of pins to use.  But even with this flexibility (if the library programmer was thoughtful enough & was able to include it), the limits of the particular Arduino and processor you have chosen may make the project difficult or impossible.  As @MikaelPatel has asked, let us know the libraries you are using so we can inspect its possibilities.

Can we use analog pins of arduino as digital ones and if so the how??

Yes. You just treat them the same as any other digital pin.  On an Arduino all pins are digital. It's just that some have additional functionality, like analog input, or PWM, or serial, or SPI, etc.

ADC pin on esp8266?

@Juraj No one said anything about an ESP8266. Which, incidentally, is NOT an Arduino.

I know, but I would not wonder if OP had one and called it Arduino

@Juraj Unlikely, since they talk of analog "pins"", (plural) and the ESP8266 only has one. They'd then talk about "the analog pin".

And they wouldn't have said "use 2 and 3 pins of Arduino". I'm unclear on how anything ESP-related came up here.

@DaveNewton It's Juraj. You're never quite sure what goes through his mind sometimes ;)


text:
Connecting TFT Display MI0283QT-9A to ESP32
I have purchased a MI0283QT-9A TFT display (https://download.mikroe.com/documents/add-on-boards/other/display/tft-proto/tft-proto-manual-v200.pdf) which is
driven by the ILI9341 display controller.
I've managed to find the following board specification: http://pub.ucpros.com/download/tft_320_240_mi0283qt_9a_v1_3_spec.pdf
First of all, the pins are named differently from all the examples I can find for connecting it to my ESP32 microcontroller. For example, the TFT specs describe:
33 SDO Serial Output Signal
34 SDI Serial Input Signal
35 RD Read execution control pin
36 WRX(D/CX) Write execution control pin ; Serial Register select s Signal
37 D/CX(SCL) Register select signal; Serial Interface Clock
38 CSX Chip Select Signal
39 TE Tearing effect out pin synchronize MPU to frame writng

But this Adafruit ILI9341 example (https://github.com/adafruit/Adafruit_ILI9341/blob/master/examples/graphicstest/graphicstest.ino) talks about CS, DC, MOSI, CLK, RST, and MISO.
I think these map as follows, can anyone confirm that?
ESP32 = TFT
--------------
DC    = RS
CLK   = WR, although maybe it should connect to DC???
CS    = CSX
MOSI  = SDI
RST   = RST
MISO  = SDO

I'm really unsure about the first two!
Second, in the PDF it refers to note 1 on page 11:

So as far as I can tell, I need to set the voltage high/low on the four IM* pins, depending upon the interface I want to use. So the second question is which interface does the Adafruit ILI9341 library use?

The wiring depends on what mode you are using the board in - which mode you select from the table of modes you show (what settings you give to IM0-IM3).

It sounds like you want a 4-wire 8-bit serial SPI compatible interface.  To get that you have to set the IMx pins to the right state to enable that interface.  That means:

IM0 = LOW
IM1 = HIGH
IM2 = HIGH
IM3 = HIGH

You can hard-wire those to GND for LOW and +3.3V for HIGH.
That will then configure it to work in the right mode for you, where it gives you access to the following pins:
| Display  | ESP32   | Function                    |
|----------|---------|-----------------------------|
| SCL (RS) | SCK     | Serial clock                |
| SDI      | MOSI    | Serial data Master -> Slave |
| SDO      | MISO    | Serial data Slave -> Master |
| D/CX (WR)| DC      | Data / Command register sel |
| CSX      | CS      | Chip Select (Active Low)    |
| RST      | RST     | Reset                       |

what does "active low" mean, next to CS?

is the RST pin on the ESP32, the EN pin, or some pin of my choice?

It means that the input is considered "activated" when it receives a LOW signal. I.e., the chip is activated when you apply LOW to that pin.

RST and DC are pins of your choice. They are just GPIOs to control the screen.

thanks for the help. I still have a problem with SCL and DCX: according to the specs: TFT Pin36: WRX//D/CX) Write execution control pin ; Serial Register select s Signal; TFT Pin37: D/CX(SCL)  Register select signal; Serial Interface Clock.   none of those names are on TFT board. but we do have RS = Register Select => so DC is the RS pin. that means SCL/SCK must be the WR pin. ok, ill check that.

forget the above comment.  Thanks for the help. I still have a problem with SCL and DCX: according to the specs: TFT Pin36: WRX//D/CX) Write execution control pin ; Serial Register select s Signal; TFT Pin37: D/CX(SCL)  Register select signal; Serial Interface Clock.   There is no pin on the board with the name D/CX(SCL), but there is one called RS and one called WR. So I guess WR is the DC and RS is the clock?

Map the pins using the schematic.  Pin 36 is DC in serial mode. That's LCD-WR# on the board (WR). Pin 37 is SCL in serial mode. 37 is RS on the board. So DC -> WR and SCK -> RS. The board is really labelled from a 16-bit 8080 interface perspective.

OK, I started using the SPI pins of the ESP32 rather than GPIO pins. DC/WR=12; SCK/RS=18; CS=15; SDI/MOSI=23; RST=14; MISO/SDO=19. the board now flickers, although it doesnt show what it supposed to. and the program now outputs non-zero values: Display Power Mode: 0xFF; MADCTL Mode: 0xE0; Pixel Format: 0xFF; Image Format: 0xFF; Self Diagnostic: 0xFF. see also https://github.com/espressif/arduino-esp32/blob/master/docs/esp32_pinmap.png

The IM0 pin was unplugged from gnd => stuck it back in, and now it works perfectly. thanks!!!

Excellent.  There's not much I haven't learned about TFTs over the years ;)

Same (TFT proto board) tested Arduono DUE.
Pins IM1-3 HI, IM0 LO. (4-wire 8-bit data serial interface)
SDI - MOSI, SDO - MISO,RS - CLK, RD - HI, WR - D9, CS - D10, Reset - Reset (D8)
Driver UTFT myGLCD (ILI9341_S5P, MOSI, SCK, 10,8,9);
or
// For the Adafruit shield, these are the default.
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341 (TFT_CS, TFT_DC);

Backlight needs resistor!


text:
Speed of built in DAC/ADC in Arduino Due
Can someone tell me how fast the built in DAC (and ADC) in an Arduino Due can be written or read? I currently don't have the equipment to measure but need the information to plan my next steps.
I try to move galvanometer mirrors and want to make the voltage/position updates as small as possible. How fast are the internal DACs compared to an SPI connection (where I have to write 2 Byte).

You can find all the specs on the cpu datasheet: http://www.atmel.com/images/atmel-11057-32-bit-cortex-m3-microcontroller-sam3x-sam3a_datasheet.pdf

Could you give me a hint on where I find this information in that 1500 page document? And how does this chip talk to the arduino?

I think the galvanometer is orders of magnitude slower than the DAC. It has to overcome it's inertia, and requires quite some time to stabilize.

The hardware can handle position updates in the range of around 30kHz. Before moving to the Due, I used an RPi 2 with an SPI DAC and couldn't reach that update rate. I hope that you are right, but some numbers on the update rate would be great.

See sections 43, Analog-to-Digital Converter (ADC), and 44, Digital-to-Analog Converter Controller (DACC), in the Atmel-11057-32-bit-Cortex-M3-Microcontroller-SAM3X-SAM3A_Datasheet.pdf specsheet.
In particular, subsection 43.2, Embedded Characteristics, says: “1 MHz Conversion Rate”.  Some time diagrams appear quite a few pages later that suggest 10-bit conversions can be done more rapidly than 12-bit.
For the DAC (or DACC, per the specsheet), section 44.6, Functional Description, says:

The DACC uses the master clock (MCK) divided by two to perform conversions. This clock is named DACC Clock.
  Once a conversion starts the DACC takes 25 clock periods to provide the analog result on the selected analog
  output.

AIUI, the Due's master clock frequency is 84 MHz, so DACC Clock frequency is 42 MHz, whence 25 cycles take 575 ns, which is an update frequency of about 1.74 MHz.
For more details about the ADC, see eg
Analog performance, particularly of Due's 12 bit ADC at djerickson.com.

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


text:
Is there a library for non-SAMD Arduinos to use the DMP on MPU9250
I would like to use the DMP of the MPU9250 with my BTLE Feather board but the docu of the official library says that only SAMP-Processors are supported.
Is the a different library I can use?

it uses the Wire library. I don't see anything SAMD specific. Try it

I did have a look at the MPU9250 DMP library provided by Sparkfun and it seems that it is specifically built for their own board which has an M0 chip on the board. However looking at the library, there seems to be no reasons why it would not work with any other board. The main reason why it might not work with something like the 32u4 board would be because the end firmware is too large or the program need too much RAM that what the 32u4 has.
There is a fix provided on the github issues page for using it with a Nano, which might help you get it work with the 32u4 here and there is another library here that you might be able to use or build up on.
However the best way might be to use a M0 chip itself if you really want to use the same IMU since getting the library to work can turn out tricky. Adafruit does sell a M0 with a Bluetooth board here that you might be able to use.

Thanks for finding the M0-feather. It's just a bit too late, but I think I'll buy one and see if the values change. I can run the examples without problem on the 32u4, but I just wonder if the drift comes from some timing problems or subtlety that is not obvious.


text:
Which board/shield to generate (non-PWM) analog outputs?
I am currently building a project involving a laser scanner (two galvanometers with mirrors that deflect a laser beam) that I want to control. The galvos need +-10V differential signals (and I'd like to have a least 12Bit) that I want create with some small board.
Most Arduinos I know use PWM to create an analog output which is not usable for this project. I found the Teensy3.1 which has at least one 12Bit DAC so that also doesn't work. An alternative would be a DAC breakout board like "MCP4725" but it would be nicer to just have a single board with no additional parts.
The best thing would be a small board with already two 12Bit DACs. (even If I had to upscale the voltage +-10v)
Is there a board I haven't found so far? Or have I missed a completely different approach?

Why is filtering the PWM not an option?

Would it be a solution? I'm not that deep into electronics, so it could possibly be a solution for me. How does it work?

Adding a capacitor to smooth out the PWM?

For 12-bit dual DAC you want the MCP4822 which has two channels of 0-4.095V in 1mV steps.
The output of that you would then need to pass through a suitable amplifier arrangement with an op-amp giving a gain of 5 and adding an offset of -10V.  The gain would change the 0-4.095V to 0-20.475V, and the -10V offset would change that to -10V to +10.475V.  If you want to get more precise you could use an offset of -10.2375V (it's not easy to make an offset voltage that precise) then you would get -10.2375V to 10.2375V in 12-bit resolution.
It's doubtful you'll find a board already made up with that specific arrangement (it's fairly specialised) but it's not something that's hard to make - all the components are available as DIP or other through hole components, and the circuit for the amplification stage is pretty simple (check for non-inverting op-amp circuits online, there's millions), so building it up on strip board or matrix board would be easy enough.

Thanks! Did you already know this component or how did you search for it? I only found SMD-parts (like the MAX5322) when searching and I don't have the equipment for them.

It's a component I know well. I have a number of them in my bits box, they're very useful.

If you already used it, could you maybe check if I understand the chip correctly: To communicate, I send two-byte messages as described on page 22 and select the output via bit 15, set Bit 13 to 1 to get the 4.095-Range, SHDN(12) to 1 to enable the output and fill 11-0 with my data. To synchronize the outputs, I set the LDAC-Pin(5) to high (VDD, Pin1), write messages for both outputs, set it back to VSS (Pin7) and then the output-voltage is updated.

From what I recall that sounds right, Yes.

I just found thist library: http://hacking.majenko.co.uk/MCPDAC :) I think that's an easier way to use the chip

You might find thats out of date. Check github for the latest version

https://github.com/MajenkoLibraries/MCPDAC

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


text:
Run code once after programming
I'm using EEPROM to store project settings non-volatile.
After reuploading the sketch to my board (over SPI via ArduinoISP), the EEPROM is reset to full 0xFFs and I have to manually do a "software reset" with a second switch, which initializes the EEPROM with its default values.
Is it possible to run a segment of code once, and only once, after booting up the first time after being programmed?
I'm working around it by checking whether a piece of EEPROM is 1 at startup when it would always be 0 after the initialization and during usage, but surely there's a cleaner alternative than checking for an EEPROM bit each time.

Personally I think your way is very clean, program an EEPROM bit, set it, and change it after doing a one time initialization. It's also very flexible, in case you want to do it multiple times (just use a counter in EEPROM for example). Or in case the initialization is not done correctly, you can omit resetting the bit.

change the high fuse setting in boards.txt to preserve the EEPROM content at ISP

@Juraj The solution with the fuse has worked, although I had to flash it manually through avrdude (D6 instead of DE).
Is it normal that changing it in the boards.txt would not update it when flashing (/ flashing using ArduinoISP)?

The fuses are only written when you select the "burn bootloader" option in the Arduino IDE. PS You can also use AVRdude to write to the EEPROM directly.

see the EEPROM library's eeprom_crc example

This is a X->Y problem. Here is a solution for X:
Bit 3 of high fuse of the ATmega328p controls if EEPROM memory is preserved through the chip erase. You can change the high fuse setting in boards.txt. Restart the IDE to apply the new setting.
The fuses are written when you select the "burn bootloader" option in the Arduino IDE.

I feel like editing the boards.txt file is a bit less "portable" than I'd prefer. I believe checking whether an EEPROM that's guaranteed to be 0 after initialization is 1 (after flashing) is cleaner.

portable? someone else will flash it over ISP?

Yes, unfortunately. I've described how to wire the ArduinoISP up to the project board and how to flash it using the IDE, but editing the file seems a bit too much.


text:
Timer 1 COMPA ISR - default behaviour?
I'm creating a LCD frequency generator.
When TIMER1 reaches a set value, it's set to toggle Pin 9 (via OC1A).
Accidentally, I left the TIMER1 "interrupt on compare match A" enabled, but never defined the TIMER1_COMPA_vect interrupt vector.
This made the Uno reset itself - but not running through the bootloader, just the program part - whenever TIMER1_COMPA_vect would've been called.
Once I defined the ISR, even without it having any content, it would run as expected.
Is there a default content for ISRs, which resets the device / starts just after the bootloader? Shouldn't the compiler detect a completely missing ISR?

The compiler cannot detect a missing ISR since it is very difficult, in
the general case, to tell whether any particular interrupt-enable bit
has been set by the program.
The avr-libc library does indeed provide a “catch-all” ISR and, as
stated by the manual,

the default action is to reset the device by jumping to the reset
  vector.

If you don't like this behavior, you can override this catch-all with
your own, as explained in the manual (search for “Catch-all
interrupt vector”).

Very interesting, that solves my confusion - thank you.


text:
ESP8266 as ISP for Arduino Mega2560
I'm trying to use an ESP8266 Node MCU 1.0 (ESP-12E Module) as an ISP to program an Arduino Mega2560 over Wifi with no USB cable. (USB connected to ESP8266 module just for power).
I used the sketch 'Arduino_Wifi_AVRISP' from the Arduino IDE and modified the STASSID & STAPSK to match my wifi settings.
I followed the procedure found in this other post and was able to program the ESP8266 with success:
ESP8266 as ISP program for ATMega16
However, when I run the command line:
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude" -C"C:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -c stk500v2 -p m2560 -P net:192.168.1.246:328 -Uflash:w:C:\Users\dom\AppData\Local\Temp\arduino_build_199262/blink.ino.hex:i

I get the following response:
avrdude: Version 6.3-20171130
     Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
     Copyright (c) 2007-2014 Joerg Wunsch

     System wide configuration file is "C:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf"

     Using Port                    : net:192.168.1.246:328
     Using Programmer              : arduino
avrdude: ser_drain(): read error: The parameter is incorrect.

avrdude: ser_drain(): read error: The parameter is incorrect.

avrdude: ser_drain(): read error: The parameter is incorrect.

     AVR Part                      : ATmega2560
     Chip Erase delay              : 9000 us
     PAGEL                         : PD7
     BS2                           : PA0
     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        65    10     8    0 no       4096    8      0  9000  9000 0x00 0x00
       flash         65    10   256    0 yes    262144  256   1024  4500  4500 0x00 0x00
       lfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
       hfuse          0     0     0    0 no          1    0      0  9000  9000 0x00 0x00
       efuse          0     0     0    0 no          1    0      0  9000  9000 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
       signature      0     0     0    0 no          3    0      0     0     0 0x00 0x00

     Programmer Type : Arduino
     Description     : Arduino

avrdude: stk500_getparm(): (a) protocol error, expect=0x14, resp=0x14

avrdude: stk500_getparm(): (a) protocol error, expect=0x14, resp=0x10
     Hardware Version: 4744608
     Firmware Version: 0.2
     Topcard         : STK502
     Vtarget         : 1.8 V
     Varef           : 0.0 V
     Oscillator      : Off
     SCK period      : 0.1 us

avrdude: stk500_initialize(): (b) protocol error, expect=0x10, resp=0x01
avrdude: initialization failed, rc=-1
     Double check connections and try again, or use -F to override
     this check.

avrdude: stk500_disable(): protocol error, expect=0x14, resp=0x10

avrdude done.  Thank you.

Everything is connected as it is in the post previously mentioned. What could be causing me to get this issue?
Does it not use the "arduino" protocol for Arduino Mega2560?
Are the 3.3v pins just not sufficient to program the 5v Arduino?
As I mentioned, I'm only using USB to power the the ESP8266, not the Arduino so I don't damage the ESP pins.
Thank you.

see the avrdude command used by IDE (in the console).

When I compile the sketch I want to upload i get this avr command in the Arduino IDE console:
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude" -C"C:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -patmega2560 -cwiring -PCOM4 -b115200 -D -Uflash:w:C:\Users\dom\AppData\Local\Temp\arduino_build_742925/blink.ino.hex:i

So i turned it into this to be able to program the Mega2560 thru the ESP8266 via Wifi over the CMD prompt:
"C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avrdude" -C"C:\Program Files (x86)\Arduino\hardware\tools\avr/etc/avrdude.conf" -v -patmega2560 -cwiring -P net:192.168.1.246:328 -D -Uflash:w:C:\Users\dom\AppData\Local\Temp\arduino_build_742925/blink.ino.hex:i

And it returned this now:
     Using Port                    : net:192.168.1.246:328
     Using Programmer              : wiring

avrdude: ser_drain(): read error: The parameter is incorrect.
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_ReceiveMessage(): timeout
avrdude: stk500v2_getsync(): timeout communicating with programmer

now I remembered. the "Arduino as ISP" has only stk500v1 protocol and avrdude uses stk500v2 "wiring" configuration for Mega.

do you know my ArduinoOTA library for Mega? https://github.com/jandrassy/ArduinoOTA


text:
Sound sensor only detect peaks
I'm using this SparkFun Sound Sensor in my project for a simple ambient sound meter.
I'm just trying to monitor the raw analog envelope output for the moment.
My problem is that the output only changes with peak sounds, like a clap in my hands for example. But when the ambient sound is louder, people talking or loud music, the output doesn't change.

It seems you have to increase the gain, see inside the document
Sound dectector hookup guide
The following fragment:

Also take into account it needs between 3.5 and 5.5 V, while 5 V is ideal (see Quick start at the beginning of the same document.

I thought this is only for the sound detection (gate output) but I'll give it a try, thank you for the insight!

I never used this component, but I guess it will improve the sound sensivity, which is what should be increased if you get too less gain.

I've tried it and it changed nothing :(

Sorry to hear … a poor man solution would be to use an opamp/amplifier before the input of this sound detector.

Maybe, it's above my knowledge at the moment.
Thank you for you replies though :)


text:
Controllino Mega and Fatek HMI
I have a setup that controls the rotation of two stepper motor using Arduino UNO, HBS860H stepper drivers, 4X4 keypad and LCD screen. I have replaced the Arduino Uno by a Controllino Mega and it works good. Now I am trying to replace the Keypad and LCD screen by a FATEK HMI PN2043NK.
I have the sketch for the Controllino,
I can use RS485 to communicate both devices.
I use FV Designer to program the HMI, but I don't understand how to run the sketch from the HMI.
I need some help with a simple example Please, any help I could use to start learning to communicate the HMI with the Controllino and run the steppers will be welcome.

I am unfamiliar with those devices, but I would assume you write software for both which uses RS485 to send messages between them. It'll be up to you what those messages are and what they mean, and how you respond to them.

The usual "sketch" is "always" running on your arduino (Controllino) unless it is put into a non-run mode (like when loading a program) or doesn't have power.  What you need in your sketch is to do something IF a command is received on the serial (RS485).  Rather than simply running the command you want, the sketch needs to check the serial and only execute the command if the HMI sent the correct signal.
For motor control, you could use G-code where your HMI sends G-code move commands over RS485 and your Controllino executes them.  A handy RS232 example is grbl.


text:
Modbus programming
I have a Controllino Mega running a code that rotates a stepper one revolution CW, and one revoluction CCW.
I need the program to run, just when a signal is received from an HMI that I have connected to the Controllino via ethernet.
This is my first time using modbus. I have seen some examples using the modbus library, and I know I have to declare the variables in void setup, but don't know how many variables I need and if they  have to be analog or digital. I don't know either how to read those variable within void loop.
    #include <SPI.h>
    #include <Controllino.h>
    #include <Ethernet.h>
    #include "MgsModbus.h"

    MgsModbus Mb;

    const int pul = 46;  // pin 46 to PUL -
    const int dir = 47;  // pin 47 to DIR -

    void setup ()
     {

        byte mac[] = {0x90, 0xA2, 0xDA, 0x0E, 0x94, 0xB5};
        IPAddress ip(10, 7, 4, 17);
        IPAddress gateway(10, 7, 4, 17);
        IPAddress subnet(255, 255, 255, 0);
        Ethernet.begin(mac, ip, gateway, subnet);
        delay(5000); // Time to open the terminal
        Serial.begin(9600);

        pinMode (pul, OUTPUT);
        pinMode (dir, OUTPUT);
     }

     void loop()
     {

 Mb.MbsRun();

   digitalWrite(dir, HIGH);
  /*Turns the motor 400 steps*/
  for (int i = 0; i < 400; i++)
  {
    digitalWrite(pul, HIGH);
    delayMicroseconds(1000);
    digitalWrite(pul, LOW);
    delayMicroseconds(1000);
  }

 delay(1000);

  digitalWrite(dir, LOW);
/*Turns the motor 400 steps*/
  for (int i = 0; i < 400; i++)
  {
    digitalWrite(pul, HIGH);
    delayMicroseconds(1000);
    digitalWrite(pul, LOW);
    delayMicroseconds(1000);
  }

delay(1000);

 }

is Arduino slave or master?

Arduino is the slave.

then setup the registers. the library has examples


text:
Quadcopter oscillation using PID
I am building an Arduino based flight controller for a quadcopter and have got it flying but it is not performing how I want it to. The drone is flying but when I release the sticks the drone does  not stay perfectly still. There is some random and small oscillations that occur when it is just hovering.
Right now I am using a single PID controller for each axis though functions like this.
dt=0.005;
error = *in - *set;

P = (error * kp);
I = I + (error * ki)*dt;
D_M = ((*in - in1)*kd)/dt;
D_E = ((error - error1)*kd)/dt;
D=D_M*(1-jerk) + D_E*(jerk);

I = constrain(I, LOWER_BOUND*0.75, UPPER_BOUND*0.75);
in1 = *in;
error1 = error;
pid = P + I + D;

pid = constrain(pid, LOWER_BOUND, UPPER_BOUND);
*out = pid;

The error is the Euler angle and the setpoint is the angle I want it to go to.
I then output the PID controller values to the motors using the Arudino Servo library.
  motor1 = throttle;
  motor2 = throttle;
  motor3 = throttle;
  motor4 = throttle;

  motor1 += rollOUT;
  motor2 += rollOUT;
  motor3 -= rollOUT;
  motor4 -= rollOUT;

  motor1 -= pitchOUT;
  motor2 += pitchOUT;
  motor3 -= pitchOUT;
  motor4 += pitchOUT;

  motor1 += yawOUT;
  motor2 -= yawOUT;
  motor3 -= yawOUT;
  motor4 += yawOUT;

Is there something I am missing about quadcopter PID controllers? Thank you for the help!

Are the disturbances due to external effects (wind and turbulence)? Do they occur in still air, such as in a quiet indoor environment? In other words, can you tell whether the PID controller is the source of the problem or is just less-than-perfect at overcoming external forces? A feedback controller depends on the error-signal as its source of information, so by definition, it can never do a perfect job. If it could, its source of information would go to zero, i.e., it would "blind" itself.

@JRobert I am flying indoor with no outside disturbance. The quad flys and stays extremely steady for about 2 seconds and then these small but random "bumps" make itnwobble before it steadies out again. I've read that some people use angular rates instead of angles? Is that common? And if so how do I know the angular rate to set it at with a certain error?

I'm beyond my knowledge here (no drone experience), but I have to wonder about the "steady - wobble - steady again" cycles, especially if they are regular. Something seems to be disturbing it - software, electronic, atmospheric - especially since it seems very capable of holding steady, even if its only for short periods. It might be interesting (but challenging ): to log some raw sensor data and look for corresponding noise or other displacements.

Check kd relative to the measurement error.  Maybe the measurement error noise is significant enough that multiplying its derivative by your 200*kd factor is enough to bump the system.

I'd suggest setting Kd to zero, Kp to a minimal value and letting the integral alone function as the controller. Any response to an error might be slow but the integrator alone will control a process with zero error. After observing the response of the integral for a period of time, hopefully without the problem you referenced, gradually introduce proportional control and watch for the periodic instability. If increasing the proportional gain results in oscillation, reduce the proportional back to a stable value and gradually introduce more derivative gain. I have worked with PID throughout my career and the instability you described sounds like something I'd expect to see originating from the derivative control action. No sensor is perfectly noise free and even if the noise is low amplitude, the rate of change may still be fairly large which will result in a very obvious periodic instability in the flight of your drone.
If this is the case, finding the source of the induced noise may not be easy. Perhaps reducing the derivative gain and using mostly proportional and integral control will effectively filter and attenuate the instability you're noticing. Good luck.

"Good luck." It's difficult to say, being four years later, whether or not they'll get that. I'll vote it up for the effort and that someone may find it useful.

I saw it was dated 2019 but thought the reply might benefit others struggling with debugging PID control and tuning issues. Isolating PID related operational perturbations is a fairly common event in a number of industries well outside of drones. - JL


text:
Unable to set LCD contrast using DAC pin on ESP32
I have followed the instructions at https://www.arduino.cc/en/Tutorial/HelloWorld and have my LCD displaying some text. I've also connected the LED back light (LCD pins 15&16).
I wanted to replace the potentiometer used to set the contrast, with a connection to the DAC pin. It needs to be about 0.8V.
When I connect the contrast pin from the LCD to my DAC pin on my ESP32 board, it doesn't work, the contrast is too high. Using a volt meter, it measures about 2.5V.
If I disconnect the LCD contrast pin from my DAC pin, the voltage measured is 0.8V.
Any ideas or examples on how to control the LCD contrast using a DAC pin?
I wondered if I need to add a resistor or something.

https://www.esp32.com/viewtopic.php?t=5098

The DAC in the ESP32 is ok for sourcing current but not so good at sinking current, and that is what you need.
A amplifier set up as a voltage follower would work.

Could a simple pull-down resistor work as well?

Sure. Much easier :) It would need to be a balance. Low enough to pull down but not too strong for the output.

Got more details please?

One Ohm would look like a short. 10K would look like it wasn't even there. I would try something like 150-330 Ohms. You could try a resistor by itself. Find one that gives you a reasonable contrast. Then go a little lower in resistance and add the D/A output. The resistance on its own does the pulling down, the D/A just is there to bring it back some.

Sorry, I meant where do I connect what? (iI'm a noob)

Connect one side of the resistor to the contrast pin, the other to ground. After you are happy with the resistor value then connect the D/A output to the contrast pin.


text:
How can I reduce the memory usage on my code?
I wrote this code to control my christmas tree. It takes up the majority of the memory on my Arduino Uno:
Sketch uses 31822 bytes (98%) of program storage space. Maximum is 32256 bytes.
Global variables use 1882 bytes (91%) of dynamic memory, leaving 166 bytes for local variables. Maximum is 2048 bytes.
Low memory available, stability problems may occur.

Does anyone know how I can reduce the memory usage?
Code:
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>

#define TREEONE 3
#define TREETWO 4
#define TREETHREE 5
#define TREEFOUR 10

SdFat sd;
SFEMP3Shield MP3player;

const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
//10 for basement 50 for testing

const uint16_t monoMode = 1;

int song = 3;
int num = 0;
int count = 0;

//put arrays here
byte arrayTree[] = {17,16,9,8,3,2,5,4,17,16,9,8,3, ...etc };

void setup() {
  initSD();
  initMP3Player();

  pinMode(TREEONE, OUTPUT);
  pinMode(TREETWO, OUTPUT);
  pinMode(TREETHREE, OUTPUT);
  pinMode(TREEFOUR, OUTPUT);

  digitalWrite(TREEONE, HIGH);
  digitalWrite(TREETWO, HIGH);
  digitalWrite(TREETHREE, HIGH);
  digitalWrite(TREEFOUR, HIGH);
}

void loop() {
  if(!MP3player.isPlaying()){
    MP3player.playTrack(song);
    MetallicaChristmas();
  }
}

void initSD() {
  if(!sd.begin(SD_SEL, SPI_HALF_SPEED))
    sd.initErrorHalt();
  if(!sd.chdir("/"))
    sd.errorHalt("sd.chdir");
}

void initMP3Player() {
  uint8_t result = MP3player.begin();
  MP3player.setVolume(volume, volume);
  MP3player.setMonoMode(monoMode);
}

void treeFunc() {
    //delay(arrayTimes[i]);
    num = arrayTree[count];

    //TREEONE
    if(num>15){
      if((num%2)==0){
        digitalWrite(TREEONE,HIGH);
      }else{
        digitalWrite(TREEONE,LOW);
      }
    }
    //TREETWO
    if((num%16)>7){
      if((num%2)==0){
        digitalWrite(TREETWO,HIGH);
      }else{
        digitalWrite(TREETWO,LOW);
      }
    }
    //TREETHREE
    if((num%8)>3){
      if((num%2)==0){
        digitalWrite(TREETHREE,HIGH);
      }else{
        digitalWrite(TREETHREE,LOW);
      }
    }
    //TREEFOUR
    if((num%4)>1){
      if((num%2)==0){
        digitalWrite(TREEFOUR,HIGH);
      }else{
        digitalWrite(TREEFOUR,LOW);
      }
    }
  count = count + 1;
}

void MetallicaChristmas()
{
  //event 1
  delay(670);
  treeFunc();
  delay(248);
  treeFunc();
  //event 2
  delay(116);
  treeFunc();
  delay(248);
  treeFunc();
  //event 3
  delay(100);
  treeFunc();
  delay(248);
  treeFunc();
  //event 4
  delay(132);
  treeFunc();
  delay(248);
  treeFunc();
  //event 5
  delay(125);
  treeFunc();
  delay(248);
  treeFunc();
  //event 6

  ...etc.

I see some ints that could be replaced with byte, that would save a couple of bytes. Other than that, it seems to be the libraries you are using.   If you need more room tho, jump to a '1284P processor. 128K of flash, 16k SRAM. I offer boards in several form factors, your code will port right over with the MightyCore add-in to the Arduino IDE.  https://www.crossroadsfencing.com/BobuinoRev17

Please show the full sketch. How long is the arrayTree array? Is every other number 1 less than the previous number? How long is the MetallicaChristmas function? There is a smaller sdfat library, but I don't know if it is compatible with SFEMP3Shield. Read about PROGMEM and struct.

I think that if you store the delays in an array, just like arrayTree. And use PROGMEM on both arrays your code will become smaller and use less dynamic memory. And also make it easier to read/maintain.

Without a full sketch, we can not compile it ourself to see how far we can get to reduce memory usage.

O, there it is: https://arduino.stackexchange.com/questions/60109/problem-with-mp3-shield-and-function-calling-combination

As well as PROGMEM (as described in the comments), there are a couple of other efficiencies that you can make:

A function call is expensive (takes a lot of code space), and you are performing a LOT of them!

The repetitious calls to delay() followed by treeFunc() are wasteful. Your commented-out line
//delay(arrayTimes[i]);

looks like you were going to do the right thing, so I’d restore that (use count instead of i) and put the delay() numbers in a new int arrayTimes[] array.
PROGMEM this array too, of course!
Once you’ve done this, you can remove all the calls to delay(). You’ll be left with nothing but repeated calls to treefunc(), which you can replace with a single loop:
for (count=0;count<sizeof(arrayTree);++count) {
   treeFunc();
} // for

Don’t forget to get rid of the count = count + 1; line from treeFunc() - it’s now in the for loop.

Also expensive is calling the same function twice except with different parameters in both sides of the if in treeFunc(). Instead of:
if (<condition>) {
   Function(1);
} // if
else {
   Function(0);
} // else

you can instead do:
Function(<condition>);

For this to work, you need to know that HIGH has the value 1 and LOW has the value 0 - and that a true condition has the value 1 and a false condition has the value 0.
So, you need to change the if () slightly:
digitalWrite(THREEONE, (num%2)>0);

Finally, the mod % operator itself is very expensive, since it is effectively a division, and the Arduino chip doesn’t know how to divide - so the code to do so is large. But the code you’ve written is using binary arithmetic, which the Arduino can do instantly - you just have to write it as such.

Instead of (num%2)>0 use num & B0001.
Instead of (num%4)>1 use num & B0010.
Instead of (num%8)>3 use num & B0100.
Instead of (num%16)>7 use num & B1000.

You’ve probably copied the guts of this code from somewhere else, and while it works it isn’t very efficient. Writing the code as above will greatly reduce your code size, exchanging repeated calls for much smaller PROGMEM arrays.


text:
Problem with MP3 Shield and function calling combination
I wrote this code to control my Christmas tree. It plays the Holy Night Code perfectly but never transitions to the next song. In addition, it plays random notes after the song is finished. Does anyone know what the error is?
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>

#define TREEONE 3
#define TREETWO 4
#define TREETHREE 5
#define TREEFOUR 10

SdFat sd;
SFEMP3Shield MP3player;

const uint8_t volume = 10; // MP3 Player volume 0=max, 255=lowest (off)
//10 for basement 50 for testing

const uint16_t monoMode = 1;

byte song = 1;
byte totalsongs = 10;
int num = 0;
int i;

//put arrays here
const PROGMEM uint16_t arrayTimesMC[] = {670, 249, 116, 249, 100, 249, 132, 249, 125, 249, 102, 249, 116, 249, 82, 249, 130, 249, 118, 249, 94, 249, 125, 249, 100, 249, 110, 249, 95, 249, 134, 249, 156, 249, 125, 249, 107, 249, 142, 249, 110, 249, 73, 249, 96, 249, 119, 249, 115, 249, 83, 249, 101, 249, 168, 249, 120, 249, 111, 249, 108, 249, 102, 249, 104, 249, 106, 249, 115, 249, 122, 249, 136, 249, 100, 249, 99, 249, 136, 249, 138, 249, 113, 249, 111, 249, 117, 249, 148, 249, 115, 249, 102, 249, 100, 249, 108, 249, 140, 249, 115, 249, 93, 249, 148, 249, 119, 249, 91, 249, 136, 249, 84, 249, 185, 249, 104, 249, 126, 249, 148, 249, 83, 249, 74, 249, 97, 249, 105, 249, 166, 249, 128, 249, 95, 249, 158, 249, 122, 249, 220, 249, 42, 249, 66, 249, 180, 249, 387, 249, 236, 249, 350, 249, 3571, 249, 622, 249, 744, 249, 711, 249, 707, 249, 727, 249, 691, 249, 682, 249, 570, 198, 0, 249, 333, 249, 67, 249, 401, 249, 103, 249, 355, 249, 107, 249, 712, 249, 687, 249, 749, 249, 688, 249, 424, 249, 53, 249, 371, 249, 92, 249, 330, 249, 112, 249, 387, 249, 98, 249, 709, 249, 704, 249, 702, 249, 693, 249, 785, 249, 33, 147, 0, 171, 0, 249, 93, 249, 64, 124, 0, 165, 0, 249, 100, 249, 82, 149, 0, 137, 0, 249, 56, 249, 66, 148, 0, 142, 0, 249, 124, 249, 59, 216, 0, 190, 0, 249, 87, 249, 14, 171, 0, 105, 0, 74, 0, 249, 46, 249, 38, 150, 0, 183, 0, 249, 67, 249, 46, 152, 0, 192, 0, 249, 55, 249, 30, 182, 0, 136, 0, 172, 0, 166, 0, 249, 73, 162, 0, 160, 0, 175, 0, 141, 0, 249, 56, 179, 0, 158, 0, 155, 0, 160, 0, 249, 54, 249, 58, 249, 91, 119, 0, 112, 0, 162, 0, 200, 0, 136, 0, 152, 0, 181, 0, 199, 0, 249, 59, 249, 64, 122, 0, 142, 0, 156, 0, 216, 0, 154, 0, 130, 0, 160, 0, 209, 0, 249, 49, 249, 102, 125, 0, 132, 0, 205, 0, 224, 0, 158, 0, 164, 0, 162, 0, 172, 0, 174, 0, 139, 0, 173, 0, 148, 0, 169, 0, 170, 0, 113, 0, 178, 0, 170, 0, 108, 0, 124, 0, 249, 10, 144, 0, 100, 0, 208, 0, 138, 0, 249, 225, 215, 0, 249, 59, 249, 4, 249, 77, 249, 84, 249, 32, 249, 90, 249, 54, 249, 89, 249, 20, 89, 0, 249, 43, 249, 50, 249, 69, 249, 58, 249, 89, 249, 67, 249, 48, 249, 50, 249, 88, 249, 58, 249, 59, 249, 108, 249, 157, 239, 0, 249, 78, 249, 74, 249, 25, 249, 104, 249, 111, 249, 32, 249, 56, 249, 76, 249, 42, 249, 104, 249, 36, 249, 58, 249, 88, 249, 48, 249, 73, 249, 73, 249, 78, 249, 39, 249, 94, 249, 124, 249, 67, 249, 92, 249, 60, 249, 47, 150, 0, 169, 0, 249, 101, 249, 5, 166, 0, 144, 0, 249, 102, 249, 22, 196, 0, 173, 0, 249, 81, 249, 12, 136, 0, 209, 0, 249, 69, 249, 325, 249, 77, 249, 303, 249, 142, 249, 373, 249, 124, 249, 365, 249, 122, 249, 354, 249, 34, 249, 367, 249, 104, 249, 402, 249, 86, 249, 404, 249, 110, 249, 332, 249, 51, 249, 381, 249, 92, 249, 402, 249, 76, 249, 406, 249, 38, 249, 404, 249, 48, 249, 420, 249, 64, 249, 418, 249, 82, 249, 369, 249, 63, 249, 442, 249, 11, 249, 362, 249, 92, 249, 423, 249, 70, 249, 380, 249, 57, 249, 369, 249, 104, 249, 354, 249, 98, 249, 410, 249, 72, 249, 424, 249, 50, 249, 768, 249, 61, 170, 0, 131, 0, 153, 0, 206, 0, 249, 40, 129, 0, 162, 0, 146, 0, 184, 0, 249, 103, 129, 0, 156, 0, 131, 0, 186, 0, 249, 79, 176, 0, 131, 0, 141, 0, 194, 0, 249, 60, 146, 0, 154, 0, 135, 0, 201, 0, 249, 67, 147, 0, 155, 0, 143, 0, 194, 0, 249, 220, 102, 0, 104, 0, 249, 55, 249, 56, 249, 374, 249, 725, 249, 723, 249, 673, 249, 689, 249, 711, 249, 744, 249, 751, 249, 617, 249, 753, 249, 698, 249, 760, 249, 74, 161, 0, 212, 0, 249, 17, 249, 50, 132, 0, 172, 0, 249, 64, 249, 34, 149, 0, 191, 0, 249, 94, 249, 96, 124, 0, 151, 0, 249, 66, 249, 18, 203, 0, 146, 0, 228, 0, 132, 0, 249, 62, 162, 0, 170, 0, 175, 0, 162, 0, 249, 79, 164, 0, 218, 0, 166, 0, 148, 0, 249, 38, 249, 37, 249, 66, 123, 0, 138, 0, 166, 0, 194, 0, 166, 0, 155, 0, 165, 0, 165, 0, 249, 23, 249, 100, 142, 0, 162, 0, 150, 0, 172, 0, 142, 0, 136, 0, 168, 0, 249, 10, 249, 14, 249, 114, 151, 0, 249, 41, 162, 0, 249, 118, 249, 16, 163, 0, 152, 0, 249, 90, 249, 30, 167, 0, 167, 0, 249, 121, 249, 16, 192, 0, 168, 0, 249, 71, 249, 74, 123, 0, 163, 0, 249, 115, 249, 32, 155, 0, 166, 0, 249, 90, 249, 45, 139, 0, 149, 0, 249, 117, 249, 62, 182, 0, 189, 0, 249, 42, 249, 39, 142, 0, 173, 0, 145, 0, 156, 0, 249, 60, 183, 0, 141, 0, 155, 0, 182, 0, 249, 39, 175, 0, 170, 0, 155, 0, 149, 0, 249, 103, 249, 42, 249, 118, 118, 0, 132, 0, 136, 0, 222, 0, 134, 0, 136, 0, 162, 0, 184, 0, 249, 36, 249, 106, 142, 0, 120, 0, 140, 0, 232, 0, 184, 0, 139, 0, 158, 0, 214, 0, 239, 0, 249, 156, 110, 0, 112, 0, 228, 0, 192, 0, 168, 0, 146, 0, 176, 0, 172, 0, 163, 0, 112, 0, 173, 0, 239, 0, 120, 0, 172, 0, 146, 0, 173, 0, 140, 0, 136, 0, 191, 0, 92, 0, 125, 0, 165, 0, 162, 0, 216, 0, 249, 55, 158, 0, 128, 0, 249, 95, 249, 60, 221, 0, 127, 0, 249, 102, 249, 24, 148, 0, 155, 0, 249, 74, 249, 62, 153, 0, 138, 0, 249, 115, 249, 64, 165, 0, 147, 0, 249, 77, 249, 56, 143, 0, 163, 0, 249, 100, 249, 58, 168, 0, 146, 0, 249, 80, 249, 45, 158, 0, 168, 0, 249, 110, 249, 31, 168, 0, 134, 0, 249, 38, 104, 0, 187, 0, 134, 0, 160, 0, 132, 0, 135, 0, 142, 0, 249, 108, 145, 0, 157, 0, 154, 0, 152, 0, 249, 82, 136, 0, 163, 0, 165, 0, 146, 0, 249, 459, 117, 0, 146, 0, 249, 90, 130, 0, 166, 0, 154, 0, 194, 0, 249, 68, 154, 0, 140, 0, 158, 0, 168, 0, 249, 97, 155, 0, 146, 0, 134, 0, 184, 0, 249, 708, 249, 710, 249, 741, 249, 708, 249, 419, 126, 0, 119, 0, 82, 0, 112, 0, 84, 0, 98, 0, 86, 0, 109, 0, 98, 0, 113, 0, 249, 63, 55, 0, 158, 0, 135, 0, 210, 0, 161, 0, 138, 0, 249, 61, 141, 0, 195, 0, 139, 0, 155, 0, 223, 0, 248};
const PROGMEM byte arrayTreeMC[] = {17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 5, 4, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 5, 4, 9, 8, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 3, 2, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 31, 30, 31, 30, 31, 30, 31, 30, 5, 4, 5, 4, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 31, 30, 31, 30, 31, 30, 31, 30, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 5, 4, 11, 10, 17, 16, 15, 14, 3, 2, 5, 4, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 5, 4, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 17, 16, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 13, 12, 3, 2, 3, 2, 5, 4, 9, 8, 9, 8, 17, 16, 9, 8, 3, 2, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 9, 8, 9, 8, 17, 16, 17, 16, 17, 16, 5, 4, 3, 2, 3, 2, 5, 4, 5, 4, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 9, 8, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 17, 16, 17, 16, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 9, 8, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 31, 30, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 9, 8, 31, 30, 17, 16, 9, 8, 17, 16, 17, 16, 3, 2, 5, 4, 9, 8, 17, 16, 31, 30, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 5, 4, 3, 2, 9, 8, 3, 2, 5, 4, 3, 2, 17, 16, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 17, 16, 3, 2, 5, 4, 3, 2, 5, 4, 11, 10, 21, 20, 11, 10, 21, 20, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 17, 16, 17, 16, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 17, 16, 9, 8, 5, 4, 3, 2, 3, 2, 5, 4, 9, 8, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 9, 8, 17, 16, 13, 12, 11, 10, 21, 20, 11, 10, 21, 20, 3, 2, 11, 10, 29, 28, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 21, 20, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 31, 30, 11, 10, 21, 20, 11, 10, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 21, 20, 11, 10, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 9, 8, 3, 2, 5, 4, 17, 16, 3, 2, 9, 8, 5, 4, 17, 16, 3, 2, 5, 4, 9, 8, 3, 2, 17, 16, 5, 4, 31, 30};
const PROGMEM uint16_t arrayTimesHN[] = {28, 246, 1542, 246, 646, 246, 390, 246, 38, 246, 1222, 246, 70, 246, 358, 246, 70, 246, 326, 246, 70, 246, 1542, 246, 326, 246, 70, 246, 358, 246, 70, 246, 650, 246, 290, 246, 70, 246, 680, 246, 320, 246, 70, 246, 1550, 246, 1540, 246, 640, 246, 330, 246, 70, 246, 1250, 246, 70, 246, 360, 246, 70, 246, 330, 246, 0, 246, 1550, 246, 390, 246, 0, 246, 360, 246, 70, 246, 650, 246, 320, 246, 100, 246, 620, 246, 360, 246, 70, 246, 1540, 246, 1250, 246, 40, 246, 650, 246, 670, 246, 650, 246, 650, 246, 350, 246, 40, 246, 360, 246, 40, 246, 640, 246, 360, 246, 40, 246, 610, 246, 680, 246, 620, 246, 710, 246, 350, 246, 40, 246, 330, 246, 70, 246, 1540, 246, 680, 246, 640, 246, 650, 246, 360, 246, 40, 246, 630, 246, 660, 246, 640, 246, 360, 246, 70, 246, 650, 246, 640, 246, 330, 246, 70, 246, 330, 246, 70, 246, 640, 246, 650, 246, 640, 246, 360, 246, 70, 246, 620, 246, 640, 246, 650, 246, 360, 246, 70, 246, 610, 246, 680, 246, 640, 246, 330, 246, 100, 246, 650, 246, 610, 246, 360, 246, 70, 246, 360, 246, 40, 246, 640, 246, 650, 246, 640, 246, 650, 246, 680, 246, 610, 246, 650, 246, 680, 246, 610, 246, 650, 246, 670, 246, 650, 246, 680, 246, 640, 246, 650, 246, 360, 246, 40, 246, 640, 246, 650, 246, 250, 246, 250, 246, 246};
const PROGMEM byte arrayTreeHN[] = {31, 30, 17, 16, 17, 16, 17, 16, 9, 8, 9, 8, 5, 4, 5, 4, 9, 8, 5, 4, 3, 2, 5, 4, 5, 4, 9, 8, 17, 16, 5, 4, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 31, 30, 31, 30, 31, 30, 17, 16, 17, 16, 9, 8, 9, 8, 5, 4, 5, 4, 9, 8, 5, 4, 3, 2, 31, 30, 5, 4, 9, 8, 17, 16, 7, 6, 17, 16, 9, 8, 5, 4, 3, 2, 5, 4, 31, 30, 31, 30, 9, 8, 9, 8, 5, 4, 17, 16, 9, 8, 5, 4, 9, 8, 3, 2, 9, 8, 5, 4, 9, 8, 9, 8, 9, 8, 5, 4, 17, 16, 9, 8, 5, 4, 9, 8, 3, 2, 9, 8, 5, 4, 3, 2, 21, 20, 21, 20, 5, 4, 9, 8, 5, 4, 21, 20, 21, 20, 21, 20, 9, 8, 3, 2, 11, 10, 11, 10, 17, 16, 17, 16, 17, 16, 9, 8, 21, 20, 29, 28, 21, 20, 9, 8, 3, 2, 19, 18, 19, 18, 23, 22, 9, 8, 5, 4, 19, 18, 19, 18, 5, 4, 9, 8, 17, 16, 11, 10, 11, 10, 17, 16, 5, 4, 17, 16, 17, 16, 11, 10, 11, 10, 5, 4, 3, 2, 21, 20, 21, 20, 17, 16, 3, 2, 19, 18, 13, 12, 15, 14, 29, 28, 21, 20, 9, 8, 5, 4, 3, 2, 5, 4, 19, 18, 31, 30, 31, 30, 31, 30, 30};

//put arrays here

void setup() {
  initSD();
  initMP3Player();

  pinMode(TREEONE, OUTPUT);
  pinMode(TREETWO, OUTPUT);
  pinMode(TREETHREE, OUTPUT);
  pinMode(TREEFOUR, OUTPUT);

  digitalWrite(TREEONE, HIGH);
  digitalWrite(TREETWO, HIGH);
  digitalWrite(TREETHREE, HIGH);
  digitalWrite(TREEFOUR, HIGH);
}

void loop() {
  MP3player.playTrack(2);
  OHolyNight();
  delay(92000);
  MP3player.stopTrack();

  MP3player.playTrack(3);
  MetallicaChristmas();
  delay(192000);
  MP3player.stopTrack();
}

void initSD() {
  if (!sd.begin(SD_SEL, SPI_HALF_SPEED))
    sd.initErrorHalt();
  if (!sd.chdir("/"))
    sd.errorHalt("sd.chdir");
}

void initMP3Player() {
  uint8_t result = MP3player.begin();
  MP3player.setVolume(volume, volume);
  MP3player.setMonoMode(monoMode);
}

void AllLights() {
  digitalWrite(TREEONE, LOW);
  digitalWrite(TREETWO, LOW);
  digitalWrite(TREETHREE, LOW);
  digitalWrite(TREEFOUR, LOW);
}

void MetallicaChristmas() {
  for (i = 0; i < sizeof(arrayTimesMC); i++) {
    delay(pgm_read_word_near(arrayTimesMC + i));
    num = pgm_read_byte_near(arrayTreeMC + i);

    if (num > 15) {
      if ((num % 2) == 0) {
        digitalWrite(TREEONE, HIGH);
      } else {
        digitalWrite(TREEONE, LOW);
      }
    }
    if ((num % 16) > 7) {
      if ((num % 2) == 0) {
        digitalWrite(TREETWO, HIGH);
      } else {
        digitalWrite(TREETWO, LOW);
      }
    }
    if ((num % 8) > 3) {
      if ((num % 2) == 0) {
        digitalWrite(TREETHREE, HIGH);
      } else {
        digitalWrite(TREETHREE, LOW);
      }
    }
    if ((num % 4) > 1) {
      if ((num % 2) == 0) {
        digitalWrite(TREEFOUR, HIGH);
      } else {
        digitalWrite(TREEFOUR, LOW);
      }
    }
    if (i == sizeof(arrayTimesMC)) {
      break;
    }
  }
}

void OHolyNight() {
  for (i = 0; i < sizeof(arrayTimesHN); i++) {
    delay(pgm_read_word_near(arrayTimesHN + i));
    num = pgm_read_byte_near(arrayTreeHN + i);

    if (num > 15) {
      if ((num % 2) == 0) {
        digitalWrite(TREEONE, HIGH);
      } else {
        digitalWrite(TREEONE, LOW);
      }
    }
    if ((num % 16) > 7) {
      if ((num % 2) == 0) {
        digitalWrite(TREETWO, HIGH);
      } else {
        digitalWrite(TREETWO, LOW);
      }
    }
    if ((num % 8) > 3) {
      if ((num % 2) == 0) {
        digitalWrite(TREETHREE, HIGH);
      } else {
        digitalWrite(TREETHREE, LOW);
      }
    }
    if ((num % 4) > 1) {
      if ((num % 2) == 0) {
        digitalWrite(TREEFOUR, HIGH);
      } else {
        digitalWrite(TREEFOUR, LOW);
      }
    }
    if (i == sizeof(arrayTimesHN)) {
      break;
    }
  }
}

I think this part  sizeof(arrayTimesHN) doesn't work as you think. the random notes may be played, because the for loop proceedes further than it should, reading memory, that does not belong to the array. Try to use a constant or a define at this point. Maybe someone else can write an answer,  what the sizeof really does here (I'm not sure about it and this is just a guess)

@chrisl The sizeof operator returns size of the variable in bytes. It's used on the array of uint16_t, so the result will be element count times 2. As it is now, it'll result in buffer overflow.

Well, it's not really buffer overflow as it's not overwritten, it's just reading the data beyond the end of array

Since KIIV didn't write an answer to this question, I will do it.
You are using this for loop:
for (i = 0; i < sizeof(arrayTimesHN); i++)

The sizeof() function will return the size of the array in bytes. Since the array is of type uint16_t, each element has a size of 2 bytes (16 bit). Concluding: The sizeof() function will return a number twice as high, as the actual element count of the array. The delays and state number, that you use for the LEDs, will be read from memory, that lies after the array. We don't know, what is saved there (or if there is actually some valid data or only random data), so this will seem random. That random notes are played by the MP3 Player must be a problem with the library (I'm not sure about that). What does the library do, if a song is finished, but you didn't call the stopTrack() method yet?

In the LED functions (for example OHolyNight()) you are using delays, but you also set a big delay after the execution of the function. I guess, the big delay is the duration of the song. So you delay twice. The first comes with the accumulated delays in the LED function (while the LED lights are changing). The second delay will kick in after that (when the LED function is finished). Maybe you thought, that it doesn't proceed to the next song, because you didn't wait for 92 seconds (your first big delay).

Lastly, in your LED functions you have this if statement:
if (i == sizeof(arrayTimesHN)) {
  break;
}

This is unnecessary, you used a for loop with the condition i < sizeof(arrayTimesHN), so that i cannot ever be equal to sizeof(arrayTimesHN) inside of the loop.


text:
4x4 keypad stops reacting
I am having an issue with the a 4×4 keypad. It usually works fine but sometimes the keypad stops reacting or no key is pressed but it still shows a random keypress on the LCD. The only solution is to unplug and plug again. I thought it may be the length of the wires for the keypad. I uses 3 ft wires from the keypad to the Arduino. Has anyone faced similar issues?

3' is not that long really, but the internal pullups of the Arduino are quite weak, and you are in what looks like a noisy (electrically speaking) environment. So maybe it is EMI causing things to happen that you don't want to happen. Consider making the keypad a standalone system with a balanced communication system between that and the main box.

The keypad and the LCD need to be connected to the arduino. I can power 5V to the LCD from a separate source, but the keypad has to be connected to the arduino.

What I am suggesting is have an Arduino (one of the small ones?) connected directly to the keypad (very short wires then), and use a serial protocol (rs232, rs485, etc) to connect that Arduino to the existing Arduino.

Try to test with Arduino, keypad, and LCD only to make sure that other components do not affect them. You can refer to Arduino - Keypad - LCD tutorial


text:
RTC shield with LCD and Keypad
I am having issues with a code that I have been modifying.
I can change the TIME, and DATE from a keypad, and see the data on the serial monitor, but it is not recording on the SD Card. Anyone that could help me. Thank you.
#include <OneWire.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include "RTClib.h"

LiquidCrystal_I2C lcd(0x27,20,4)

RTC_DS3231 rtc;
DateTime   now;

const byte ROWS = 4;
 const byte COLS = 4;
 char keys[ROWS][COLS] = {
 {'1','2','3','A'},
 {'4','5','6','B'},
 {'7','8','9','C'},
 {'*','0','#','D'}
 };

 byte rowPINS[ROWS] = {10,9,8,7};
 byte colPINS[COLS] = {6,5,4,11};

 int i1,i2,i3,i4;
 char c1,c2,c3,c4;
 char keypressed;

 Keypad myKeypad = Keypad(makeKeymap(keys),rowPINS,colPINS, ROWS, COLS);

#define DS18B20_PIN   A3

File dataLog;
boolean sd_ok = 0;

void setup()
{

  rtc.begin();          // initialize RTC chip

  lcd.init();     // initialize LCD module
  lcd.backlight();
  lcd.setCursor(0, 3);  // move cursor to column 0, row 3 (last row)
  lcd.print("Temp:");

// open serial communications and wait for port to open:
  Serial.begin(9600);
  Serial.print("Initializing SD card...");

// initialize the SD card
  if ( !SD.begin() )
    Serial.println(F("initialization failed!"));  // initialization error
else {   // initialization OK
    sd_ok = 1;
    Serial.println(F("initialization done."));
    if( SD.exists("Log.txt") == 0 )   // test if file with name 'Log.txt' already exists
    {  // create a text file named 'Log.txt'
      Serial.print("\r\nCreate 'Log.txt' file ... ");
      dataLog = SD.open("Log.txt", FILE_WRITE);   // create (&open) file Log.txt
      if(dataLog) {                               // if the file opened okay, write to it:
        Serial.println(F("OK"));
        // write some texts to 'Log.txt' file
        dataLog.println("    DATE    |    TIME  | TEMPERATURE");
        dataLog.println("(dd-mm-yyyy)|(hh:mm:ss)|");
        dataLog.close();   // close the file
      }
      else
        Serial.println(F("error creating file."));
    }
  }
   Serial.println(F("\r\n    DATE    |    TIME  | TEMPERATURE"));
   Serial.println(F("(dd-mm-yyyy)|(hh:mm:ss)|"));
}

// main loop
void loop()
{
  now = rtc.now();  // read current time and date from the RTC chip
  RTC_display();    // display time & calendar

  while(keypressed == NO_KEY){

  keypressed = myKeypad.getKey();

  now = rtc.now();  // read current time and date from the RTC chip
  RTC_display();    // display time & calendar

static byte p_second;
  if( (now.second()-1==0) ||  (now.second() % 5 == 0) && (p_second != now.second()) )
  {   // read & print temperature value from sensor every 10 seconds
    unsigned int ds18b20_temp;
    char buffer1[12], buffer2[26];
    bool sensor_ok = 0;

    p_second = now.second();
    if( ds18b20_read(&ds18b20_temp) )
    {
      sensor_ok = 1;
      if (ds18b20_temp & 0x8000)           // if temperature < 0
      {
        ds18b20_temp = ~ds18b20_temp + 1;  // change temperature value to positive form
        sprintf(buffer1, "-%02u.%04u%cC", (ds18b20_temp/16) % 100, (ds18b20_temp & 0x0F) * 625, 223);
      }
      else
      {      // otherwise (temperature >= 0)
        if (ds18b20_temp/16 >= 100)          // if temperature >= 100.0 °C
          sprintf(buffer1, "%03u.%04u%cC", ds18b20_temp/16, (ds18b20_temp & 0x0F) * 625, 223);
        else      // otherwise ( 0 <= temperature < 100.0)
          sprintf(buffer1, " %02u.%04u%cC", ds18b20_temp/16, (ds18b20_temp & 0x0F) * 625, 223);
      }
    }
    else
      sprintf(buffer1, "   ERROR  ");

    lcd.setCursor(5, 3);
    lcd.print(buffer1);

    sprintf( buffer2, " %02u-%02u-%04u | %02u:%02u:%02u | ", now.day(), now.month(), now.year(),
                      now.hour(), now.minute(), now.second() );
    if(sensor_ok) {
      buffer1[8] = 194;   // put degree symbol
      buffer1[9] = 176;
      buffer1[10] = 'C';  // put 'C' letter
      buffer1[11] = '\0'; // put string terminator
    }
    // print data on PC serial monitor
    Serial.print(buffer2);
    Serial.println(buffer1);
    // write data to SD card
    if(sd_ok)
    {  // if the SD card was successfully initialized
      // open Log.txt file with write permission
      dataLog = SD.open("Log.txt", FILE_WRITE);
      dataLog.print( buffer2 );
      dataLog.println( buffer1 );
      dataLog.close();   // close the file
    }

  }

  delay(100);   // wait 100ms

  }

if (keypressed == '*')
             {
              lcd.clear();
              lcd.print("     Setup");
             delay(1000);
              lcd.clear();
              lcd.print("Setup year");

             char keypressed2 = myKeypad.waitForKey();
                    if (keypressed2 != NO_KEY && keypressed2 !='*' && keypressed2 !='#' && keypressed2 !='A' && keypressed2 !='B' && keypressed2 !='C' && keypressed2 !='D' )
                      {
                       c1 = keypressed2;
                       lcd.setCursor(0, 1);
                       lcd.print(c1);
                       }
                 char      keypressed3 = myKeypad.waitForKey();
                    if (keypressed3 != NO_KEY && keypressed3 !='*' && keypressed3 !='#' && keypressed3 !='A' && keypressed3 !='B' && keypressed3 !='C' && keypressed3 !='D' )
                      {
                       c2 = keypressed3;
                       lcd.setCursor(1, 1);
                       lcd.print(c2);
                       }
                   char  keypressed4 = myKeypad.waitForKey();
                   if (keypressed4 != NO_KEY && keypressed4 !='*' && keypressed4 !='#' && keypressed4 !='A' && keypressed4 !='B' && keypressed4 !='C' && keypressed4 !='D' )
                      {
                       c3 = keypressed4;
                       lcd.setCursor(2, 1);
                       lcd.print(c3);
                       }
                   char   keypressed5 = myKeypad.waitForKey();
                   if (keypressed5 != NO_KEY && keypressed5 !='*' && keypressed5 !='#' && keypressed5 !='A' && keypressed5 !='B' && keypressed5 !='C' && keypressed5 !='D' )
                      {
                       c4 = keypressed5;
                       lcd.setCursor(3, 1);
                       lcd.print(c4);
                       }

                     i1=(c1-48)*1000;        //the keys pressed are stored into chars I convert them to int then i did some multiplication to get the code as an int of xxxx
                     i2=(c2-48)*100;
                     i3=(c3-48)*10;
                     i4=c4-48;
                     int N_year=i1+i2+i3+i4;
                   delay(500);
                     lcd.clear();
                     lcd.print("Setup month");

////////////////////////////////////////////////////////////////
                     char keypressed6 = myKeypad.waitForKey();  // here all programs are stopped until you enter the four digits then it gets compared to the code above
                    if (keypressed6 != NO_KEY && keypressed6 !='*' && keypressed6 !='#' && keypressed6 !='A' && keypressed6 !='B' && keypressed6 !='C' && keypressed6 !='D' )
                      {
                       c1 = keypressed6;
                       lcd.setCursor(0, 1);
                       lcd.print(c1);
                       }
                    char   keypressed7 = myKeypad.waitForKey();
                    if (keypressed7 != NO_KEY && keypressed7 !='*' && keypressed7 !='#' && keypressed7 !='A' && keypressed7 !='B' && keypressed7 !='C' && keypressed7 !='D' )
                      {
                       c2 = keypressed7;
                       lcd.setCursor(1, 1);
                       lcd.print(c2);
                       }

                     i1=(c1-48)*10;
                     i2=c2-48;
                    int N_month=i1+i2;
                     delay(500);

                     lcd.clear();
                     lcd.print("Setup Day");

 ////////////////////////////////////////////////////////////////
                      char keypressed8 = myKeypad.waitForKey();  // here all programs are stopped until you enter the four digits then it gets compared to the code above
                    if (keypressed8 != NO_KEY && keypressed8 !='*' && keypressed8 !='#' && keypressed8 !='A' && keypressed8 !='B' && keypressed8 !='C' && keypressed8 !='D' )
                      {
                        c1 = keypressed8;
                       lcd.setCursor(0, 1);
                       lcd.print(c1);
                       }
                      char keypressed9 = myKeypad.waitForKey();
                    if (keypressed9 != NO_KEY && keypressed9 !='*' && keypressed9 !='#' && keypressed9 !='A' && keypressed9 !='B' && keypressed9 !='C' && keypressed9 !='D' )
                      {
                        c2 = keypressed9;
                       lcd.setCursor(1, 1);
                       lcd.print(c2);
                       }

                     i1=(c1-48)*10;
                     i2=c2-48;
                    int N_day=i1+i2;
                    delay(500);
                     lcd.clear();
                     lcd.print("Setup hour");

////////////////////////////////////////////////////////////////////////////////////:
                     char keypressed10 = myKeypad.waitForKey();  // here all programs are stopped until you enter the four digits then it gets compared to the code above
                    if (keypressed10 != NO_KEY && keypressed10 !='*' && keypressed10 !='#' && keypressed10 !='A' && keypressed10 !='B' && keypressed10 !='C' && keypressed10 !='D' )
                      {
                       c1 = keypressed10;
                       lcd.setCursor(0, 1);
                       lcd.print(c1);
                       }
                    char   keypressed11 = myKeypad.waitForKey();
                    if (keypressed11 != NO_KEY && keypressed11 !='*' && keypressed11 !='#' && keypressed11 !='A' && keypressed11 !='B' && keypressed11 !='C' && keypressed11 !='D' )
                      {
                        c2 = keypressed11;
                       lcd.setCursor(1, 1);
                       lcd.print(c2);
                       }

                     i1=(c1-48)*10;
                     i2=c2-48;
                    int N_hour=i1+i2;
                    delay(500);
                     lcd.clear();
                     lcd.print("Setup minutes");

////////////////////////////////////////////////////////////////////////////////////:
                    char keypressed12 = myKeypad.waitForKey();  // here all programs are stopped until you enter the four digits then it gets compared to the code above
                    if (keypressed12 != NO_KEY && keypressed12 !='*' && keypressed12 !='#' && keypressed12 !='A' && keypressed12 !='B' && keypressed12 !='C' && keypressed12 !='D' )
                      {
                        c1 = keypressed12;
                       lcd.setCursor(0, 1);
                       lcd.print(c1);
                       }
                   char    keypressed13 = myKeypad.waitForKey();
                    if (keypressed13 != NO_KEY && keypressed13 !='*' && keypressed13 !='#' && keypressed13 !='A' && keypressed13 !='B' && keypressed13 !='C' && keypressed13 !='D' )
                      {
                        c2 = keypressed13;
                       lcd.setCursor(1, 1);
                       lcd.print(c2);
                       }

                     i1=(c1-48)*10;
                     i2=c2-48;
                    int N_minutes=i1+i2;
                    delay(500);
                     lcd.clear();

                  rtc.adjust(DateTime(N_year, N_month, N_day, N_hour, N_minutes, 0));

                  RTC_display();
                  lcd.setCursor(0, 3);  // move cursor to column 0, row 3 (last row)
                  lcd.print("Temp:");

                  //myRTC.setDS1302Time(22, N_minutes, N_hour, 1, N_day, N_month, N_year); //once we're done setting the date and time we transfer to values to the RTC module
                                                                                //the 22 stands for seconds you can add a setup for it too if you want
                                                                                //the 1 stands for day of the week, as long I don't show it on the screen I don't change it
                    keypressed=NO_KEY; //the "*" key is stored in "keypressed" so I remove that value from it otherwise it will get me in the setup again
              }

}

//////////////////////////////////////// RTC functions ////////////////////////////////////////
void RTC_display()
{
  char _buffer[17];
  char dow_matrix[7][10] = {" SUNDAY  ", " MONDAY  ", " TUESDAY ", "WEDNESDAY",
                             "THURSDAY ", " FRIDAY  ", "SATURDAY "};
  lcd.setCursor(4, 0);
  lcd.print( dow_matrix[now.dayOfTheWeek()] );

  // print time
  sprintf( _buffer, "TIME: %02u:%02u:%02u", now.hour(), now.minute(), now.second() );
  lcd.setCursor(0, 1);
  lcd.print(_buffer);
  // print date
  sprintf( _buffer, "DATE: %02u-%02u-%04u", now.day(), now.month(), now.year() );
  lcd.setCursor(0, 2);
  lcd.print(_buffer);
}

////////////////////////////////////// end RTC functions //////////////////////////////////////

////////////////////////////////// DS18B20 sensor functions ///////////////////////////////////
bool ds18b20_start()
{
  bool ret = 0;
  digitalWrite(DS18B20_PIN, LOW);  // send reset pulse to the DS18B20 sensor
  pinMode(DS18B20_PIN, OUTPUT);
  delayMicroseconds(500);          // wait 500 us
  pinMode(DS18B20_PIN, INPUT);
  delayMicroseconds(100);          // wait to read the DS18B20 sensor response
  if (!digitalRead(DS18B20_PIN))
  {
    ret = 1;                  // DS18B20 sensor is present
    delayMicroseconds(400);   // wait 400 us
  }
  return(ret);
}

void ds18b20_write_bit(bool value)
{
  digitalWrite(DS18B20_PIN, LOW);
  pinMode(DS18B20_PIN, OUTPUT);
  delayMicroseconds(2);
  digitalWrite(DS18B20_PIN, value);
  delayMicroseconds(80);
  pinMode(DS18B20_PIN, INPUT);
  delayMicroseconds(2);
}

void ds18b20_write_byte(byte value)
{
  byte i;
  for(i = 0; i < 8; i++)
    ds18b20_write_bit(bitRead(value, i));
}

bool ds18b20_read_bit(void)
{
  bool value;
  digitalWrite(DS18B20_PIN, LOW);
  pinMode(DS18B20_PIN, OUTPUT);
  delayMicroseconds(2);
  pinMode(DS18B20_PIN, INPUT);
  delayMicroseconds(5);
  value = digitalRead(DS18B20_PIN);
  delayMicroseconds(100);
  return value;
}

byte ds18b20_read_byte(void)
{
  byte i, value;
  for(i = 0; i < 8; i++)
    bitWrite(value, i, ds18b20_read_bit());
  return value;
}

bool ds18b20_read(int *raw_temp_value)
{
  if (!ds18b20_start())  // send start pulse
    return(0);
  ds18b20_write_byte(0xCC);   // send skip ROM command
  ds18b20_write_byte(0x44);   // send start conversion command
  while(ds18b20_read_byte() == 0);  // wait for conversion complete
  if (!ds18b20_start())             // send start pulse
    return(0);                      // return 0 if error
  ds18b20_write_byte(0xCC);         // send skip ROM command
  ds18b20_write_byte(0xBE);         // send read command

  // read temperature LSB byte and store it on raw_temp_value LSB byte
  *raw_temp_value = ds18b20_read_byte();
  // read temperature MSB byte and store it on raw_temp_value MSB byte
  *raw_temp_value |= (unsigned int)(ds18b20_read_byte() << 8);

  return(1);  // OK --> return 1
}

why is the title of your post RTC shield with LCD and Keypad when the problem is with the SD card?

run an SD card read/write example sketch to confirm functionality


text:
Arduino TFT LCD Data Logger
Can I use Arduino TFT LCD Module ILI9341 as a data logger? It has an SD card slot at the back, I wonder if the data will be saved on the SD card? Thanks!

yes, you certainly can

Sure. If you plug it in to your Arduino and write a sketch to do data logging using the SD card on the TFT screen.


text:
Does using multiple HX711 amplifiers change the supply voltage of an Arduino?
I’m creating essentially a load cell using an Arduino Nano and an HX711 amplifier. However, I want to have two HX711 amplifiers running off the same Arduino. Will that change the supply voltage since I’m using two (ex. Does it change from 5V to 2.5V)? I need an accurate supply voltage for the Wheatstone bridge equations to determine strain from the strain gauge readings, but I’m unsure what adding another amplifier will do to the supply voltage.

how are you connecting them?

Sorry - should have specified that. They all share a single clock line and use different data lines. I’m using the HX711 multi library.

your question is all about the supply voltage, but you did not say anything about any connections to the power supply

Power supply module connected to a 9V battery, on the breadboard with the Arduino nano.

It sounds like you want to power the HX711's to the 5V line on the Arduino. As long as you don't exceed the current limits on the Arduino's voltage regulator, that should be fine. (connect each to 5V and to ground. Don't try to run them in series.)

Will that change the supply voltage

No. Components and circuits connected in parallel add together their current requirements, but the voltage stays the same.


text:
How to get time from RTC after wake up from sleep?
I have a setup with an Arduino Pro Mini, a DS1307 RTC, a microSD shield and a microswitch. I've set an interrupt to the microswitch, so it'll wake up the Arduino when it changes status. Here is some relevant code:
void setup() {
  rtc.begin();
  pinMode(button, INPUT);
  SD.begin(chipSelect);

  /*Omitted the same write to file as in button_ISR()*/
}

void loop() {
  delay(5000);
  goToSleep();
}

void goToSleep() {
  sleep_enable();
  attachInterrupt(digitalPinToInterrupt(button), button_ISR, CHANGE);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  delay(500);
  sleep_cpu();
}

void button_ISR() {
    sleep_disable();
    detachInterrupt(0);
    rtc.begin();
    String data = (digitalRead(button))?"OPEN":"CLOSE";
    File dataFile = SD.open("datalog.txt", FILE_WRITE);
    if(dataFile) {
      DateTime now = rtc.now();
      dataFile.print(now.year(), DEC);
      dataFile.print('.');
      dataFile.print(now.month(), DEC);
      dataFile.print('.');
      dataFile.print(now.day(), DEC);
      dataFile.print(". (");
      dataFile.print(daysOfTheWeek[now.dayOfTheWeek()]);
      dataFile.print(") ");
      dataFile.print(now.hour(), DEC);
      dataFile.print(":");
      dataFile.print(now.minute(), DEC);
      dataFile.print(":");
      dataFile.print(now.second(), DEC);
      dataFile.print(";");
      dataFile.println(data);
      dataFile.close();
    }
    delay(1000);
}

If I don't call rtc.now(), and omit the DateTime prints, the code perfectly writes "OPEN" and "CLOSE" in the txt. I have the same dateTime writing inside the setup(), with "START", and it perfectly writes the current date/time.
What am I missing? How could I get the time from RTC after wake up?

You should not sleep in an ISR. You should not write to a file either. Actually, the best you can do is leave the ISR empty, and move all its contents to right after sleep_cpu();.

@EdgarBonet yup, this was the solution :) If you make it an answer, I'll accept it. Thanks!

You should not delay in an ISR, for two reasons:

Interrupts are disabled while the ISR runs, and delay() relies on
interrupts.

Interrupts are used to handle time-critical tasks. The longer the
interrupts are disabled, the larger the chances that one of those
time-critical tasks is handled too late. Thus, ISRs should execute as
fast as possible.

In this particular case, if we try to make the ISR as short as possible,
the optimal version is this:
void button_ISR() {}

Since the interrupt is meant to wake up the Arduino, and nothing more,
everything the ISR does can be done at wake-up, right after
sleep_cpu();.
A few more comments and suggestions:

set_sleep_mode(SLEEP_MODE_PWR_DOWN); can be done once and for all in
setup()

instead combining sleep_enable(), sleep_cpu() and
sleep_disable(), you can use a single call to sleep_mode()

you most probably do not need to reinitialize the RTC and re-open the
file at every loop iteration: do this only once, in setup()

String objects are not friendly to a small Arduino's memory; in this
case you can get rid of them by simply replacing the word String
with const char *

if you are using RTClib, you may want to use the
DateTime::toString() method, which can make your code
shorter and simpler.