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 - Thierry

Pages: [1] 2 3 ... 39
1
Bibliothèques / Re : Bibliothèque DCCpp
« le: novembre 25, 2021, 03:05:58 pm »
Bonjour

Sur le fond, rien ne distingue la voie de programmation de la voie principale. J'y ai même ajouté la gestion des fonctions et quelques autres manques par rapport à l'original DCC++ .

2
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« 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...

3
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: septembre 09, 2021, 05:55:41 pm »
Bonjour

La partie RMT de l'ESP32 est maintenant utilisée par l'Esp32CommandStation d'Atany https://github.com/atanisoft/ESP32CommandStation pour la génération des trames DCC. Ca semble bien correspondre au besoin, mais je ne me suis pas penché dessus. C'est un peu le même principe que le PWM qui lui aussi utilise des alternances bien calibrées... On peut imaginer que l'adoption de cette fonctionnalité de l'ESP32 est intervenue pour corriger les mêmes problèmes de timing que nous.

4
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: septembre 01, 2021, 08:37:59 am »
Les timings sont bien bons, effectivement. Et l'analyseur logique qui décode le DCC tout en surveillant les trames, c'est juste génial !

5
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: août 30, 2021, 04:46:35 pm »
C'est aussi pour ça que j'ai préféré repartir de DCCpp et éviter les surcharges de Labox...

6
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: août 30, 2021, 11:04:57 am »
Oui, dans HMI.cpp, l'analyse du courant consommé est à base d'analogRead. Il faudrait mettre les lignes 730 et 751-752 en remarque:

D:\Documents\Arduino\libraries\LaBox\src\hmi\hmi.cpp:
  728  {
  729    _HMIDEBUG_FCT_PRINTLN("hmi::readVoltage().. Begin"); 
  730:   voltage = (float) (analogRead(PIN_VOLTAGE_MES) * HMI_VoltageK);
  731  #ifdef _HMIDEBUG_SIMUL
  732    voltage = ((float)random(175, 185)) / 10;
  ...
  744  {
  745    _HMIDEBUG_FCT_PRINTLN("hmi::readCurrent().. Begin");   
  746:   //current = analogRead(PIN_CURRENT_MES) * HMI_CurrentK ;
  747    // DB : remplacé par une moyenne de 50 mesures
  748    float base = 0;
  749  for (int j = 0; j < 50; j++)
  750  {
  751: float val = (float) analogRead(PIN_CURRENT_MES);
  752  base += val;
  753  }

7
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: août 30, 2021, 09:22:59 am »
Aujourd'hui, la lecture du courant se passe effectivement dans la loop principale DCCpp::loop() . Il y a à la fois la lecture de courant sur la voie principale puis sur la voie de programmation, ce qui signifie 100 analogRead par loop(). C'est sans doute trop fréquent, et on pourrait vraisemblablement ne laisser la mesure que chaque dixième de seconde, voire quart de seconde. Mais ça resterait encore trop fréquent et perturberai encore les timings à ces moments là. La lecture de CV est aussi perturbée, mais bien plus rarement, effectivement.
Il y a l'option dans ESP32_Timer pour faire faire la mesure au second core, mais si les choses s'améliorent un peu, ça reste trop perturbant pour les timings. Je pense qu'analogRead touche des choses bas-niveau de l'ESP qui sont communes à tous les coeurs.
Les tests de Michel montrent que la fonction remplaçante fait bien son boulot. Merci Michel ! Il faut maintenant vérifier que les timings DCC sont bons avec la lecture analogique débranchée (UNDEFINED_PIN sur le troisième argument de beginMain() dans Labox.ino...), et si c'est le cas, alors il faudra implémenter la nouvelle lecture analogique partout et revérifier avec le sniffer.

8
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: août 29, 2021, 11:51:52 am »
Deuxième partie de mon analyse : DCCpp.

Pour éviter toute influence de ce que nous avons ajouté dans Labox avec les throttles et les diverses modifications, j'ai décidé de repartir de DCCpp. Lui ne s'occupe que du signal proprement dit. Le fichier ino utilisé (joint ici, avec aussi mon DCCpp du moment) est une variante de l'exemple autotest. En effet, il me fallait trouver un protocole de test suffisamment fiable et répétitif. Si en plus je pouvais me passer d'un circuit et de matériel roulant... Bref, une séquence programmée répétitive, avec un nombre d'actions bien déterminé devait faire l'affaire. Après réflexion, je me suis dit qu'en fait je n'avais pas besoin d'actions ! La simple génération de paquets 'Idle' devaient suffire à tester les timings. Ils contiennent suffisamment de bit à 0 et 1 pour tester. Il suffit d'allumer le DCC, d'attendre un peu, de clore le DCC puis d'afficher un rapport. C'est ce que fait le .ino avec une attente de 10s.
Avant de passer par la première étape citée plus tôt avec mon ESP32_timer.ino indépendant, j'avais tenté de remplacer l'interruption classique de DCCpp par une variante introduite dans la version officielle depuis peu, la version avec une seule interruption (USE_ONLY1_INTERRUPT). Contrairement à la routine classique qui décide à chaque changement de bit de la durée du prochain timing (58us ou 96us), la nouvelle dispose d'un timing constant à 58us, et compte les appels : 2 pour un un (un front montant, un front descendant) ou 4 pour un zéro (deux pour le front montant, deux autres pour le front descendant). Le gros avantage c'est que ça m'a permis de reporter mon calcul de timings quasiment tel quel depuis mon programme indépendant.
C'est en essayant de reproduire les timings de ESP32_Timer que je me suis aperçu de l'influence d'analogRead. En effet, si on ne demande pas de surveiller le courant (passer UNDEFINED_PIN comme dernier argument de DCCpp::beginMain() ) les timings bruts sont bien meilleurs. Je n'ai pas fait le test pour savoir si du coup le sniffer y trouvait son compte. A tester.

Evidemment, tout ça ne sert à rien si on a pas une solution à offrir. Pas question de se passer de la mesure de courant, que ce soit pour gérer les court circuits ou pour la programmation. Sur le net, j'ai fini par trouver une fonction de remplacement d'analogRead qui va plus vite.

#include <soc/sens_reg.h>
#include <soc/sens_struct.h>

int local_adc1_read(int channel)
{
uint16_t adc_value;

SENS.sar_read_ctrl.sar1_dig_force = 0; // switch SARADC into RTC channel
SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PU; // adc_power_on
SENS.sar_meas_wait2.force_xpd_amp = SENS_FORCE_XPD_AMP_PD; // channel is set in the convert function

// disable FSM, it's only used by the LNA.
SENS.sar_meas_ctrl.amp_rst_fb_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_fsm = 0;
SENS.sar_meas_ctrl.amp_short_ref_gnd_fsm = 0;
SENS.sar_meas_wait1.sar_amp_wait1 = 1;
SENS.sar_meas_wait1.sar_amp_wait2 = 1;
SENS.sar_meas_wait2.sar_amp_wait3 = 1;

//set controller
SENS.sar_read_ctrl.sar1_dig_force = false;      //RTC controller controls the ADC, not digital controller
SENS.sar_meas_start1.meas1_start_force = true;  //RTC controller controls the ADC,not ulp coprocessor
SENS.sar_meas_start1.sar1_en_pad_force = true;  //RTC controller controls the data port, not ulp coprocessor
SENS.sar_touch_ctrl1.xpd_hall_force = true;     // RTC controller controls the hall sensor power,not ulp coprocessor
SENS.sar_touch_ctrl1.hall_phase_force = true;   // RTC controller controls the hall sensor phase,not ulp coprocessor

//start conversion
SENS.sar_meas_start1.sar1_en_pad = (1 << channel); //only one channel is selected.
while (SENS.sar_slave_addr1.meas_status != 0);
SENS.sar_meas_start1.meas1_start_sar = 0;
SENS.sar_meas_start1.meas1_start_sar = 1;
while (SENS.sar_meas_start1.meas1_done_sar == 0);
adc_value = SENS.sar_meas_start1.meas1_data_sar; // set adc value!

SENS.sar_meas_wait2.force_xpd_sar = SENS_FORCE_XPD_SAR_PD; // adc power off return adc_value;

return adc_value;
}

Je vous rassure, je n'y comprend rien non plus. Ca fait appel à des fonctions de base de l'ESP32 dont se sert aussi le classique analogRead. Effectivement, ça va plus vite, mais dans mon b...l provisoire, je ne l'ai pas testé en situation réelle. Je ne sais pas où sont mes potars ! Il faudrait au moins tester que ça marche sur un programme de lecture de potar de base en comparant la valeur qu'elle retourne à celle que retourne le vrai analogRead. Si la fonction marche, on pourra alors envisager de remplacer tous nos appels à analogRead par cette fonction. Elle réclame un channel et pas un numéro de pin, alors il faut utiliser
int channel = digitalPinToAnalogChannel(pin);
pour faire la conversion.


9
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: août 29, 2021, 11:14:16 am »
Bonjour à tous

Après trois semaines de vacances à la maison, beaucoup de bricolage, et aussi un peu de programmation pour voir de quoi est fait l'ESP32, j'ai enfin quelques éléments de réponse sur notre problème de timing découvert voilà maintenant plusieurs mois...

Premier objectif pour moi, tester les timings interruptions simples sur ESP32. Rien ne permet de penser que ces interruptions ne fonctionnent pas bien, mais quand on cherche à résoudre un problème, on commence par la base... J'ai donc pondu un fichier ino (joint ici) avec un programme de test de timing. Il fonctionne -a priori- aussi bien en ESP32 que sur un Nano. Son but est d'abord de compter le temps entre deux appels à la fonction d'interruption et de rendre un rapport après un certain nombre de mesures. Je l'ai fixé à peu près au maximum d'un entier non signé, c'est à dire 60000 mesures. Ce devrait statistiquement être suffisant. Chaque interruption va mesurer le temps passé depuis le précédent appel, et selon le résultat, incrémenter un compteur. Comme le temps est idéalement fixé à 58us, j'ai donc utilisé une matrice de compteurs qui vont stocker le nombre trouvé de timings à +-10us autour du temps référence. C'est donc une matrice de 48 à 68, mais comme elle commence à 48, c'est en réalité une matrice de 20 longs non signés. L'élément 0 donne le compteur des 48us, l'élément 1 de 49us, etc... Deux autres compteurs sont ajoutés : l'élément 20 qui compte le nombre de timings en dessous de 48us, et l'élément 21 qui compte le nombre au dessus de 68us. Trois autres temps sont mesurés : le timing le plus court de toute la série, le plus long, et le temps passé à l'intérieur de la fonction d'interruption. Un pourcentage permet de rendre compte de la proportion de timings à la valeur idéale de 58us, et aussi la proportion de timings conformes à la norme NMRA, c'est à dire entre 55 et 61us inclus. Le timing moyen est aussi calculé.
Pour mieux comprendre l'influence de ce qui tourne autour de l'interruption, j'ai ajouté des define à l'entrée du programme pour jouer avec différents paramètres:
  • LOOP_COMPUTE ajoute un traitement qui se veut un peu lourd dans la loop, un calcul de nombres premiers.
  • LOOP_ANALOG_READ ajoute à la loop l'analyse du courant consommé à base d'analogRead tel qu'elle est faite dans DCCpp.
  • INT_COMPUTE alourdit la routine d'interruption en faisant des digitalRead. Et on se rend compte là que le ESP32 est bien plus rapide là que le Nano... L'ESP32 passe malgré tout de 2 à 20us...
  • SET_PIN fait alterner une broche digitale dans la routine d'interruption. C'est ce que fait DCCpp pour le signal DCC.
  • INT_SECOND_CORE envoie la routine d'interruption sur le second coeur. Bien sûr ça ne marche qu'en ESP32...

Voici le rapport sans rien activer du tout, juste la mesure des temps :

isr : 2
min : 54
max : 62
ave : 57.50
< 48: 0
= 48: 0
= 49: 0
= 50: 0
= 51: 0
= 52: 0
= 53: 0
= 54: 120
= 55: 0
= 56: 120
= 57: 0
= 58: 59520 (99.20%)
= 59: 0
= 60: 120
= 61: 0
= 62: 120
= 63: 0
= 64: 0
= 65: 0
= 66: 0
= 67: 0
> 68: 0

NMRA compliant: 59760 (99.60%)

Le temps passé dans la routine d'interruption est de 2us, ce qui est très raisonnable avec un temps moyen de 57.5us très correct.
L'ensemble des temps mesurés se situe entre 54 et 62us, on est donc à près de 100% de réussite sur une norme NMRA.
Le timer de l'ESP32 fonctionne sur une démultiplication des ticks donnés par la fréquence du processeur. Ca explique les timings réguliers toutes les deux us : 54, 56, 58, 60, 62, 64... Certaines fois le timer doit arriver un chouilla trop tôt ou trop tard...

Voyons ce que ça donne avec LOOP_COMPUTE, INT_COMPUTE et SETPIN activés :
isr : 23
min : 53
max : 63
ave : 57.50
< 48: 0
= 48: 0
= 49: 0
= 50: 0
= 51: 0
= 52: 0
= 53: 120
= 54: 0
= 55: 120
= 56: 0
= 57: 240
= 58: 59043 (98.40%)
= 59: 241
= 60: 0
= 61: 120
= 62: 0
= 63: 120
= 64: 0
= 65: 0
= 66: 0
= 67: 0
> 68: 0

NMRA compliant: 59764 (99.60%)

Le temps passé dans la routine d'interruption s'est bien alourdi, mais le bilan global reste correct. On a un peu de timings perturbés à 57 ou 59us, et les temps mini/maxi se sont un peu aggravés, mais restent corrects.

Voyons ce qui se passe si l'on active uniquement la mesure de courant LOOP_ANALOG_READ:

isr : 3
min : 25
max : 90
ave : 57.50
< 48: 2352
= 48: 0
= 49: 0
= 50: 0
= 51: 0
= 52: 0
= 53: 0
= 54: 198
= 55: 960
= 56: 1849
= 57: 6489
= 58: 6554 (10.92%)
= 59: 20937
= 60: 17559
= 61: 1059
= 62: 174
= 63: 91
= 64: 99
= 65: 857
= 66: 272
= 67: 214
> 68: 344

NMRA compliant: 55407 (92.33%)

Et là c'est le drame... Les temps mini/maxi ont explosé, seulement 10% des timings sont respectés. Et même si d'un point de vue NMRA 92% des timings sont respectés, ont voit bien que dans un signal DCC de grandes disparités peuvent intervenir entre les fronts montants et les fronts descendants du signal... Le fait de passer la routine d'interruption sur le second coeur améliore un peu le traitement, mais pas au point de redevenir acceptable.

Le constat est sans appel, l'analogRead ESP32 est très lent. J'ai lu quelque part qu'il lui fallait 100us pour faire sa tâche, et que pendant une partie de ce temps les interruptions sont bloquées... C'est un problème que le nano n'a pas.
Voilà pour la partie théorique de l'analyse. Reste à trouver une solution et à l'appliquer à DCCpp et donc à Labox.

10
Le logiciel DCC++ / Re : Mini centrale DCC++ pour banc nettoyage
« le: juillet 15, 2021, 02:46:02 pm »
Il est fort ce msport  :) (ça rime !)

11
Le logiciel DCC++ / Re : Mini centrale DCC++ pour banc nettoyage
« le: juillet 10, 2021, 06:28:24 pm »
Il me semble que sauf rare exception, les locos digitalisées fonctionnent aussi en analogique. Donc du 12v continu serait sans doute suffisant si le but est juste de faire tourner les roues !

12
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: juin 04, 2021, 08:18:30 pm »
Oui, la lecture continue est causée par le menu, pas par la fonction d'identification... Je pense que ce n'est pas le bon événement qui est utilisé. Cedric ? Ton avis ?

13
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: juin 04, 2021, 06:59:00 pm »
Suite au remarques, petite version 0.9.1 pour tenter d'améliorer les choses :

- La lecture affiche maintenant la valeur lue sur la console, ça n'y était même pas !
- Toute lecture de Cv, et pas uniquement celles faites par identifyLocoId(), provoque la mise en route DCC.
- Un délai de 50ms a été ajouté au cas où entre deux tentatives...
- Enfin le meilleur pour la fin, l'application Z21 permet maintenant de lire les Cvs en demandant à les lire sur la voie de programmation ! Bien pratique pour tester...

De mon côté, j'ai essayé ma vieille G2000 semble t-il équipée d'un décodeur Viessmann, une Class 66 Kato qui prétends avoir un décodeur Trix (?), et une Bachmann S4. Toutes les trois répondent, à des degrés divers. La lecture d'une Cv isolée par l'appli z21 marche mieux que l'identification par LaBox... Enfin la Bachmann veut aussi avancer dès qu'elle est sur les rails alors qu'aucune throttle n'est encore connectée ! A noter que les durées de ack sont bien plus conformes avec la Kato et la Bachmann... Bien plus que le décodeur Viessmann.

Pour Dominique, petite explication des affichages de lecture de bit   'Bit  : 0, ACK   , samples : 24, gaps : 1, max : 32, start : 22992us, duration : 1006us'  :

- samples : nombre de valeurs mesurées, généralement entre 100 et 102 lors d'un NO_ACK. La mesure est interrompue lorsque que la fin d'un ACK est détectée, donc le nombre de mesures est inférieur.
- gaps : parmi les mesures, nombre de celles qui ont dépassé le seuil.
- max : seuil le plus haut mesuré parmi les gaps. Rappelons que la valeur par défaut du ackThreshold est fixée à 30... La valeur est en relatif par rapport à la valeur de base relevée avant les mesures. Donc autour de 0 lorsqu'il n'y a pas de ack, et à ackThreshold plus un chouilla lors d'un ack.
- start: date de début du ack depuis le début de la boucle de mesures.
- duration : durée du ack.

A noter aussi que la Bachmann renvoie des valeurs d'environ 100, la Kato de plus de 200, tandis que la G200 monte à 450 ! Il y a peut être de grosses différences de consommation entre les modèles de décodeur, et/ou des moteurs des machines.
Peut être qu'en réduisant le seuil à 20 ou 25, on aurait plus de résultats à tester sur des machines peu puissantes.

14
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: juin 04, 2021, 04:01:24 pm »
La ligne en question était le HMI.begin() du setup dans le .ino, mais ce n'est plus commenté normalement.

15
Vos projets / Re : projet centrale "LaBox" wifi DCC++ Can
« le: juin 03, 2021, 08:48:26 pm »
Nouvelle version 0.9.0 de LaBox.
Le but de cette nouvelle version était principalement de régler ces histoires de lecture de Cv. On verra plus tard pour l'écriture !

- La nouvelle fonctionnalité de mise en route du DCC (powerOn() ) dès la demande de lecture a provoqué le premier problème : j'ai ajouté un délai de 200ms lors de l'alumage du DCC pour permettre au décodeur dans la loco de s'initialiser correctement. C'est ce qui expliquait la perte systématique du premier bit...
- J'ai transformé la routine d'aquisition du ack pour qu'elle dépende d'un temps au delà duquel le ack n'est pas validé (100ms) et non de la durée de deux boucles imbriquées.
- J'ai ajouté un affichage en debug du résultat plus parlant je pense, y compris pour la vérification de ce qui a été lu.
- Les routines DCCpp::readCvMain() et DCCpp::readCvProg() ont été crées pour forcer trois essais de lecture à chaque Cv lue. Dès qu'une vérification valide la lecture, on passe au CV suivant.
- J'ai supprimé le lissage effectué lors de la lecture du ack pour prendre les valeurs brutes...
- analogRead() a été remplacée par une fonction plus bas niveau de l'ESP32 et plus rapide.

Avec ces premières mesures, la lecture de l'adresse de la loco fonctionne à 99% (en tout cas sur ma vieille G2000 ...) .

- J'ai ajouté une fonction DCCpp::getDecoderInfo() qui est censée renvoyer les données du constructeur grace à la lecture des Cv 8 et 7. Une matrice constante a été créée à partir des fichiers de config de JMRI pour cette liste, plus complète que celle du NMRA.

Malgré ces avancées, il subsiste des problèmes :
- Justement, la lecture du Cv8 ne fonctionne pas du tout, et je n'ai pas d'explication... Donc getDecoderInfo a le mérite d'exister, mais elle n'est pas testée !
- Les timings renvoyés par l'affichage du résultat du ack sont fantaisistes. Un ack devrait durer en 4000 et 6500 micro-secondes d'après le NMRA, hors j'en trouve à plus de 20000 et à moins de 2000 ! J'ignore si le calcul de temps est le problème ou si c'est juste ma G2000 et son décodeur qui font des fantaisies. A noter que dans DCC++Ex pour Uno/Mega, le timing est précisément mesuré et ce qui en sort (entre 2000 et 8500us chez eux) n'est pas validé !

Voili, voilou.

Pages: [1] 2 3 ... 39