ESP32 interruption, signal rebooting issue

Hello everyone,
I have an issue for my interruption function. I want to read the unint_64 v bit per bit: when bit=1 then dcc_sig_freq=dcc_sig_1_freq (8261 Hz, 50% duty/resolution 11), when bit=0 then dcc_sig_freq=dcc_sig_0_freq (5000 Hz, 50% duty/resolution 11).
The problem I am facing with is when I loop with while for example and I put the 48 bits in a table, the esp32 is rebooting all the time. How can I avoid this? And how each bit of unint_64 v can be read with the good frequence without causing rebooting? Thanks


#include "driver/ledc.h"

volatile uint64_t masque;
volatile uint64_t dccBit;
volatile int trame[48];
volatile int trame_simplifie[48];




#define CRAN_0 0
#define CRAN_1 1
#define CRAN_2 2
#define CRAN_IDLE 5

byte dccSpeed;
byte addr;
byte adresse;
byte vitesse;
byte cksum;

int msg; // 1 = forward;0 stop

const int dcc_pin = 19;  // DCC signal
const int pwn_pin = 18;  //switch off/on

// setting PWM properties
#define dcc_sig_1_freq 8621 //  = 115,99 microseconds
#define dcc_sig_0_freq 5000 // 200µs 5000 Hz donne 200 microseconds
const int dcc_pin_channel = 0; // channel PWM 0
unsigned int dcc_sig_resolution = 11; // resolution at 11
unsigned long dcc_sig_duty = 1024; // duty 50% is 1024
uint32_t dcc_sig_freq = dcc_sig_1_freq; // on part de la fréquence du bit 1 toutes les trames commencent par une série de 20 bits a 1


struct __attribute__((packed)) t_message { // 48 bits to send
   uint64_t stop: 1;       // 1 bit à 1
     uint64_t cksum: 8;      // 8 bits de verification
       uint64_t zero2: 1;      // 1 bit à 0  
         uint64_t speeddir: 8;   // 8 bits de direction et de vitesse   
           uint64_t zero1: 1;      // 1 bit à 0
           uint64_t address: 8;    // 8 bits d'adresse
             uint64_t start: 1;      // 1 bit à 0
               uint64_t debut: 20;     // 20 bits à 1
};


void dumpMessageBits(t_message& message) {// message to send
  int j=0;
  uint64_t v;
  memcpy(&v, &message, sizeof v);
  //for (int8_t i = 47; i >=0; --i
//  ) Serial.print(bitRead(v, i) ? '1' : '0');
//  Serial.println();
}


void buildMessage(t_message& message, byte address, byte speedAndDir) {
  message.debut = 0b11111111111111111111;
  message.start = 0b0;
  message.address = address;
  message.zero1 = 0b0;
  message.speeddir = speedAndDir;
  message.zero2 = 0b0;
  message.cksum = address ^ speedAndDir; // au hasard, prendre les bons octets
  message.stop = 0b1;

  dumpMessageBits(message);
}

t_message unMessage;




void dcc_sig_isr() {// interruption function I want that for each bit in Uint_64 v when bit = 1 then dcc_sig_freq=1 or when bit = 0 then dcc_sig_freq=0. In order to make thing easier


if (dcc_sig_freq == dcc_sig_0_freq) dcc_sig_freq = dcc_sig_1_freq ;
 else dcc_sig_freq = dcc_sig_0_freq ;
 
ledc_set_freq(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_0, dcc_sig_freq);


}

//}
//}


void setup() {
  Serial.begin(115200);
   pinMode(pwn_pin, OUTPUT); 
  
 // configuration du canal pwm 0 avec une fréquence et la résolution
  ledcSetup(dcc_pin_channel, dcc_sig_freq, dcc_sig_resolution); // on set up le canal avec une résolution de 1 bit cad 50%
  ledcAttachPin(dcc_pin, dcc_pin_channel); /// et ensuite on l attache au PIN19
  ledcWrite(dcc_pin_channel, dcc_sig_duty);
  // programme l'interruption à la fin de la période
  attachInterrupt(dcc_pin, dcc_sig_isr, RISING); // l'interruption "dcc_sig_isr" provoquée à la fin de chaque période (voire au début de la suivante) =>moi non plus
 
}


// fonction de calcul 3 octets
void SpeedAndDir(byte addr, byte SelectCran, byte SelectSpeed, bool SelectDirection) // vecteur de direction et de vitesse 
{
  byte type;
  byte ext;
  byte dir;
  byte cksum=0;
  uint64_t paquet=0;


      switch(SelectCran) {

          case 0:   ////DCC_PACKET_TYPE_STEP_14
              dccSpeed=map(SelectSpeed,0,128,0,14);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

              
          case 1: ///DCC_PACKET_TYPE_STEP_28

              dccSpeed=map(SelectSpeed,0,128,0,28);
              if (dccSpeed) dccSpeed+=3; // pas de cran 1,2,3
              ext=(((dccSpeed&0x01)<<5)|dccSpeed)>>1;   /// 
              dir=(SelectDirection?0x60:0x40)|ext;
              break;
              
          case 2:  //DCC_PACKET_TYPE_STEP_128;
               dccSpeed=map(SelectSpeed,0,128,0,126);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

           case 5:  //IDLE;
               dir=0b00000000;
              break;              
      }

buildMessage(unMessage, addr,dir);

}


void loop() {
SpeedAndDir(32, CRAN_1,101,1);

if (Serial.available() )
msg = Serial.parseInt();  // Lit le message reçu et l'affiche sur le moniteur
(msg)?digitalWrite(pwn_pin,HIGH):digitalWrite(pwn_pin,LOW);
Serial.print(msg);
delay(500);

}



I suggest checking the use of memcpy. It's very easy to write in the wrong memory area, crash the stack or other important data.

Hi Railroader, thanks for your advice. Done. I think this is ok. I have amended/changed the interruption function like this:

void dcc_sig_isr() {
for (int8_t i = 47; i >=0; --i) 
{dcc_sig_freq=bitRead(v, i) ? dcc_sig_1_freq : dcc_sig_0_freq;
ledc_set_freq(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_3, dcc_sig_freq);}
}

with the timer 3 it is very much better. I have a clear signal 58 microseconds for bit 1 and duty is 50,1%. But bits 0 do not "print" or work. I have checked with a debug.print(bitRead(v,i)?'1','0') that everyting is ok.for the moment I get only bit One.
do you see the issue by any chance?


#include "driver/ledc.h"

volatile uint64_t masque;
volatile uint64_t dccBit;
volatile int trame[48];
volatile int trame_simplifie[48];
bool alter =1;



#define CRAN_0 0
#define CRAN_1 1
#define CRAN_2 2
#define CRAN_IDLE 5

byte dccSpeed;
byte addr;
byte adresse;
byte vitesse;
byte cksum;
uint64_t v;

int msg; // 1 = marche;0 arret

const int dcc_pin = 19;  // Sortie du signal DCC     
const int pwn_pin = 18;  // Sortie du signal DCC envoi courant

// setting PWM properties
#define dcc_sig_1_freq 8621 //  = 115,99 microS 
#define dcc_sig_0_freq 5000 // 200µs 5000 Hz donne 200 microS
const int dcc_pin_channel = 0; // on ouvre un canal qu on reliera à une sortie PWMN
unsigned int dcc_sig_resolution = 11; // resolution fixe a 11
unsigned long dcc_sig_duty = 1024; // duty 50% est 1024
uint32_t dcc_sig_freq = dcc_sig_1_freq; // on part de la fréquence du bit 1 toutes les trames commencent par une série de 20 bits a 1


struct __attribute__((packed)) t_message { // total de 48 bits à envoyer
   uint64_t stop: 1;       // 1 bit à 1
     uint64_t cksum: 8;      // 8 bits de verification
       uint64_t zero2: 1;      // 1 bit à 0  
         uint64_t speeddir: 8;   // 8 bits de direction et de vitesse   
           uint64_t zero1: 1;      // 1 bit à 0
           uint64_t address: 8;    // 8 bits d'adresse
             uint64_t start: 1;      // 1 bit à 0
               uint64_t debut: 20;     // 20 bits à 1
};


void dumpMessageBits(t_message& message) {
 // int j=0;
  //uint64_t v;
  memcpy(&v, &message, sizeof v);
  //for (int8_t i = 47; i >=0; --i) Serial.print(bitRead(v, i) ? '1' : '0');

}


void buildMessage(t_message& message, byte address, byte speedAndDir) {
  message.debut = 0b11111111111111111111;
  message.start = 0b0;
  message.address = address;
  message.zero1 = 0b0;
  message.speeddir = speedAndDir;
  message.zero2 = 0b0;
  message.cksum = address ^ speedAndDir; // au hasard, prendre les bons octets
  message.stop = 0b1;

  dumpMessageBits(message);
}

t_message unMessage;




void dcc_sig_isr() {

for (int8_t i = 47; i >=0; --i) 
{dcc_sig_freq=bitRead(v, i) ? dcc_sig_1_freq : dcc_sig_0_freq;
ledc_set_freq(LEDC_HIGH_SPEED_MODE, LEDC_TIMER_3, dcc_sig_freq);}
}



void setup() {
  Serial.begin(115200);
   pinMode(pwn_pin, OUTPUT); 

  ledcSetup(dcc_pin_channel, dcc_sig_freq, dcc_sig_resolution);
  ledcAttachPin(dcc_pin, dcc_pin_channel);
  ledcWrite(dcc_pin_channel, dcc_sig_duty);

  attachInterrupt(dcc_pin, dcc_sig_isr, RISING);
 
}


// fonction de calcul 3 octets
void SpeedAndDir(byte addr, byte SelectCran, byte SelectSpeed, bool SelectDirection) // vecteur de direction et de vitesse 
{
  byte type;
  byte ext;
  byte dir;
  byte cksum=0;
  uint64_t paquet=0;


      switch(SelectCran) {

          case 0:   ////DCC_PACKET_TYPE_STEP_14
              dccSpeed=map(SelectSpeed,0,128,0,14);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

              
          case 1: ///DCC_PACKET_TYPE_STEP_28

              dccSpeed=map(SelectSpeed,0,128,0,28);
              if (dccSpeed) dccSpeed+=3; // pas de cran 1,2,3
              ext=(((dccSpeed&0x01)<<5)|dccSpeed)>>1;   /// 
              dir=(SelectDirection?0x60:0x40)|ext;
              break;
              
          case 2:  //DCC_PACKET_TYPE_STEP_128;
               dccSpeed=map(SelectSpeed,0,128,0,126);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

           case 5:  //IDLE;
               dir=0b00000000;
              break;              
      }

buildMessage(unMessage, addr,dir);

}


void loop() {
SpeedAndDir(32, CRAN_1,101,1);

if (Serial.available() )
msg = Serial.parseInt();  // Lit le message reçu et l'affiche sur le moniteur
(msg)?digitalWrite(pwn_pin,HIGH):digitalWrite(pwn_pin,LOW);
//Serial.print(msg);
delay(500);

}




  

Your advanced use of this controller is outside my comfort zone. Programming microprocessors in assembler during a long time I've used memcpy and know how easily it goes wrong and demolish memory areas...

Hello,

I m following your advice Railraoder.

I have skiped the memcpy. Now I want to test the signal. In the interruption function I am using the following phrase : start with bit 0 (100 microseconds HIGH, 100 microsecs LOW) and bit 1 then (58 microsecs HIGH, 58n ms LOW). This is OK.

  if (dcc_freq==dcc_freq_0) dcc_freq=dcc_freq_1;
 else dcc_freq=dcc_freq_0;
 dcc_freq==dcc_freq_0;

and the second phrase that should give the same result than the first one but the signal is not the same: there is no alternation of 1 and 0 just something constant: start with the bit Zero first 100 ms HIGH and then Bit 1 LOW during 58ms.
I want to get 100ms HIGH, 100ms LOW+58ms HIGH, 58ms LOW
So maybe the interruption is not well calibrated in the second phrase?


for (int i=7;i>=0;--i) {
  if(trame[i]==1){
    dcc_freq=dcc_freq_1;
    ledcSetup(0,dcc_freq,12);
  }else{
  dcc_freq=dcc_freq_0;
    ledcSetup(0,dcc_freq,12);

#include "driver/ledc.h"

volatile uint64_t masque;
volatile uint64_t dccBit;
volatile int trame[8]={1,0,1,0,1,0,1,0};



#define CRAN_0 0
#define CRAN_1 1
#define CRAN_2 2
#define CRAN_IDLE 5

byte dccSpeed;
byte addr;
byte adresse;
byte vitesse;
byte cksum;
uint64_t v;

int msg; // 1 = marche;0 arret

const int dcc_pin = 19;  // Sortie du signal DCC     
const int pwn_pin = 18;  // Sortie du signal DCC envoi courant

// setting PWM properties
#define dcc_freq_0 5000
#define dcc_freq_1 8621
uint32_t dcc_freq=dcc_freq_1;


struct __attribute__((packed)) t_message { // total de 48 bits à envoyer
   uint64_t stop: 1;       // 1 bit à 1
     uint64_t cksum: 8;      // 8 bits de verification
       uint64_t zero2: 1;      // 1 bit à 0  
         uint64_t speeddir: 8;   // 8 bits de direction et de vitesse   
           uint64_t zero1: 1;      // 1 bit à 0
           uint64_t address: 8;    // 8 bits d'adresse
             uint64_t start: 1;      // 1 bit à 0
               uint64_t debut: 20;     // 20 bits à 1
};

void buildMessage(t_message& message, byte address, byte speedAndDir) {
  message.debut = 0b11111111111111111111;
  message.start = 0b0;
  message.address = address;
  message.zero1 = 0b0;
  message.speeddir = speedAndDir;
  message.zero2 = 0b0;
  message.cksum = address ^ speedAndDir; // au hasard, prendre les bons octets
  message.stop = 0b1;

  dumpMessageBits(message);
}

t_message unMessage;




void dumpMessageBits(t_message& message) {
 // int j=0;
  //uint64_t v;
  //memcpy(&v, &message, sizeof v);
  //for (int8_t i = 47; i >=0; --i) Serial.print(bitRead(v, i) ? '1' : '0');
//for (int i=7;i>=0;--i) {
// Serial.print(bitRead(unMessage.address,i)?1:0);
//}
}



void fonction_ISR() {
  //if (dcc_freq==dcc_freq_0) dcc_freq=dcc_freq_1;
 // else dcc_freq=dcc_freq_0;
  //dcc_freq==dcc_freq_0;
for (int i=7;i>=0;--i) {
  if(trame[i]==1){
    dcc_freq=dcc_freq_1;
    ledcSetup(0,dcc_freq,12);
  }else{
  dcc_freq=dcc_freq_0;
    ledcSetup(0,dcc_freq,12);
}
}
}






void setup() {
  Serial.begin(115200);
   pinMode(pwn_pin, OUTPUT); 
ledcAttachPin(19,0);
ledcSetup(0,dcc_freq,12);
ledcWrite(0,2048);
attachInterrupt(19, fonction_ISR, RISING);
 
}


// fonction de calcul 3 octets
void SpeedAndDir(byte addr, byte SelectCran, byte SelectSpeed, bool SelectDirection) // vecteur de direction et de vitesse 
{
  byte type;
  byte ext;
  byte dir;
  byte cksum=0;
  uint64_t paquet=0;


      switch(SelectCran) {

          case 0:   ////DCC_PACKET_TYPE_STEP_14
              dccSpeed=map(SelectSpeed,0,128,0,14);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

              
          case 1: ///DCC_PACKET_TYPE_STEP_28

              dccSpeed=map(SelectSpeed,0,128,0,28);
              if (dccSpeed) dccSpeed+=3; // pas de cran 1,2,3
              ext=(((dccSpeed&0x01)<<5)|dccSpeed)>>1;   /// 
              dir=(SelectDirection?0x60:0x40)|ext;
              break;
              
          case 2:  //DCC_PACKET_TYPE_STEP_128;
               dccSpeed=map(SelectSpeed,0,128,0,126);
              if (dccSpeed) dccSpeed++; // pas de cran 1
              dir=(SelectDirection?0x60:0x40)|dccSpeed;
              break;

           case 5:  //IDLE;
               dir=0b00000000;
              break;              
      }

buildMessage(unMessage, addr,dir);

}


void loop() {
SpeedAndDir(3, CRAN_1,101,1);

if (Serial.available() )
msg = Serial.parseInt();  // Lit le message reçu et l'affiche sur le moniteur
(msg)?digitalWrite(pwn_pin,HIGH):digitalWrite(pwn_pin,LOW);
//Serial.print(msg);
delay(500);

}




  

Does the code run without self reset/restart/reboot now?
Regarding the purpose of the code and methods You are working on, I have no clue what it's all about.

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