Auteur Sujet: Nouveaux AVR:coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE: utiliser le HARD:  (Lu 9994 fois)

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
    Bonjour

    Souvent le terme ARDUINO englobe de nombreux anspects aux frontières parfois mal connues.

    L IDE Arduino (interface de programmation)  est une interface simplifiant la réalisation du code puis son injection dans des microprocesseurs.
    Il utilise le langage C++.

    Il a permis de développer la communauté de pratiquants de l'électronique en passant de l'électronique discrète (à composants "standards"  à l'électronique programmable.

    A LOCODUINO comme ailleurs les domaine d'application sont nombreux.

    ARDUINO doit une part de son succès à la réalisation de cartes mues par un CPU microcontrôleur offrant des performances redoutables pour un prix très compétitif.

    Parmi les plus connus et souvent utilisés ici on retrouve dans la famille AVR:

    les ARDUINO UNO et MICRO équipés de la puce ATMEGA328P
    les AVR MEGA à base de CPU ATMEGA2560
    les TINY à base  de CPU ATTINYx5 comme les ATTINY85, 45, 25.[/li]


On voit ici que des chiffres apparaissent et il vont avoir un rôle pour identifier les générations de processeurs et ou leur ressources.
Sur le ATTINY85 on retrouve 8K de mémoire contre 4K seulement pour le 45 et seulement 2 pour le 25.
Le chiffre 5 étant l'indice de la série de ces processeurs.

Apparus il y a plus de 10 ans ces processeurs ont vu leur descendance s'étendre en apportant leur lot d'innovations et d'apports.

A titre d exemple de nouveaux processeurs sont aussi devenus "compatibles ARDUINO", c'est à dire programmables via l'interface IDE ARDUINO.
Les plus connus sont le LESP8266 et l'ESP32 (dans leur différentes déclinaisons)

Dans la lignée de leur ainés chez ATMEL MICROCHIP les AVR on vu la gamme complétée des AVRx:
On distingue 2 groupes de façon générale: (avec qq exceptions):
les TINY dont le nombre de broches est <=24
les "MEGA" qui ont dont un nombre de broches >24

Dans ces 2 groupes plusieurs générations se sont suivies: série 0, série 1, série 2.

On se reportera aux datasheets de chaque item pour leur caractéristiques propres.

Toutefois ces CPU disposent d'organes communs, souvent méconnus dont nous allons présenter quelques éléments utiles:
TIMER
EVENT
GLU LOGIC
COMPARATOR

Pour assurer la portabilité entre le code et le soft on a recours a des frameworks qui vont faire "en sous marin" des opérations complexes avec une mise en œuvre simplifiée.
Pour les AVRx on dispose de 3 framework selon les CPU:

AVRX MEGA série 0 : les célèbres ATMEGAx08 et X09 dont le ATMEGA4809 qui équipe les ARDUINO NANOEVERY ==>framework MEGACOREX
https://github.com/MCUdude/MegaCoreX

AVRX "TINY" pour les "petits CPU" serie 0, 1 et 2: ==>framework MEGATINYCORE
https://github.com/SpenceKonde/megaTinyCore

AVRX "MEGA" serie 0, 1, 2 avec : ==>framework DXCORE
https://github.com/SpenceKonde/DxCore

Ltr


« Modifié: mai 04, 2024, 12:34:24 am par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #1 le: mai 02, 2024, 06:10:52 pm »
On retrouve dans ces framworks des librairies qui vont piloter des couches hardware de ces processeurs.

On peut naturellement se passer de leur apport mais il faudra dans ce cas re écrire une bonne partie de code pour piloter ces éléments hardware.

Autant bénéficier des solutions "universelles" déjà testées et approuvées par une large communauté.
Ces framework étant à présent "matures" et continue d'évoluer pour prendre en comptes des correctifs ou de nouveaux CPU.

Nous avons évoqué précédemment des composants additionnel sur ces nouvelles puces.

Nous allons en traiter 3 ici:
le "GLU LOGIC"
le "COMPARATOR"
l "EVENT"

Chacun dispose de sa bibliothèque et pour l utiliser nous ajouterons  en tête de programme:
#include "nom_de_la_librairie;h"
Maintenant de quoi retourne t il:
GLU LOGIC:
C est en fait un ensemble de portes logiques configurables à la demande.
On peut disposer sur chaque bloc logique appelé LUT de 3 entrées et d'une sortie.
Ces entrées et sorties peuvent être de différentes natures: entrée de pins, event, état d'un composant interne,...
De nombreuses combinaisons sont offertes et il est même possible dans certaines conditions de chainer ces portes logiques.

L intérêt de cette logique programmée est qu'elle est INDEPENDANTE des ressources du coeur du CPU. = elles n'utilisent pas de ressources du cœur du CPU pour fonctionner.
C est l'équivalant de composants externes placés dans la puce comme "bonus" en étant en plus très rapides, moins encombrant et donc globalement plus performant.

A titre d exemple voici un paramétrage du 3eme LUT ( 3eme bloc logique):

sur un ATTINY1626: (MEGATINY1626)

  //LOGIC LUT3:
    Logic3.enable = true;                                //ENABLE LUT3
    Logic3.input0 = logic::in::ac;           //AC0 level OUT : sortie du comparateur
    Logic3.input1 = logic::in::input;       //PC1 input : correspond ici à la broche PC1
    Logic3.input2 = logic::in::event_a;   //evenement_a
    Logic3.output = logic::out::enable;  //output on PIN PA5
    Logic3.truth = 0x0a;                       //table de vérité de combinaison des 3 entrées input0, 1 ,2: =10 = 0x0a ==> la sortie est a 1 quand uniquement l'entrée input2 est à 1. sinon 0

    Logic3.init();
    Logic3.start();


Cette exemple, non le plus simple, montre surtout la diversité des éléments combinables et il sera surement plus simple dans vos premières mises en œuvre de test de réaliser les exemples fournis par ces frameworks. ( NAND, AND, NOR, XOR, OR,...)

N'hésitez pas à commenter ces premiers éléments de présentation pour que nous l'enrichissions collectivement.

Ltr
« Modifié: mai 20, 2024, 01:49:48 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #2 le: mai 02, 2024, 06:22:57 pm »
Dans l'exemple donné vous remarquerez qu'il n'est pas nécessaire de déclarer en INPUT et OUTPUT les broches.

La librairie du framework va s'en occuper tt seule comme une grande.  8)

Il peut en être différemment lorsque l'on combine des éléments plus complexes entre eux!

Voir l'exemple de code plus complet donné dans le post: https://forum.locoduino.org/index.php?topic=1707.0 pages 4 et 5.

Ltr

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #3 le: mai 02, 2024, 08:49:16 pm »
Prenons un exemple simple pour illustrer:

Nous travaillons avec un ATTINY1626.

https://ww1.microchip.com/downloads/aemDocuments/documents/MCU08/ProductDocuments/DataSheets/ATtiny1624-26-27-DataSheet-DS40002234B.pdf

Voir la tableau page 18 qui reprend les attributions de broches.


CAS: AND à 2 entrées:

Dans un code habituel nous ferions la lecture de 2 entrées et nous ferions l'association de leur état pour produire une sortie selon la combinaison en entrée


/*
 * WE USE:
 * PIN_PB0 PIN_PB1 as INPUT
 * PIN_PB3 as OUTPUT
 */

#define ENTREE_1 PIN_PB0
#define ENTREE_2 PIN_PB1

#define SORTIE_1 PIN_PB3

void setup() {
  // put your setup code here, to run once:

  pinMode(ENTREE_1,INPUT);
  pinMode(ENTREE_2,INPUT);

  pinMode(SORTIE_1,OUTPUT); 

}

void loop() {

  bool IN1 = digitalRead(ENTREE_1);
  bool IN2 = digitalRead(ENTREE_2);

  bool OUT_STATE = IN1 & IN2;

  digitalWrite(SORTIE_1,OUT_STATE);

}


Ce code est optimisable car les utilisations des fonctions digitalRead(), digitalWrite() sont gourmandes en temps.
Nous utiliserions pour cela de mode de manipulation direct des ports (et donc l'écriture dans les registres)

Explications ici par exemple:
https://github.com/SpenceKonde/DxCore/blob/master/megaavr/extras/DirectPortManipulation.md

On utilise aussi 3 des 4 registres internes pouvant stoker chacun 1 byte.
Leur accès est ce qui est le plus rapide

Code optimisé:

#define SORTIE1_ON  PORTB.OUTSET = PIN3_bm
#define SORTIE1_OFF PORTB.OUTCLR = PIN3_bm

#define IN1 GPIOR0
#define IN2 GPIOR1
#define OUT_STATE GPIOR3


void setup() {
  // put your setup code here, to run once:

  //PIN_PB0 AS INPUT:
  PORTB.DIRSET = PIN0_bm;

  //PIN_PB1 AS INPUT:
  PORTB.DIRSET = PIN1_bm;

  //PIN_PB3 AS OUTPUT
  PORTB.DIRCLR = PIN3_bm;

}

void loop() {
  // put your main code here, to run repeatedly:

  IN1 = PORTB.IN & PIN0_bm;
  IN2 = PORTB.IN & PIN1_bm;

  OUTSTATE = IN1 & IN2;

  if(OUTSTATE)
  {
    SORTIE1_ON;
  }
  else
  {
    SORTIE1_OFF;
  }
}


En revanche nous avons perdu ici la "portabilité" du code d'un hardware vers un autre au bénéfice d'une performance accrue sur le hardware dédié.



« Modifié: mai 02, 2024, 09:29:04 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #4 le: mai 02, 2024, 09:02:29 pm »
Poursuivons ici avec l'utilisation de la librairie LOGIC toujours avec les mêmes broches:



#include "Logic.h"

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

void INIT_LOGIC_BLOCK2()
{
  Logic2.enable = true;                          //ENABLE LUT2
  Logic2.input0 = logic::in::input;       //input PIN_PB0
  Logic2.input1 = logic::in::input;       //input PIN_PB1
  Logic2.input2 = logic::in::masked;      //masked = not used
  Logic2.output = logic::out::enable;     //use OUTPUT
  Logic2.output_swap = logic::out::no_swap; // use PIN_PB3 as OUTPUT
  Logic2.truth = 0x08;                    //AND OUT ON IF BOTH IN ARE HIGH

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

void setup() {

  INIT_LOGIC_BLOCK2();

}

void loop() {
 

}



Il n'y a plus de code dans la boucle principale, tout se fait en HARD et SANS aucune intervention du CPU!

Ltr

« Modifié: mai 20, 2024, 01:50:19 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #5 le: mai 02, 2024, 09:26:32 pm »
Et si maintenant on désire utiliser une autre broche mais qui n'est pas celle disponible par défaut en entrée sur le bloc logique?

Est ce possible?

La réponse est OUI!

Comment va t on faire?

Cela n'est pas immédiat et il faut faire appel à un autre composant de ce hardware moderne: le bloc EVENT.

EVENT:

EVENT est ce qu'on pourrait appeler un élément de liaison entre un producteur et un consommateur ( et même plusieurs consommateurs si besoin).
Ceux ci peuvent être de différentes natures

Le producteur appelé GENERATOR (Générateur) est toujours unique sur une entrée d'EVENT

En revanche les consommateurs appelés USERS peuvent être multiples. C'est à dire que l'on peut aiguiller parallèlement une même information à plusieurs consommateurs USERS.

Prenons un cas simple complémentaire de notre exemple précèdent.

Nous voulons non plus utiliser la broche PIN_PB1 en entrée mais la broche PIN_PA1.

Nous devons alors:
déclarer PIN_PA1 comme INPUT
déclarer PIN_PA1 comme GENERATOR
attribuer un consommateur.
Lier de ce consommateur sur l'entrée 1 du bloc logique à la place de PIN_PB1
Ici nous voulons une liaison sur la deuxième entrée du bloc logic2
Nous pouvons par exemple définir la sortie event_a du blog logique 2.


Cela se traduit comme ceci:


#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 = true;                          //ENABLE LUT2
  Logic2.input0 = logic::in::input;       //input PIN_PB0
  //Logic2.input1 = logic::in::input;     //input PIN_PB1
  Logic2.input1 = logic::in::event_a;     //event_a OF LUT2
  Logic2.input2 = logic::in::masked;      //masked = not used
  Logic2.output = logic::out::enable;     //enable OUTPUT
  Logic2.output_swap = logic::out::no_swap; //use PIN_PA3
  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();
 
}

void setup() {

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

  INIT_EVENT();
 
  INIT_LOGIC_BLOCK2();

}

void loop() {
 

}



Pratique!

Et si on désire changer la sortie? comment procéder?

2 cas de figures sont possibles mais les combinaisons sont plus limitées.
Il faut donc regarder les autres contraintes que nous rencontrerons dans le reste du montage et des conditions de fonctionnement pour faire un choix judicieux!

Nous allons le traiter dans l'exemple suivant.

« Modifié: mai 20, 2024, 01:50:42 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #6 le: mai 02, 2024, 09:48:37 pm »
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 = true;                      //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!)
« Modifié: mai 20, 2024, 01:51:17 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #7 le: mai 02, 2024, 10:07:33 pm »
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 = true;                       //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.
« Modifié: mai 20, 2024, 01:51:44 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #8 le: mai 02, 2024, 10:15:40 pm »
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

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #9 le: mai 02, 2024, 11:31:00 pm »
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

« Modifié: mai 02, 2024, 11:41:03 pm par laurentr »

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Re : Les nouveaux AVR: coeur AVRx avec MEGACOREX, DXCORE, MEGATINYCORE
« Réponse #10 le: mai 04, 2024, 12:15:42 am »
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


« Modifié: mai 04, 2024, 12:22:07 am par laurentr »

trimarco232

  • Sr. Member
  • ****
  • Messages: 345
    • Voir le profil
Bonjour ,
merci Laurent pour cette présentation !
je découvre notamment l'existences des frameworks , qui simplifient l'écriture et surtout rendent les choses + compréhensives , c'est mieux que les exemples de Microchip , qui s'éloignent à peine du bare metal

pour les comparateurs , j'activerais systématiquement l'hystérésis : pour les entrées très raides , ce n'est pas utile , mais pour les signaux variables , cela évite d'avoir ceci : _______|‾|_|‾|_|‾‾‾‾‾‾‾‾ , en sortie lors des transitions
dans ton exemple , tu as utilisé une tension externe comme tension de référence , mais on pourra souvent utiliser une tension interne , voir le DAC si la valeur est critique , cela économise une broche ; il peut cependant se produire que cette tension de référence soit disponible sur l'entrée (-) alors que , zut , on la voulait sur l'entrée (+) : dans ce cas il suffit d'intervertir le rôle des entrées (+) et (-) , et d'actionner l'inverseur en sortie du comparateur (en fait amha , l'inversion en sortie permet surtout de permuter les entrées , si besoin)
on notera aussi la présence de la broche de sortie , non disponible sur les AVR classique : elle permet par exemple , par une contre-réaction positive , d'obtenir des valeurs d'hystérésis supérieures aux 50mV disponible dans le hardware du comparateur

concernant le Configurable Custom Logic (CCL) , il y a une très intéressante notte d'application , qui montre notamment qu'on peut faire une porte à 5 entrées , en combinant 2 portes à 3 entrées , mais pas que , voir aussi l'astucieuse configuration du TRUTHn register : https://ww1.microchip.com/downloads/en/AppNotes/TB3218-Getting-Started-with-CCL-90003218A.pdf

laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
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



laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Bnjour à tous.

J'ai corrige une petite erreur typographique présente dans les exemples donnés.

Sur les blocs logiques j avais simplement mi:

LogicN.enable;
Ce qui est faux et doit etre remplacé par:

LogicN.enable = true;
Ex
Logic2.enable = true;
Mea culpa!




laurentr

  • Hero Member
  • *****
  • Messages: 648
    • Voir le profil
Bonjour

Malgré un emploi du temps pro bien chargé les tests se poursuivent.

J ai d abord des corrections à apporter dans les exemples fournis sur la partie EVENT.

Il faut en effet utiliser set_generator() en lieu et place de assign_generator() dans la syntaxe fournie


#include "Event.h"

void INIT_EVENT()
{
  //Event0.set_generator(gen0::pin_pa1); // OK BUT USE NEXT LINE FOR BETTER EFFCIENTCY
  Event0.set_generator(PIN_PA1); //BETTER & FASTER
  Event0.set_user(user::ccl2_event_a);          //EVENT A OF LUT2

  Event0.start();

  Event1.set_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.set_user_pin(PIN_PA7); //route on PA7

  Event1.start();
 
}




Il est recommandé lorsque cela est possible de "passer en dur" certains éléments comme les broches d'entrée ou de sortie. ( on peut mettre des alias si besoin de portabilité et des simplifications de modifications en volume)( sinon se tourner vers assign_generator() (se rapporter aux notices des librairies)

Les tests se poursuivent.

Notez que lors de mes tests sur un ATTINY826 je ne suis pas parvenu à utiliser la sortie "MUX" vers PA7 du bloc CCL0 ( LUT0). BUG? 
Attention peu de PIN sont utilisables pour ces usages. (PORTx PIN 2 et PIN 7 si présentes!)
(voir datahseet du composant)

De plus si vous utiliser 1 sortie EVENOUTx c est exclusif sur le port en question, vous ne pouvez pas utiliser la pin alternative sur un autre event. ( en gros c est dessert OU fromage MAIS PAS LES DEUX!)
Donc vigilance dans les usages d'attribution!!

Il est donc prudent de tester unitairement aussi chaque élément!...