Auteur Sujet: Décodeur de locomotive multifonctions  (Lu 8934 fois)

laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #60 le: décembre 29, 2023, 03:47:30 am »
Hello


Voici de quoi tester!

RAILCOM est maintenant intégré dans la gestion de l'interruption avec les timing ad hoc gérant ses propres émissions.

Voila ce que cela donne

Modif de la LIB d'AIKO avec ces fichiers:

//******************************************************************************************************
//
// file:      sup_isr.cpp
// purpose:   DCC receiving code for ATmega(X) processors
// author:    Aiko Pras +LTR
// version:   2021-05-15 V1.0.0 ap Initial version
//            2023-12-xx V1.2.1 ADD RAILCOM
//
// Purpose: Select the best DCC capture code for a specific processor and board.
//
// This version of the software runs only on ATmega processors, and not on (for example) the ESP32
//
// For traditional ATmega processors, such as used on the Arduino UNO and MEGA boards, we use an
// approach where a change of the DCC input signal triggers an ISR. The ISR sets a timer to 77us,
// and once the timer fires the DCC input pin's value is read to determine if we have a 0 or a 1.
// See sup_isr_Mega.h for details
//
// For the newer ATMegaX processors, such as the ATmega4808, 4809, AVR128DA and AVR128DB,
// we try to exploit the new Event system peripheral, which can offload  certain task to hardware
// and thereby considerably improves the quality of the captured DCC input signal. Timing has become
// very precise, which means that the code should be able to run in multi-protocol environments and
// conform to the timing requirements as defined by the Rail Community (RCN-210)/
// To exploit these, the MegaCoreX or DxCore boards should be installed by the ARduino IDE:
// https://github.com/MCUdude/MegaCoreX
// https://github.com/SpenceKonde/DxCore
// See sup_isr_MegaCoreX_DxCore.h for details
// 
// If the ATMegaX 4809 processor is used on an Arduino Nano Every, but instead of the MegaCoreX board
// the 'standard' Arduino megaAVR board has been selected in the Arduino IDE, a similar decoding
// approach is used as with the traditional ATmega processors: a change of the DCC input signal
// triggers an ISR; the ISR sets a timer and once the timer fires the DCC input pin's value is read.
// Note that performance of this approach on new processors gives considerably more overhead than on
// the traditional processors. Therefore it is strongly adviced to switch to a MegaCoreX board.
//
//******************************************************************************************************
#include <Arduino.h>

#if defined(__AVR_MEGA__)
  // Only runs on Atmega (AVR) processors
  #if defined(__AVR_XMEGA__)
    // These are the new megaAVR 0, AVR DA and AVR DB processors and MegaTiny     
    #if defined (ARDUINO_AVR_NANO_EVERY)
      // This is the Arduino Nano Every, using an Arduino megaAVR board
      #include "sup_isr_Nano_Every.h"     
    #elif defined(MEGACOREX) && !defined WITH_RAILCOM
      // megaAVR 0
      #include "sup_isr_MegaCoreX_DxCore.h"
    #elif defined(MEGACOREX) && defined WITH_RAILCOM
      // megaAVR 0 & RAILCOM
      #include "sup_isr_MegaCoreX_DxCore_RAILCOM.h" 
    #elif defined(_AVR_FAMILY)
      //AVR DA DB DD (EA)(EB) or MegaTiny CPU Core
      #if !defined WITH_RAILCOM
        #include "sup_isr_MegaCoreX_DxCore.h"
      #else
        #include "sup_isr_MegaCoreX_DxCore_RAILCOM.h"
      #endif
    #endif
  #else
    // These are the traditional ATmega processors
    // Examples are ATmega16A, 328 and 2560
    #include "sup_isr_Mega.h"
  #endif
#else
  #if defined(MIGHTYCORE)
    // The 8535 isn't defined as __AVR_MEGA__, but works
    #include "sup_isr_Mega.h"
  #endif
#endif



laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #61 le: décembre 29, 2023, 03:50:05 am »
La suite en 2 parties (pour s affranchir des limites de 20K caractères)

sup_isr_MegaCoreX_DxCore_RAILCOM.h :
PART 1:
//******************************************************************************************************
//
// file:     sup_isr_MegaCoreX_DxCore_RAILCOM.h
// purpose:  DCC receive code for ATmegaX processors, such as ATmega 4808, 4809, AVR DA, AVR DB, ...
//           using a MegaCoreX or DxCore board
// author:   Aiko Pras + LTR
// version:  2021-09-01 V1.2.0 ap - Uses the Event system to connect the DCC input pin to a TCB timer.
//           2023-12-10 V1.2.2 add RAILCOM support LTR
//
// Result:   1. The received message is collected in the struct "dccrec.tempMessage".
//           2. After receiving a complete message, data is copied to "dccMessage.data".
//           3. The flag "dccMessage.isReady" is set.
//
// Used hardware resources:
//  - DccPin: Any ATmega pin can be used to receive the DCC input signal
//            Polarity of the J/K signal is not important.
//  - Timer:  One TCB timer. Default is TCB0, but the default can be changed by setting one of the
//            #defines (DCC_USES_TIMERB1, DCC_USES_TIMERB2 or DCC_USES_TIMERB3)
//            No dependancies exist with other timers, thus the TCA prescaler is NOT used.
//  - Event:  One of the Event channels available in ATmegaX processors.
//            The software automatically selects an available channel.
//            Not every pin can be connected to every Event channel. If other software has already
//            claimed usage of some channels, it might be necessary to select a DCC input pin on
//            another port. See also: https://github.com/MCUdude/MegaCoreX#event-system-evsys
//
// Howto: This part of the library takes advantage of the Event system peripheral that is implemented
// in the novel ATmegaX processors, and which is supported by MegaCoreX and DxCore.
// The DCC pin is used as input for an Event channel. The output of that Event channel triggers a TCB
// timer in 'Capture Frequency Measurement Mode'. If an event occurs in this Mode, the TCB
// captures the counter value (TCBn.CNT) and stores this value in TCBn.CCMP. The Interrupt flag is
// automatically cleared after the low byte of the Compare/Capture (TCBn.CCMP) register is read.
// The value in TCBn.CCMP is the number of ticks since the previous event, thus the time since the
// previous DCC signal transition. This time determines if the received DCC signal represents (half of)
// a zero or one bit.
// Since we do not want to introduce any dependency between our TCB timer and the TCA prescaler,
// TCB is used at clock speed. This requires us to use TCB in 16 bit mode. If we would have used the
// TCA prescaler, TCB could have been run in 8-bit mode, saving us roughly 8 clock cycli.
// To conform to the RCN-210 standard, we measure the times for both first as well as second half bit.
// Therefore the TCB ISR is called twice for every DCC bit.
// Since the TCB can only trigger on positive or negative edges of the input signal, the trigger
// direction is inverted after each interrupt.
//
// This code uses the Event system of MegaCoreX and DxCore:
// https://github.com/MCUdude/MegaCoreX#event-system-evsys
// https://github.com/SpenceKonde/DxCore
//
// Note: Railcom has now been implemented.
// Timer CNT + CCMP to determine the exact moment when
// the railcom data should be set. The railcom condition occured if conditions meet timings and DCC pins state.
// A UART is started to send the railcom data in RC appropriate periods according CV28 CV29 settings.
//
//
/* IMPLEMENTED BY LTR by adding new define values for RAILCOM

*/
//
//******************************************************************************************************
#include <Arduino.h>
#include <Event.h>
#include "sup_isr.h"

#include "CLASS_RAILCOM_GLOBAL.h"


//******************************************************************************************************
// 1. Declaration of external objects
//******************************************************************************************************
// The dccMessage contains the "raw" DCC packet, as received by the TCB ISR in this file
// It is instantiated in, and used by, DCC_Library.cpp
extern DccMessage dccMessage;

//RAILCOM items:
extern RAILCOM railcom;

//******************************************************************************************************
// 2. Defines that may need to be modified to accomodate certain hardware
//******************************************************************************************************
// Timer to use: TIMERB0 (TCB0), TIMERB1 (TCB1), TIMERB2 (TCB2), TIMERB3 (TCB3)
// In many cases TCB0 or TCB1 are still available for own use.
// The default is TCB0, which is available on all processor variants.
// This can be overruled by setting one of the following defines:
// #define DCC_USES_TIMERB1
// #define DCC_USES_TIMERB2
// #define DCC_USES_TIMERB3


// GPIOR (General Purpose IO Registers) are used to store global flags and temporary bytes.
// For example, in case of dccHalfBit, GPIOR saves roughly 8 clock cycli per interrupt.
// In case the selected GPIORs conflict with other libraries, change to any any free GPIOR
// or use a volatile uint8_t variable
#define dccrecState GPIOR0                     // fast: saves 3 clock cycli, but requires a free GPIOR
// volatile uint8_t dccrecState;               // slow, but more portable
#define tempByte GPIOR1                        // fast
// volatile uint8_t tempByte;                  // slow
#define dccHalfBit GPIOR2                      // fast
// volatile uint8_t dccHalfBit;                // slow

//ADD VARIABLES FOR RAILCOM:

#define FLAG_RAILCOM_IN_CUTOUT GPIOR3          //fast
//volatile bool FLAG_RAILCOM_IN_CUTOUT         //slow


//******************************************************************************************************
// 3. Defines, definitions and instantiation of local types and variables
//******************************************************************************************************
// 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

//ADD RAILCOM VALUES: LTR 20231210 follow RCN-217: https://normen.railcommunity.de/RCN-217.pdf last updated on 20231123

#define RAILCOM_CUTOUT_MIN_START_TIME   F_CPU/1000000 * 26        //MIN CUTOUT START TIME
#define RAILCOM_CUTOUT_MAX_START_TIME   F_CPU/1000000 * 32        //MAX CUTOUT START TIME

#define RAILCOM_CH1_START_TIME          F_CPU/1000000 * 75        //MIN CH1 START TIME
#define RAILCOM_CH1_MAX_START_TIME      F_CPU/1000000 * (80+15)   //MAX CH1 SEND START TIME
#define RAILCOM_CH1_END_TIME            F_CPU/1000000 * 177       //MAX CH1 END TIME
#define RAILCOM_CH2_START_TIME          F_CPU/1000000 * 193       //MIN CH2 START TIME
#define RAILCOM_CH2_MAX_START_TIME      F_CPU/1000000 * (193+15)  //MAX CH2 SEND START TIME
#define RAILCOM_CH2_END_TIME            F_CPU/1000000 * 454       //END CH2
#define RAILCOM_CUTOUT_MAX_END_TIME     F_CPU/1000000 * 488       //MAX CUTOUT TIME



// #define ZERO_BIT_MAX 65535
// Change the defines for ZERO_BIT_MAX to enable (disable) zero-bit stretching.
// To avoid integer overflow, we don't allow 10000 microseconds as maximum, but 65535 (maxint)
// For a 16Mhz clock this is equivalent to 4096 microseconds. This might work on most systems.
// For a discussion of zero bit streching see: https://github.com/littleyoda/sigrok-DCC-Protocoll/issues/4

// Possible values for dccrecState
#define WAIT_PREAMBLE       (1<<0)
#define WAIT_START_BIT      (1<<1)
#define WAIT_DATA           (1<<2)
#define WAIT_END_BIT        (1<<3)

// Possible values for dccHalfBit
#define EXPECT_ZERO         (1<<0)
#define EXPECT_ONE          (1<<1)
#define EXPECT_ANYTHING     (1<<2)

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



//******************************************************************************************************
// 4. Initialise timer and event system
//******************************************************************************************************
void DccMessage::initTcb(void) {
  // Step 1: Instead of calling a specific timer directly, we use alias via #defines
  #if defined(DCC_USES_TIMERB0)
    #define TIMER_DCC_CONTROL TCB0 
  #elif defined(DCC_USES_TIMERB1)
    #define TIMER_DCC_CONTROL TCB1
  #elif defined(DCC_USES_TIMERB2)
    #define TIMER_DCC_CONTROL TCB2
  #elif defined(DCC_USES_TIMERB3)
    #define TIMER_DCC_CONTROL TCB3
  #else 
    // fallback to TCB0 (every platform has it)
    #define TIMER_DCC_CONTROL TCB0;
  #endif
  // Step 2: fill the registers. See the data sheets for details
  noInterrupts();
  // Clear the main timer control registers. Needed since the Arduino core creates some presets:
  TIMER_DCC_CONTROL.CTRLA = 0;
  TIMER_DCC_CONTROL.CTRLB = 0;
  TIMER_DCC_CONTROL.EVCTRL = 0;
  TIMER_DCC_CONTROL.INTCTRL = 0;
  TIMER_DCC_CONTROL.CCMP = 0;
  TIMER_DCC_CONTROL.CNT = 0;
  TIMER_DCC_CONTROL.INTFLAGS = 0;
  // Initialise the control registers:
  TIMER_DCC_CONTROL.CTRLA = TCB_ENABLE_bm;                    // Enable the TCB peripheral, clock is CLK_PER (=F_CPU)
  TIMER_DCC_CONTROL.CTRLB = TCB_CNTMODE_FRQ_gc;               // Input Capture Frequency Measurement mode
  TIMER_DCC_CONTROL.EVCTRL = TCB_CAPTEI_bm | TCB_FILTER_bm;   // Enable input capture events and noise cancelation
  TIMER_DCC_CONTROL.INTCTRL |= TCB_CAPT_bm;                   // Enable CAPT interrupts
  interrupts();
}

void DccMessage::initEventSystem(uint8_t dccPin) {
  // Note: this code uses the new Event Library of MegaCoreX, DXCore & MEGATINYCore:
 
  noInterrupts();

  Event& myEvent = Event::assign_generator_pin(dccPin);

  #if defined(DCC_USES_TIMERB0)
    myEvent.set_user(user::tcb0_capt);
  #elif defined(DCC_USES_TIMERB1)
    myEvent.set_user(user::tcb1_capt);
  #elif defined(DCC_USES_TIMERB2)
    myEvent.set_user(user::tcb2_capt);
  #elif defined(DCC_USES_TIMERB3)
    myEvent.set_user(user::tcb3_capt);
  #else
    // fallback to TCB0 (every platform must have it)
    myEvent.set_user(user::tcb0_capt);
  #endif


  //start EVENTS:
  myEvent.start();

  interrupts();
}


//******************************************************************************************************
// 5. attach() / detach()
//******************************************************************************************************
void DccMessage::attach(uint8_t dccPin, uint8_t ackPin) {
  // Initialize the local variables
  _dccPin = dccPin;
  tempByte = 0;
  dccrecState = WAIT_PREAMBLE;
  dccrec.bitCount = 0;
  // initialise the global variables (the DccMessage attributes)
  dccMessage.size = 0;
  dccMessage.isReady = 0;
  // Initialize the peripherals: (TCBx) timer and the Event system.
 
  initTcb();

  initEventSystem(dccPin);
  // Initialise the DCC Acknowledgement port, which is needed in Service Mode
  // If the main sketch doesn't specify this pin, the value 255 is provided as
  // (invalid) default.
  if (ackPin < 255) pinMode(ackPin, OUTPUT);
 
}


void DccMessage::detach(void) {
  noInterrupts();
  // Clear all TCB timer settings
  // For "reboot" (jmp 0) it is crucial to set INTCTRL = 0
  TIMER_DCC_CONTROL.CTRLA = 0;
  TIMER_DCC_CONTROL.CTRLB = 0;
  TIMER_DCC_CONTROL.EVCTRL = 0;
  TIMER_DCC_CONTROL.INTCTRL = 0;
  TIMER_DCC_CONTROL.CCMP = 0;
  TIMER_DCC_CONTROL.CNT = 0;
  TIMER_DCC_CONTROL.INTFLAGS = 0;

  // Stop the Event channel  interrupts();
  interrupts();
 
}

« Modifié: décembre 29, 2023, 03:52:06 am par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #62 le: décembre 29, 2023, 03:51:01 am »
La suite

sup_isr_MegaCoreX_DxCore_RAILCOM.h :
PART2:

//******************************************************************************************************
// 6. The Timer ISR, which implements the DCC Receive Routine
//******************************************************************************************************
// Execution of this DCC Receive code typically takes between 3 and 8 microseconds.
// Select the corresponding ISR
#if defined(DCC_USES_TIMERB0)
  ISR(TCB0_INT_vect) {
#elif defined(DCC_USES_TIMERB1)
  ISR(TCB1_INT_vect) {
#elif defined(DCC_USES_TIMERB2
  ISR(TCB2_INT_vect) {
#elif defined(DCC_USES_TIMERB3)
  ISR(TCB3_INT_vect) {
#else
  // fallback to TCB0 (all platform have it)
  ISR(TCB0_INT_vect) {
#endif
 
  TIMER_DCC_CONTROL.EVCTRL ^= TCB_EDGE_bm;                         // Change the event edge at which we trigger
  uint16_t  delta = TIMER_DCC_CONTROL.CCMP;                        // Delta holds the time since the previous interrupt
  uint8_t DccBitVal;

  if(delta < RAILCOM_CUTOUT_MIN_START_TIME)
  {
    //It may be a glitch or parasit so cancel elapsed time since last interupt < 26us
    FLAG_RAILCOM_IN_CUTOUT = false;   
    TIMER_DCC_CONTROL.CNT = 0;
    dccrecState = WAIT_PREAMBLE;
    dccHalfBit = EXPECT_ANYTHING;
    dccrec.bitCount = 0;
    railcom.stop_TX();

    return; //it s a glitch so ignore it and leave ISR
  }

  if(FLAG_RAILCOM_IN_CUTOUT == false)
  {
    railcom.stop_TX(); //FORCE TX STATE READY
   
    //check if we are in CUTOUT TIMINGS [26us;32us] + last bit received was "1" to set a end of DCC message:
    if( ( (delta <= RAILCOM_CUTOUT_MAX_START_TIME) && (delta >= RAILCOM_CUTOUT_MIN_START_TIME) ) && (dccrecState == WAIT_PREAMBLE))
    { //WE ARE IN CUTOUT START INTERVAL  && LAST "END BYTE" PREVISOULY RECEIVED OK
     
      FLAG_RAILCOM_IN_CUTOUT = true;

    }
    else //we should receive now O or 1 bits:
    {       
      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
          TIMER_DCC_CONTROL.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;
        }
      }   

      #include "sup_isr_assemble_packet.h"
   
    } //END BITS MANAGEMENT
  } //end FLAG RAILCOM == false

  /* /NOT REQUIRED HERE DUE TO EVER TESTED PREVIOUSLY
  if((FLAG_RAILCOM_IN_CUTOUT) && (dccrecState != WAIT_PREAMBLE)) //WE ARE NOT IN RAILCOM CUTOUT CONDITIONS
  {
    FLAG_RAILCOM_IN_CUTOUT = false;
    TIMER_DCC_CONTROL.CNT = 0;
    dccrec.bitCount = 0;
    dccHalfBit = EXPECT_ANYTHING;
    dccrecState = WAIT_PREAMBLE;
   
    return; //LEAVE ISR
   
  }
  */

  if(FLAG_RAILCOM_IN_CUTOUT) ///WE ARE IN RAILCOM CUTOUT AT GOOD POINT
  {     
    if((!railcom.CH1_EMISSION_STATE) && (!railcom.CH2_EMISSION_STATE)) //SEND ANY DATA ON ANY CHANNEL
    {
      //railcom.stop_TX(); //FORCE TX IN WAIT STATE AT LEVEL ON

      do{railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta ) <= RAILCOM_CH2_END_TIME); //WAIT TILL END OF CUTOUT TIMING LEAVING AREA //shoule be an immediate leave too

      //LEAVING AREA OCCURED SO RESET VALUES AND LEAVE ISR
      FLAG_RAILCOM_IN_CUTOUT = false;
      TIMER_DCC_CONTROL.CNT = 0;
      dccrec.bitCount = 0;
      dccrecState = WAIT_PREAMBLE;
      dccHalfBit = EXPECT_ANYTHING;
      railcom.stop_TX(); //SET TX IN WAIT STATE

      return; //LEAVE ISR

    }   
    else if((railcom.CH1_EMISSION_STATE) && (railcom.CH2_EMISSION_STATE)) //CH1 & CH2  EMMISSION AUTHORISED
    {     
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH1_START_TIME); //WAIT TILL 75us ARRIVAL TO START TO SEND BYTE ON UART
   
      if( ((TIMER_DCC_CONTROL.CNT + delta ) >= RAILCOM_CH1_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME) ) //WE ARE IN THE CH1 PERIOD
      {
        if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH1_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO START SENDING CH1 BYTES?
        {
          //TOO LATE TO START SENDING BYTES SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //2 BYTES TO SEND IF CH1 EMISSION AUTORIZED
        railcom.Send_CH1_Messages();
      }

      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH2_START_TIME);  //WE ARE BETWEEN CH1 AND CH2 EMISSION INTERVAL SO WAIT TILL CH2 START TIME if required

      if( ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) ) //WE ARE IN CH2 TIMING AREA
      {
        if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO SEND CH2 BYTES?
        {
          //TOO LATE TO START SENDING CH2 SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;       
          TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //3 BYTES TO SEND IF CH2 EMISSION AUTORISED
        //SENDUARTCH2BYTE0
        //SENDUARTCH2BYTE1
        //SENDUARTCH1BYTE2

        railcom.Send_CH2_Messages();
   
      }

      //SENDING CH2 IS OVER BEFORE CH2 END TIME SO MAY REQUIRE TO WAIT BEFORE LEAVING AREA, this case should theorically never happen!)
      do {railcom.stop_TX();} while ( (TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME);
     
      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_END_TIME) && (TIMER_DCC_CONTROL.CNT + delta <= RAILCOM_CUTOUT_MAX_END_TIME))
      {
        //SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CUTOUT_MAX_END_TIME)) //should never happen
      {
        //CUTOUT AREA IS OVER AND SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

    }
    else if((railcom.CH1_EMISSION_STATE) && (!railcom.CH2_EMISSION_STATE)) //CH1 EMISSION AUTHORISED & CH2 EMMISSION NOT AUTHORISED
    {
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH1_START_TIME); //WAIT TILL 75us ARRIVAL TO START TO SEND BYTE ON UART
   
      if( ((TIMER_DCC_CONTROL.CNT + delta ) >= RAILCOM_CH1_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME) ) //WE ARE IN THE CH1 PERIOD
      {
        if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH1_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO START SENDING CH1 BYTES?
        {
          //TOO LATE TO START SENDING BYTES SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX();

          return; //LEAVE INTERUPT
        }
       
        //2 BYTES TO SEND IF CH1 EMISSION AUTORIZED
        railcom.Send_CH1_Messages();
      }

      //CH1 EMISSION IS OVER BUT MAY BE EARLIER AS CH1 END TIMOUT
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME);  //WAIT CH1 END AREA if required

      //WE ARE NOW BETWEEN CH1 END TIME AND CH2 END TIME
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME);  //WAIT CH2 END AREA

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_END_TIME) && (TIMER_DCC_CONTROL.CNT + delta <= RAILCOM_CUTOUT_MAX_END_TIME))
      {
        //SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CUTOUT_MAX_END_TIME)) //should never happen
      {
        //CUTOUT AREA IS OVER AND SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR

      }

    }   
    else if((!railcom.CH1_EMISSION_STATE) && (railcom.CH2_EMISSION_STATE)) //CH1 EMISSION NOT AUTHORISED & CH2 EMISSION AUTHORISED
    {
      do {railcom.stop_TX();} while((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH2_START_TIME); //WAIT TILL CH1 AREA IS OVER

      if ( ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) )
      {
        if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH2_MAX_START_TIME)
        {
          //TOO LATE TO START SENDING BYTES SO ABORT:
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //3 BYTES TO SEND IF CH2 EMISSION AUTORISED
        //SENDUARTCH2BYTE0
        //SENDUARTCH2BYTE1
        //SENDUARTCH1BYTE2
        railcom.Send_CH2_Messages();

      }

      //SENDING IS OVER BUT EARLIER AS CH2 END STATE SO WE WAIT A BIT => theorically should never happen
      do {railcom.stop_TX();} while ( ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) ) ; //WAIT TILL END CUTOUT CH2 AREA CONDITIONS

      if(((TIMER_DCC_CONTROL.CNT + delta) <=  RAILCOM_CUTOUT_MAX_END_TIME ) && ((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH2_END_TIME))
      {
        //CUTOUT AREA TIMING CH2 IS OVER NOW SO UPDATE VALUES:
        FLAG_RAILCOM_IN_CUTOUT = false; //LEAVE CUTOUT STATE
        TIMER_DCC_CONTROL.CNT = 0; //RESET CNT
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE   
       
        return; //LEAVE ISR BETWEEN 454 & 488us //should be leave earlier too but need to wait hten to receive new dcc bits   
      }

      if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CUTOUT_MAX_END_TIME) //should never happen
      {
        //WE ARE OVER THE CUTOUT AREA
        FLAG_RAILCOM_IN_CUTOUT = false; //LEAVE CUTOUT STATE
        TIMER_DCC_CONTROL.CNT = 0; //RESET CNT
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }
    }
  }

} //END ISR


trimarco232

  • Sr. Member
  • ****
  • Messages: 283
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #63 le: décembre 29, 2023, 10:42:20 am »
au temps pour moi , j'ai indiqué le principe pour des AVR classiques , ce qui t'a confusionné ...
les comparateurs des nouveaux AVR disposent de leur propre MUX d'entrée , donc le principe est le suivant :
PRINCIPE POUR LES NOUVEAUX AVR :

trimarco232

  • Sr. Member
  • ****
  • Messages: 283
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #64 le: décembre 29, 2023, 11:08:59 am »
la contrainte , c'est qu'il faut choisir 2 pins qui peuvent être reliées à la fois à l'ADC et à un comparateur , mais il y a moult combinaisons possibles , à déterminer lors du dessin du PCB
à vérifier , mais rien ne semble empêcher que les 2 périphériques puissent être reliés simultanément , donc en permanence , aux 2 pins : cela simplifie bien l'analyse
pour que tout le monde comprenne , détaillons un peu  ; le décodeur est aimenté par un pont de Graetz , qui fixe peu ou prou le GND du décodeur à la tension du rail négatif (ce qui fait que du GND du décodeur est également proche du GND de la station DCC)
vu du décodeur , les tensions sur les 2 rails ont donc cette allure :


trimarco232

  • Sr. Member
  • ****
  • Messages: 283
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #65 le: décembre 29, 2023, 11:27:24 am »
les tensions vues sur le rail de droite sont l'inverse de celles du rail de gauche
j'ai représenté une différence entre les 2 tensions , on est donc sur une section dont l'ABC est actif
l'ADC mesure chaque rail après son front montant , on peut donc déterminer si on est en ABC actif , ou pas

le comparateur va voir la même chose :

trimarco232

  • Sr. Member
  • ****
  • Messages: 283
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #66 le: décembre 29, 2023, 11:33:59 am »
ici , c'est sur le rail gauche qu'on a l'impulsion tronquée à 29us , dont on va capturer le front montant , qui sert de base aux timings du cutout ; c'est aussi sur ce rail qu'on va devoir vérifier que la tension est bien revenue à 0v , au bout de 29us , pour lancer le canal 1
d'où la nécessité de choisir le "bon" rail , parmi les 2 , en entrée du comparateur

laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #67 le: décembre 29, 2023, 03:01:50 pm »
Bonjour

Merci pour ces updates. On voit en effet que c est un peu diffèrent.

Les nouveaux AVR disposent tous à minima d'un ADC. La série 1 des MEGATINY en dispose de 2! ( c est la seul série qui en dispos d autant!).
Toutefois les plus "véloces" ( AVR Dx) ont 2 entrées (une pour pole "négatif" et l'autre pour pole "positif". Ce n'est pas le cas sur les séries plus anciennes comme la série 0 des AVR (ATMEGAx08 et x09) et les MEGATINY des séries 0 et 1.

Ces quelques différences à priori minimes nous imposent donc aussi d'être vigilant sur les besoins vs capacités du hard surtout si l approche se veut d'une solution "transposable" d'un CPU à l'autre.

J ai quand même (encore) un gros point dure. Je ne dois pas être le seul...

Traitons le cas de base avec justement un AVR X08 ou X09 de la série 0. ( ce cas est exploitable sur tous les hard)

A un instant T0 tu n'as qu'avec l'ADCMUX 1 canal de lié au DAC. Si c est la rail de gauche alors on le considère comme "positif" et son voisin de droite est lui un "pseudo GND".
(On pourrait aussi être dans un cas inverse mais il faut bien amorcer dans un sens ou l autre)

Ensuite, dans le temps les "signaux" DCC vont s'inverser.

Il y a donc bien un "fait générateur" qui va modifier la valeur du PORMUX de l'ADC pour connecter alors l'autre broche? ( ou alors tu lis toujours sur la même?) C est la"truc magique" que je ne capte pas!

Je serai tenté de dire que cela pourrait être justement la sortie du COMPARATEUR qui filtre sur les fronts montants chaque changement. ( encore aucune idée de la façon de l'écrire à ce stade ou j essaye de voir les bloc, leurs relations et donc leur liaisons.

Ou alors tu as autre chose en vue mais je n ai pas encore transcrit le concept en solution.


Laurent



laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #68 le: décembre 29, 2023, 09:21:28 pm »
Bonsoir

Au sujet des "poly affectations des broches" rien ne semble l interdire ni non plus le permettre.

ATMEL START ne le permet pas. ( est ce l outils qui est limité?)

MPLAB MCC indique qu'il y a bien un lien avec plusieurs usages.

Je ne sais pas ce que sort ATMEL STUDIO à ce sujet...

C est donc un peu un flou... qu il faut pourtant lever.


Ltr


trimarco232

  • Sr. Member
  • ****
  • Messages: 283
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #69 le: décembre 30, 2023, 05:18:38 pm »
oui , il faut faire un petit test pour valider le principe ... par exemple une petite maquette avec une CS qui tourne à une vitesse divisée par 1000 ... on n'y coupera pas
normalement , la capture se fait toujours sur le même rail , mais pour l'ABC , il faut mesurer les 2 rails : on peut par exemple déclencher une mesure après un front montant , puis l'autre après un front descendant
je pense que si on fait cette mesure une seule fois pour chaque packet , ça peut suffire

laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #70 le: décembre 31, 2023, 04:39:14 pm »
Bonjour

Je vais essayer de définir la trame de l enchainement des principales étapes sur la base de ma compression actuelle du processus.
Les initialisation des blocs seront traiter en conséquence plus tard une fois que cette trame sera " au carré"

Pre requis:
choisir 2 pins sur le CPU pour y introduire le signal DCC via pont diviseur
ces 2 pins sont idéalement:
  • capable de faire de la lecture de valeur analogique ( entrees de l ADC)
    des entrées de l AC ( Comparator)
    coupable à un timer B

Pour une portabilité "optimale" on se reportera au tableau fourni précédemment. ( Pour les AVR le port D est optimal et rempli les conditions posées)

Une fois posées les entrées + et - du comparateur on a donc un état qui permet en sortie de comparateur d identifié si on est à un instant T avec un signal venant du rail de droite ou du rail de gauche.

Rm par CONVENTION avec l'analogique le rail de droite dans le sens normal de la marche est TOUJOURS le pole +.

On s appliquera le même principe ici en définissant SIGN_DCC_R comme le signal, provenant du rail de droite sur l'entrée non inverseuse du comparateur ( +)
Et réciproquement SIGN_DCC_L sur l entrée inverseuse (-) ( pole GND du rail en analogique)

(voir plus tard la table logique)

Ces précisions apportées, exploitons à présent la sortie du comparateur.

Au niveau du comparateur, sur la détection RISING, donc à chaque changement d'état montant du signal en entrée sur le comparateur ( sur chaque pole) dans le cas où le signal DCC est sur le rail de droite alors  la sortie du comparateur = "1",  on peut actualiser  la lecture sur le pole du rail droit relié à  ADC ( ADC0.PORMUX= PIN_SIGN_DCC_R) et inversement lorsque la sortie est sur la valeur opposée.
Si la sortie du comparateur = 0 on pourra procéder a la lecture de l'autre rail.

On doit voir si on fait une lecture simple ou échantillonnée ( 2 lectures? 4? 8 ? ...)

Si on est dans un ISR pour ces mesures on aura tendance à en sortir au plus vite... donc à réduire l échantillonnage à un faible nombre de valeurs.

On comparera alors si les 2 valeurs sont d ordre similaire ( avec une marge seuil bas < val mesurée < seuil haut) ou les seuils bas et hauts seront issus de la lecture de l autre pole mesuré auquel est affecté aussi avec un coefficient de "correction" par exemple seuil bas_rail_droit = 0.8 x val_seuil_mesuré_sur_rail_gauche, en deca de ce seuil alors on serait dans le cas d'un freinage ABC. On appliquerait alors une fonction visant à réduire progressivement la vitesse du moteur ( alors que la valeur reçue et émise par la centrale reste la valeur de vitesse désirée de l engin moteur.)

Lorsque la symétrie du signal DCC est rétablie ( donc que les conditions ayant entrainées le déclanchement du signal ABC ont disparue) alors notre engin doit reprendre son déplacement avec une accélération progressive jusqu'à la vitesse de commande émise par la centrale.

Nous avons donc le mécanisme de base.
Sur un timing DCC on sait que la bascule interviendra proche de 58us pour un demi bit 1 au plus court sinon proche de 29us pour un cutout railcom.

Dans ce cas on en déduit que le temps maxi de la séquence "lecture" devra être contenu en deçà de ces valeurs (sinon impacts et effets de bords)

Ltr






laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #71 le: décembre 31, 2023, 05:35:14 pm »
Phase 2:

Nous avons notre sortie de comparateur qui va donc exploiter soit une sortie physique soit un interruption. ( au choix l'un ou l'autre pas les deux!)

On pourrait exploiter la sortie en la reliant à une entrée liée au timer en charge de la détection des bits des trames DCC. Câblage externe. Mais on se priverait alors d'exploiter un ISR qui pourrait traiter cela plus nativement et inclure aussi plus d'actions diverses ( mais toujours les plus brèves possibles) (dont entre autre les lectures sur les entrées de l ADC).

Cote ABC on aura quelques chose proche de ceci:

uint16_t GET_ABC_VAL()//GIVE RESULT FROM ACTIV INPUT FOR ABC USAGES
{
  if(comparator.read())                     //SELECT INPUT ACCORDING ACTIV PIN
  {
    ADC0.MUXPOS = DCC_PIN_RIGHT;            //RAIL + AS INPUT
  }
  else
  {
    ADC0.MUXPOS = DCC_PIN_LEFT;             //RAIL - AS INPUT
  }

  ADC0.COMAND = ADC_STCONV_bm;                   //START MEASURMENT
 
  while( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )    //WAIT TILL IT IS OVER
  {
    ; //WAIT TILL IT IS IN PROGRESS
  }
 
  ADC0.INTFLAGS = ADC_RESRDY_bm;              //CLEAR INTERRUPT FLAG WRITTING 1
 
  return ABC_IN_VALUE = ADC0.RES;                 // PUSH VALUE
 
  }


Si cette interruption est justement celle qui gère de décodage les bits 0 et 1 en lien avec un TIMERBx on doit avoir le moteur de traitement opérationnel. Comment y parvenir?

Il faut pour cela identifier la maille pour liaisonner ces éléments entre eux. ( l'AC et la capture sur le TIMERB via la broche DCC_IN, pour notre cas liée au rail de droite)

C est le lien du schéma de Trimarco entre la sortie du COMPARATEUR (AC)  et l'entrée du TIMERBn en entrée.

Cela a beau être un "grand mécano" la construction n'est toutefois pas innée pour moi (sorry!)

Reste donc cette liaison à produire.

Ltr




laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #72 le: décembre 31, 2023, 07:54:09 pm »
Il semble que cette configuration soit en fait "triviale" avec les lignes ci dessous ( soit j'ai encore du grain à moudre :) )

Considérons que les trames DCC sont traitées sur le TIMERB0 mis en mode FREQ (Input Capture Frequency Measurement Mode).

EVSYS_GENERATOR_AC0_OUT_gc est bien la sortie du comparateur ( pas nécessairement la sortie physique mais l'état de sortie de la comparaison réalisée par le composant)

EVSYS.CHANNEL0 = EVSYS_GENERATOR_AC0_OUT_gc;   /* Analog Comparator 0 out */ //On liaisonne le CHANNEL0 à la sortie du comparateur
EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL0_gc;     /* Connect user to event channel 0 */ //On applique au TIMBERB0 le CHANNEL0 comme source

On liaisonne ainsi les états de sortie ( 0 ou 1)   du comparateur comme les trames entrantes dans la capture du TIMERB0 de façon identique au fait qu'elles proviendraient alors d une broche

Dans la lib d AIKO c est la broche  "dccPin" qui traite cela.

Il va donc falloir voir pour ajuster le tout selon ces éléments.

Ltr






laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #73 le: janvier 03, 2024, 01:13:01 pm »
Bonjour

Quelles que news en ce début d année que je souhaite excellente à chacun.

L'intégration de la partie COMPARATEUR est traitée en sus de la partie RAILCOM ( qui inclue l'émission des trames RC sur TX).
Cela compile sur les différents HARD. Il faudra encore tester ensuite et vérifier à l'oscillo. (chaque chose en son temps!)

La partie COMPARATEUR est traitée de façon à être "transparente" pour "s'auto construire" ( en cas de non paramétrage natif) sur les différents hardwares de 20 broches et plus. Il faut cependant OBLIGATOIREMENT  respecter les conditions suivantes d'attribution de broches: (on peut forcer une conf par paramétrage dans les instructions de compilation ( sous platformio) ou via des #define à commenter/décommenter selon les souhaits retenus)

  • choix des proches sur le port D pour les AVR ( Atmega serie 0, AVR DA DB DD EA EB: par défaut PD2(rail+) & PD3(rail-) ou Alternative ALT1 PD6(rail+) & PD7(rail-)

  • choix des broches sur le port A pour les MEGATINY séries 0 1 2. Par défaut PA6(rail+) & PA7 (rail-) ALT1: sur le port B (à préciser je ne l ai pas en tête à l instant)

Toutes les autres combinaisons exotiques ne sont pas supportées mais, la solution proposée reste valable. Elle pourra faire l'objet d'évolutions ultérieures à ce niveau au besoin. Elles seraient dans ce cas dictées par des besoins de routage HARDWARE pour faciliter un design ou corriger un bug sur les sélections proposées.

Je suis actuellement penché sur la partie ADC.
J ai quelques lacunes sur son initialisation à combler pour avoir une approche satisfaisante de l'initialisation et une syntaxe efficace.

La multiplicité des versions d ADC des CPU, impose de traiter chaque cas ce qui est un peu long à construire. Cela progresse néanmoins.


Je profite de la circonstance pour poser les bases d'une réflexion pour la mesure de la FCEM et des lectures des entrées ABC.

Utilisation du TIMER RTC avec un intervalle de temps défini? Ou laisser dans la boucle les lectures, ou bien encore profiter du cutout...

A voir
je suis preneur des idées à ce sujet.

Laurent






« Modifié: janvier 04, 2024, 10:28:54 am par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 587
    • Voir le profil
Re : Décodeur de locomotive multifonctions
« Réponse #74 le: janvier 05, 2024, 11:49:04 am »
Bonjour

L'utilisation du TIMER RTC peut être problématique.

En effet nativement un interruption liée au RTC ( ou au PIT) est prioritaire sur celle qui proviennent de la capture de notre TIMERB utilisé par la décodage. Ce qui signifie que lorsque elle se produit alors on ne "voit" pas les inputs du signal DCC qui doit en principe être prioritaire. Elle a donc besoin d'être "aussi brève que possible"

On a donc le choix de rester dans la boucle, quitte à pousser une interruption de type RTC sur une simple bascule de valeur qui ouvrirait un traitement sur la boucle principale via changement d'état d une variable de type BOOL

Autre solution, changer la priorisation des vecteurs d interruption en passant celui lié à la gestion des trames DCC comme étant celui le plus prioritaire.(modif de la valeur CPUINT.LVL1VEC) ( ou la chaine des interruptions CPUINT.CTRLA pour l'activation du mode ROUNDROBIN en ciblant celui qui constitue le plus prioritaire dans la pile)

A voir dans ce cas aussi les effets de bord  si par exemple avec une gestion de PWM sur le TIMERA cela "mouline toujours bien"...

Le cas d'usage la variable dans la boucle globale et de l'ISR semble plus simple ( variable à déclarer comme "volatile bool mavariable;" pour être modifiable dans l ISR et hors ISR sans écueil!)

Le déclanchement de mesure de la BEMF dans la boucle avec modification de la condition de départ toutes les 100ms semble être jouable selon ce mode

Laurent