Voir les contributions

Cette section vous permet de consulter les contributions (messages, sujets et fichiers joints) d'un utilisateur. Vous ne pourrez voir que les contributions des zones auxquelles vous avez accès.


Messages - laurentr

Pages: [1] 2 3 ... 42
1
Vos projets / Re : Éclairage voitures
« le: mai 19, 2024, 08:16:04 pm »
Bonsoir Fred

Tu t'attaques a un "gros morceau".

Je pense que ton idée est valable mais qu'elle va se heurter à quelques déconvenues.
Aussi je pense te donner des indications pour éviter de "dérailler". Cela ne doit pas te décourager ou t empêcher de tester tes montages.

Théoriquement le concept 1 fil parait possible mais il n est pas recommandé car il y a des conditions très particulières pour que cela soit opérationnel. Il vaut mieux "oublier".

Dans mon montage tu as vu 2 transistors l un passe la puissance pour les bandeaux de leds ( je ne recommande pas les rubans 12v... mais ca reste une option valable)  l'autre les instructions de commande venant d un décodeur DCC.

Ces 2 montages n ont pas les mêmes entrées sorties et tensions c est la raison de la présence de ces 2 composants ( l un est un NPN (rouge noir)
l autre un NMOSFET type (BSS138 par exemple).
Le second pilote le 1er.

Chacun agissant dans une boucle (presque) dédiée en quelque sorte.

Les rectangles sont des résistances dont il faudra calculer les valeurs.

Le BUS a forcement 2 fils le + et le -.( départ et retour si tu préfères.)

Rassure toi il m'arrive toujours d'avoir des montages qui ne fonctionnent pas toujours comme attendus.
A défaut de maitriser des outils de simulation il faut tester "en live" et reprendre ce qui ne fonctionne pas comme attendu.

Tu as de quoi expérimenter!
Lance toi sur un montage a blanc sur un plaque d essai. Tu eprouveras ainsi mieux les solutions.



2
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.

3
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.

4
Vos projets / Re : Éclairage voitures
« le: mai 18, 2024, 01:38:56 pm »
Voila pour illustrer la version la plus basique


5
Vos projets / Re : Éclairage voitures
« le: mai 18, 2024, 01:02:31 pm »
Bonjour Fred

Je vais reformuler:

A/Quel est le besoin:
simple jour/nuit sur une ligne de train? sur des voitures individuellement pilotées ? des leds individuellement pilotées?
Selon celui ci les solutions sont différentes.

Sans tous les cas il faut tenir compte de la consommation du montage car si tu veux éviter de faire chauffer ton convertisseur de tension il est recommandé de passer sur un convertisseur de type DC DC ( BUCK = abaisseur,) pour passer du level DCC ver 5V ou 3v3 par exemple)

Si tu insères un microprocesseur de type AVR ( Arduino) tu vas ajouter de 10 à 15ma et probablement un peu plus pour un ESP32.

Pour éviter le scintillement tu vas aussi devoir ajouter une  réserve d'énergie: condensateur ou super condensateur dont tu dois réguler la charge et idéalement exploiter la tension de sortie pour compenser sa baisse progressive via un convertisseur DC DC de type BOOST cette fois ci.

Tout cela va occuper un certain volume et il faut l'avoir en tête. Parallèlement le cout de mise en œuvre augmentera plus tu auras de composants à insérer.

Pour ce qui est de la suppression du relais un transistor fera office d'interrupteur pour alimenter ou non la ligne de train si tu passes par cette solution.
Il faut juste dimensionner celui ci a la puissance à commuter.

6
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?


7
Vos projets / Re : Éclairage voitures
« le: mai 17, 2024, 03:07:26 pm »
Bonjour

Puisque c est un sujet que je connais particulièrement bien je vais pouvoir donner des éléments concrets d'appréciation.

Si tu recherches une commande de type "jour/nuit" le pilotage de la chaine et son exécution est a dimensionné en regard de la conso du montage ( les leds principalement)
Avec 5v et 10K par led cela revient à paralléliser les résistances de 10k... cela va avoir une incidence directe selon leur nombre total...
On peut cette faire une moyenne mais cela reste approximatif.
L échelle des modeles va influer aussi...

Conté conso il faudra privilégié un convertisseur de type DC DC pour éviter les échauffements de convertisseur de tension et de la puissance appelée.

S en suit du coup le stockage anti clignotement qui va avec. Le rôle des super capa joue ici à plein son rôle si on décide d y avoir recours ( ce qui implique un circuit de régulation de charge et possiblement un convertisseur de type BOOST pour repasser en 3v3 ou 5V et/ou le maintenir.

Tu vois donc que le cahier des charges à visée qualitative a des incidences sur ce qu'il faut intégrer et donc possiblement des couts.

Enfin ajouter un CPU pour le contrôle de tout cela ajoute aussi une énergie a intégrer au dispositif.

Alors in fin comment s en sort on?
Les critères sont:
le/les niveau(x) de besoin(s) à couvrir
le niveau de technicité retenu
les contraintes techniques ( encombrement, volumes,...)
le cout de la solution mis en œuvre.


Pour faire echo aux propos du post:
batterie or not batterie?
cpu additionnel (lequel) ou pas
universalité ou montage spécifique à une /des catégories de matériels
chaine de liaison entre les solutions...

Pour une ligne de train avec des ordres de pilotage individualisés il faut à minima 4 fils (bus TWI/I2C: plots SLA SDA +5V GND) voir 6 avec les 2 pôles DCC de chaque rail.
Sinon il faut un CPU par véhicule avec la circuiterie qui va autour.

Enfin j exclurai le relais qui n est à réserver qu'au pire des scenarii ou un transistor ne permet pas d obtenir un résultat analogue ou qu'une  isolation particulière est requise.

Espérant t avoir apporté des clés de réflexion utiles.

Laurent



8
Vos projets / Re : RailCom: Générateur de CutOut avec booster
« le: mai 14, 2024, 03:40:37 pm »
Bonjour Bruno

Ce qui est décrit est une option. Elle semble valable mais n'est pas dans l'esprit du moment. ( au moins sur la version en cours)
Par ailleurs cela impose d avoir une parfaite inter synchro entre les éléments, impose d avoir la gestion du reverse localement.

In fine la souplesse acquise est à mettre en balance avec le cout.

Toutefois les modules conçus ici et utilisés sont parfaitement réutilisables sur un design socle diffèrent.

Ltr

9
Oui les possibilités sont presque illimitées et il devient grâce à ces outils de concevoir des choses très modulable "on demend"!

Je note ta remarque sur l'hysterisys qui ne manque pas d intérêt. A teste "sur site"!

Les seules limites par exemple pour le comparateur est de ne jamais devoir dépasser le Vmax de 5V sur les broches sinon il faut brider ( résistance & zener par exemple)

J ai utilise une fonction simple pour comparer deux valeurs entre elle provenant de deux sources connues "calibrées".
On peut comme tu le soulignes utiliser des valeurs internes ce qui est un peu plus complexe pour les néophytes mais reste tout à fait utilisable simplement avec ces librairies. ( je ne l'ai pas personnellement encore expérimenté)

Une autre astuce est d utiliser un composant de référence de tension externe si on veut avoir précision et moins se faire de nœuds au cerveau. Un TL431 peut bien faire le lob au besoin.

Les exemples de portes logiques en cascades sont intéressant à exploiter aussi dans l'optique de ne pas avoir à encoder tout cela au niveau soft et de bénéficier de la souplesse de la logique programmable.

On pourra trouver qu'il en manque encore et que plus ne seraient pas mal venues!

La série 2 des TINY semble indiquer qu'on peut utiliser en parallèle la sortie physique et simultanément établir une liaison via EVENT ce qui augmente de fait les combo de sorties possibles.

Je n'ai pas retrouve ce cas d'usages/possibilités sur les AVR Dx y compris les DD.

Mes remarques sont pour dire que si plus de deux blocs logiques sont requis alors il faut passer sur les TINY série 2 à minima sinon sur les AVR Dx.

A 'inverse si on veut bénéficier de plusieurs comparateurs (max3) il faut être sur la série 1 TINY ou AVR DA & DB exclusivement.

J ai garde le meilleur pour la fin sur les portes logiques!

Et bien nous connaissons ce qui va se passer selon ce qui est mis sur les entrées... et bien il ne reste que simplement par soft dans notre code à piloter des sorties de broches qui seront alors reliées par des pistes aux entrées... et la logique fera le reste si j ose dire à la vitesse de l'éclaire avec un temps de commutation proche de celui de bascule d une ou plusieurs broche au niveau code.

Rudement efficace!

Je sens bien toutefois qu'il va falloir illustrer toute cette circuiterie à travers un petit projet démo qui mettra en avant les apports.

Je réfléchis, je verrai bien la gestion d'un carrefour routier par exemple mais on doit pouvoir trouver d'autres cas à illustrer.

Des idées?

Ltr



10
COMPARATOR:

Tout d abord rappelons le rôle d'un comparateur.
Ce rôle est de déterminer entre 2 valeurs celle qui est la plus élevée et de donner un résultat par une valeur numérique de type "0" ou "1" en sortie.

Ces valeurs en entrée sont ANALOGIQUES. Typiquement des voltages qui sur nos CPU ne devront pas dépasser  la plage 0V 5V sur les entrées.
Des composants externes peuvent offrir d'autres caractéristiques notamment avec des amplitudes de tensions en entrée plus étendues.
A titre d exemple voir le LM393.

On parle souvent d'entrée inverseuse et non inverseuse notée respectivement + et -.

Pour le comparateur intégré à nos CPU vedettes nous allons dans cet exemple utiliser un mécanisme de base: basculer un état se sortie lorsque qu'un seuil est dépassé.

Pour cela on donne une valeur seuil de référence qui est comparée à une valeur qui va évoluer. Lorsque celle qui évolue dépasse celle de référence la sortie du comparateur bascule d'état et inversement lorsque les seuils se recroisent.

Voici notre code exemple toujours sur un ATTINY1626.


Notez que cette famille de  CPU ne dispose que  d' 1 comparateur.
Les ATTINY de la série 1 en disposent de 3 comme les AVR DA et DB.


#include "Comparator.h"

void INIT_COMPARATOR()
{
  //COMPARATOR:
   
    //POSITIV SIDE: AS FLOATING VALUE INPUT:
    Comparator.input_p = comparator::in_p::in0;     //INPUT P0 PIN_PA7
    //Comparator.input_p = comparator::in_p::in1;   //INPUT P1 PIN_PB5
    //Comparator.input_p = comparator::in_p::in2;   //INPUT P2 PIN_PB1
    //Comparator.input_p = comparator::in_p::in3;   //INPUT P3 PIN_PB6
   
    //NEGATIV SIDE: AS REFERENCE VALUE INPUT:
    //Comparator.input_n = comparator::in_n::in0;   //INPUT N0 PIN_PA6
    Comparator.input_n = comparator::in_n::in1;     //INPUT N1 PIN_PB4
    //Comparator.input_n = comparator::in_n::in2;   //INPUT N2 PIN_PB0
   
    Comparator.reference = comparator::ref::disable;
   
    Comparator.hysteresis = comparator::hyst::disable; 

     
    Comparator.output = comparator::out::enable;     //OUTÜT PIN_PA5
    //Comparator.output = comparator::out::disable;        // No output pin, signal not inverted internally
    //Comparator.output = comparator::out::disable_invert; // No output pin, signal inverted internally
    //Comparator.output = comparator::out::enable;         // Enable output pin (PA7), signal not inverted internally
    //Comparator.output = comparator::out::invert;         // Enable output pin (PA7), signal inverted internally
    //Comparator.output = comparator::out::enable_invert;  // Identical to out::invert
   
           
    Comparator.init();
   
    Comparator.start(); // Start comparator
 
}


void setup() {

  INIT_COMPARATOR();
 
}

void loop() {


}


Dans cet exemple on sélectionne un entrée flottante (positiv input) une entrée de référence (negativ input), on active la pin de sortie, on initialise cette combinaison d éléments et on démarre le composant.

La sortie sur la broche PA5 s'active si une tension sur la broche d'entrée est supérieure à la valeur sur celle de référence.
Inversement elle s'éteint si les seuils sont inversés.

On peut avoir un état de fonctionnement inverse à l aide de l'option d'inversion

Comparator.output = comparator::out::invert;
Bon tout ca c est très bien mais si je ne veux pas sortir sur la broche PIN_PA5... je fais comment?

Comme précédemment nous passerons par EVENT pour établir une liaison vers une broche de sortie de type EVOUTx ce qui offre 5 nouvelles possibilités au choix:
EVOUTA sur PIN_PA2 ou PIN_PA7
EVOUTB sur PIN_PB2 ou PIN_PB7
EVOUTC sur PIN_PC2

Et si cela ne suffit pas on peut passer par le bloc LOGIC en se servant de la sortie logique du comparateur comme un élément d'entrée d'un ou plusieurs bloc logique.

On récupère alors en sortie jusqu'à 6 nouvelles affectations exploitables.( 6 sur les CPU x06 et 8 sur les CPU x07) (les sorties LUTn OUT)


On le voit de suite les possibilités se multiplient, toutefois, on peut encore se sentir à l'étroit parfois et ou vouloir disposer d'encore plus de possibilités.
Pour cela on montera en gamme de CPU vers un modèle comportant plus de combinaisons, de composants programmables et in fine le plus souvent de leur nombre total de broches.

Ltr



11
Vos projets / Re : RailCom: Générateur de CutOut
« 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

12
COMPLEMENTS SUR EVENT:

Il ne faut pas confondre les notions suivantes:

EVOUTx comme EVOUTA EVOUTC qui sont des sorties physiques c'est à dire des PORTS liés à des broches et event_a ou event_b qui sont des éléments de type logiciel assurant une liaison entre éléments.

Pour les plus curieux je vous recommande d'essayer de visualiser ce que permet de faire l'outil ATMEL START pour combiner visuellement les éléments.

https://start.atmel.com/


Tous les CPU n'y sont pas présents (les derniers AVR DD n'y sont pas) mais vous y trouverez facilement les CPU usuels ( ATMAGE4809 par exemple) ou de cet exemple ATTINY1626

A titre d exemple voici le code que va generer l outils pour iniitaliser le bloc logic ( ici avec d autre valur que celle de notre exemple)


#include <ccl.h>

/**
 * \brief Initialize CCL peripheral
 * \return Return value 0 if success
 */
int8_t DIGITAL_GLUE_LOGIC_0_init()
{

// CCL.SEQCTRL0 = CCL_SEQSEL_DISABLE_gc; /* Sequential logic disabled */

// CCL.SEQCTRL1 = CCL_SEQSEL_DISABLE_gc; /* Sequential logic disabled */

CCL.TRUTH0 = 4; /* Truth 0: 4 */

// CCL.LUT0CTRLC = CCL_INSEL2_MASK_gc; /* Masked input */

CCL.LUT0CTRLB = CCL_INSEL0_AC0_gc    /* AC0 OUT input source */
                | CCL_INSEL1_IN1_gc; /* IO pin LUTn-IN1 input source */

CCL.LUT0CTRLA = CCL_CLKSRC_CLKPER_gc     /* Peripheral Clock */
                | CCL_EDGEDET_DIS_gc     /* Edge detector is disabled */
                | CCL_FILTSEL_DISABLE_gc /* Filter disabled */
                | 1 << CCL_ENABLE_bp     /* LUT Enable: enabled */
                | 1 << CCL_OUTEN_bp;     /* Output Enable: enabled */

CCL.TRUTH1 = 1; /* Truth 1: 1 */

CCL.LUT1CTRLC = CCL_INSEL2_EVENTB_gc; /* Event input source B */

CCL.LUT1CTRLB = CCL_INSEL0_AC0_gc       /* AC0 OUT input source */
                | CCL_INSEL1_EVENTA_gc; /* Event input source A */

CCL.LUT1CTRLA = CCL_CLKSRC_CLKPER_gc     /* Peripheral Clock */
                | CCL_FILTSEL_DISABLE_gc /* Filter disabled */
                | 1 << CCL_ENABLE_bp     /* LUT Enable: enabled */
                | 1 << CCL_OUTEN_bp;     /* Output Enable: enabled */

CCL.TRUTH2 = 4; /* Truth 2: 4 */

CCL.LUT2CTRLC = CCL_INSEL2_IN2_gc; /* IO pin LUTn-IN2 input source */

CCL.LUT2CTRLB = CCL_INSEL0_AC0_gc    /* AC0 OUT input source */
                | CCL_INSEL1_IN1_gc; /* IO pin LUTn-IN1 input source */

CCL.LUT2CTRLA = CCL_CLKSRC_CLKPER_gc     /* Peripheral Clock */
                | CCL_EDGEDET_DIS_gc     /* Edge detector is disabled */
                | CCL_FILTSEL_DISABLE_gc /* Filter disabled */
                | 1 << CCL_ENABLE_bp     /* LUT Enable: enabled */
                | 0 << CCL_OUTEN_bp;     /* Output Enable: disabled */

CCL.TRUTH3 = 4; /* Truth 3: 4 */

CCL.LUT3CTRLC = CCL_INSEL2_EVENTB_gc; /* Event input source B */

CCL.LUT3CTRLB = CCL_INSEL0_AC0_gc       /* AC0 OUT input source */
                | CCL_INSEL1_EVENTA_gc; /* Event input source A */

CCL.LUT3CTRLA = CCL_CLKSRC_CLKPER_gc     /* Peripheral Clock */
                | CCL_EDGEDET_DIS_gc     /* Edge detector is disabled */
                | CCL_FILTSEL_DISABLE_gc /* Filter disabled */
                | 1 << CCL_ENABLE_bp     /* LUT Enable: enabled */
                | 0 << CCL_OUTEN_bp;     /* Output Enable: disabled */

CCL.CTRLA = 1 << CCL_ENABLE_bp      /* Enable: enabled */
            | 0 << CCL_RUNSTDBY_bp; /* Run in Standby: disabled */

// CCL.INTCTRL0 = CCL_INTMODE0_BOTH_gc /* Sense both edges */
// | CCL_INTMODE1_BOTH_gc /* Sense both edges */
// | CCL_INTMODE2_BOTH_gc /* Sense both edges */
// | CCL_INTMODE3_BOTH_gc; /* Sense both edges */

return 0;
}


A défaut d être familier avec ce langage plus "brut" l'apport de la librairie LOGIC prend ici tout son sens.

Rappelons une fois encore que toutes les combinaisons ne sont pas possibles et il faudra être attentif aux contraintes et restrictions imposées.

Il peut y avoir plusieurs façons de faire, parfois l'une apparaitra  "meilleure" ou plus adaptée. Chacun étant libre de ses choix.


Ltr


13
Au travers des exemples mis en œuvre nous avons déjà couvert simplement l'utilisation de:

LOGIC
EVENT

A l'aide de ces éléments avec une syntaxe "simplifiée" sur laquelle il faut être rigoureux,  nous pouvons déjà bien combiner de multiples cas d'usage de ces hardwares méconnus

Je vous propose ensuite de passer à COMPARATOR.

Stop ou encore?

Ltr

14
Bon c est bien mais si je ne veux pas non plus me servir de la broche PIN_PB6 y a  t il d autres solutions?

OUI

Pour cela nous allons de nouveau nous servir de EVENT pour établir une liaison entre la sortie du LUT2 et une broche de type EVOUTx
X étant le port en question

La aussi parfois plusieurs solutions sont offertes pour sélectionner la broche précise parmi un choix limité.

Toujours dans notre exemple à base de ATTINY1626 nous allons router la sortie vers le port A sur une broche supportant l'EVOUTA

Sont alors possibles les choix suivant:
choix par défaut PIN_PA2
choix alternatif PIN_PA7

pour cela il nous faudra préciser les valeurs attendues




puis voici le code complet:



#include "Logic.h"

#include "Event.h"

//PIN_PB0 PIN_PB1 and PIN_PB3 are mapped by default on LOGIC BLOCK CCL LUT2

void INIT_LOGIC_BLOCK2()
{
  Logic2.enable;                          //ENABLE LUT2
  Logic2.input0 = logic::in::input;       //input PIN_PB0
  //Logic2.input1 = logic::in::input;     //input PIN_PB11
  Logic2.input1 = logic::in::event_a;     //event_a OF LUT2
  Logic2.input2 = logic::in::masked;      //masked = not used
  //Logic2.output = logic::out::enable;   //active output
  Logic2.output = logic::out::disable;   //disable output
  //Logic2.output_swap = logic::out::no_swap;    // Use position, pin 3 on the port so here PIN_PB3
  //Logic2.output_swap = logic::out::pin_swap;   // Use alternative position, pin 6 on the port so here PIN_PB6
  Logic2.truth = 0x08;                    //AND OUT ON IF BOTH IN ARE HIGH

  Logic2.init();
  Logic2.start();
   
}

void INIT_EVENT()
{
  Event0.assign_generator_pin(gen0::pin_pa1);
  Event0.set_user(user::ccl2_event_a);          //EVENT A OF LUT2

  Event0.start();

  Event1.assign_generator(gen::ccl2_out);
  //Event1.set_user_pin(user::evouta_pin_pa2); //route on PA2
  Event1.set_user_pin(user::evouta_pin_pa7); //route on PA7

  Event1.start();
 
}


Pour memo le fait de passer d un port X vers un autre s appelle le "MUXING" ou routage.

Vous verrez souvent dans les datasheet le terme PORTMUX.  C'est cette fonctionnalité qui permet dans les limites du possible du hardware de permuter les attributions de broches selon des choix pré définis.

15
Le tableau de la page 18 nous indique que le LUT2 peut

sortir sur la broche PIN_PB3
sortir sur la broche PIN_PB6

Par défaut avec la ligne

Logic2.output = logic::out::enable;     //enable OUTPUT PIN le routage se fait sur la broche par défaut soit PIN_PA3 ( la librairie met par défaut la broche usuelle

La ligne suivante n'est donc pas obligatoire mais sera mise pour être complet.:

Logic2.output_swap = logic::out::no_swap; //use PIN_PA3 as OUTPUT for LUT2 

Pour un routage vers la broche alternative PIN_PB6 il faut saisir ceci:


Logic2.output = logic::out::enable;     //active OUTPUT
Logic2.output_swap = logic::out::pin_swap; // Use alternative position, pin 6 on the port so here PIN_PB6

d où le code complet:



#include "Logic.h"

#include "Event.h"

//PIN_PB0 PIN_PB1 and PIN_PB3 are mapped by default on LOGIC BLOCK CCL LUT2

void INIT_LOGIC_BLOCK2()
{
  Logic2.enable;                          //ENABLE LUT2
  Logic2.input0 = logic::in::input;       //input PIN_PB0
  //Logic2.input1 = logic::in::input;     //input PIN_PB11
  Logic2.input1 = logic::in::event_a;     //event_a OF LUT2
  Logic2.input2 = logic::in::masked;      //masked = not used
  Logic2.output = logic::out::enable;     //active output
  //Logic2.output_swap = logic::out::no_swap;    // Use position, pin 3 on the port so here PIN_PB3
  Logic2.output_swap = logic::out::pin_swap;   // Use alternative position, pin 6 on the port so here PIN_PB6
  Logic2.truth = 0x08;                    //AND OUT ON IF BOTH IN ARE HIGH

  Logic2.init();
  Logic2.start();
   
}

void INIT_EVENT()
{
  Event0.assign_generator_pin(gen0::pin_pa1);
  Event0.Event3.set_user(user::ccl2_event_a);          //EVENT A OF LUT2

  Event0.start();
 
}

void setup() {

  PORTA.DIRCLR = PIN1_bm; //INPUT for PIN_PA1 = pinMode(PIN_PA1,INPUT) but faster!!

  INIT_EVENT();
 
  INIT_LOGIC_BLOCK2();

}

void loop() {
 

}


Rm: A noter que par défaut la librairie mettra en œuvre par défaut la valeur no_swap si vous ne l'avez pas saisie! (ouf!)

Pages: [1] 2 3 ... 42