Auteur Sujet: projet centrale "LaBox" wifi DCC++ Can  (Lu 117634 fois)

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2454
  • 100% Arduino et N
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #630 le: septembre 16, 2021, 02:06:44 pm »
Dans la foulée, un essai valide cette faisabilité mais c'est un exemple qui n'est pas encore intégré avec le reste (donc il peut y avoir des interactions):

La maquette utilisée : LaBox complète avec son booster, connectée au sniffer ESP32.

Les résultats récupérés par msport.

Le code de l'exemple qui ne nécessite aucune bibliothèque.

Je reviendrai sur les détails au retour de mes courses...

« Modifié: septembre 16, 2021, 07:43:27 pm par Dominique »
Cordialement,
Dominique

Thierry

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 668
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #631 le: septembre 16, 2021, 02:18:08 pm »
Super, il va falloir implanter ça dans DCCpp-LaBox et voir si le résultat est toujours le même...

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2454
  • 100% Arduino et N
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #632 le: septembre 16, 2021, 07:14:29 pm »
Ce que j'ai fait n'est pas sorcier, en partant d'un exemple.
L'IDE Arduino propose un générateur de code morse, moi j'ai pris un exemple de télécommande infrarouge ailleurs sur le web.

Les includes sont tous dans le core ESP32 (aucune bibliothèque à ajouter):
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "Arduino.h"

#include "esp32-hal.h"

J'ai ensuite créé une série de bits d'un paquet IDLE qui sera répété indéfiniment.
#define NR_OF_IDLE_BITS 40


///////////////////////////////////////////////////////////////////////////////
// The NMRA DCC Signal is sent as a square wave with each half having
// identical timing (or nearly identical). Packet Bytes have a minimum of 11
// preamble ONE bits in order to be considered valid by the decoder. For
// RailCom support it is recommended to have at least 16 preamble bits. For the
// Programming Track it is required to have a longer preamble of at least 22
// bits. Packet data follows immediately after the preamble bits, between the
// packet bytes a DCC ZERO is sent. After the last byte of packet data a DCC
// ONE is sent.
//
// DCC ZERO:
//    ----------------
//    |      96      |
// ---|     usec     |      96      ---
//                   |     usec     |
//                   ----------------
// DCC ONE:
//    --------
//    |  58  |     
// ---| usec |  58  ---
//           | usec |
//           --------
//
// The timing can be adjusted via menuconfig with the above being the default
// values when using the APB clock.
// Une trame IDLE est émise quand il n’y a pas de trame de commande à envoyer,
// de façon à alimenter continuellement la voie :
// 111111111111 0 11111111 0 00000000 0 11111111 1
//
///////////////////////////////////////////////////////////////////////////////
int IDLE_pattern[NR_OF_IDLE_BITS] = {1,1,1,1,1,1,1,1,1,1,1,1, 0, 1,1,1,1,1,1,1,1, 0, 0,0,0,0,0,0,0,0, 0, 1,1,1,1,1,1,1,1, 1};
rmt_data_t idle_data[NR_OF_IDLE_BITS];
rmt_obj_t* rmt_send = NULL;
et les 2 variables idle_data (les formes de bits à émettre et rmt_send, pointeur nécessaires au driver.

Ensuite, tout est dans le setup:
void setup()
{
    Serial.begin(115200);
    Serial.println("init RMT pin33");
   
    if ((rmt_send = rmtInit(33, true, RMT_MEM_64)) == NULL) // init sur DCC pin = 33
    {
        Serial.println("init sender failed\n");
    }

    /**
    *    Sets the clock/divider of timebase the nearest tick to the supplied value in nanoseconds
    *    return the real actual tick value in ns
    */
    float realTick = rmtSetTick(rmt_send, 1000); // a calculer pour 1 uS
    Serial.printf("real tick set to: %fns\n", realTick);

    int i=0;
    /*
     * Preparation du jeu d'essai : une trame IDLE
     */
    for (i=0;i<NR_OF_IDLE_BITS; i++) {
      if (IDLE_pattern[i]==0) { // UN
        idle_data[i].level0 = 1;
        idle_data[i].duration0 = 96;
        idle_data[i].level1 = 0;
        idle_data[i].duration1 = 96;
      } else {                  // ZERO
        idle_data[i].level0 = 1;
        idle_data[i].duration0 = 58;
        idle_data[i].level1 = 0;
        idle_data[i].duration1 = 58;
      }
    }
    pinMode(32, OUTPUT); 
    digitalWrite(32, HIGH); 
    Serial.println("loop");

    // Send the data
    rmtLoop(rmt_send, idle_data, NR_OF_IDLE_BITS);
}

rmtInit(33, true, RMT_MEM_64) définit la pin de sortie de l'ESP32, le mode émission seulement et la taille du tampon mémoire utilisé.
rmtSetTick(rmt_send, 1000) définit la période des TICKS, ici proches de la microseconde, ce que confirme realTick.

Ensuite la variable Idle_data est garnie avec les valeurs correspondant à chaque bit de la trame DCC
        idle_data.level0 = 1;        // le 1/2 bit haut
        idle_data.duration0 = 96; //aura une durée de 96 uS
        idle_data.level1 = 0;        // le 1/2 bit bas
        idle_data.duration1 = 96; // également 96 uS

Et l'instruction rmtLoop(rmt_send, idle_data, NR_OF_IDLE_BITS) se charge d'envoyer le signal DCC automatiquement et de façon répétitive.

De ce fait tout cet exemple tient dans le setup.

Mais j'aurai pu utiliser dans la loop l'instruction rmtWrite(rmt_send, idle_data, NR_OF_IDLE_BITS) avec les même arguments,
qui pourrait donner les mêmes résultats ou permettre d'émettre des séquences de trames DCC plus complexes.
Mais il vaut mieux contrôler les flux entre le programme et le tampon RMT, probablement comme l'indique Sébastien en utilisant les interruptions disponibles lorsqu'une fraction du tampon est disponible, car la norme DCC nécessite que les émissions soient permanentes pour alimenter le matériel roulant.

Maintenant il faut intégrer ce mécanismes avec toutes les autres tâches (Wifi, Serial, Can, I2C, AnalogInputs, ..)

Mais cela peut nous rassurer pour le moment, en espérant que ce projet puisse intéresser plusieurs contributeurs pour se renforcer  :D ;D
« Modifié: septembre 16, 2021, 07:39:53 pm par Dominique »
Cordialement,
Dominique

AmadeusHF

  • Full Member
  • ***
  • Messages: 192
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #633 le: septembre 17, 2021, 02:56:54 pm »
Tu as remarqué que tu avais 732 paquets DCC émis, et 732 "second half" d'un bit à UN qui étaient plus longues d'une microseconde ?

Lorsque tu utilises le RMT en mode LOOP, pour envoyer une cyclique une trame unique finie, il "perd" un cycle après le dernier bit de la trame, le temps de repartir au début. C'est dans la doc. Tu as donc un bit à UN (le bit de fin de ta trame je pense) dont la seconde partie dure une uSec de plus.

Normalement, en mode WRAP AROUND, dans lequel le buffer d'émission est saturé, ce phénomène ne se produit pas.
En mode CYCLE (LOOP) que tu as utilisé, le RMT identifie la fin de la séquence par le marqueur 0/0 de la liste, ce qui explique le cycle perdu....en mode WRAP AROUND, le buffer est saturé à 100% et il n'y a pas de marqueur de fin....donc pas d'introduction d'un cycle perdu.

Théoriquement !

A vérifier dans la pratique.
Sébastien.
La perfection est un chemin, non un but...

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2454
  • 100% Arduino et N
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #634 le: septembre 17, 2021, 04:20:13 pm »
Merci Sébastien.
Maintenant j’ai une base pour expérimenter les autres modes, le mode LOOP n’étant sûrement pas celui qu’il faut dans LaBox
Cordialement,
Dominique

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2454
  • 100% Arduino et N
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #635 le: octobre 24, 2021, 09:58:34 am »
Il reste un test à faire (je viens d’y penser): lancer des lectures analogiques de tension (mesures de courant) périodiques pour vérifier qu’elles ne dégradent pas la précision du RMT.

A suivre…
Cordialement,
Dominique

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2454
  • 100% Arduino et N
    • Voir le profil
Re : projet centrale "LaBox" wifi DCC++ Can
« Réponse #636 le: novembre 02, 2021, 09:09:11 pm »
Je suis rassuré ! ;D

J'ai ajouté dans la loop une lecture périodique de la pin 36 qui sert à la mesure de courant
    int val = analogRead(36);
    Serial.print(val); Serial.print('-');
    linecount++;
    if (linecount > 50) {
      Serial.println();
      linecount = 0;
    }
    delay(25);

Donc toutes les 25 millisecondes, une mesure de tension a lieu avec analogRead et un Serial.print suit dans la foulée, de quoi perturber notre trame IDLE émise par RMT si le driver RMT est influencé dans l'environnement freeRTOS.

Et bien, QUE NENI, les durées des bits DCC restent parfaites durant les 2 secondes de lecture, mesure et rapport des caractéristiques du DCC sortant de LaBox !!

20:58:24.995 -> Bit Count/4 sec=29294 (Zeros=8055, Ones=21239), Glitches=0
20:58:24.995 -> Valid Packets=733, NMRA out of spec=0, Checksum Errors=0, Lost pkts=0, Long pkts=0
20:58:25.029 -> 0 half-bit length (us): 95.5 (95-96) delta < 1
20:58:25.029 -> 1 half-bit length (us): 57.5 (57-59) delta < 2
20:58:25.029 -> --
20:58:25.029 -> Idle                    11111111 00000000

Donc, le driver RMT travaille de son coté, indépendamment de freeTROS.
« Modifié: novembre 03, 2021, 06:42:37 am par Dominique »
Cordialement,
Dominique