Auteur Sujet: Récupération données DCC: CircularBuffer et ShiftOut  (Lu 47034 fois)

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Récupération données DCC: CircularBuffer et ShiftOut
« le: décembre 07, 2017, 12:05:56 am »
Bonsoir,
J'ai commencé depuis quelques temps la réalisation de décodeurs d'accessoires sur base ARDUINO.
J'utilise la bibliothèque DCC_Decoder. Le système marche très bien pour les aiguillages mais je me suis aperçu récemment que du côté des signaux il y avait des ratés.
Après analyse, tests et interrogations sur les forums, je suis arrivé à la conclusion que le traitement des données, que je faisais à la suite du void BasicAccDecoderPacket_Handler, me faisait louper des données.
j'ai donc inclus une autre bibliothèque, CircularBuffer, pour enregistrer les données immédiatement après le "Handler" puis les récupérer et les traiter, cette fois-ci dans la "loop".
Et là, impeccable, je ne loupais plus de données, au vu du Serial.print.
J'ai donc continué le traitement des données pour activer les sorties: tout est OK jusqu'au calcul de la valeur à envoyer (ici CDE4) mais rien ne se passe avec le ShiftOut (j'utilise des registres à décalage).
J'en viens à me demander si l'instruction ShiftOut ne se percute pas avec la fonction buffer.shift() de CircularBuffer!
Je précise que je travaille avec CDM-Rail et que je ne suis pas un grand spécialiste de la programmation (cela ressemble sûrement à "la programmation pour les nuls")
Ci-dessous une copie de mon code que j'ai allégé pour aller au plus simple, mais avec lequel j'ai bien un problème au moment de l'envoi du ShiftOut.
------------------------------------------------------------------------------------------------------------------------------------

#include <DCC_Decoder.h>
#define kDCC_INTERRUPT    0    // pin 2 for UNO
#include <CircularBuffer.h>

CircularBuffer <int, 100> storadresse;
CircularBuffer <byte, 100> storaction;

int add = 0;
int act = 0;
int old_add = 0;
int old_act = 0;
int action = 0;

const int CLOCK2 = 8;
const int LATCH2 = 9;
const int DATA2 = 10;

int OUT4[8];

int CDE4 = 0;

//Handler DCC
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data){
  //Serial.print(address);
  //Serial.print("    ");
  //Serial.println(data);
 storadresse.push (address);
 storaction.push (data);
  }
void setup() {     
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
  Serial.begin (115200); 
  Serial.println("Debut test");
}
void loop() {
  DCC.loop();

  while(!storadresse.isEmpty()) {
   add = storadresse.shift();
   act = storaction.shift();

 if ((add != old_add) || (act != old_act)){
    old_add = add;
    old_act = act;
// Conversion de l'adresse NMRA en adresse decodeur d'accessoire
   add -= 1;
   add *= 4;
   add += 1;
   add += (act & 0x06) >> 1;
   action =(act & 0x01);
   Serial.print(add);
   Serial.print("   ");
   Serial.println(action);

  //Gestion des signaux
 
 //Registre à décalage OUT4
  if((add >=127) && (add <= 134)){ 
    if(action = 1){
    OUT4[add - 127] = bit(add - 127);
    }
    else{
    OUT4[add - 127] = 0;
    }
  }//fin boucle OUT4
         
//Envoi OUTT4

    CDE4 = OUT4[0]+OUT4[1]+OUT4[2]+OUT4[3]+OUT4[4]+OUT4[5]+OUT4[6]+OUT4[7];
    Serial.println(CDE4);
   
    digitalWrite(LATCH2, LOW);
    shiftOut(DATA2, CLOCK2, LSBFIRST, CDE4);     
    digitalWrite(LATCH2, HIGH);

   } //fin nouvelle donnée
  } //fin while   
} //fin loop
--------------------------------------------------------------------------------------------------------------------

Merci d'avance à ceux qui pourront m'aider
« Modifié: décembre 08, 2017, 07:57:30 am par Jean-Luc »

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #1 le: décembre 07, 2017, 10:53:10 pm »
Désolé, je clos le post.
le problème est dans le SETUP: il manque la définition en OUTPUT pour CLOCK, LATCH et DATA

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1714
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #2 le: décembre 08, 2017, 07:56:46 am »
Souvent il suffit d'exposer son problème pour le voir sous un autre jour et détecter l'erreur  :)
Cordialement

CATPLUS

  • Sr. Member
  • ****
  • Messages: 435
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #3 le: décembre 08, 2017, 09:29:01 am »
Bonjour

Aurais-tu STP l'amabilité de nous faire partager ton fichier ".ino" revisé
et le montage qui va avec.

Cordialement

Marcel
Best Regards

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #4 le: décembre 08, 2017, 11:56:05 pm »
Effectivement il y avait une grossière erreur (suite à un effacement malheureux ou un copier/coller raté)) que je ne voyais pas, d'où l'intérêt de faire appel à d'autres paires d'yeux.
Tout est rentré dans l'ordre.
J'ai encore du boulot pour finaliser mon projet mais j'ai commencé à écrire un document pour rassembler tout ça (schémas, programme, photos de cartes, ...).
En attendant, ci-dessous le programme, sûrement perfectible, qui me permet de piloter 12 signaux, au travers de 3 registres à décalage
-------------------------------------------------------------------------------------------------------------
#include <DCC_Decoder.h>
#define kDCC_INTERRUPT    0    // pin 2 for UNO

#include <CircularBuffer.h>

CircularBuffer <int, 100> storadresse;
CircularBuffer <byte, 100> storaction;
int add = 0;
int act = 0;
int old_add = 0;
int old_act = 0;
int action = 0;

//pour les 595
const int CLOCK1 = 4;
const int LATCH1 = 5;
const int DATA1 = 6;

int OUT5[8];
int OUT6[8];
int OUT7[8];

int CDE5 = 0;
int CDE6 = 0;
int CDE7 = 0;

//Handler DCC

void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data){
 storadresse.push (address);
 storaction.push (data);
}
void setup() {
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
  Serial.begin(115200);
  Serial.println("ADRESSE      ACTION");
 
  pinMode(LATCH1, OUTPUT);
  pinMode(CLOCK1, OUTPUT);
  pinMode(DATA1, OUTPUT);

//mise à zéro OUT5, OUT6, et OUT7
   digitalWrite(LATCH1, LOW);
  shiftOut(DATA1, CLOCK1, MSBFIRST, 0);
  shiftOut(DATA1, CLOCK1, MSBFIRST, 0);
  shiftOut(DATA1, CLOCK1, MSBFIRST, 0);
  digitalWrite(LATCH1, HIGH); 
}

void loop() { 
  DCC.loop();

  while(!storadresse.isEmpty()) {
   add = storadresse.shift();
   act = storaction.shift();

 if ((add != old_add) || (act != old_act)){
    old_add = add;
    old_act = act;

// Conversion de l'adresse NMRA en adresse decodeur d'accessoire
   add -= 1;
   add *= 4;
   add += 1;
   add += (act & 0x06) >> 1;
   act =(act & 0x01);
   Serial.print(add);
   Serial.print("   ");
   Serial.println(act);
 
 //Gestion des signaux
  if((add >=151) && (add <= 174)) { //boucle adresse feux
   
 //Registre à décalage OUT5
  if((add >=151) && (add <= 158)) {
    if(act == 1){
    OUT5[add - 151] = bit(add - 151);
    }
    else{
    OUT5[add - 151] = 0;
    }
  }//fin boucle OUT5
 
   //Registre à décalage OUT6
  if((add >=159) && (add <= 166)) {
    if(act == 1){
    OUT5[add - 159] = bit(add - 159);
    }
    else{
    OUT5[add - 159] = 0;
    }
  }//fin boucle OUT6
 
   //Registre à décalage OUT7
  if((add >=167) && (add <= 174)) {
    if(act == 1){
    OUT5[add - 167] = bit(add - 167);
    }
    else{
    OUT5[add - 167] = 0;
    }
  }//fin boucle OUT7
   
//envoi data vers OUT5, OUT6 et OUT7

    CDE5 = OUT5[0]+OUT5[1]+OUT5[2]+OUT5[3]+OUT5[4]+OUT5[5]+OUT5[6]+OUT5[7];
    CDE6 = OUT6[0]+OUT6[1]+OUT6[2]+OUT6[3]+OUT6[4]+OUT6[5]+OUT6[6]+OUT6[7];
    CDE7 = OUT7[0]+OUT7[1]+OUT7[2]+OUT7[3]+OUT7[4]+OUT7[5]+OUT7[6]+OUT7[7];

    digitalWrite(LATCH1, LOW);
    shiftOut(DATA1, CLOCK1, LSBFIRST, CDE7);
    shiftOut(DATA1, CLOCK1, LSBFIRST, CDE6);
    shiftOut(DATA1, CLOCK1, LSBFIRST, CDE5);           
    digitalWrite(LATCH1, HIGH);
     
         }//fin boucle adresse feux
      }//fin boucle si nouveaux data   
  }//fin while
}//fin loop
----------------------------------------------------------------------------------------------------------------------

CATPLUS

  • Sr. Member
  • ****
  • Messages: 435
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #5 le: décembre 09, 2017, 06:30:45 am »
Bonjour

Merci pour ce partage :)
On attends la suite......

Cordialement
Marcel
Best Regards

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #6 le: janvier 22, 2018, 03:59:55 pm »
J'aurais besoin que quelques spécialistes (plus que moi) regardent mon code.
Ce code fonctionne bien dans 95% des cas (sous CDM-Rail). par contre, dans le cas de commande d'itinéraires, quand, par exemple, 3 aiguillages doivent être commandés en même temps, et malgré le fait que CDM temporise les envois (0,5s), je loupe des commandes.
Il me semblait, qu'à partir du moment où je remplis un fichier FIFO dans le cadre de la routine d'interruption et que je le traite en dehors de cette routine (dans la LOOP) je ne pouvais rien rater.
Est-ce que j'ai bien compris? et est-ce que mon code est correct?
Une petite indication, en m'aidant des Serial.print (qui ne sont là que pour la mise au point), j'ai constaté qu'en supprimant les SHIFOUT je ne loupais plus de commandes DCC.

Ci-dessous mon code.

//Programme de gestion des aiguillages de la zone Bréauté
#include <DCC_Decoder.h>
#define kDCC_INTERRUPT    0    // pin 2 for UNO
#include <CircularBuffer.h>

CircularBuffer <int, 100> storadresse;
CircularBuffer <byte, 100> storaction;

int add = 0;
int act = 0;
int old_add = 0;
int old_act = 0;
int action = 0;

const int LATCH1 = 6;
const int CLOCK1 = 7;
const int DATA1 = 5;

int OUT1[8];
int OUT2[8];
int OUT3[8];

int CDE1 = 0;
int CDE2 = 0;
int CDE3 = 0;


//Handler DCC
void BasicAccDecoderPacket_Handler(int address, boolean activate, byte data){
  storadresse.push (address);
  storaction.push (data);
  Serial.print(address);
  Serial.print("   ");
  Serial.println(data);
}

void setup() {
  DCC.SetBasicAccessoryDecoderPacketHandler(BasicAccDecoderPacket_Handler, true);
  DCC.SetupDecoder( 0x00, 0x00, kDCC_INTERRUPT );
  Serial.begin (115200);

  Serial.println(" DCC brut          ADRESSE   ACTION");
 
  pinMode(LATCH1, OUTPUT);
  pinMode(CLOCK1, OUTPUT);
  pinMode(DATA1, OUTPUT);

}

void loop() {
  DCC.loop();

   while(!storadresse.isEmpty()) {
   add = storadresse.shift();
   act = storaction.shift();

 if ((add != old_add) || (act != old_act)){
    old_add = add;
    old_act = act;
   
  // Conversion de l'adresse NMRA en adresse decodeur d'accessoire
  add -= 1;
  add *= 4;
  add += 1;
  add += (act & 0x06) >> 1;
  action = (act & 0x01);
  Serial.print("                        ");
    Serial.print(add);
    Serial.print("    ");
    Serial.println(action);
   
//Gestion aiguillages
 
//registre à décalage OUT1
  if((add >= 1) && (add <= 8)) {
    if (action == 1) {
      OUT1[add-1] = bit(add - 1);
    }
    else {
      OUT1[add-1] = 0;
    }
  } //fin OUT1

//registre à décalage OUT2
  if((add >= 9) && (add <= 16)) {
    if (action == 1) {
      OUT2[add-9] = bit(add - 9);
    }
    else {
      OUT2[add-9] = 0;
    }
  } //fin OUT2

  //registre à décalage OUT3
    if((add >= 17) && (add <= 24)) {
    if (action == 1) {
      OUT3[add-17] = bit(add - 17);
    }
    else {
      OUT3[add-17] = 0;
    }
  } //fin OUT3
 
//envoi des commandes

  CDE1 = OUT1[0]+OUT1[1]+OUT1[2]+OUT1[3]+OUT1[4]+OUT1[5]+OUT1[6]+OUT1[7];
  CDE2 = OUT2[0]+OUT2[1]+OUT2[2]+OUT2[3]+OUT2[4]+OUT2[5]+OUT2[6]+OUT2[7];
  CDE3 = OUT3[0]+OUT3[1]+OUT3[2]+OUT3[3]+OUT3[4]+OUT3[5]+OUT3[6]+OUT3[7];
 
  digitalWrite(LATCH1, LOW);
  shiftOut(DATA1, CLOCK1, LSBFIRST, CDE3);
  shiftOut(DATA1, CLOCK1, LSBFIRST, CDE2);
  shiftOut(DATA1, CLOCK1, LSBFIRST, CDE1);       
  digitalWrite(LATCH1, HIGH);
 
     }//fin boucle si nouveaux data
   }//fin while   
  }//fin programme principal

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1714
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #7 le: janvier 22, 2018, 04:20:27 pm »
Commence par retirer les

  Serial.print(address);
  Serial.print("   ");
  Serial.println(data);

De debug dans ton handler, ça prend des plombes à s'executer. Ça peut aussi bloquer ton application car ça ne doit pas être utilisé dans un handler d'interruption.

Ensuite tu as un problème de concurrence sur tes buffers entre le programme principal et ton handler d'IT.
Cordialement

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #8 le: janvier 22, 2018, 05:59:50 pm »
OK pour enlever les "serial.print". C'était mon intention mais j'avais le problème sans ça.

Par contre, tu peux m'expliquer la "concurrence" entre les buffers?

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 3039
  • 100% Arduino et N
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #9 le: janvier 22, 2018, 06:33:40 pm »
Peut-être faut-il arrêter les interruptions avant
   add = storadresse.shift();
   act = storaction.shift();
et les rétablir après ?

Cette discussion est intéressante : je ne connaissais pas la biblio CircularBufffer !
Cordialement,
Dominique

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1714
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #10 le: janvier 23, 2018, 08:21:38 am »
Oui,

Si une interruption survient alors que l'un des shift est en cours d'exécution, l'un des push va modifier un tampon circulaire qui est au milieu de son shift avec pour conséquence une altération des données ou des index de lecture et d'écriture. Il faut effectivement bloquer les IT pour les deux shift.
Cordialement

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #11 le: janvier 23, 2018, 08:11:55 pm »
D'accord mais qu'est ce qui se passe si des données DCC arrivent pendant cet instant de blocage?

Et, question d'un néophyte dans le domaine des IT: comment bloque-t-on une IT et comment on la réactive?



Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1714
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #12 le: janvier 23, 2018, 08:48:33 pm »
Si les IT sont bloquées, l’IT la plus prioritaire sera prise en compte quand les IT seront débloquées. Donc à moins de bloquer pendant une durée supérieure au temps dl’arrivée de deux IT consécutives de même type, rien ne sera perdu. Mais, dans le cas du DCC, le temps est important et il ne faut pas que le temps de blocage conduise à mal interpréter les bits d’une trame DCC.

Pour bloquer les IT, il faut appeler la fonction noInterrupts(). Pour les débloquer, interrupts().

https://www.arduino.cc/reference/en/language/functions/interrupts/nointerrupts/
https://www.arduino.cc/reference/en/language/functions/interrupts/interrupts/

Cordialement

Loco28

  • Newbie
  • *
  • Messages: 24
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #13 le: janvier 23, 2018, 09:57:03 pm »
Donc, si j'ai bien compris, j'ajoute une ligne "nointerrupts() avant mes 2 lignes ".shift" et j'ajoute une ligne "interrupts()" juste après?

Jean-Luc

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 1714
    • Voir le profil
Re : Récupération données DCC: CircularBuffer et ShiftOut
« Réponse #14 le: janvier 23, 2018, 10:29:10 pm »
Exactement
Cordialement