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

laurentr

  • Hero Member
  • *****
  • Messages: 611
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #60 le: mai 02, 2024, 06:01:40 am »
CODE PART2:

void INIT_SYSTEM_WITH_RAILCOM(){

  //COMPARATOR:

  //when inverting > non inverting ==> AC OUT = high
  //measured current will be connected to inverting input (L6203 SENSE PIN trough a 10K resistor)
   
    Comparator.input_p = comparator::in_p::in1; //inverting PIN_PB5
    Comparator.input_n = comparator::in_n::in1; //non inverting PIN_PB4
    Comparator.reference = comparator::ref::disable;
    Comparator.hysteresis = comparator::hyst::disable;
    Comparator.output = comparator::out::disable; // No output pin, signal not inverted internally

    Comparator.init();
   
    Comparator.start(); // Start comparator
 
  //DEFINE CCL LUT3:
    //NEED EVENT CHANNEL FIRST TO ROUTE INSIDE LUT3: USE EVENT CHANNEL 3

    Event3.assign_generator_pin(gen3::pin_pa6);   //PIN_PA6 AS EVENT CH3 SOURCE
    Event3.set_user(user::ccl3_event_a);          //EVENT A OF LUT3

    Event3.start();

    Logic3.enable;                       //ENABLE LUT3
    Logic3.input0 = logic::in::ac;       //AC0 level OUT
    Logic3.input1 = logic::in::event_a;  //EVENT_A from EVENT CH3
    Logic3.input2 = logic::in::masked;   //not used
    Logic3.output = logic::out::disable; //NOT USED, use EVENT CH2 instead
    Logic3.truth = 0x04;     

    Logic3.init();


    Event2.assign_generator(gen::ccl3_out);
    Event2.set_user(user::evouta_pin_pa7);

    Event2.start();   
 
  //DEFINE CCL LUT0: 
    Logic0.enable;                       //ENABLE LUT0
    Logic0.input0 = logic::in::masked;   //UDPI NOT USED
    Logic0.input1 = logic::in::pin;      //PIN_PA1
    Logic0.input2 = logic::in::pin;      //PIN_PA2
    Logic0.output = logic::out::disable; //NOT USED, use EVENT CH5 instead
    Logic0.truth = 0x04;                 // Set truth table

    Logic0.init();

    Event5.assign_generator(gen::ccl0_out); //source LUT0 OUT
    Event5.set_user(user::tcb0_capt);       //route to TCB0
    Event5.set_user(user::ccl1_event_a);    //event A CCL1
    Event5.set_user(user::ccl2_event_a);    //event A CCL2

    Event5.start();

    Event1.assign_generator_pin(gen1::pin_pa3); //PA3 INPUT
    Event1.set_user(user::ccl1_event_b);        //event B CCL1
    Event1.set_user(user::ccl2_event_b);        //event B CCL2

    Event1.start();

    Logic1.enable;                        //ENABLE LUT1
    Logic1.input0 = logic::in::event_a;   //logic1 in0 event A
    Logic1.input1 = logic::in::event_b;   //logic1 in1 event B
    Logic1.input2 = logic::in::masked;    //not used
    Logic1.output = logic::out::disable;  //OUTPUT NOT USED, OUT STATE will go to EVENT CH0
    Logic1.truth = 0x01;                  // Set truth table

    Logic1.init();

    Event0.assign_generator(gen::ccl1_out);
    Event0.set_user(user::evoutb_pin_pb2);

    Event0.start();

    Logic2.enable;                        //ENABLE LUT2
    Logic2.input0 = logic::in::event_a;   //logic2 in0 event A
    Logic2.input1 = logic::in::event_b;   //logic2 in1 event B
    Logic2.input2 = logic::in::masked;    //not used
    Logic2.output = logic::out::enable;   //PIN_PB3 OUTPUT TO DRIVE L6203 IN
    Logic2.truth = 0x02;                  // Set truth table

    Logic2.init();

    Event4.set_generator(gen::ac0_out);    //source AC0 out
    Event4.set_user(user::evoutc_pin_pc2); //manage LED_SHORCUT_OVERLOAD

    Event4.start();
   
    Logic0.start();
    Logic1.start();
    Logic2.start();
    Logic3.start();

}

void INIT_SYSTEM_SIMPLE_AMPLIFICATOR(){

  //COMPARATOR:
   
    Comparator.input_p = comparator::in_p::in1;
    Comparator.input_n = comparator::in_n::in1;
    Comparator.reference = comparator::ref::disable;
    Comparator.hysteresis = comparator::hyst::disable;
    Comparator.output = comparator::out::disable_invert; // No output pin, signal inverted internally

    Comparator.init();
   
    Comparator.start(); // Start comparator

  //EVENT CH1:
    Event1.assign_generator_pin(gen1::pin_pa1);   //PIN_PA1 AS EVENT CH1 SOURCE
    Event1.set_user(user::ccl1_event_a);          //EVENT A OF LUT0
    Event1.set_user(user::ccl2_event_a);          //EVENT B OF LUT2

    Event1.start();

  //EVENT CH2:
    Event2.assign_generator_pin(gen2::pin_pa2);   //PIN_PA2 AS EVENT CH2 SOURCE
    Event2.set_user(user::ccl1_event_b);          //EVENT A OF LUT0
    Event2.set_user(user::ccl2_event_b);          //EVENT B OF LUT2

    Event2.start();

  //LOGIC LUT1:
    Logic1.enable;                       //ENABLE LUT3
    Logic1.input0 = logic::in::event_a;  //AC0 level OUT
    Logic1.input1 = logic::in::event_b;  //EVENT_A from EVENT CH3
    Logic1.input2 = logic::in::masked;   //not used
    Logic1.output = logic::out::disable; //NOT USED, use EVENT CH0 instead
    Logic1.truth = 0x04;   

    Logic1.init();

  //EVENT CH0:
    Event0.assign_generator(gen::ccl1_out);
    Event0.set_user(user::evoutb_pin_pb2);

    Event0.start();

  //LOGIC LUT2:
    Logic2.enable;                        //ENABLE LUT2
    Logic2.input0 = logic::in::event_a;   //logic1 in0 event A
    Logic2.input1 = logic::in::event_b;   //logic1 in1 event B
    Logic2.input2 = logic::in::masked;    //not used
    Logic2.output = logic::out::enable;   //OUTPUT PIN_PB3
    Logic2.truth = 0x02;                  // Set truth table

    Logic2.init();

  //LOGIC LUT3:
    Logic3.enable;                       //ENABLE LUT3
    Logic3.input0 = logic::in::ac;       //AC0 level OUT
    Logic3.input1 = logic::in::masked;   //not used
    Logic3.input2 = logic::in::masked;   //not used
    Logic3.output = logic::out::disable; //NOT USED, use EVENT CH2 instead
    Logic3.truth = 0x02;     

    Logic3.init();

  //EVENT CH3:
    Event3.assign_generator(gen::ccl3_out);
    Event3.set_user(user::evouta_pin_pa7); //L6203_ENABLE_PIN

    Event3.start();

  //EVENT CH4:
    Event4.assign_generator(gen::ac0_out);
    Event4.set_user(user::evoutc_pin_pc2);

    Event4.start();

  //START LOGIC NODES:
    Logic1.start();
    Logic2.start();
    Logic3.start();


}



CODE PART3:


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(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

  }
}


//------------------------------------------ DCC Interrupt -------------------------------------------


//------------------------------------------- ISR Timers ----------------------------------------------------
ISR(TCB0_INT_vect) {

  TCB0.EVCTRL ^= TCB_EDGE_bm;                          // Change the event edge at which we trigger
  uint16_t  delta = TCB0.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
      TCB0.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 AC0 notifications
     
      CUTOUT(RAILCOM); //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;
  }
}

ISR(AC0_AC_vect) {
 
    AC0.INTCTRL = 0; 

}




Ltr

laurentr

  • Hero Member
  • *****
  • Messages: 611
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #61 le: mai 02, 2024, 06:02:49 am »
CODE PART 4:


void setup()
{
  INIT_PINS(); //init first PINS

  //SIMPLE_AMPLIFICATOR = digitalRead(SIMPLE_AMPLIFICATOR_MODE_INPUT_PIN);
  AMPLIFICATOR_MODE = PORTC.IN & PIN4_bm; //faster

  if(AMPLIFICATOR_MODE == false)
  {   
    LED_SIMPLE_AMPLIFICATOR_MODE_PIN_OFF;

    INIT_TCB();

    INIT_ADDITIONNAL_PINS();

    //RAILCOM = digitalRead(RAILCOM_MODE_SELECTOR_INPUT_PIN);
    RAILCOM = PORTC.IN & PIN3_bm; //faster

    INIT_SYSTEM_WITH_RAILCOM();

    if (RAILCOM == false) //NO RAILCOM
    {
      //force these states out:
      LOGIC_ENABLE_OUT_PIN_ON;
      LOGIC_CUTOUT_OUT_PIN_ON;

      LED_RAILCOM_ENABLE_PIN_OFF;
    }
    else
    {
      LED_RAILCOM_ENABLE_PIN_ON;
    }
  }
  else
  {
    LED_RAILCOM_ENABLE_PIN_OFF;
    RAILCOM = false;
    LED_SIMPLE_AMPLIFICATOR_MODE_PIN_ON;
   
    INIT_SYSTEM_SIMPLE_AMPLIFICATOR();
  }

}


void loop(){

  //NOTHING TO DO! ALL IS AUTOMATIC :)

}





Plus qu'a se pencher sur un dessin de PCB pour donner vie à ce dispositif!

Ltr
« Modifié: mai 02, 2024, 06:05:46 am par laurentr »

trimarco232

  • Sr. Member
  • ****
  • Messages: 302
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #62 le: mai 02, 2024, 03:37:01 pm »
Laurent ,
les gens sont peu familiers avec la valorisation de tels hardwares , notamment les programmateurs , qui ont du mal avec l'électronique , et qui ont une culture de portabilité de leurs codes
si tu as du temps , tu peux faire une description didactique du projet , avec des dessins décrivant le principe général , et le rôle de chaque hardware particulier : cela permettra aux gens de voir les avantages des nouveaux microcontrôleurs , et de les comprendre , et de les approuver

laurentr

  • Hero Member
  • *****
  • Messages: 611
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #63 le: mai 02, 2024, 05:09:45 pm »
Hello Marc

Tu as raison la facilitera "l'adoption" et montrera la plus value de ces processeurs sur leur ainés dans le cas présent.

Je vais ouvrir un post dédié car cela sera utile en dehors de ce projet.

Je vais préparer ce qu'il faut pour mieux comprendre de quoi il retourne

J'ai profité de mes essais pour implémenter la commande externe avec gestion ad hoc de la led d'indication.
J ai du pour cela très légèrement revoir le mapping et ajouter quelques variables pour que "cela passe crème" sans voir besoin de ressources supplémentaires.

Ltr

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2917
  • 100% Arduino et N
    • Voir le profil
Re : Re : RailCom: Générateur de CutOut
« Réponse #64 le: mai 03, 2024, 10:20:41 am »

Je vais ouvrir un post dédié car cela sera utile en dehors de ce projet.


Peux-tu indiquer le lien vers ce sujet ?
Au passage, j'ai regroupé 2 sujets séparés (ça fait désordre !) et c'est peut-être celui-là : RailCom: Générateur de CutOut avec booster
https://forum.locoduino.org/index.php?topic=1709.0
Cordialement,
Dominique

laurentr

  • Hero Member
  • *****
  • Messages: 611
    • Voir le profil
Re : RailCom: Générateur de CutOut
« Réponse #65 le: mai 03, 2024, 01:12:03 pm »
Merci Dominique


Voici le lien pour comprendre les apports de ces nouveaux CPU:

https://forum.locoduino.org/index.php?topic=1712.0