analogWrite() resets the Mega2560

A strange behavior:
I am using a tricolor RGB LED on pins 44, 45, and 46 of Mega 2560.
My typical code to call a color function is :

void ledred() {
  analogWrite(rLED, 10);   // pwm  to control the bright
  analogWrite(gLED, 0);
  analogWrite(bLED, 0);
 }

If I call the function the processor resets the program just after the call.

But if I call two times like

ledred();
ledred();

The program runs normally.

The problem occur only in my code. If tested just the parts in a simple sketch it runs normally.
I do not include my complete code because it is too long.

What you have shown should work. I suspect the reason it doesn't work is in the code you have not shown.

Could you describe "resets the program"?

Thanks for using code tags when you do post the offending code.

It start again.

Sorry. It is so little but i will correct.

Do you have current limiting capacitors on the LEDs?

Your problem sounds like the kind of monkey business that happens when there is a memory leak, like writing past the end of an array....

No resistors. But I have used PWM in many other applications without problems.
If call function two times it run normally
If function is called one time the program reset and start again

I am posting the whole code:

/// AC GY-953 TX RX Funcionando o heading e o autoheading
/// gravação float eeprom ok
// retornei para 9600 por ocorrencia de  erros mas precisa mais testes
// adaptado para LEONARDO 32U4 BEETLE. FUNCIONOU NA PORTA HW serial1
// funcionou o GPS sem o GY953. agora só adicionar
// adicionado heading  COG
// precisa incluir auto offset e manual align da bussola com COG gps if sog > x
// resolvido o bug do CRC
#include <EEPROM.h> // necessario para eeprom
//#include <SoftwareSerial.h>
//#include <stdlib.h> // funçao atoi parece nao afetar se desbilitar
#include <TinyGPS++.h>

#include "Wire.h"
#include "MCP4725.h"
MCP4725 MCP1 (0x61);
MCP4725 MCP2 (0x60);


//#include <math.h>  //
static const int RXPin = 16, TXPin = 14; // funcionam invertidos tb   LEONARDO  MOSI=16(PB2)  MIS0=14(PB3) SCK= 15    SCL=3  SDA=4  A0=18 A1=19 A2=20 LED_BUILTIN=13
//SoftwareSerial ss(RXPin, TXPin);// Rx, Tx
TinyGPSPlus gps; // The TinyGPS++ object
//static const uint32_t GPSBaud = 9600;  //SELECIONA AQUI O BAUD RATE DE ENTRADA DO GPS
static const uint32_t GPSBaud = 115200;  //SELECIONA AQUI O BAUD RATE DE ENTRADA DO GPS
//============================================================
const byte buff_len = 90; // aqui é do CRC calculador
char CRCbuffer[buff_len];
// create pre-defined strings to control flexible output formatting
String cr = "";
String msg = "";
//=====================================================
TinyGPSCustom UT(gps, "GNRMC", 1); // $GNRMC sentence, 1th element  UTC
TinyGPSCustom OK(gps, "GNRMC", 2); // $GNRMC sentence, 2th element  Status
TinyGPSCustom LA(gps, "GNRMC", 3); // $GNRMC sentence, 3th element  Latitude
TinyGPSCustom NS(gps, "GNRMC", 4); // $GNRMC sentence, 4th element  N /S
TinyGPSCustom LO(gps, "GNRMC", 5); // $GNRMC sentence, 5th element  Longitude
TinyGPSCustom WE(gps, "GNRMC", 6); // $GNRMC sentence, 6th element  W/ E
TinyGPSCustom SO(gps, "GNRMC", 7); // $GNRMC sentence, 7th element  SOG
TinyGPSCustom CO(gps, "GNRMC", 8); // $GNRMC sentence, 8th element  COG
TinyGPSCustom DA(gps, "GNRMC", 9); // $GNRMC sentence, 9th element  DATE
TinyGPSCustom MA(gps, "GNRMC", 10); // $GNRMC sentence, 10th element Mag Var
TinyGPSCustom EW(gps, "GNRMC", 11); // $GNRMC sentence, 11th element E/W mag
TinyGPSCustom SY(gps, "GNRMC", 12); // $GNRMC sentence, 12th element System Mode
//=======================================
const int BUFFER_SIZE = 11;  // tamanho do buffer da resposta EULER = 10 bytes  6 bytes de dados
char buf[BUFFER_SIZE];// reserva 11 chars
char buf2[13]; // buffer para receber 8 bytes
byte head1, head2, head3;
byte head4;

float roll;
byte roll1;
byte roll2;
float pitch;
byte pitch1;
byte pitch2;

long yaw; // só funciona com word ou long
byte yaw1;
byte yaw2;

float SOG;
float COG;
float offsetcog;
float headingRaw;
float heading ;
String HEADING;
float headmax = 0.00 ;
float headmin = 359.99;
float h1; //valor fixo do autoheading
float h2; // valor do heading atual para o AH
float corr; // valor da correção para o AH
float realN; // offset para o real North
//==============================
void setup() {

#define rLED 46  // 
#define gLED 44
#define bLED 45
#define LED_BUILTIN 13

pinMode(47,OUTPUT); // terra pa leds
digitalWrite(47,LOW); //habilita terra para os leds

  pinMode(rLED, OUTPUT); //red
  pinMode(gLED, OUTPUT); //green
  pinMode(bLED, OUTPUT); //blue

  pinMode(A0, INPUT_PULLUP); // adc para o DAC1
  pinMode(A1, INPUT_PULLUP); // adc para o DAC2
  //pinMode(A2, INPUT_PULLUP);
  
  MCP1.begin();
  MCP2.begin();

 MCP1.writeDAC(1900, true); // teste escerever memoria EEPROM
 MCP2.writeDAC(2100, true);
 delay(50);  
  
  Serial.begin(115200); 
  //ss.begin(115200);
  //ss.begin(9600); // baud do GY953
  Serial3.begin(9600); //baud do GY953
  //Serial1.begin(115200);
  Serial1.begin(115200); //serial do GPS // Habilitar para o GPS
  while (!Serial) ; // necessario se quiser imprimir desde o setup 32u4
  Serial.println("============================================================");
  Serial.println ("Software: AC SENSOR GY-953 MODO TX RX 9600 COM NORTH SET E AUTOHEADING");
  //Serial.println ("Hardware: Leonardo Beetle 32u4 + GY-953 + GNSS HD8040 ");
  Serial.println ("Hardware: MEGA 2560 + GY-953 + GNSS HD8040 ");
  Serial.println ("Autor: ACJacques");
  Serial.println ("Versão:  está sendo incluido os  2 DACS MCP4725");
  const char compile_date[] = __DATE__ " " __TIME__;
  Serial.print("Compilado em ");
  Serial.println (compile_date);
  Serial.println( __FILE__);
  Serial.println ("Inicia em 2 segundos");
  Serial.println("============================================================");
  delay (2000);
  //setbaud115(); // alterar se precisar no GY953  . tb no ss.begin. para para habilitar a mudança cicle power
  //setbaud96(); //  
  calGy();
  calMag();
  //realNset(); // chama gravar realN
  realNget(); // recupera realN
  //toggleAcc();
  toggleGy();
  getheading();
  delay (200);
  getheading();
  delay (200);
}
//================================
void loop() {
//piscaled(); // se habilitar aqui fica rapido demais
//getheading(); // pega o heading do gy-953
//delay (20);
if (  
    UT.isUpdated()  //  basta 1 encode para ficar 1 hz
//  ||  OK.isUpdated() //
//  ||  LA.isUpdated() 
//  ||  NS.isUpdated() 
//  ||  LO.isUpdated() 
//  ||  WE.isUpdated() 
//  ||  SO.isUpdated() 
//  ||  CO.isUpdated() 
//  ||  DA.isUpdated() 
//  ||  MA.isUpdated() 
//  ||  EW.isUpdated() 
//  ||  SY.isUpdated()
    ) // is updated
    {  // açoes em seguida abaixo
 //========================
 getheading();
 HEADING= String(heading,2);
 if (heading > headmax) headmax = heading;
 if (heading < headmin) headmin = heading;
//makeACHDT();   // 
makeGNRMC(); 
//Serial.print ("Headmin= ");
//Serial.print (headmin);
//Serial.print ("   Headmax= ");
//Serial.print (headmax);
//Serial.print ("   Drift= ");
//Serial.println (headmax - headmin);
piscaled();
//analogWrite(bLED,10);
//digitalWrite((47), !digitalRead(47));
//digitalWrite(47,LOW);
//ledmagenta();
ledblue();
//ledred();
delay(50);
ledoff();
//digitalWrite(47,LOW);
  //analogWrite(rLED,20);
  //digitalWrite(46,HIGH);
  //analogWrite(gLED,20);
  //analogWrite(bLED,20);  

//   MCP1.setValue(2008); // max 4095
//   MCP2.setValue(2000); 
//   Serial.print("MCP1= ");
//   Serial.println(MCP1.getValue());
//   //Serial.println(MCP1.readDAC());
//   Serial.println(analogRead(A0));
//   Serial.print("MCP2= ");
//   Serial.println(MCP2.getValue());
//   //Serial.println(MCP2.readDAC());
//   Serial.println(analogRead(A1));


    } // fim açoes em seguida 
//=========================
    while (Serial1.available() > 0)  //necessário habilitar
    gps.encode(Serial1.read());
 } // loop
//==========================
void autoheadcalc () ///algoritimo de calculo de erro  do rumo
{
 h1 = 100; // 'este é o rumo fixo alvo
 h2= heading;// esse é o rumo atual 
 if ((h1 > 180) & (h2 < 180) & (abs(h1-h2)) > 180) {  
 corr= -(h2+(360-h1)) ;//  'valor de correcao calculado
 if (corr > 179.99) corr = -179.99;  //corr = float .desnecessario se corr for inteiro (use 180)
 if (corr < -179.99) corr = 179.99; 
 return;
}
 if( (h1 < 180) & (h2 > 180) &  (abs(h1-h2)) > 180){ 
 corr= h1+(360-h2); //  'valor de correcao calculado
 if (corr > 179.99) corr = -179.99; 
 if (corr < -179.99) corr = 179.99; 
 return;
}
 corr = (h1-h2) ; //'valor de correcao calculado
 if (corr > 179.99) corr = -179.99; 
 if (corr < -179.99) corr = 179.99; 
 return;
}

void readGY953() /// le os  10 bytes mas o buffer precisa de 11
{
  //int rlen = ss.readBytes(buf, BUFFER_SIZE);
  int rlen = Serial3.readBytes(buf, BUFFER_SIZE);
}
//=========================
void reset953(){
    Serial3.write(0XA5);
    Serial3.write(0X59);
    Serial3.write(0XFE);
    delay(200);
}
//=========================
void toggleAcc(){
    Serial3.write(0XA5);
    Serial3.write(0X51);
    Serial3.write(0XF6);
    delay(200);    
}
//==============================
void toggleMag(){
    Serial3.write(0XA5);
    Serial3.write(0X53);
    Serial3.write(0XF8);
    delay(200);
}
//===============================
void toggleGy(){
    Serial3.write(0XA5);
    Serial3.write(0X52);
    Serial3.write(0XF7);
}
//===============================
void askmags(){
  //comando para ler magnetometros
    Serial3.write(0XA5);
    Serial3.write(0XE5);
    Serial3.write(0X8A);
    delay(200);
}
//==================================
void askeuler(){
  //comando para ler angulos EULER
    Serial3.write(0XA5);
    Serial3.write(0X95);
    Serial3.write(0X3A);
}
//==================================
void setbaud115 (){
  Serial3.write(0XA5);
  Serial3.write(0XAF);
  Serial3.write(0X54);
  Serial.println("Baud changed to 115200. Restart power");
  delay (2000);
}
//===========================
void setbaud96 (){
  Serial3.write(0XA5);
  Serial3.write(0XAE);
  Serial3.write(0X53);
  Serial.println("Baud changed to 9600. Restart power");
  delay (2000);
}
//===========================
void calMag (){
  Serial3.write(0XA5);
  Serial3.write(0X58);
  Serial3.write(0XFD);
  Serial.println("Calibration Magnetic Started. Start rotations until LED lit");
  delay (2000);
}
//===========================
void calGy (){
  Serial3.write(0XA5);
  Serial3.write(0X57);
  Serial3.write(0XFC);
  Serial.println("Calibration zero Roll Pitch & Gyros done");
  delay (2000);
}
//===========================
void getoffsetCOG(){
SOG = atof(SO.value()); //converte string cog to float  //speed 
COG = atof(CO.value()); //converte string cog to float  // course
offsetcog = (headingRaw -COG);
//Serial.println (COG); 
//Serial.println (offsetcog);  
} 
//============================
void realNset(){
  //realN = (360-heading); // salva a diferença de heading
   realN = 81; // valor a ser subtraido
   EEPROM.put(10, realN); //endereço 10 da memoria mas pode ser qq um  // grava na EEPROM
  }
//===========================
void realNget(){
  realN = 0;
  EEPROM.get(10, realN); // le EEPROM
  Serial.print("EEPROM Offset to True North is ");
  Serial.println( realN,2);
  delay (1000);
}
//===========================
void headingTrueN(){    // aplica o offset ao heading
heading = (heading - realN);
if (heading > 359.99) heading = (heading-359.99);
if (heading <0.00) heading = (heading+359.99);
}
//================================
void piscaled (){
        digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
        delay(2);                       // wait for a second
        digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
        delay(2);
}
// -----------------------------------------------------------------------
void outputMsg(String msg) {
  msg.toCharArray(CRCbuffer, sizeof(CRCbuffer)); // put complete string into CRCbuffer
  byte crc = convertToCRC(CRCbuffer); // call function to compute the crc value
  cr= ""; //zera a  substring 
  if (crc < 16) cr="0";   //acrescenta o zero se menor que 16
  cr = cr + String(crc, HEX); // acrescenta o crc 
  cr.toUpperCase(); // converte a string cr para maiusculas
  //msg = (msg+ cr) ;  // acrescenta a string cr na msg
  //msg.concat(cr);  // mesmo concatenando a msg aqui nao sai crc lá na frente
  //finalizou a string
  //Serial.println (msg); // imprime a string completa // estranho se imprimir em outro lugar nao sai o CRC
}
// -----------------------------------------------------------------------
byte convertToCRC(char *buff) {
  // NMEA CRC: XOR each byte with previous for all chars between '$' and '*'
  char c = 0 ;
  byte i = 0 ;
  byte start_with = 0;    // index of starting char in msg
  byte end_with = 0;      // index of starting char in msg
  byte crc = 0;
  for (i = 0; i < strlen(CRCbuffer); i++) {
    c = buff[i];
    if (c == '$') {start_with = i; }
    if (c == '*') {end_with = i;   }
  }
  if (end_with > start_with) {
    for (i = start_with + 1; i < end_with; i++) {     // XOR every character between '$' and '*'
      crc = crc ^ buff[i] ;  // xor the next char
    }
  }
  else { // else if error, print a msg
    Serial.println("CRC ERROR");
  }
  return crc;
  // based on code by Elimeléc López - July-19th-2013 bug corrected by WILDBILL  
}
//=================================================
void getCal(){
  Serial3.write(0XA5);
  Serial3.write(0X58);
  Serial3.write(0XFD);
  int rlen = Serial3.readBytes(buf, BUFFER_SIZE); ///precisa mais 2 bytes
}
//=============================
void getheading(){
    askeuler();
   // check if data is available
    //if (ss.available() > 0)
    if (Serial3.available() > 0)  
    readGY953(); // read the incoming bytes:
//    head1 = buf[0];
//    head2 = buf[1];
//    head3 = buf[2];
//    head4 = buf[3];
    roll1 = buf[4];
    roll2 = buf[5];
    roll = ((roll1 <<8) + roll2); // concatena 
    roll  = (roll/100); // +180 - 180
    pitch1 = buf[6];
    pitch2 = buf[7];
    pitch = ((pitch1 <<8) + pitch2); // concatena
    pitch = (pitch/100);//  +90  - 90 
    
    yaw1 = buf[8];
    yaw2 = buf[9];
//    //yaw = ((buf[8] <<8) + buf[9]); // concatena mais simples dá erro nos leading zeros
    yaw = ((yaw1 <<8) + yaw2); // concatena mais simples
//  //yaw = word(yaw1,yaw2); // concatena   
//  //yaw = (float)yaw; // transforma para float
      heading= ((yaw +18000)); // a divisao por 100 precisa ficar separado para ter decimos 
      heading = (heading/100);
      if (heading >= 0.00)  { // não imprime evita erros se negativo
      if (heading > 359.99) heading =0.00;
      headingRaw = heading; // salva o raw na variavel
      headingTrueN(); // aplica o offset no heading
      autoheadcalc(); // calculo do erro 
      if (heading > 359.99) heading =0.00;
      //Serial.print("Heading= ");
      //if (heading < 100) Serial.print("0");
      //if (heading < 10) Serial.print("0");
      //Serial.println(heading);
      //Serial. print("     Ah= ");
      //alinhamento embaixo  perto do zero não funcionou
      //if (corr >0.00) {
      //if (corr < 100) Serial.print(" 0");
      //if (corr < 10) Serial.print(" 0");
      //Serial.println(corr);
      //getoffsetCOG();
    } // if heading
      else { Serial.println("Heading invalido");}
      //      delay (50);
//  consegue as coordenadas abaixo mesmo sem codificar o gps
//Serial.print("Lat= ");
//Serial.print (gps.location.lat(),8);
//Serial.print("     Lon= ");
//Serial.println (gps.location.lng(),8); 
  }
//=====================================
void makeGNRMC() {
msg ="";
cr ="";
msg = "$GNRMC," ;
msg.concat(UT.value());
msg.concat(",");
msg.concat(OK.value());
msg.concat(",");
msg.concat(LA.value());
msg.concat(",");
msg.concat(NS.value());
msg.concat(",");
msg.concat(LO.value());
msg.concat(",");
msg.concat(WE.value());
msg.concat(",");
msg.concat(SO.value());
msg.concat(",");
msg.concat(HEADING);  //insere heading da bussola gy-953
//msg.concat(CO.value());
msg.concat(",");
msg.concat(DA.value());
msg.concat(",");
msg.concat(MA.value());
msg.concat(",");
msg.concat(EW.value());
msg.concat(",");
msg.concat(SY.value());
msg.concat("*");

outputMsg(msg);  // envia a msg e chama função que calcula e acrescenta a CRC a string
msg.concat(cr); // acrescenta o CRC calculado
Serial.println (msg); // imprime a string completa
msg ="";
cr ="";
}
//======================================
void makeACHDT(){
msg ="";
cr= "";
msg = "$ACHDT";
msg.concat (",");
msg.concat (HEADING);
msg.concat (",");
msg.concat ("T");
msg.concat ("*");
//Serial.println(msg);
outputMsg(msg);  // envia a msg e chama funcção que calcula e acrescenta a CRC a string
msg.concat(cr); // acrescenta o CRC calculado
Serial.println (msg); // imprime a string completa
msg ="";
cr ="";
}
//==============================================
// algo estranho precisa escrever 2 vezes senao o programa reseta.
void ledred() {
  //  digitalWrite (rLED,HIGH);
  //  digitalWrite (gLED,LOW);
  //  digitalWrite (bLED,LOW);
  analogWrite(rLED, 10);
  analogWrite(gLED, 0);
  analogWrite(bLED, 0);
  analogWrite(rLED, 10);
  //analogWrite(gLED, 0);
  //analogWrite(bLED, 0);
}
void ledgreen() {
  //  digitalWrite (rLED,LOW);
  //  digitalWrite (gLED,HIGH);
  //  digitalWrite (bLED,LOW);
  analogWrite(rLED, 0);
  analogWrite(gLED, 10);
  analogWrite(bLED, 0);
  analogWrite(gLED, 10);
}
void ledblue() {
  //  digitalWrite (rLED,LOW);
  //  digitalWrite (gLED,LOW);
  //  digitalWrite (bLED,HIGH);
  analogWrite(rLED, 0);
  analogWrite(gLED, 0);
  analogWrite(bLED, 10);
  analogWrite(bLED, 10);
}
void ledyellow() {
  //  digitalWrite (rLED,HIGH);
  //  digitalWrite (gLED,HIGH);
  //  digitalWrite (bLED,LOW);
  analogWrite(rLED, 10);
  analogWrite(gLED, 10);
  analogWrite(bLED, 0);
}
void ledcyan() {
  //  digitalWrite (rLED,LOW);
  //  digitalWrite (gLED,HIGH);
  //  digitalWrite (bLED,HIGH);
  analogWrite(rLED, 0);
  analogWrite(gLED, 10);
  analogWrite(bLED, 10);
}
void ledmagenta() {
  //  digitalWrite (rLED,HIGH);
  //  digitalWrite (gLED,LOW);
  //  digitalWrite (bLED,HIGH);
  analogWrite(rLED, 10);
  analogWrite(gLED, 0);
  analogWrite(bLED, 10);
}
void ledwhite() {
  //  digitalWrite (rLED,HIGH);
  //  digitalWrite (gLED,HIGH);
  //  digitalWrite (bLED,HIGH);
  analogWrite(rLED, 10);
  analogWrite(gLED, 20);
  analogWrite(bLED, 10);
}
void ledoff() {
  //  digitalWrite (rLED,LOW);
  //  digitalWrite (gLED,LOW);
  //  digitalWrite (bLED,LOW);
  analogWrite(rLED, 0);
  analogWrite(gLED, 0);
  analogWrite(bLED, 0);
}
//==============================

Just luck. With no resistors, the maximum current of the I/O pin is easily exceeded. It really makes no difference that it's PWM. The output driver can blow in microseconds.

I hope the applications weren't permanent installations...

BTW the cheezy way to attempt a fix is to just increase all your buffer sizes.

Also how much system memory are you consuming? What does the compile message report?

O sketch usa 16852 bytes (6%) de espaço de armazenamento para programas. O máximo são 253952 bytes.
Variáveis globais usam 2158 bytes (26%) de memória dinâmica, deixando 6034 bytes para variáveis locais. O máximo são 8192 bytes.

Unused.

Why do you write the red channel twice?

Not yet implemented. I will be in future to get calibration state of GY953 that will be 12 bytes....

Just to avoid the strange reset mentioned.
I dont know WHY this solve the problem......

I have noted that the problem does not happen when call a two color
like yellow, magenta , or cyan or white..... then i make some experiences and i found that calling two times have solved !
I dont know the CAUSE and dont KNOW why two times have solved !

try

void ledred() {
  analogWrite(bLED, 0);
  analogWrite(gLED, 0);
  analogWrite(rLED, 10);
}

Tested. Doesnt work. Same problem

This have worked fine:

void ledred() {
   analogWrite(bLED, 1);
  analogWrite(gLED, 0);
  analogWrite(rLED, 10);
    }

If any other color is set to 1 . not to 0
Crazy......

So try duplicating blue and green, just like you did for red... maybe. It doesn't answer any questions. So something I couldn't get to the bottom of - how often do you call this 'ledred()'? Some systems resync PWM any time a value is written to it. So if you write too near the PWM frequency, it messes up the signal. The Mega, I don't know, except that I had some simple PWM'ed LEDs as a clock backlight. They worked at the time. IIRC at the time I was aware of that issue, and only updated the LEDs a few times a second.

As the Arduino PWM frequency (especially UNO, Mega) is in the few hundred Hz range, a decent pace of brightness and colour change isn't impossible. The human eye can't discern much over 30Hz or so.

How are your LEDs wired ?
If the issue is related to colour combinations, it sounds like some strange current path.

1 Like