Auteur Sujet: LaBox" : Une Centrale DCC polyvalente et abordable  (Lu 11940 fois)

Jozef

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #135 le: avril 29, 2024, 06:28:38 pm »
Bonjour,
Je n'arrive pas a diriger deux train avec ma BOX connecté à un smartphone et son application Z21.
Il y a t il une raison ?

Thierry

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 749
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #136 le: avril 29, 2024, 06:50:59 pm »
Bonjour.
Non pas de raison. Si les deux locos ont une adresse différente, je les pilote sans problème.

gbo95

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #137 le: avril 29, 2024, 10:46:19 pm »
Nous utilisons LaBox au club sur notre réseau N. Samedi dernier nous avions une douzaine de locos activées, dont 8 simultanément présentes sur les voies, pilotées par un smartphone et une tablette à double commande, soit  3 simultanées en pilotage direct.

lebelge2

  • Newbie
  • *
  • Messages: 33
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #138 le: mai 16, 2024, 08:07:20 pm »
Bonjour.

Je viens de recevoir un ESP32 pour construire « La Box »
Pressé d’explorer le code pour la rendre compatible RailCom.

La modification est très simple, ajout de deux delay au bon endroit.
Dans le fichier DCCRMT.cpp, chercher :

void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {

La modifier comme ci-dessous.

void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {             
  delayMicroseconds(22);
  digitalWrite(25,1);
  delayMicroseconds(412);  //  ___________---___________
  digitalWrite(25,0);
  RMTChannel *tt = channelHandle[channel];
  if (tt) tt->RMTinterrupt();
  if (channel == 0)
    DCCTimer::updateMinimumFreeMemoryISR(0);
}
et dans le setup(), mettre la pin D25 en sortie :
pinMode(25, OUTPUT);

L’introduction du CutOut dans la trame DCC se fait de manière matérielle avec un circuit TTL logique 7400 (4 portes Nand) ,  voir les photos en pièces jointes.
De cette façon le signal DCC original n’est pas altéré, que du contraire, il est temponné.
Placer des Delay dans une interruption, n’est pas très élégant, il est possible de les remplacer par des Timers.

Bien à vous.

Brunotoutsimple

  • Newbie
  • *
  • Messages: 15
    • Voir le profil
Re : Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #139 le: mai 16, 2024, 09:19:45 pm »
Bonjour.

Je viens de recevoir un ESP32 pour construire « La Box »
Pressé d’explorer le code pour la rendre compatible RailCom.

La modification est très simple, ajout de deux delay au bon endroit.
Dans le fichier DCCRMT.cpp, chercher :

void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {

La modifier comme ci-dessous.

void IRAM_ATTR interrupt(rmt_channel_t channel, void *t) {             
  delayMicroseconds(22);
  digitalWrite(25,1);
  delayMicroseconds(412);  //  ___________---___________
  digitalWrite(25,0);
  RMTChannel *tt = channelHandle[channel];
  if (tt) tt->RMTinterrupt();
  if (channel == 0)
    DCCTimer::updateMinimumFreeMemoryISR(0);
}
et dans le setup(), mettre la pin D25 en sortie :
pinMode(25, OUTPUT);

L’introduction du CutOut dans la trame DCC se fait de manière matérielle avec un circuit TTL logique 7400 (4 portes Nand) ,  voir les photos en pièces jointes.
De cette façon le signal DCC original n’est pas altéré, que du contraire, il est tamponné.
Placer des Delay dans une interruption, n’est pas très élégant, il est possible de les remplacer par des Timers.

Bien à vous.

Bonsoir

Super Lebelge2!
Etant novice, Vous dites que c'est pas très élégant de mettre des delays pour des interruptions et c'est ce que j'avais lu pour les interruptions pour Arduino. Est-ce que vous serait possible de modifier le programme afin d'introduire les Timers que vous le suggérez.
Vous dites d'ajouter la ligne suivante dans le setup(), c'est où? SVP
dans le setup(), mettre la pin D25 en sortie :
pinMode(25, OUTPUT);
« Modifié: mai 16, 2024, 09:42:49 pm par Brunotoutsimple »
Cordialement
Bruno

trimarco232

  • Sr. Member
  • ****
  • Messages: 309
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #140 le: mai 17, 2024, 05:42:10 pm »
Bonjour ,
j'ai des questions (voir des doutes) quant-à la fiabilité d'un tel montage (mais c'est peut-être juste parce que je suis loin d'avoir tout compris) :
- les gens de DCC-EX , c'est des costauds , si on pouvait implémenter le cutout de manière assez fiable dans l'ESP32 , pourquoi ne l'auraient-ils pas fait ?
- c'est le RMT qui est utilisé , car il permet de dérouler le packet indépendamment des errances des cores
- à la fin d'un RMT , il faut recharger les données (pour le packet suivant) , dans le cadre d'une interruption : il vaut mieux que cette interruption se fasse au cours d'un bit dcc 0 , par exemple le packet start bit , car c'est le moment où on peut se permettre des libertés dans les délais , moyennant le stretch de ce bit , ce qui est permis par la norme
- ce code créé plusieurs approximations dans le timing :
- - la latence de l'interruption : 4 à 8us , et pire si des opérations wifi sont en cours
- - les delayMicroseconds() , c'est pas des sciences exactes , en particulier pour un ESP32
- - le digitalWrite , pareil
.
donc , je ne doute pas que tu trouves des signaux acceptables à l'analyseur logique , mais qu'en est-il quand l'ESP32 est un peu sollicité , notamment s'il fait des opérations wifi ?

lebelge2

  • Newbie
  • *
  • Messages: 33
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #141 le: mai 17, 2024, 09:08:00 pm »
Trimarco.
Je vais tester la fiabilité de mon système dans les prochains jours.
Il y a quand même une tolérance de 6µs (26 à 32µs après le bit de stop).
Je vais mesurer si je reste dans cette fenêtre avec le µp en charge (WiFi)

gbo95

  • Newbie
  • *
  • Messages: 13
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #142 le: mai 17, 2024, 11:27:15 pm »

Sur Locoduino, dans la deuxième page sur le projet La Box, on peut lire :
Le choix du pont en H L6203 a été fait à l’époque où le LMD18200 s’est avéré plus cher et ses modules difficiles à trouver. Mais il ne permet pas de réaliser les lectures RailCom, faute de broche "Brake".

La broche "Brake" coupe la sortie de puissance mais en plus court-circuite les sorties. C'est prévu à l'origine pour piloter un moteur, et le freiner en court-circuitant sa force électromotrice (FEM). Pour le DCC, ceci permet à un décodeur d"envoyer un petit courant dans le détecteur de son canton. Ce détecteur est alors capable de lire l'information codée par cette circulation de courant.

Créer un cut-out à haute impédance ne permet pas la circulation d'un courant envoyé par un décodeur.
Il faut alors que le "lecteur de railcom" crée un court-circuit pendant le cut-out afin de permettre la circulation de courant. Je ne connais pas assez ces équipements pour savoir si cela existe.

trimarco232

  • Sr. Member
  • ****
  • Messages: 309
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #143 le: mai 18, 2024, 12:25:35 am »
oui , on a un principe de boucle de courant , cela permet au détecteur railcom d'entendre des décodeurs multifonctions qui sont bien éloignés dans le réseau
si on n'est pas trop loin , ça va aussi marcher sans boucle de courant (j'en dirai + quand j'aurai expérimenté moi-même)
le L6203 n'a pas besoin de broche Brake , vu que la combinaison IN1/2 = LOW/LOW donne SINK1/2 (le brake , donc)
« Modifié: mai 18, 2024, 12:49:01 am par trimarco232 »

trimarco232

  • Sr. Member
  • ****
  • Messages: 309
    • Voir le profil
Re : Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #144 le: mai 18, 2024, 12:32:23 am »
Trimarco.
Je vais tester la fiabilité de mon système dans les prochains jours.
Il y a quand même une tolérance de 6µs (26 à 32µs après le bit de stop).
Je vais mesurer si je reste dans cette fenêtre avec le µp en charge (WiFi)
bien , alors on saura
(pour moi 26 à 32us , ça fait une tolerance de 3us ; après petit calcul , la durée est de 29us après le bit stop , puis de 442us pour le cutout proprement dit)

laurentr

  • Hero Member
  • *****
  • Messages: 617
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #145 le: mai 18, 2024, 12:42:32 pm »
Hello Marc

J ai qq difficultés à comprendre certaines de valeurs que tu indiques.

Comme source je pars de la RCN217:
https://normen.railcommunity.de/RCN-217.pdf


Le 454 OK  fin émission canal 2
464 arrivée sur le 4eme bit 1 ou le 1 bit = 58us
le 488 ok fin cutout max

Je ne retrouve pas la valeur de 471 ( sur quels éléments se base t elle) Autant 442+29 = 471 ok mais le reste sic je pédale...
Idem le +7us ? ( temps de montées de la sortie de commande?)

Si tu veux bien nous éclairer?


trimarco232

  • Sr. Member
  • ****
  • Messages: 309
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #146 le: mai 18, 2024, 11:17:27 pm »
(oui , ce truc n'est pas si évident , on a vite fait de se planter)
si j'ai bien interprété le dessin , concernant le cutout , au niveau de la CS (génération du DCC) , on doit se conformer à 2 valeurs , qui comme toutes les autres , sont mesurées depuis le front montant de ce qui aurait été le 1er bit du preamble , et qui sera donc tronqué :
- Cutout Start : TCS  : 26µs à 32µs // soit 29us pour qui sait faire des timings précis  8)
- Cutout End :  TCE   : 454µs à 488µs // soit 471us         ii                        ii
la durée du cutout est donc l'heure de sa fin , 471us , moins celle de son début , 29us , ce qui donne "mes"   442us

"mes" 7us , ce n'est pas bien important ; si on prend "mes" valeurs pour le cutout , et que la CS continue de générer des pulses à 58us comme si de rien était , le cutout se terminerait 7us avant le fin du 4ème bit du preamble (largement amputé , du coup) ; ces 7us peuvent varier pour les CS ne respectant pas les 58us (comme certains ne se gênent pas d'en faire)
pour ma part , je laisse tomber ces 7us : je recommence un bit 1 entier , 1er bit du vrai preamble , dès la fin du cutout

je voulais parler des 442us , notamment vis à vis du programme de lebelge2 , où j'ai lu :  delayMicroseconds(412);  ?

laurentr

  • Hero Member
  • *****
  • Messages: 617
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #147 le: Aujourd'hui à 02:44:14 am »
C est plus clair comme cela:
 471 se retrouvent avec = (488 -454)/2 + 454 :)

Avec les AVR on peut aller très précisément sur les plages en question grâce aux timer B.
Aussi voila le genre de trame que l'on doit pouvoir traiter pour le résultat qui nous intéresse mais qui requiert un AVR en plus de l'ESP32

Valeurs en accord avec les remarques portées sur le Security Gap d'OPEN DCC: https://www.opendcc.de/info/railcom/railcom_f.shtml

De plus on y inclus les marges des timings selon ce qui sera perçu en entrée.= et toujours conforme au respect de la norme.


// Values for half bits from RCN 210, section 5: http://normen.railcommunity.de/RCN-210.pdf
#define ONE_BIT_MIN                             F_CPU / 1000000 * 52
#define ONE_BIT_MAX                             F_CPU / 1000000 * 64
#define ZERO_BIT_MIN                            F_CPU / 1000000 * 90
#define ZERO_BIT_MAX                            F_CPU / 1000000 * 119


// Values for half bits from RCN 217,
#define ENABLE_STOP_TIME                        F_CPU / 1000000 * 26    // CUTOUT MIN START VALUE
#define ENABLE_START_TIME                       F_CPU / 1000000 * 488  // CUTPOUT MAX STP¨VALUE

// Values according OPEN DCC best practices:
#define CUTOUT_START_TIME                       F_CPU / 1000000 * 30   //4us security gap cutout at start
#define CUTOUT_STOP_TIME                        F_CPU / 1000000 * 484   //4us secutity gap cutout at stop



  //TIMER B IS ALREADY STARTED AND CNT GO UP     
  if(TCB0.CNT < ENABLE_STOP_TIME) //< 26us
  {
    //ENABLE ON
    LOGIC_ENABLE_OUT_PIN_ON;
    while(TCB0.CNT < ENABLE_STOP_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((TCB0.CNT < CUTOUT_START_TIME) && (TCB0.CNT >= ENABLE_STOP_TIME)) // >=26us & <30us
  {
    //ENABLE OFF
    LOGIC_ENABLE_OUT_PIN_OFF;
    while(TCB0.CNT < CUTOUT_START_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((TCB0.CNT < CUTOUT_STOP_TIME) && (TCB0.CNT >= CUTOUT_START_TIME)) // >=30us & <484us
  {
    //MAKE CUTOUT:
    LOGIC_CUTOUT_OUT_PIN_ON;
    while(TCB0.CNT < CUTOUT_STOP_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((TCB0.CNT < ENABLE_START_TIME) && (TCB0.CNT >= CUTOUT_STOP_TIME)) // >=484 us & < 488us
  {
    //STOP CUTOUT
    LOGIC_CUTOUT_OUT_PIN_OFF;
    while(TCB0.CNT < ENABLE_START_TIME) {;}; //WAIT TILL IS OVER
  }
  else if ((TCB0.CNT >= ENABLE_START_TIME)) // >=488us
  {
    //ENABLE PIN ON:
    LOGIC_ENABLE_OUT_PIN_ON;

    //CUTOUT IS OVER

  }
}


A eprouver encore par quelques tests de validation.

trimarco232

  • Sr. Member
  • ****
  • Messages: 309
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #148 le: Aujourd'hui à 10:18:12 am »
oui , mais ce n'est pas comme ça que je ferais ; si on utilise un MCU fiable pour seconder l'ESP32 , on peut :
1) décoder le packet , genre décodeur ou sniffer , méthode au choix , Aiko Prass , par exemple ; mettre le packet en RAM
2) ressortir le packet avec toutes les caractéristiques que l'on veut : timings précis , cutout , ceci en fonction du pont en H à commander

cette méthode , a toutefois 1 inconvénient lié la désynchronisation : comme les timings en entrée ne sont pas les mêmes qu'en sortie , il faut ajuster
et 1 contrainte à respecter logiquement : si on veut mettre plusieurs booster , il faut les placer en aval du petit MCU ; cela rend alors inutile les security gaps
« Modifié: Aujourd'hui à 10:22:09 am par trimarco232 »

laurentr

  • Hero Member
  • *****
  • Messages: 617
    • Voir le profil
Re : LaBox" : Une Centrale DCC polyvalente et abordable
« Réponse #149 le: Aujourd'hui à 01:03:54 pm »
C est la méthode que je teste actuellement. (sur un ATTINY826) ( avec la partie "logic", "event" n cie)

Dans l'ISR du TIMER affecté au décodage des trames DCC:


//------------------------------------------- ISR ----------------------------------------------------
ISR(DCC_TIMER_INT_vect) {

  DCC_TIMER.EVCTRL ^= TCB_EDGE_bm;                          // Change the event edge at which we trigger
  uint16_t  delta = DCC_TIMER.CCMP;                        // Delta holds the time since the previous interrupt
  uint8_t DccBitVal;

  if ((delta >= ONE_BIT_MIN) && (delta <= ONE_BIT_MAX)) {
    if (dccHalfBit & EXPECT_ONE) {                     // This is the second part of the 1 bit
      dccHalfBit = EXPECT_ANYTHING;
      DccBitVal = 1;
    }
    else if (dccHalfBit & EXPECT_ANYTHING) {           // This is the first part of the 1 bit
      dccHalfBit = EXPECT_ONE;
      return;
    }
    else {                                             // We expected a 1, but received 0 => abort
      DCC_TIMER.EVCTRL ^= TCB_EDGE_bm;                     // Likely J/K should be changed
      dccHalfBit = EXPECT_ANYTHING;
      dccrecState = WAIT_PREAMBLE;
      dccrec.bitCount = 0;
      return;
    }
  }
  else if ((delta >= ZERO_BIT_MIN) && (delta <= ZERO_BIT_MAX)) {
    if (dccHalfBit & EXPECT_ZERO) {                    // This is the second part of the 0 bit
      dccHalfBit = EXPECT_ANYTHING;
      DccBitVal = 0;
      }
    else if (dccHalfBit & EXPECT_ANYTHING) {           // This is the first part of the 0 bit
      dccHalfBit = EXPECT_ZERO;
      return;
    }
    else {                                             // We expected a 0, but received 1 => abort
      dccHalfBit = EXPECT_ANYTHING;
      dccrecState = WAIT_PREAMBLE;
      dccrec.bitCount = 0;
      return;
    }
  }
  else {
    // We ignore other halfbits, to avoid interference with orther protocols.
    // In case railcom would be implemented, here we could detect the cutout start (26..32us)
    return;
  } 


  dccrec.bitCount++;

  switch( dccrecState )
  {
    // According to NMRA standard S9.2, a packet consists of:
    // - Preamble
    // - Packet Start Bit
    // - Address Data Byte:
    // - Data Byte Start Bit + Data Byte [0 or more times]
    // - Packet End Bit

    case WAIT_PREAMBLE:
        // The preamble to a packet consists of a sequence of "1" bits.
        // A digital decoder must not accept as a valid, any preamble
        // that has less then 10 complete one bits
        if( DccBitVal )                                   // a "1" bit is received
        {
          if( dccrec.bitCount > 10 )
            dccrecState = WAIT_START_BIT;
        }
        else
        {
          dccrec.bitCount = 0;                            // not a valid preamble.
        }
    break;

    case WAIT_START_BIT:
      // The packet start bit is the first bit with a value of "0"
      // that follows a valid preamble. The packet start bit terminates the preamble
      // and indicates that the next bits are an address data byte
      if( !DccBitVal )                                  // a "0" bit is received
      {
        dccrecState = WAIT_DATA;
        dccrec.tempMessageSize = 0;
        // Initialise all fields
        uint8_t i;
        for(i = 0; i< MaxDccSize; i++ )
        {
          dccrec.tempMessage[i] = 0;
        } 
        dccrec.bitCount = 0;     
      }

    break;

    case WAIT_DATA:
      //==================
      if( dccrec.bitCount == 8 )                        // byte is complete
      {
        if(dccrec.tempMessageSize == MaxDccSize )       // Packet is too long - abort
        {
          dccrecState = WAIT_PREAMBLE;
          dccrec.bitCount = 0;
        }
        else
        {
          dccrecState = WAIT_END_BIT;                  // Wait for next byte or end of packet
        }
      }

    break;

    case WAIT_END_BIT:
      // The next bit is either a Data Byte Start Bit or a Packet End Bit
      // Data Byte Start Bit: precedes a data byte and has the value of "0"
      // Packet End Bit: marks the termination of the packet and has a value of "1"
 
      if(DccBitVal) // End of packet?
      {
        // Complete packet received and no errors
        // we are in a CUTOUT AREA NOW
        noInterrupts();
        //no new external event change the sequence actions queue above till queue is over,
        //just add ~500ms latency on any AC0 notifications by interrupt
       
          CUTOUT(bitRead(RAILCOM,0)); //proceed cutout till end of it
         
          //cutout is over now, continue

          dccrecState = WAIT_PREAMBLE; //next step will be at this state

        interrupts();   
     
      }
      else  // Get next Byte   
      {
        dccrecState = WAIT_DATA;
        dccrec.bitCount = 0;                              // prepare for the next byte 
      }   
   
    break;
  }
}


fonction CUTOUT:


void CUTOUT(bool RAILCOM_ACTIV_OR_NOT){
 
  if(RAILCOM_ACTIV_OR_NOT == false) //NO RAILCOM CUTOUT TO INSERT
  {
    //BY PASS CUTOUT: FORCE SOME PINS STATE ON:
    LOGIC_ENABLE_OUT_PIN_ON;
    LOGIC_CUTOUT_OUT_PIN_ON;

    return;
  }

  //RAILCOM ACTIV: NEED TO INSERT CUTOUT
 
  //TIMER B IS ALREADY STARTED AND CNT GO UP     
  if(DCC_TIMER.CNT < ENABLE_STOP_TIME) //< 26us
  {
    //ENABLE ON
    LOGIC_ENABLE_OUT_PIN_ON;
    while(DCC_TIMER.CNT < ENABLE_STOP_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((DCC_TIMER.CNT < CUTOUT_START_TIME) && (DCC_TIMER.CNT >= ENABLE_STOP_TIME)) // >=26us & <30us
  {
    //ENABLE OFF
    LOGIC_ENABLE_OUT_PIN_OFF;
    while(DCC_TIMER.CNT < CUTOUT_START_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((DCC_TIMER.CNT < CUTOUT_STOP_TIME) && (DCC_TIMER.CNT >= CUTOUT_START_TIME)) // >=30us & <484us
  {
    //MAKE CUTOUT:
    LOGIC_CUTOUT_OUT_PIN_ON;
    while(DCC_TIMER.CNT < CUTOUT_STOP_TIME) {;}; //WAIT TILL IS OVER
  }
  else if((DCC_TIMER.CNT < ENABLE_START_TIME) && (DCC_TIMER.CNT >= CUTOUT_STOP_TIME)) // >=484 us & < 488us
  {
    //STOP CUTOUT
    LOGIC_CUTOUT_OUT_PIN_OFF;
    while(DCC_TIMER.CNT < ENABLE_START_TIME) {;}; //WAIT TILL IS OVER
  }
  else if ((DCC_TIMER.CNT >= ENABLE_START_TIME)) // >=488us
  {
    //ENABLE PIN ON:
    LOGIC_ENABLE_OUT_PIN_ON;

    //CUTOUT IS OVER

  }
}




Comme tu le soulignes on a en fait une sortie cote ESP32 qui est une source DCC "universelle" ( voir non amplifiée)  qui peut ensuite être distribuée à tous les CPU effectuant le CUTOUT qui pilotent eux les ponts en H. (L6203 pour  mon cas)
On est alors aligné sur tous les segments.
Les sorties de l'ESP32 sont alors assimilables aux plots CD sur les centrales LENZ pour la synchro inter booster

Pour moi le Security Gap reste de mise pour écarter tout écart restant inter booster lorsqu'un véhicule reste à cheval puisque chaque électronique peut encore varier d'un pouillième...

Il y a donc bien une recomposition du signal entre l'émetteur (EP32) et tous les consommateurs (derrière le(s) pont(s) H) d'un un léger décalage mais qui est constant entre la source unique et tous les consommateurs.
« Modifié: Aujourd'hui à 01:07:17 pm par laurentr »