Auteur Sujet: RailCom: Générateur de CutOut  (Lu 31817 fois)

lebelge2

  • Jr. Member
  • **
  • Messages: 79
    • Voir le profil
RailCom: Générateur de CutOut
« le: avril 24, 2024, 02:26:08 pm »
Bonjour.
Certaines centrales DCC notamment les DIY ne sont pas compatibles RailCom car ne génèrent pas le CutOut.
Ce petit montage à base, seulement d’un Arduino Uno, Nano ou Micro s’insère entre la centrale et le Booster.
Il génère le CutOut  afin de la rendre compatible RailCom.
Testé sur un Booster L298N et L6203.
Si dessous, le code et le schéma.
Bien à vous.

// RailCom: Programme pour insérer un CutOut dans les trames DCC.  Arduino Uno, Nano, Micro.
// Testé avec Bridge Driver L6203 et L298N
// V.1.0.   24-04-24
// lebelge2@yahoo.fr

volatile uint8_t dccrecState;
volatile uint8_t tempByte;
#define WAIT_PREAMBLE    0
#define WAIT_START_BIT   1
#define WAIT_DATA        2
#define WAIT_END_BIT     3
#define MaxDccSize 6                         // DCC messages can have a length upto this valu
#define PinIn1 3                             // Entrée signalDcc sans CutOut
#define PinOut1 4                            // Sortie signal DCC avec CutOut
#define PinOut2 5                            // Sortie signal DCC inversé avec CutOut

class DccMessage {
  public:
    volatile uint8_t size;
    volatile uint8_t data[MaxDccSize];        // The contents of the last dcc message received
} dccMessage;

struct {
  uint8_t bitCount;                           // Count number of preamble bits / if we have a byte
  volatile uint8_t tempMessage[MaxDccSize];   // Once we have a byte, we store it in the temp message
  volatile uint8_t tempMessageSize;           // Here we keep track of the size, including XOR
} dccrec;                                     // The received DCC message is assembled here

struct {
  uint8_t port;
  uint8_t bit;                                // Bitmask for reading the input Port
  volatile uint8_t *portRegister;
} dccIn;

void setup() {
  Serial.begin(9600);
  pinMode(PinIn1, INPUT);
  pinMode(PinOut1, OUTPUT);
  pinMode(PinOut2, OUTPUT);
  init_timer2();
  attachInterrupt(digitalPinToInterrupt(PinIn1), Dcc_Interrupt, CHANGE );
  dccIn.port = digitalPinToPort(PinIn1);
  dccIn.bit = digitalPinToBitMask(PinIn1);
  dccIn.portRegister = portInputRegister(dccIn.port);
  Serial.println ("SetUp OK");
}

void loop() {

}

void CutOut(void) {
  delayMicroseconds(8);
  asm("sbi 0x0B, 4");
  asm("sbi 0x0B, 5");
  delayMicroseconds(425);
  asm("cbi 0x0B, 4");
  asm("cbi 0x0B, 5");
}
//----------------------------------------------------------------------------------------------------------
void init_timer2(void) {
#define T2_PRESCALER   8
#define T2_PRESCALER_BITS   ((0<<CS02)|(1<<CS01)|(0<<CS00))
#define T77US (F_CPU * 77L / T2_PRESCALER / 1000000L)
#if (T77US > 254)
#warning T77US too big, use either larger prescaler or slower processor
#endif
#if (T77US < 32)
#warning T77US too small, use either smaller prescaler or faster processor
#endif
  noInterrupts();              // disable all interrupts
  TCCR2A = 0;                  // should be zero for our purpose
  TCCR2B = 0;                  // 0 => timer is stopped
  TCNT2 = 256L - T77US;        // preload the timer
  TIMSK2 |= (1 << TOIE2);      // the timer is used in overflow interrupt mode
  interrupts();                // enable all interrupts
}
//----------------------------------------------------------------------------------------
void Dcc_Interrupt() {
  if (digitalRead(PinIn1) == true) {
    asm("cbi 0x0B, 5");
    asm("sbi 0x0B, 4");
    TCCR2B |= (T2_PRESCALER_BITS);  // Start Timer 2
  }
  else {
    asm("cbi 0x0B, 4");
    asm("sbi 0x0B, 5");
  }
}
//-----------------------------------------------------------------------------------
ISR(TIMER2_OVF_vect) {
  uint8_t DccBitVal;
  DccBitVal = !(*dccIn.portRegister & dccIn.bit);
  TCCR2B = 0;                                    // 0 => timer is stopped
  TCNT2 = 256L - T77US;                          // preload the timer
  dccrec.bitCount++;
  switch (dccrecState) {
    case WAIT_PREAMBLE:
      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:
      if ( !DccBitVal ) {                        // a "0" bit is received
        dccrecState = WAIT_DATA;
        dccrec.tempMessageSize = 0;
        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:
      if ( DccBitVal ) {                           // End of packet?
        CutOut();
        dccrecState = WAIT_PREAMBLE;
      }
      else                                         // Get next Byte
        dccrecState = WAIT_DATA;
      dccrec.bitCount = 0;                         // prepare for the next byte
  }
}


trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #1 le: avril 24, 2024, 11:36:06 pm »
Bonjour,
encore une réalisation remarquable , bravo !
« Modifié: avril 25, 2024, 09:14:09 am par trimarco232 »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #2 le: avril 24, 2024, 11:54:39 pm »
Bonjour lebelge,

Je suis très intéressé et en même temps certaines choses m'étonnent.

Je comprends bien le principe adopté pour insérer le cutout à la place de certains bits du préambule. Mais encore faut il qu'il y ait assez de bits ! Si la centrale ne génère que 16 bits de préambule, ou 14 ? Avec une centrale en DIY, on peut générer le nombre de bits que l'on veut, mais une centrale du commerce ?

Par ailleurs, pour activer le transfert, il faut que le booster court-circuite la sortie pour que le décodeur envoie un courant dans la boucle ainsi créée. Or je ne vois pas comment tu réalises cela ici ? Avec un LMD18200 qui dispose d'une entrée BRAKE, c'est très simple. Sur un L603 je crois que l'on peut le faire avec la pin ENABLE1 et  ENABLE1 (mais je ne vois pas cela dans ton montage). Et avec un L298N ?

Merci pour tes réponses.

Christophe
« Modifié: avril 25, 2024, 07:23:13 am par bobyAndCo »

CATPLUS

  • Sr. Member
  • ****
  • Messages: 435
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #3 le: avril 25, 2024, 07:41:12 am »
Bonjour LeBelge

Trés intéressé et voir plus, un autre ami est sur le même projet (en cours de mise au point). Pour le soft (je me garderais bien de faire une remarque, "Christophe est beaucoup plus compétent")
4 questions:
Sur le schéma, la sortie de la centrale a un seul fil via la broche "3" du Nano, la question où brancher le second fil de la centrale?
Les centrales ont 2 bornes de sorties "J & K" merci de nous donner les branchements.
En cas de court-circuit, comment réagi le montage?
Une  centrale réglée pour 4 voir plus ampères, garde-t-on la puissance?

Je soupçonne que vous avez tester votre montage, auriez-vous une photo ou vidéo

Merci pour votre réponse

Marcel
Best Regards

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : Re : RailCom: Générateur de CutOut
« Réponse #4 le: avril 25, 2024, 09:24:07 am »
(...) on peut générer le nombre de bits que l'on veut, mais une centrale du commerce ?
je me permets de répondre , en fonction de ce que j'ai cru comprendre)
avec une centrale du commerce , il faut connaître le preamble pour savoir si c'est compatible (vous noterez le niveau de réflexion) ; en général , c'est compatible , si non c'est sniffer + scheduler , pas la même approche
Citer
on peut le faire avec la pin ENABLE1 et  ENABLE1 (mais je ne vois pas cela dans ton montage). Et avec un L298N ?
(...)
en l'état , c'est prévu pour un IC pont en H classique , cad. 1/0 = 1/0  ,  0/1 = 0/1 et , pour le cutout , 1/1 = 0/0
pour des IC ou des shields avec une entrée brake dédiée , il faut adapter/compléter le soft
« Modifié: avril 25, 2024, 09:46:12 am par trimarco232 »

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : Re : RailCom: Générateur de CutOut
« Réponse #5 le: avril 25, 2024, 09:35:51 am »
(...) où brancher le second fil de la centrale?
on n'en branche qu'un , en adaptant la tension  , ou mieux :
- en DIY , on se prend à la sortie DCC de l'arduino
- avec une centrale du commerce , on va chercher ce signal directement sur la carte
Citer
En cas de court-circuit, comment réagi le montage?
Une  centrale réglée pour 4 voir plus ampères, garde-t-on la puissance?
ces questions ne concernent pas le montage en lui-même , mais le (les) pont en H se trouvant en aval
c'est d'abord orienté DIY , mais on peut peut-être insérer ceci dans une centrale du commerce , cad. entre la génération du signal DCC et la partie puissance , mais c'est à étudier au cas par cas , ça risque d'être lourd , voire impossible
Citer
Je soupçonne que vous avez tester votre montage, auriez-vous une photo ou vidéo
why not , mais amha , les dessin et chrono-diagrammes sont assez parlants


« Modifié: avril 25, 2024, 09:49:35 am par trimarco232 »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #6 le: avril 25, 2024, 09:53:23 am »
Bonjour Marc,

Merci d’apporter des éclairages. Je ne suis pas aussi sûr que toi que les centrales du commerce génèrent (beaucoup) plus de bits de préambule que nécessaire soit 12, 14 ou 16.

Sait-on par exemple combien de bit de préambules sont générés dans DCC-Ex, soft qui est à la base de la Box ?

Oui pour obtenir le signal de DIR soit les 1 (HIGH) soit les 0 (LOW), baiser en tension l’un des conducteurs du signal DCC, sans doute une bonne idée. Comment procèderais-tu pour « tenir » dans un 5V max ?

Il est plus facile à implanter directement en sortie du µcontroleur. Ce qui est désigné sur le schéma comme « entrée DCC » serait en fait la sortie DIR. C’est elle qui génère soit les 1 (HIGH) soit les 0 (LOW).

Pour le court-circuit, tu penses que mettre EN1 et EN2 en cc suffit ! cad. 1/0 = 1/0 , 0/1 = 0/1 et , pour le cutout , 1/1 = 0/0 Tu as certainement raison, je ne suis pas ici dans ma zone de confort pour ce qui est de mes compétences.

Merci de nous permettre à tous de mieux appréhender ce sujet.

Christophe




« Modifié: avril 25, 2024, 09:55:22 am par bobyAndCo »

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #7 le: avril 25, 2024, 10:10:07 am »
Au niveau du soft, j’ai aussi quelques interrogations quant à certains choix.

Par exemple, je suis à peu près certain que cette commande écrite en partie en assembleur est malgré tout moins rapide en exécution qu’une écriture directe sur les ports.

void Dcc_Interrupt() {
  if (digitalRead(PinIn1) == true) {
    asm("cbi 0x0B, 5");
    asm("sbi 0x0B, 4");
    TCCR2B |= (T2_PRESCALER_BITS);  // Start Timer 2
  }
  else {
    asm("cbi 0x0B, 4");
    asm("sbi 0x0B, 5");
  }
}

Et que le digitalRead() aurait pu être très avantageusement remplacé par une lecture du port !!!

Ceci n’est pas très important à ce stade mais pourra faire partie des réflexions d’évolution

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #8 le: avril 25, 2024, 11:25:15 am »
concernant DCC-EX , leur principe actuel est de générer le cutout en aval de la centrale (pour être compatible avec AVR et ESP-32) , donc il doivent forcément générer un nombre suffisant de bits de preambles
si tu veux je vérifie , et je regarde comment insérer le HW dans LaBox

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #9 le: avril 25, 2024, 11:29:59 am »
Oui je veux bien que tu regardes si tu peux. Selon moi, ce doit être proche du "minimum syndical" mais probablement pas plus de 16.

En modifiant très légèrement DCC-Ex cela est certainement modifiable... mais attention à l'occasion de mises à jour !

et je regarde comment insérer le HW dans LaBox

Pas comprendre HW ?

Merci

Christophe

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : Re : RailCom: Générateur de CutOut
« Réponse #10 le: avril 25, 2024, 11:46:41 am »
(...)
Par exemple, je suis à peu près certain que cette commande écrite en partie en assembleur est malgré tout moins rapide en exécution qu’une écriture directe sur les ports.
- on ne peut pas aller + vite que l'assembleur , mais on peut écrire l'équivalent en C (me souviens plus comment)
- écrire directement sur le PORT , quelque soit la méthode , a pour inconvénient de modifier toutes les sorties du PORT , voir si c'est gênant ou pas
je crois le + rapide c'est :
PINB = 0b00110000 ; // on bascule les bits 4 et 5 sans toucher aux autres

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #11 le: avril 25, 2024, 11:54:22 am »
(...)
Par exemple, je suis à peu près certain que cette commande écrite en partie en assembleur est malgré tout moins rapide en exécution qu’une écriture directe sur les ports.
- on ne peut pas aller + vite que l'assembleur , mais on peut écrire l'équivalent en C (me souviens plus comment)
- écrire directement sur le PORT , quelque soit la méthode , a pour inconvénient de modifier toutes les sorties du PORT , voir si c'est gênant ou pas
je crois le + rapide c'est :
PINB = 0b00110000 ; // on bascule les bits 4 et 5 sans toucher aux autres

Si on peut aller plus vite que l'assembleur quand on travaille avec l'IDE Arduino. C'est le cas ici et le fichier a bien comme extension .ino. Christian explique précisément cela dans son article : https://www.locoduino.org/spip.php?article280

Timing d’une fonction
Dans certains cas, l’IDE d’Arduino ne permet pas d’obtenir ce qu’on veut. Consultez la page du site Arduino qui décrit la fonction delayMicroseconds() et examinez le petit programme fourni en fin de page et repris dans la figure 3.

Selon Arduino, ce programme tout simple ne donnera pas le résultat escompté.
Si vous examinez à l’oscilloscope le signal obtenu sur la sortie (ici broche 8), vous constaterez un signal carré cyclique dont la demi-période fait 53,5 µs au lieu de 50 µs comme le voulait le programmeur et parfois ce signal montre une demi-période de presque 60 µs. Comme il est dit sur la page du site d’Arduino, cette approximation est due à l’exécution de code qui a été rajouté par l’IDE.


Il en est de même pour digitalRead() ou digitalWrite() dont on estime le temps d'exécution entre 16 et 20 fois supérieur à l'écriture ou la lecture directe du port.

Voir également : https://docs.arduino.cc/retired/hacking/software/PortManipulation/

Je crois le + rapide c'est :
PINB = 0b00110000 ; //

Nous sommes d'accord.

Ceux qui commence à s'attaquer à ce type de programmation ne sont pas des perdreaux de l'année, ils savent adapter les ports selon la platelorme. Et rien n'empèche de mettre des #define en début de programme selon les µc.
« Modifié: avril 25, 2024, 12:03:09 pm par bobyAndCo »

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #12 le: avril 25, 2024, 12:14:51 pm »
HW , pardon , c'est parce que tu es un pro du SW

l'assembleur , c'est juste en Anglais ce que la machine fait en réel , donc on ne peut pas aller + vite ; bien entendu , un truc mal écrit en assembleur pourra aller moins vite qu'un truc bien écrit en Basic ...

le nombre de bits des preambles DCC-EX , c'est dans "DCCWaveform.h" :
// Number of preamble bits.
const int   PREAMBLE_BITS_MAIN = 16;
const int   PREAMBLE_BITS_PROG = 22;

bobyAndCo

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1088
  • HO avec DCC++
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #13 le: avril 25, 2024, 12:24:42 pm »
le nombre de bits des preambles DCC-EX , c'est dans "DCCWaveform.h" :
// Number of preamble bits.
const int   PREAMBLE_BITS_MAIN = 16;
const int   PREAMBLE_BITS_PROG = 22;

Bon d'origine on est trop court avec 16 bits que l'on fasse du Railcom Chanel 1 simplement ou Chanel 1 et 2 bien sûr. Heureusement c'est modifiable mais attention aux MAJ de DCC-Ex comme je le disais plus haut.

l'assembleur , c'est juste en Anglais ce que la machine fait en réel , donc on ne peut pas aller + vite ; bien entendu , un truc mal écrit en assembleur pourra aller moins vite qu'un truc bien écrit en Basic ...

Bon Christian nous raconte de con**ries ! Je lui en parlerai quand je vais le voir !

lebelge2

  • Jr. Member
  • **
  • Messages: 79
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #14 le: avril 25, 2024, 12:56:47 pm »
Bonjour.

- centrale du commerce :
     Il serait plus prudent d’insérer un optocoupleur entre la centrale et le montage.
Pour savoir si le préambule est suffisamment long, il suffit d’ajouter dans le programme : Serial.println(dccrec.bitCount) dans case WAIT_PREAMBLE: et mettre Serial.begin à 250000

- LMD18200 :
     Je ne possède pas encore ce module mais d’après le datasheet, au moment du CutOut, il faut que Dir soit à 0 et Brake à 1, il faudra adapter le soft plus deux sorties supplémentaires dédiées à ce module.
Je viens d’en commander un, adaptation du soft dès réception.

- Assembleur :
     Entre deux instructions il y a 0,125 µ seconde, difficile de faire mieux.

Test et essais fait avec un Arduino Mega pour centrale et Nano pour insérer le CutOut.
Logiciel :  CommandStaion-EX et Base Station.
Ci dessous, montage prototype pour essais.



« Modifié: avril 25, 2024, 03:06:03 pm par lebelge2 »