LOCODUINO

Parlons Arduino => Vos projets => Discussion démarrée par: laurentr le octobre 18, 2023, 12:24:53 am

Titre: Décodeur de locomotive multifonctions
Posté par: laurentr le octobre 18, 2023, 12:24:53 am
Bonsoir à tous
 Quitte a bien faire je pense qu'il faut “pousser” un peu plus loin sur différents axes que j expose ci après.
En terme de coût pour une fabrication industrielle finalement le delta sera surtout sur les composants mis en œuvre principalement

Premier point: la régulation de tension: on le voit tout de suite cela chauffe ce qui est contre productif à ce qui est recherché.
Point de salut sans un convertisseur DcDc pour éviter le phénomène.
Il y en a beaucoup de différentes marques avec des caractéristiques aussi très hétérogènes.
Un choix peut être opéré.
Mon dévolu irait volontiers sur un MPM3510A
C est un cousin de celui présent sur les Arduino Nano Every avec une entrée plus haute en tension jusqu'à 36v en entrée et 1.2A en sortie.
4 composants basiques autour est on a une régulation solide sur le 5v.
Son seul inconvénient va été sont prix.( proche de 5€)

Point 2 :
Plus discutable mais le 328p… est “un peu hasbeen”…
Pour le même prix de CPU et tout aussi compatible nous avons les AVR de générations plus récentes ( séries d Avr0/1/2 et leur cousins Megatiny) qui vont aussi offrir plus de possibilités et de capacités avec un prix et une dispo similaire sinon meilleure!
On a l'embarras du choix.
Disons un avr32dd32 par exemple ou un atmega4808 en 32 broches sont de bons candidats.
L intérêt du 32 broches est la portabilité au travers toutes les familles. En cas de manque de place il faudra descendre en broches au sacrifice de ressources hardware. Ou à l inverse monter vers 48 mais la toutes les déclinaisons ne seront pas disponibles.
Si 32Ko de flash sont "étroits" on pourras passer à 64Ko.
Les librairies MEGACOREX, DXCORE  et MEGATINYCORE appelleront facilement la prise en charge de ces puces.


Point 3
Comme je l'avais indiqué dans mes échanges avec “le Belge” il est possible de basculer de la lib NMRA vers celle d Aiko Pra ( AP Dcc library ) optimisée pour ce hardware ( séries 0/1/2 AVR ou MEGATINY)

Elle n'est pas aussi complète en revanche pour Railcom, Consist mode … mais ça peut être là une opportunité collective de l'enrichir.

Point 4
Les dimensions d un décodeur sont normalisées en interface 21MTC ou Plux22
En gros 15x30 mm maxi ( dim max des versions sonores…)
Donc sans le son on peut aussi cibler cet encombrement.

Pour tenir le challenge un passage en 4 couches sera de mise pour le routage …
Mais la encore rien d'insurmontable .

Point 5
Pont en H… je préconise  un TB67H450 qui conviendra même aux modèles les plus gourmands  à piloter
Sinon des demi ponts à sélectionner et au pire celui déjà sélectionné.

Point 6
Choisir des Mosfet compacts pour la gestion des I/O


Tout cela combiné doit offrir une solution robuste

Alors oui cela aura sûrement aussi un coût plus élevé surtout en faible volume mais on parle aussi d un élément plus abouti techniquement.

Qu'en pensez vous ?

Laurent



Titre: Re : Décodeur de locomotive multifonctions économique
Posté par: lebelge2 le octobre 20, 2023, 03:34:44 pm
Laurent, j’ai déjà fait des essais avec un convertisseur Dc/Dc avec des résultats très mauvais.
- Pendant le CutOut du signal RailCom, le booster met sa sortie en court-circuit donc l’entrée du conv.Dc/Dc est aussi en court-circuit, il réagit très mal !
- Les conv.Dc/Dc exigent un condensateur à leurs entrées, ce qui dégrade (lisse) le signal, la détection ABC est difficile, voir impossible.

J’en suis revenu à une régulation classique (78xx05) mais il faut limiter la consommation du microprocesseur, c’est pourquoi je n’utilise plus l ‘Atmel 32u4 (Pro Micro). Retour au 328p du Pro Mini.

Bien à vous.
Titre: Décodeur de locomotive multifonctions
Posté par: laurentr le octobre 20, 2023, 10:18:32 pm
Bonsoir

Retour intéressant au demeurant sans présager du test.

Apres il y a convertisseur DC/DC et DC/DC!
En la matière plus il "hache" vite et plus il peut être "petit en dimension.
Privilégiez les versions > 1Mhz.

Les plus compacts intègrent pratiquement tout en un seul composant. Ex le MP3510A dont je parlais précédemment

Certains sont équipés de broche ENABLE, pas tous, donc cela peut aussi être un indicateur à considérer.

Quels modèles as tu testé?

Comme indique il faut en effet "juguler" la conso du 5V au stricte nécessaire et dans ce cas alors un LDO peut "encore "convenir" si VIN reste contenu.

A titre d'exemple un AVR0 type 4809 @16Mhz tirera jusqu'au 15mA sous 5V

On peut alors relayer les sorties via des MOSFET pour piloter des leds (+résistances directement depuis le VIN via le MOSFET)  et le pont en H sans excès à ce niveau.

Un équivalent du MIC5233-5V doit tenir la route.
Ce n est pas le choix qui manque:
https://www.mouser.fr/c/semiconductors/power-management-ics/voltage-regulators-voltage-controllers/ldo-voltage-regulators/?input%20voltage%2C%20max=24%20V~~55%20V&mounting%20style=SMD%2FSMT&number%20of%20outputs=1%20Output&output%20voltage=5%20V&package%20%2F%20case=SOT-223-5~~SOT-223-6%7C~SOT-23-5~~SOT-23-6&polarity=Positive&instock=y&rp=semiconductors%2Fpower-management-ics%2Fvoltage-regulators-voltage-controllers%2Fldo-voltage-regulators%7C~Package%20%2F%20Case%7C~Input%20Voltage%2C%20Max (https://www.mouser.fr/c/semiconductors/power-management-ics/voltage-regulators-voltage-controllers/ldo-voltage-regulators/?input%20voltage%2C%20max=24%20V~~55%20V&mounting%20style=SMD%2FSMT&number%20of%20outputs=1%20Output&output%20voltage=5%20V&package%20%2F%20case=SOT-223-5~~SOT-223-6%7C~SOT-23-5~~SOT-23-6&polarity=Positive&instock=y&rp=semiconductors%2Fpower-management-ics%2Fvoltage-regulators-voltage-controllers%2Fldo-voltage-regulators%7C~Package%20%2F%20Case%7C~Input%20Voltage%2C%20Max)


Pour ce qui est du signal DCC et de son exploitation en entrée il faut peut être revoir aussi le montage proposé.
En PJ la solution que j'exploite avec succès. ( Voir cartes LABO présentées sur le forum)

A noter que la résistance de PULLUP peut être supprimée ainsi que l'arrivée +5V à l'entrée du MOSFET si on active le PULLUP sur la PIN du CPU ce qui fait gagner de la place!.

Pour ce qui est de l'ABC la encore voici un montage qui peut servir la cause.

Alors oui ca commence à faire "du monde à caser" mais le "bon" résultat est à ce prix.


Laurent



Titre: Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 27, 2023, 06:48:04 pm
Bonsoir

Intéressante mise en perspective des éléments.
Et merci pour cette contribution constructive.

Quelques observations ( constructives )

Le
Schéma en mode pdf serait un plus notable
Notamment pour diagnostic des ponts de mesure sur le pcb par exemple

Le railcom gagnerait à être fusionne avec la lib d aiko pour être efficient et portable. ( aiko indique ou ajouter les conditions pour y parvenir mais plus sûrement sur les AVR série 0 et AVR Dx et Megatiny qui disposent de la compatibilité avec les ressources  « évent »  et CCL)

Si Trimarco , bobynco  ou Thierry passent par la et qu ils se sentent inspirés … leur apport talentueux  à ce niveau serait topissime ! Mais tout autre talentueux développeur peut aussi contribuer!

Si j ai bien compris le sens des choses, le pilotage du pont en H sera verrouillé selon la polarité détectée en analogique et la tension au moteur sera alors proportionnelle à la tension appliquée sur l entrée du pont en H en sortie du pont de diodes.

On perd alors le bénéfice  du hachage PWM du moteur et du rendement ( supérieur ) qu il peut apporter  ( dont traitement BEMF)
Peut être l ajout d une lecture de tension en sortie  du pont de diodes et son exploitation peut améliorer les choses?.

Dans les deux cas de toute façon on a besoin que le cpu ( peu importe le modèle ) tourne pour exécuter le code .
Ce qui exclu que cela fonctionne sous  6v an analogique en gros puisque c est le seuil de fonctionnement de la régulation de tension du montage
Il faudrait alors lire la plage 6-v25v ( a minima)( via pont diviseur ) et la convertir puis l’exploiter
Pourquoi 25 alors que nous n exploiterions que en gros 6-16v
Et bien parceque  c est le haut de la plage dcc et Qu en conséquences en mode d hybridation Dcc et analogique  on combine sur le plus contraignant.( donc la tension la plus haute succeptible d être percue)
Si maintenant on veut une plage plus étendue par sécurité histoire de mieux protéger l entrée du CPU plusieurs solutions: diode transil ou tvs et ou pont pour couvrir une plage plus généreuse

Inconvénient sur les impacts de la résolution.  la conversion qui n est pas via les ADC totalement linéaire et qui peut aussi garder un seuil trop bas qu il faudrait par tranche de tension coefficienter pour « booster » le niveau de sortie.

Je ne vois pas trop d’autres alternatives…

A vos avis donc!?

Je verrai toujours bien un nano every à la place du nano et de son 328p… on gagne tellement avec c est un peu dommage de s en priver.

Laurent


 
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 27, 2023, 08:34:03 pm
Bonsoir

Intéressante mise en perspective des éléments.
Et merci pour cette contribution constructive. merci @ lebelge2

Quelques observations ( constructives )

Le
Schéma en mode pdf serait un plus notable
Notamment pour diagnostic des ponts de mesure sur le pcb par exemple
pareil : lebelge2 ?


Le railcom gagnerait à être fusionne avec la lib d aiko pour être efficient et portable. ( aiko indique ou ajouter les conditions pour y parvenir mais plus sûrement sur les AVR série 0 et AVR Dx et Megatiny qui disposent de la compatibilité avec les ressources  « évent »  et CCL)
à vue de nez , cela ne me paraît pas compliqué

Si Trimarco , bobynco  ou Thierry passent par la et qu ils se sentent inspirés … leur apport talentueux  à ce niveau serait topissime ! Mais tout autre talentueux développeur peut aussi contribuer!

Si j ai bien compris le sens des choses, le pilotage du pont en H sera verrouillé selon la polarité détectée en analogique et la tension au moteur sera alors proportionnelle à la tension appliquée sur l entrée du pont en H en sortie du pont de diodes. c'est la façon la + simple

On perd alors le bénéfice  du hachage PWM du moteur et du rendement ( supérieur ) qu il peut apporter  ( dont traitement BEMF)
Peut être l ajout d une lecture de tension en sortie  du pont de diodes et son exploitation peut améliorer les choses? ça risque de faire beaucoup de taf pour peu d’intérêt : qui se lancerait dans une réalisation en DiY d'un décodeur RC , ABC , son , I2C , pour finalement le faire tourner en analogique ?

Dans les deux cas de toute façon on a besoin que le cpu ( peu importe le modèle ) tourne pour exécuter le code .certes  8)
Ce qui exclu que cela fonctionne sous  6v an analogique en gros puisque c est le seuil de fonctionnement de la régulation de tension du montage
Il faudrait alors lire la plage 6-v25v ( a minima)( via pont diviseur ) et la convertir puis l’exploiter
Pourquoi 25 alors que nous n exploiterions que en gros 6-16v pareil : en diY , on doit pouvoir s'accomoder de cette limitation
Et bien parceque  c est le haut de la plage dcc et Qu en conséquences en mode d hybridation Dcc et analogique  on combine sur le plus contraignant.( donc la tension la plus haute succeptible d être percue)
Si maintenant on veut une plage plus étendue par sécurité histoire de mieux protéger l entrée du CPU plusieurs solutions: diode transil ou tvs et ou pont pour couvrir une plage plus généreuse

Inconvénient sur les impacts de la résolution.  la conversion qui n est pas via les ADC totalement linéaire et qui peut aussi garder un seuil trop bas qu il faudrait par tranche de tension coefficienter pour « booster » le niveau de sortie.

Je ne vois pas trop d’autres alternatives…

A vos avis donc!?

Je verrai toujours bien un nano every à la place du nano et de son 328p… on gagne tellement avec c est un peu dommage de s en priver.
amha l'idéal serait d'utiliser un mcu genre megatiny en UQFP 20 , avec juste 3 fils pour téléverser , et le rajouter sur la cate , tu peux faire ça , quite à passer en 4 couches et 0402 

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 27, 2023, 11:13:53 pm
Bonsoir à tous

Bonsoir Marc

Je m’y suis déjà collé ;)! Mais je vais reprendre pour plus d efficacité et optimiser avec tous les sous éléments hardware à placer.

L’heureux élu est l AVR32DD20 qui est un excellent candidat.
Il est en balance avec les Megatiny X6 et X7 en resp 20 et 24 broches mais plus laborieux pour la gestion de certains « trucs ».
Attention en 20 broches les brochages entre DD et Megatiny sont Différents donc cpu non substituables!
Juste au dessus on a la gamme des AVR en 28 broches à peine plus encombrant et on gagne quelques ressources ( dont un timer B) et dans le
panier commun on passe à 32 broches pour à peine plus de place occupée sur le PCB.

0402 oui en dessous c est plus chère et faut encore que ça passe ds les dissipations avec les valeurs
Cote condo pour la partie « haute tension » c est 0805 mini et ça peut descendre aussi en 0402 côté basse tension et petite capa sinon 0603 ou à nouveau 0805

Quitte à pousser plus loin j intégrerai volontiers quelques éléments:

Connecteur 21MTC ou PLUX22, des Mos pour séparer le cpu des I/O des consommateurs
A voir donc aussi selon la place la partie RC et ABC
Mais dans tous les cas j exclue le son sur le même PCB car je limite volontairement à 16mm*30mm ( selon la norme c est la place max d un décodeur donc pour nous exploitable sans devoir descendre trop bas dans la miniaturisation des composants.
A voir pour une extension SUSI ( qui est un I2C) pour laquelle la norme en allemand n'est pas traduite !! Mais qui serait un plus « inédit en DIY ». ( en offrant la compatibilité avec les platines de loc qui s appuient dessus ( exemple LSM).
Si on a de la place à voir si on peut glisser un autre connecteur pour partir vers le DF player … A défaut des pads feront le job
Of course 3 plots pour la prog +5v Gnd et UDPI

Simple , y a plus qu'a :)!

En revanche pour gagner en place le recours à un convertisseur Dc Dc comme le MP3510A ( oui ce et en gros 6 euros ) me
Semble être un must have! J ai quelques doutes sur un LDO petit format type Sot23 par exemple et la chaleur en cas de charge du montage, surtout dans le spectre haut des tensions d alim …
Le pont H est bien. Perso j opte pour le TB67H450 dont le brochage est identique et les caractéristiques très similaires à celui utilisé ici avec un seuil  d utilisation des 4,5V.

Bon le temps de m y pencher un peu plus dans quelques jours et on devrait pouvoir sortir un « DIY »plutôt sympa.  8)

Pour ce qui est des conditions que tu soulèves Marc je pense que s aligner sur la norme permet de s affranchir d « emmerdes » à tout va…
Et puis si tu es full dcc only il y  aura Tjr une fois ou tu auras envie que cela tourne en analogique … alors autant faire ça bien pour le coup.
Ça ne coûtera pas la blinde sans trop augmenter la complexité  donc ne pas se priver me paraît être la bonne voie. (Sauf saturation de l’espace dispo pour tout caser!)
Si ce n est pas utilisé (soft et paramétrage ) au moins le hard est là et cela peut être réutilisé sans lourde modif.

Laurent


Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 28, 2023, 12:21:07 pm
oui , mais là tu pars dans une réalisation du type commercial , tu vas perdre tout le monde d'un forum DIY en route, et tu t'approcheras du prix d'un lokpilot en restant loin de ses performances et de sa fiabilité
pour être cohérent avec un soft gratuit , forcément basique même s'il est joliment écrit , il faut un hardware du même niveau
donc amha , regarder ce qu'il y a chez jlcpb (par exemple ATTINY1616-MNR) , et prendre un maximum de composants "basic"
alors au lieu de faire , comme tu as appris : schéma → PCB → BOM , faire BOM → PCB → schéma !
Titre: Re : Décodeur de locomotive multifonctions
Posté par: Dominique le novembre 28, 2023, 12:30:08 pm
tout a fait d'accord : c'est comme cela que LaBox est née!
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 28, 2023, 02:10:35 pm
En effet c est une autre approche.

A voir ou se situe "l'optimum" et les compromis.
Par exemple sur le TINY1616 on aurait le PWM sur le Timer A, le décodage DCC sur le Timer B0 et le B1 pour millis()... le hic si on a besoin d un timer supplémentaire ( comme semble l indiquer Aiko dans les commentaires de la librairie) pour Railcom on est trop court ( ou pour d autres usages)
On doit alors monter vers un AVR en 28 ou 32 broches pour  disposer de ces ressources en plus. Donc selon le cahier des charges retenu on doit cibler le CPU.

En la matière pour du DIY la fabrication est industrielle donc il reste surtout la partie soft à injecter post assemblage à priori avec un ATMEL-ICE ou un "bricolage" pour transformer un nano en programmateur. ( la solution ATMEL ICE reste préférentielle mais elle coute déjà a elle seule le prix d un lockprogrammer ESU!). Cela réduit déjà un peu le champs de pratiquants prêt à suivre ( mais des commandes groupées sont possibles)

Donc il faut déjà se chasser de l'esprit que DIY = cout faible. Sans chasser l'idée de contenir le prix de la réalisation il y a un ticket d entrée à assumer et un cout marginal à trouver. L amortissement ne peut se faire que sur un volume.

Si on dresse la cahier des charges en quelques lignes on a:
encombrement max 16x30 mm
connecteur normalisé PLUX22 ou 21MTC
composants dispo en volume à prix modéré

Egalement à "trancher" à ce stade:
support Railcom?
support ABC?
support I2C/SUSI?
compatibilité analogique?
extension pilotage module son type DFPlayer?
Autres...


Laurent


Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 28, 2023, 02:40:58 pm
On en vient du coup à trancher entre un décodeur (pseudo) DIY basic et une version plus complète en terme de couverture technique et fonctionnelle.

J ai oublie dans le cahier des charge la mesure et le traitement de la BEMF.

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 28, 2023, 05:49:09 pm
En effet c est une autre approche.

A voir ou se situe "l'optimum" et les compromis.
Par exemple sur le TINY1616 on aurait le PWM sur le Timer A, le décodage DCC sur le Timer B0 et le B1 pour millis()... le hic si on a besoin d un timer supplémentaire ( comme semble l indiquer Aiko dans les commentaires de la librairie) pour Railcom on est trop court ( ou pour d autres usages)
On doit alors monter vers un AVR en 28 ou 32 broches pour  disposer de ces ressources en plus. Donc selon le cahier des charges retenu on doit cibler le CPU.
nope : If TCD is used as the millis timer - which is the default on any part that has a type D timer (in order to keep the timers that are more readily repurposed available

En la matière pour du DIY la fabrication est industrielle donc il reste surtout la partie soft à injecter post assemblage à priori avec un ATMEL-ICE ou un "bricolage" pour transformer un nano en programmateur. ( la solution ATMEL ICE reste préférentielle mais elle coute déjà a elle seule le prix d un lockprogrammer ESU!). Cela réduit déjà un peu le champs de pratiquants prêt à suivre ( mais des commandes groupées sont possibles)
et re nan : j'ai fait mon téléverseur /déboggeur avec un convertisseur usb-série (que tout le monde a , auquel j'ai juste ajouté une diode , ce que tout le monde peut faire

Donc il faut déjà se chasser de l'esprit que DIY = cout faible. Sans chasser l'idée de contenir le prix de la réalisation il y a un ticket d entrée à assumer et un cout marginal à trouver. L amortissement ne peut se faire que sur un volume.
tu n'auras pas de volume sans avoir fait la démo du bon fonctionnement de quelque proto : après , tu pourras tout envisager , mais un prix contenu restera un avantage déterminant

Si on dresse la cahier des charges en quelques lignes on a:
encombrement max 16x30 mm
connecteur normalisé PLUX22 ou 21MTC
composants dispo en volume à prix modéré
pour l'instant , ne pas se focaliser sur ces connecteurs : le + de l'ouvrage de lebelge2 , c'est une connectique adhoc qui permet de raccorder un module son et des afficheurs LCD , on peut garder cette exigence
 
Egalement à "trancher" à ce stade:
support Railcom? c'est l'objet du topic
support ABC? pareil
support I2C/SUSI? voir ci-avant
compatibilité analogique? à ta guise
extension pilotage module son type DFPlayer? voir ci-avant
Autres... ...


Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 29, 2023, 11:07:58 am
Bonjour

Ca libère en effet quelques perspectives plus favorables ( couts, dispo, souplesse,...)

On a donc sur le MEGATINY1616 /1617 une distribution telle que ceci:
TIMER A0 PWM
TIMER BO Traitement du signal DCC via lib d AIKO PRAS
TIMER B1 Traitement Railcom à intégrer dans la lib
TIMER D0 Millis()

RX/TX sur ports par défaut
TWI/I2C sur ports par défaut

Reste a voir ou placer la distribution des autres usages (sorties leds principalement), entrées DCC, mesure BEMF, mesure Vin, ABC, extension DFPlayer,....
On serait plus à l aise sur le 1617 mais je vais voir comment proposer une solution sur le 1616 qui est dispo plus facilement.

Reste la question du régulateur de tension... J ai une nette préférence pour un DC-DC qui évitera toute chauffe. Visons compact ( les DLO sont aussi massifs)
Dans ce qui est dispo (LCSC/JLBPCB) pour les plages de tensions qui nous intéressent et pouvant sortir par exemple 500mA on décolle vite au niveau du prix ( ex LT3502) et il faut ajouter les composants autours. ( self, diode, condo, résistances,...)
Le MPM3510A ( oui, encore lui) fait économiser sur la self, gagne en compacité pour le groupe de composants et permet de sortir jusqu'à 1,2A.
Cela peur s avérer pratique pour piloter des accessoires (servo, ampli HP, ecrans, ...) sans avoir (trop) à se soucier du contexte. Inconvénient il faut le passer en pre commande et son prix plus legerement plus élevé couvre toutefois les bénéfices acquis et rend gagnant je pense sur le delta a mettre en œuvre.
Apres il y a peut être quelques candidats alternatifs mais il faut les trouver... Vos suggestions sont bienvenues.

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 29, 2023, 04:26:44 pm
On doit se rapprocher de quelque chose comme cela.

Mais surement a optimiser encore.
Il reste la partie MOS et sorties à traiter

Laurent

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 29, 2023, 05:53:51 pm
- pour le dc/dc et les mosfets , comment font les fabricants de décodeurs ?
- il n'y a pas besoin de Rx ; le Tx sert au railcom , mais il faut peut-être y accéder pour le débogage : si tu as une place qui traîne pour une pastille ...
- pour l'emplacement des entrées et sorties , je dirais qu'il faut les mettre sur des pastilles , de manière à pouvoir migrer facilement vers un connecteur normalisé par la suite
- pour le DFPlayer , (à vérifier) , on peut prendre une des sorties AUX en software serial (je crois qu'il n'y a pas besoin de Rx) : voyons comment lebelge2 a procédé
- pour l'I2C pareil , on fera en software (je vérifie que ça existe) , donc 2 sorties AUX banalisées ; bien entendu , si les lignes I2C et le Tx alternate sont dispos en AUX , on pourra utiliser les périphériques SERIAL et I2C hardware
- enfin , à faire tant , on peut envisager une interface pour un power-pack maison , dont la conception (et la réalisation) pourra être allégée puisque piloté par le MCU du décodeur ...
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 29, 2023, 06:39:10 pm
j ai en effet sélectionne nativement les pines hard pour le TX/RX et SDA/SCL donc pas trop besoin de chercher a se compliquer les choix ( pas besoin du MUX)

on se garde le RX pour les "au cas ou" a defaut on l utilisera comme I/O supplementaire.

j ai encore à ajouter les dual mosfet pour les I/O ce que font bcp de fabricants ( dual mosfet en taille mini  sur comp à 6 broches souvent alignes) avec sur le V+ ( bleu) des décodeurs des tensions élevées et un pilotage depuis le MCU en "basse tension".

Pour les 5V il y a de tout... par exemple DOER and HEASLE a développé son propre circuit multi fonctionnalités

Pour le Power Pack ca sera hors du 16x30 mais on se servira utilement du DC-DC 5V pour charger ensuite donc disposer d'un +5V robuste est positif

Encore un peu a moudre donc :)
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 29, 2023, 11:53:46 pm
très bien
je viens juste de regarder ton schéma :
- pour l'entrée DCC , on se contentera d'une 100K 0402 (comme "tout le monde")
Edit : ben non , il faut pouvoir mesurer la tension des 2 rails pour l'ABC : il faut donc 2 ponts diviseurs sur chaque rail , reliés à 2 entrées ADC , sonc 4x 0402 en tout ; un des 2 ponts sera aussi relié (en interne ?) à l'entrée ICP d'un des 2 TIMERB
- je ne suis pas convaincu du circuit générateur railcom : si une tension DCC intempestive arrive sur le transistor en-bas à droite , alors qu'il est commandé , il fume (sa dernière cigarette) ; je pense qu'il faut un transistor en + pour le protéger , en occurrence celui en bas à gauche , qui sert de diode : on met une vraie diode à la place , et on le récupère pour protéger celui de droite
Edit : en fait , pour que la tension en DCC_L (~15v) puisse être dangereuse , il faut que que celle en DCC_R soit à ~0v (il faut que ça se reboucle) , or dans ce cas , le transistor de droite n'est plus commandé , il est donc protégé : on peut faire confiance à l'auteur de ce shéma
- pareil pour les dual mosfet , il faudra les protéger par des dual-npn
- il existe le MPM3506A , qui ne fait que 600mA , ça suffit , et qui ne coûterait que 2€50 ; il faudrait encore s'assurer de son comportement lors des arrêts de la tension d'entrée , vis-à-vis de craintes de lebelge2 (qui s'y connaît) ; j'ai regardé la doc , elle touffue , donc je n'ai pas pu avoir de certitude de ce point de vue ; toutefois , si ça fonctionne , ce serait en effet un bon plan malgré le prix , car ça nous enlève une épine du pied avec de + une empreinte minimale
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 30, 2023, 07:33:47 am
Hello

Pour donner une idée de ce que cela peut "déjà" donner petite vue d illustration de travail

On perçoit l apport compact du MPM3510A
Les dual NMOS sont des DMN67D8LDW-7.
Les 4 diodes du pont sont à 1.5A : CCS15S40,L3F
CPU ATTINY1616 ou 3216 selon besoins
Les sorties TX RX dispo sur pad
SDA et SCL pour l I2C sont sur les broches du connecteur 21MTC

Pour l entrée DCC j'utilise la INPUT PULLUP qui me semble adaptée à notre usage donc un composant de moins a implanter :)

Quelques retouches possibles bien sure selon les discussions.

Dimensions: 16mmx30mm

Laurent




Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 30, 2023, 07:43:23 am
Les MPM3510A et MPM3506 sont interchangeables sans autre forme de modification.
On peut dont tabler dessus

Pour memo cette famille équipe les NANO EVEVRY, elle est assez robuste, compacte, peu épaisse donc plutôt bien aplatée.
Le seul "défaut" de la version sur NANO EVERY est la tension limitée au max 21V qui n est plus de mise sur la série MPM35XY qui monte a 36V.

J avais d autres candidats mais pas éligibles ici en terme de compacité ou de nombre de composants à placer autours.
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le novembre 30, 2023, 01:32:29 pm
- j'ai édité mon post précédent : voir pour les 4x 0402 en entrées , au besoin regarder comment a procédé lebelge2
 -le pont en H me paraît énorme comparé au reste : ne peut-on pas tabler sur un modèle + compact (genre DRVmachin) , qui pourraient aussi servir pour commander 2 sorties AUX , on serait paré au niveau des protections

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 30, 2023, 03:24:03 pm
Hello

J ai vu et je vais voir comment porter le truc sur le projet.
Je préférais ma solution avec le NMOS car dans ce cas on est moins dépendant des tensions de la voie au delà de celle de bascule du NMOS. Pour ce qui est de la gestion de l'ABC on a alors en effet besoin de deux IO supplémentaires qui sont sous numéraires sur notre CPU 1616...

le BOD level va aussi devoir être abaissé sur la plage BODLEVEL0  pour 1,8V [1,7V; 2V] pour que toutes les tensions au dessus de 2,1V en gros soient considérées comme des 1 et 0 en dessous.
Dans le montage avec le NMOS on peut rester sur un BODLEVEL7 avec 4,3V. ([4,1V; 4,5V]

J ai aussi donc une adaptation à faire pour l'ABC. ( qui permettra aussi de détecter le sens de circulation en analogique je pense)

Pour le pont en H c est un peu une fausse impression bien que cela soit le plus imposant composant du montage. IL est encore acceptable en terme d épaisseur surtout.
L ayant déjà utilisé je le trouve "parfait pour le job" et donc tenir 1.5 A ne lui posera pas de problème si on doit monter jusque la.(même en pic)
Je n'utilise pas la fonction de mesure/limitation de courant dessus

Pour le diviseur que tu proposes avec les 4 x 100K je me pose la question de savoir s il ne faut pas qu'il soit asymétrique pour couvrir sur les PIN_IN DCC_R et PIN DCC_L une plage de tension au delà de 10/12V (V/2 <= 5,5V )(et donc du double idéalement) et garantir le niveau de tension mini d entrée pour valider la bascule d'état, et protéger le CPU. On peut aussi ajouter une diode entre l'entrée CPU et le +5V.

Reprenons un peu les mappings d'usages des 20 I/O pour éviter tout oubli. On ciblera ensuite plus finement les attributions précises ( s il faut en revoir certaines)

1 I/O pour le traitement du signal DCC ( sur évent +  interupt de la lib AIKO PRAS) ( sur le TIMER B0)
1 I/O pour détecter le cutout RC ( l'autre pole DCC?) ( sur le TIMER B1)
2 I/O pour la détection ABC ( voir la mesure du level en entrée pour l analogique)
2 I/0 PWM pour piloter le pont en H ( pilotées par le TIMER A mod split en 8bits)
1 I/O pour l UDPI
1 I/O pour le +5V
1 I/O pour le GND
2 I/O pour le "serial" TX/RX
2 I/O pour l I2C SDA SCL
7 I/O pour le pilotage des sorties amplifiées ( dommage une de plus nous aurait offert 8 sorties amplifiées mais il reste au pire RX...)

Millis()/micros() tournera sur le TIMER D. (sur cette série)

Le passage sur le 1617/3217 force les choses vers le haut à défaut ca sera 6  sorties pilotables ( Rouges et blancs indépendants de chaque cote et 2 éclairage de cabines par exemple).

Et la il y en a un qui va lever la main et dire et pour les servos et le DF Player on fait comment?
Plusieurs  options: extension I2C ou passage sur un CPU plus fourni en I/O.

Why not?

Laurent



 
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le novembre 30, 2023, 04:54:55 pm
Marc, Le Belge

Jettez un œil ici vous trouverez je pense des "inspirations"

cote code:
https://github.com/ytsurui/dcc-decoder2-firmware (https://github.com/ytsurui/dcc-decoder2-firmware)

cote hard:
https://github.com/ytsurui/dcc-decoder2-pcbdata (https://github.com/ytsurui/dcc-decoder2-pcbdata)

Je pense que la gestion ABC optimisée. Cote traitement du  DCC on ne s appuit pas la sur la lid AIKO mais rests interessante. On en benfcicie pas de ses apports.
Donc le chemin est "au milieu de tout cela"...

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 01, 2023, 07:24:49 pm
Bonsoir

J ai un peu avancé sur un possible design. (toujours en 16x30 avec connecteur 21MTC)
J ai modifié les diodes du pont. On passe des CCS15S40 (1.5A) à des RB060MM-30TR ou RB060MM-40TRou RB060MM-40TR (2A) au prix d'un encombrement légèrement plus volumineux et d une dispo plus étendue
La circuiterie pour l'ABC est intégrée ( le nombre de composants augmente un peu et les entrées DCC sont à présent derrière des ponts diviseurs pourvus d une diode vers le +5V. Idem sur la mesure BEMF.

J ai aussi profite de cette "révision" pour passer sur un MEGATINY X7 (1617 ou 3217 par exemple) à 24 broches afin de conserver 8 I/O pour le pilotage des sorties.
2 I/O sont "encore" dispo et pourrait constituer au besoin une 5 eme paire de sorties amplifiées pourquoi pas dédiées( ou pas)  à des servos? pu d autres usages (capteur à effet Hall?)
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 01, 2023, 11:25:48 pm
Hello

J ai vu et je vais voir comment porter le truc sur le projet.
Je préférais ma solution avec le NMOS car dans ce cas on est moins dépendant des tensions de la voie au delà de celle de bascule du NMOS. Pour ce qui est de la gestion de l'ABC on a alors en effet besoin de deux IO supplémentaires qui sont sous numéraires sur notre CPU 1616...
alors il faudra les protéger par des npn

le BOD level va aussi devoir être abaissé sur la plage BODLEVEL0  pour 1,8V [1,7V; 2V] pour que toutes les tensions au dessus de 2,1V en gros soient considérées comme des 1 et 0 en dessous.
Dans le montage avec le NMOS on peut rester sur un BODLEVEL7 avec 4,3V. ([4,1V; 4,5V]
le BOD level (Brown Out , pas Block Occupency) ne joue que sur le reset

J ai aussi donc une adaptation à faire pour l'ABC. ( qui permettra aussi de détecter le sens de circulation en analogique je pense)

Pour le pont en H c est un peu une fausse impression bien que cela soit le plus imposant composant du montage. IL est encore acceptable en terme d épaisseur surtout.
L ayant déjà utilisé je le trouve "parfait pour le job" et donc tenir 1.5 A ne lui posera pas de problème si on doit monter jusque la.(même en pic)
Je n'utilise pas la fonction de mesure/limitation de courant dessus
je regarde si je trouve quelque chose

Pour le diviseur que tu proposes avec les 4 x 100K je me pose la question de savoir s il ne faut pas qu'il soit asymétrique pour couvrir sur les PIN_IN DCC_R et PIN DCC_L une plage de tension au delà de 10/12V (V/2 <= 5,5V )(et donc du double idéalement) et garantir le niveau de tension mini d entrée pour valider la bascule d'état, et protéger le CPU. On peut aussi ajouter une diode entre l'entrée CPU et le +5V.
(j'ai pas écrit 4x100K) ces entrées serviront aussi à la capture : après la capture et les opération qui s'en suivent , on bascule la broche en analogique et on mesure l'ABC ; sur l'autre entrée  il faudra une interruption en milieu de bit DCC pour mesurer l'autre alternance

Reprenons un peu les mappings d'usages des 20 I/O pour éviter tout oubli. On ciblera ensuite plus finement les attributions précises ( s il faut en revoir certaines)

1 I/O pour le traitement du signal DCC ( sur évent +  interupt de la lib AIKO PRAS) ( sur le TIMER B0) pas besoin
1 I/O pour détecter le cutout RC ( l'autre pole DCC?) ( sur le TIMER B1)pas besoin
2 I/O pour la détection ABC ( voir la mesure du level en entrée pour l analogique)
2 I/0 PWM pour piloter le pont en H ( pilotées par le TIMER A mod split en 8bits)
1 I/O pour l UDPI
1 I/O pour le +5V
1 I/O pour le GND
2 I/O pour le "serial" TX/RXrx pas besoin
2 I/O pour l I2C SDA SCL
7 I/O pour le pilotage des sorties amplifiées ( dommage une de plus nous aurait offert 8 sorties amplifiées mais il reste au pire RX...)
1 I/O  le Tx pour le railcom

Millis()/micros() tournera sur le TIMER D. (sur cette série)

Le passage sur le 1617/3217 force les choses vers le haut à défaut ca sera 6  sorties pilotables ( Rouges et blancs indépendants de chaque cote et 2 éclairage de cabines par exemple).

Et la il y en a un qui va lever la main et dire et pour les servos et le DF Player on fait comment?
tx software serial
Plusieurs  options: extension I2C ou passage sur un CPU plus fourni en I/O.

Why not?

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 01, 2023, 11:45:30 pm
il faudrait qu'on ouvre un nouveau topic : la présentation de lebelge2 est terminée et fonctionne , on est hors sujet depuis un moment
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 02, 2023, 11:20:00 am
Hello


@Trimarco232
Sur le version d origine avec le NMOS pour la "transcription du signal DCC vers le CPU " c est une zener qui vient protéger le gate du NMOS.
Cela te semble insuffisant?

Les NMOS choisis ont une plage -30V/+30V donc si le gate est bien en 5V/0V et le VIN dans  la plage DCC <30V je ne vois pas le besoin de protéger (plus) le NMOS en sus.

Néanmoins je pense que tu as en tete ce type de montage en protection?
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 03, 2023, 11:47:37 am
Bonjour

Oui belle erreur sur le BOD... je devais avoir la tête ailleurs!

Bon cela dit... j ai un peu repris mon travail et poursuivi l axe de travail...

Je suis passe sur un CPU 32 broches ( cela laisse le plus grand choix entre ATMEGA 1608/3208/4808, AVR16/32/64DA32-DB32-DD32-EA32 et AVR128DA32-DB32.)
Question "dispo" et prix on couvre au plus large. )
J ai remis mon entrée via NMOS, mis la "circuiterie" pour l' ABC et le RAILCOM.
8 sorties amplifiées dispo sur F0f F0r AUX1 AUX2 AUX3 AUX4 AUX5 AUX6.
Mesure possible du BEMF.
I2C/TWI dispo sur les broches ad hoc selon la norme.( pour SUSI)
Pads TX/RX
Pad programmation (UDPI/+5V/GND)
Connecteur 21MTC classique avec possibilité de montage en direct ou en mode retourné (faibles épaisseurs)

Quelques vues. Tout y est :) c est serré mais ca rentre! PCB 4 couches 8/10mm.
J ai entouré en couleur les blocs fonctionnels principaux ce qui permet de voir leur localisation.
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 03, 2023, 12:29:33 pm
J ai profite aussi de cette révision pour rationaliser un peu plus les distributions/placements. Ce travail me permettra ensuite de passer vers une version PLUX22 avec à priori moins de difficultés.

De ce fait j ai aussi ajouté la possibilité de fournir du +5V externe ( via POWERPACK) sur la broche +5V du connecteur 21MTC.
Une diode ajoutée empêche d'injecter vers le DC-DC BUCK alors que tous les consommateurs dispose de la distribution du "+5V universel"
L idée est aussi d utiliser possiblement la broche 11 à défaut d un PAD pour y souder un fil afin d'envoyer le +5V du DC-DC directement vers le IN du "POWERPACK". On dispose ainsi d'une entrée dédiée pour celui ci sans "casser" le brochage normalisé du 21MTC.  LE POWERPACK peut alors renvoyer sur le +V si il délivre cette tension.
PAD ou broche 11....? a voir sinon au plus simple rien de plus et le POWERPACK sera charge via le +5V du connecteur et enverra la tension BOOSTEE sur le VIN ( et sa broche)
Une régulation permettra de charger notre/nos super capa et un DC-DC BOOST se chargera de rehausser celle ci.
Notre CPU sera alors "bien pourvu" en "énergie" et pourra travailler de même que le H BRIDGE.
Le boost aura la possibilité d envoyer soit la totalité de sa tension de substitution sur le VIN (pour la traction et l alim générale du circuit donc repassage par le DC-DC BUCK ) et/ou il pourra aussi adresser une tension de 5V spécifique sur la broche +5V. ( cas de sorties multiples sur le BOOST ou de plusieurs DC-DC-BOOST pour des tensions différentes)

Qui a dit LUXUEUX?  8)

Laurent ( Sous la neige du NOOOOORD)  ;D

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 04, 2023, 04:00:37 am
Bonjour

Apres quelques recherches voici ce que j ai pu trouver pour SUSI:

https://dccwiki.com/SUSI (https://dccwiki.com/SUSI)

La norme SUSI (à jour 11/2023)
https://normen.railcommunity.de/RCN-600.pdf (https://normen.railcommunity.de/RCN-600.pdf)

LIBRARIE  NATIVE ( a interfacer avec la LIB NMRADCC) (ou à adapter sur une autre LIB):
https://www.arduino.cc/reference/en/libraries/rcn600/ (https://www.arduino.cc/reference/en/libraries/rcn600/)

On y trouve aussi les explications utiles sur le versions avec des nivaux de tensions différents ( 3V3 et 5V)

Le constat c est que ce n est pas du I2C/TWI pure mais un "hersât/clone"

Mais par chance son auteru a aussi produit une autre librairie qui s interface avec "WIRE" ( la lib qui gere l I2C/TWI)

https://www.arduinolibraries.info/libraries/wire-susi (https://www.arduinolibraries.info/libraries/wire-susi)


La libraire est bien commentée (en italien) on va donc pouvoir envisager son "intégration".

Je n ai pas su identifier en revanche si au niveau HARDWARE il faut conserver le hard avec les résistances de 470r sur les lignes ou si on est en "WIRE pure" et donc si
 on s en passe? Mystère entier jusque la. Mon interprétation serait de rester en pure "WIRE" sans les résistances de 470r. Le hic  c est alors de devoir choisir le mode d'implémentation. ( car on casse la compatibilité avec le HARD standard qui équipe le matériel courant. En cas d interface "propriétaire" la question ne se pose pas trop.
Le hard du décodeur est à présent adapté aux deux cas de figure. Il suffira de remplacer par des résistance 0r celle de 470r en cas de "WIRE" pure". Les résistances de PULLUP  sur SDA et SCL restent et seule leur valeur peut avoir à évoluer.

La ou je vois quelques limites c est sur la taille de l'EEPROM qui est "réduite à 256 Bytes" sur les récents AVR DD /MEGATINY  ce qui va être "étroit" pour caser tout le monde. Seuls les AVR DA, DB et EA ont 512 Bytes (plus confortable) . Le 328P en avait en revanche 1024...


Laurent







Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 04, 2023, 10:59:21 am
Hello

Le petit frère du 21MTC est tracé.

Le PLUX22 prend 1mm de plus en longueur et passe à 31mm (on pourrait gagner quelques dixièmes) Pour les distinguer visuellement plus aisément hormis via le connecteur le PCB est passé en couleur rouge.

J y ai ajouté 2 PADS: +5V et GND qui permettront une liaison vers le POWERPACK. Pourrait s y glisser aussi un pad VIN (fil bleu classique  mais déjà sur les broches 6 et 9 contrairement au +5V absent sur les connecteurs PLUX.

Question densité on est au max je pense car il reste peu d espace libres pour placer des via puis naviguer entre les couches mais il resterait possible au prix d un petit effort supplémentaire de re placer un dual NMOS et gagner 2 sorties amplifiées supplémentaires ( plot 22 pour  AUX7 et dur le plot 1) ou laisser le plot 1 en liaison directe avec le CPU ( éventuelle entrée directe non amplifiée) à voir.

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 04, 2023, 01:32:13 pm
Hello

Pour comprendre le "INSIDE" une vue de la conception.

Ltr
Titre: Décodeur de locomotive multifonctions
Posté par: msport le décembre 04, 2023, 03:35:44 pm
Bonjour,
https://forum.locoduino.org/index.php?topic=1579.msg17410#msg17410
comme le fait remarquer Marc : la présentation de lebelge2 est terminée et fonctionne , on est hors sujet depuis un moment.
On ouvre un nouveau topic :
https://forum.locoduino.org/index.php?topic=1628.0
Laurent s'est placé dans l'optique d'une fabrication industrielle.

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 04, 2023, 06:35:23 pm
Bonjour

Merci Michel pour te transfer sur ce topic dédié .

Je vais donc reposer les bases de ce projet ici ( que nous essayerons de placer en tête du topic) pour poser le cadre.

L’idée est bien de réaliser un décodeur DCC pour locomotive en mode semi DIY.

Quezako?
Et bien la fabrication est confiée à un industriel qui fabrique et assemble et il nous reste ensuite à y injecteur le code pour piloter ce hardware puis l’installer sur nos engins et procéder aux derniers réglages personnalisés.

L’optique reste de trouver un équilibre  prix fonctionnalité performance bien qu’il soit très probable que cela soit par une production en volume qu’un optimum soit plus avantageux.
Le cahier des charges est le suivant:

Gestion du mode DCC : pilotage, gestion des CV.
Gestion des unités multiples.
Fonctionnement en mode analogique
Fonctionnalité Railcom
Fonctionnalité ABC
8 sorties amplifiées
Fonctionnalité SUSI

Traitement du BEMF

Compacité (16mmx30mmx 3,6mm )du montage pour une intégration selon connecteur normalisé.( 21MTC et PLUX22)
( un portage et une déclinaison n est pas exclue non plus )

Extension complémentaire vers POWERPACK facilitée.

Idéalement sélection de composants dispo en volume à prix descents!


Pour ce qui est du PCB les choses sont déjà très avancées et quelques vues ont été produites.
Pour ce qui est du code il y an encore des choix et de nombreux tests à mener.

Plusieurs optiques sont possibles pour socle et il est également possible que le hardware puisse recevoir plusieurs sources de code différentes.

Certains se poseront alors la question du pourquoi de lancer dans un tel projet quand les décodeurs de grandes marques ou low cost sont dispo.
La réponse est multiple:
Tout d abord le goût de faire soit même et en groupe
Concevoir et concrétiser collectivement est un net plus. Locoduino est un formidable vecteur pour cela et ce terme n’a pas encore été traité aussi loin.
L’ aspect prix est aussi un facteur motivant à challenger.
Ensuite parcequ’il paraît plausible que sur un volume donné il soit plus avantageux de réaliser soit même ces décodeurs que de les acheter, possibilité de les décliner aussi selon un cahier des charges moins ambitieux. ( qui peut le plus peut le moins  :))
Une interface de gestion pourrait même être envisagée mais la gestion des CV se fera le plus normalement possible.


Quelques choix techniques sont opérés ( retours d expériences oblige!)
Le choix de confier à un régulateur de tension de type DC-DC va nous permettre de nous affranchir des problématique de chauffe excessive de l’étage d alimentation et offrir même le luxe de préparer le terrain à d autres utilisations ( ex POWERPACK)

Le point en H fait appel à un composant tout en un. Le choix fait jusque là est dicté par une volonté de supporter 1.5A pour le moins. ( 1.2A serait au seuil bas acceptable mais la granulométries des composants n’est pas aussi fine)
D autres solutions limitent cette intensité à 0,9A en pointe ce qui pour du N est suffisant s avèrerait pour le HO un peu juste surtout pour des engins à la performance moteur moindre.

Aussi pour optimiser celle ci le décodeur permettra de traiter le PWM de pilotage du moteur à une fréquence élevée évitant ainsi les sifflements désagréables.
Une valeur proche de 40kHz présente valeur communément présente sur les produits du marché.
Le question de savoir si en analogique le décodeur pilote aussi moteur selon cette fréquence reste posée. Pour moi c est un gage de qualité et d efficacité mais un mode purement linéaire est aussi possible.

Précisons que le décodeur aura besoin de 6V environ en entrée pour pouvoir fonctionner.
La gestion des CV pourra équilibrer les seuils des vitesses pour l’engin piloté.
La mesure et le traitement du BEMF ( FCEM ) compensation de charge sera aussi de la partie.

Le choix d intégrer des protocoles/fonctionnalités avancées fait partie du challenge
ABC
BEMF
RAILCOM


Et … le son…!?
Pas au programme pour le moment mais qui sait si des déclinaisons ne verront pas le jour par la suite.

Nous allons déjà nous pencher  sur cette première approche déjà ambitieuse et plutôt complète à laquelle vous êtes invités à participer et suivre les avancements.

Laurent




Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 08, 2023, 01:11:17 am
Bonsoir

J ai apporté de légères corrections dans les attributions de broches sur le CPU afin d être sur le même port pour le traitement des signaux DCC en provenance de chacun des rails.

C est ainsi "arbitrairement"  ::) le PORTC qui reçoit sur PIN_PC0 et PIN_PC1 respectivement les entrées DCC_IN_R et DCC_IN_L.
Glissement aussi des attributions pour OUT5 OUT4 et OUT1 avec un routage aménagé.

Ces updates sont poussés sur les versions 21MTC et PLUX22.

La version PLUX22 reçoit elle un NMOS supplémentaire pour la gestion de AUX7 tandis que la PIN1 du connecteur PLUX  est éligible comme GPIO_A dans le respect de la norme. ( sait on jamais...)

Laurent



Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 09, 2023, 02:31:27 am
Bonsoir

Support RAILCOM sur la lib d AIKO PRAS.

Aiko indique dans les commentaires de sa librairie une voie qui permettrait de traiter le signal RC avec ajout d un Timer supplémentaire et la combinaison d éléments sur le CCL.

Dans le code et dans le cas des usages avec MEGACOREX, DX_CORE & MEGATINICORE s'appuyant sur EVENT.H et dans la mesure des temps écoulés ( sur CCMP)  afin de déterminer s il s agit d un bit 1 ou 0 il est précisé une possibilité d ajouter un filtre pour détecter le debut du timout RAILCOM entre 26us et 32us selon la norme ( 29us +3us ou -3us) (RCN 217 dont le dernier update est du 23/11/2023)

A ce moment si on procède à une lecture des entrées de chaque pole DCC sur le CPU et si on obtient un digitalread(PIN_X) == 0 et digitalread(PIN_Y)== 0 alors on est en présence d un début du d un railcom cutout sinon ce n'est pas le cas. ( on est dans un bit 0 ou 1 en cours de géneration)

on aurait donc quelque chose de la forme:

if( (delta =>26us) && (delta <=32us)) //et EVCTRL == RISING ? ( EVCTRL == 0)
{
  if((digitalRead(PIN_PC0)==0) && digitalRead(PIN_PC1) ==0)
  {
   flag_raicom_cutout= true;
  }
  else
 {
  flag_railcom_cutout = false;
 }

}


Traduit littéralement on a un FLAG RAILCOM actif lorsque les conditions sont remplies tel que:
on mesure sur les deux poles des broches PIN_PC0 et PIN_PC1 sont à "0" dans la plage de temps comprise entre 26us et 32 us après une interruption portée par un front montant. ( EVTCTRL == 0 pour start du counter)


A partir de la on a le flag railcom de dispo et on doit pouvoir l exploiter

if (flag_railcom_cutout == false)
{
on traite les bits selon les timings pour des bit 0 et 1
}

if(flag_railcom_cutout) //on est ds le cutout donc on va procéder aux envois d info sur les CH1 et CH2 selon le temps écoulé)
{
if((delta =>75us) && (delta <177us)
{
on active TX
on peut émettre sur le CH1 via le TX
}
else if(delta =>177) && (delta <193))
{
 on coupe l émission sur TX
}
else if((delta=>193) && (delta<454)
{
on active TX
on peut emmètre sur le CH2
}
else if ((delta >454) && (delta <=488)
{
on coupe TX
flag_railcom_cutout = false; // fin cut out
}

si on a le flag_cutout_railcom == true alors on n'assemble pas de bit dans l étape suivante et on attend donc de nouveau que le flag repasse a false pour y procéder.

Cela me semble pouvoir fonctionner ainsi.

On peut être encore plus "efficace" avec l utilisation du CCL sur la lecture des PIN_PCx et exploiter ce résultat lorsque le flag est à false - d ou l intérêt d avoir placé les DCC_IN_R et DCC_IN_R sur les broches du LUT1 sur IN0 et IN1   :D

Cependant l ISR est activé a chaque changement de polarisation (TCB_EDGE) hors le changement d état sur la proche DCC_IN ( ici PIN_PC0)  ne risque t il pas d induire un biais lors du cutout?( le moment ou PIN_PC0 passe à "0" génère une interruption puisque c est un "FALLING" et introduit un reset du CNT par la fonction dcc_interupt()) et donc le temps de référence se trouve alors décalé ( et faux!) . D ou peut etre le besoin de cette seconde detection exclusive sur du front "RISING" comme point de départ ou d une conservation de la valeur CCMP dans une variable du timing qui s incrémente sur les  fronts montant "RISING" . Cette valeur devient pour le cutout le point "0" ( de depart) de mesure du temps delta.

Cette seconde mesure doit alors etre portee sur une configuration de type Input Capture Pulse-Width Measurement mode

On essaye alors via la meme broche DCC_IN ne prenant cette fois que les fronts "RISING" une mesure de "delta2"  et on a le flag cutout actif ou non

Je cherche donc the solution!

@Trimarco232 qu en penses tu?
Vois tu une autre approche? ( celle d AIKO?) ( il y  a aussi celle à laquelle tu faisais allusion via les interruptions)

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 11, 2023, 11:55:23 pm
Bonsoir

J ai un peu avancé malgré plusieurs tentatives infructueuses ( c est aussi bcp comme cela que l'on apprend)
Ce qui est en dessous pourra peut être paraitre abscond mais permet de mieux comprendre le cheminement. Les "sachants" zapperont, les autres pourront s'inspirer de la démarche et s approprier les mécanismes sous jacents associés. Pédagogie! Pédagogie!!

Je me suis "égaré" sur une voie que je pensais "bonne" au départ. L'idée était d'exploiter quelques unes des informations laissées par Aiok. Je m'y suis "mal pris" en ayant oublié que ce qui se passe dans une ISR est "isolé" de ce qui se passe dans la LOOP principale et non traité en parallèle. (au moins sur AVR)

L'écriture des conditions pour un déclanchement du FLAG_RAILCOM_CUTOUT se fait par mesure de l'état sur la( les) pin d'entrées du signal DCC sur le CPU lors de l'intervalle compris entre 26us et 32us ( digitalRead(PIN_PC0 et PC1) à défaut d exploiter la génération d un CCL avec un "&" sur ces deux I/O. ( ce qui serait en principe plus rapide en le liant à un EVENT).
Le temps requis pouvant être un peu long et nous faire sortir de la (très courte) période de 6us  on préfèrera un digitalReadFast pour gagner en efficacité. Et celui ci pourrait aussi être un peu long d où le bénéfice d utiliser le résultat de l'event qui analyse la combinaison des PIN en entrée...
On regardera comment exploiter cela un peu plus tard.

En fait ce "fait générateur" doit donner le START d'un simple compteur timerB en mode PERIODIC_CNT_MODE sur un timer libre dont la valeur d'une variable incrémentée à intervalle de temps fixe et régulier sera comparée aux seuils des timings des actions d'émission RAILCOM. On pourra alors enclencher les émissions sur TX des info "qui vont bien"!

Des que le fllag railcom est actif on sort de l'interruption d'assemblage des bits 0 ou 1 des messages. Celui ci sera libéré une fois le cycle railcom achevé.

J'avais pensé resté dans une ISR pour émettre des actualisations avec des FLAGS successifs que la boucle principale aurait alors traité. OUI MAIS si on est dans une ISR alors on est pas dans la LOOP et on ne passe de l un à l autre que lorsque l ISR est achevée ( sauf à se hasarder sur l'utilisation du complément NO_BLOCK comme paramètre du vecteur d'interruption.)
Ca aurait pu être une bonne piste!

Il faut donc reconstruire différemment.

La valeur CCMP du "timer DCC" est la représentation du "temps écoulé" entre deux interruptions du front montant au front descendant. ( et inversement)
La permutation de lecture se fait par inversion du bit "EDGE" sur timer_EVCTRL à chaque changement d'état sur la broche dccPin.
Si on compte dans le sens "montant" alors timer_EVCTRL aura la valeur == 0.

Le front montant représente le temps T0 servant de référentiel à nos mesures. La valeur CCMP pourra alors alors être ajoutée à la variable incrémentée par le TIMERBx ( ou soustraite des valeurs de temps à mesurer) afin de compenser l alignement temporel des éléments entre timers/compteurs. Il serait même juste d'ajouter alors le "delta" que represente l'incrementation du CNT du premier timer couvrant les mesures sur les PINS PC0 et PC1.
J ignore si l event serait aussi à compenser mais on serait la surement plus proche d"EPSILON*" que de delta pour les matheux qui suivent!  8) (*EPSILON quantité infime souvent négligeable)

Je pense aussi que de regrouper RIALCOM en une CLASSE dédiée sera un plus... ( je vais m appuyer sur les travaux de lebelge2 qui a mis en œuvre les fonctions d'encodage dans son projet  et y exploiter des infos)
On pourra alors y traiter des fonctions gérant l encodage des valeurs, leur émission, mesure des temps de référence...

Bon passons à la pratique à présent!

Laurent


Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 16, 2023, 11:43:39 am
Bonjour ,
je suis assez booké ces temps-ci , alors , pêle-mêle :
Citer
si on obtient un digitalread(PIN_X) == 0 et digitalread(PIN_Y)== 0
si les 2 entrés sont sur le même port , on peut faire : if (IN_portX & 0b00100100) , en plaçant les 1 sur les entrées ; on doit même avoir une option où IN_portX peut être lu en 1 cycle (pareil si on est pressé en écriture , utiliser SET_portX , ou CLEAR , ou TOGGLE)
utiliser EVCTRL est une autre option : (filter)CCL(NAND) -> EVCTRL(filter) -> CAPT ; ça aurait été mieux qu'Atmel mette un filtre programmable au niveau du CAPT , pour éliminer les parasites , mais aussi les dead-time du pont en H de la station , environ 1us où les 2 entrées peuvent êtres lues simultanément à LOW , en confusion avec le début d'un cutout
je me refuse d'indiquer une préférence entre le polling des entrées (on a tout le temps pour le faire) , et l'utilisation de CCL et des armes des nouveaux AVR : l'idéal serait de disposer d'un proto qui permet d'évaluer les 2 ...
concernant les ISR , tu découvres , c'est bien ; j'en profite pour faire noter une chose , qui a peut-être une certaine importance : avec les nouveaux AVR , on peut fixer une certaine priorité pour les ISR ; ce n'est certes pas une priorité de préemption comme pour les ARM , mais une priorité de queue ; cela signifie que si ton interruption prioritaire est déclenchée alors qu'une autre ISR est en cours , ton interruption ne pourra pas interrompre l'autre ISR (d'où  l'intérêt que les ISR soient le plus court possible) , mais elle sera prioritaire par rapport aux éventuelles autres interruptions en attente , c'est déjà ça
j'en suis réduit à la même réponse de Normand concernant l'utilisation du soft d'Aiko vs celui de lebelge2 (affaire interne au Benelux) ; par contre , je suis persuadé qu'il vaut mieux utiliser le hard de lebelge2 , beaucoup plus simple que celui , nippon (ni mauvais) de ton schéma ; donc en un 1er temps , concernant le cutout , pour simplifier et avancer , tu pourrais faire du lebelge2 intégral (un peu de rétroingénierie  sans doute) , puis quand ça marche , migrer progressivement vers la solution d'Aiko , afin d'utiliser les pouvoirs des nouveaux AVR ; en tous les cas je pense que la solution japonaise est à écarter , car trop compliquée et mal documentée
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 17, 2023, 05:20:42 pm
Bonjour Marc

Merci pour tes indications.

Pour ce qui est des priorisations intra ISR j ai en effet vu de quoi il retourne. Je n'étais pas très familier de leur usage directement. On peut en effet définir un niveau supérieur d ISR pour l un de entre eux et/ou préciser le "point de départ dans leur ordre d enchainement (Round Robin). Il reste aussi l option "NO_BLOCK" mais aux risques et périls associés de son usage.

Je me suis récemment offert une" bible": le livre de TOM ALMY qui est une source puissante de connaissances que je ne peux que recommander (mais c est en anglais!).

J ai un peu avancé et j'ai procédé de la façon suivante sur ce qu'il me reste à tester ( et les journées ne font que 24h afgh!!)

J ai gardé la Librairie d AIKO PRAS (AP_DCC_LIBRARY) que j ai enrichi d une CLASS_RAILCOM et d un fichier CONSTANTES.h qui contient des valeurs qui vont ensuite être utilisées en interne ( notamment des temps utilisés par RAILCOM)

j ai recomposé les timings de détection de la valeur CCMP pour isoler celui du CUTOUT et place un FLAG à l'exécution ou non de la gestion des  bits 0 et 1 si l on est dans un CUTOUT ou non.


Je choisi volontairement d'attribuer le décodage des trames du signal DCC sur le TIMERB1 (DCC_USES_TIMERB1)
J affecte le TIMERB0 à un fonction de comptage "basic" (TCB_CNTMODE_INT_gc).

Je place les valeurs adéquates pour que lors de l'ISR ce compteur lorsque il est démarré incrémente chaque 1us une variable de 16bits (uint16_t microseconds_ticks) qui va représenter le temps écoulé depuis le point temporel "T0" qui est utilisé ensuite pour les différentes mesures temporelles.
TCB0 au niveau interruption est en haut de liste des priorités d'exécution et peu d autres éléments peuvent luis "passer devant" assurant en principe une mesure efficace voir très précise du temps incrémenté.

Pourquoi alors ne pas utiliser micros()? Pas de micro dans un ISR!

Comme AIKO utilise la vitesse du CPU sans "prescaler" on procèdera de même sur le TIMERB0.

On peut donc écrire pour être sur la même échelle la valeur CCMP du TIMERB0.

On procède pour cela en écrivant TCB0.CCMP =(F_CPU/1000000);
Ainsi à 16Mhz toutes les 16 itérations il s est écoulé 1us (16 000 000 / 1000000 = 16) (16 * 1 /16000000 = 0.000001 seconds = 1us)
Pour 20Mhz on a une mise à l échelle automatique pour cette fois 20 itérations. (20 000 000 /1000000 = 20) (20 * 1/20000000 = 0.000001 seconds = 1us )
Même musique à 24Mhz.

IST(TCB0_int_vect)
{
   microseconds_tick++; //incrementation
   bitSet(TCB0.INTFLAGS,0); // reset de l ISR
}



Ce compteur est démarré sous condition lors de la détection du CUTOUT entre 26us et 32us dans les éléments du code d'AIKO.

J ajoute en effet la condition de lecture de la tension sur les entrées des signaux DCC pour confirmer le fait d être dans le CUTOUT. Dans le cas du CUTOUT il n y a aucune tension dans la voie ("0V"c e qui place les entrées CPU recevant les signaux DCC à "1".
Un digitalRead() étant trop long à s exécuter d autres solutions sont utilisées (voir plus bas)

On place alors un FLAG de type bool en état actif (FLAG_RAICOM_IN_CUTOUT = true;)
Juste avant de démarrer le compteur sur le TIMERB01 il faut donc passer le temps écoulé à la variable microseconds_ticks afin que cela soit le point de départ actualisé du comptage.
Pour cela j'ajoute le nombre microseconds_ticks+=(uint16_t) (TCB1.CCMP + TCB1.CNT)/(F_CPU/1000000);
Puis on peut démarrer le TIMERB0 via bitSet(TCB0.CTRLA,0); (mise à 1 du bit 0 du registre CTRLA du TIMERB0)

Dans une fonction void Process() de la CLASS_RAILCOM on établi alors les mesures entre les intervalles pour envoyer les bons messages sur le TX au fur et à mesure que le temps s écoule.
Une fois le timing du CUTOUT dépassé donc microseconds_ticks >454us et <488us (ou >488us au cas où)
on procède;
stop du compteur B0 ( BitClear(TCB0.CTRLA,0); ) (mise à 0 du bit 0 d u registre CTRLA du TIMBERB0)
reset de la valeur CNT du compteur B0 via  TCB0.CNT = 0
microseconds_ticks = 0;
FLAG_RAILOM_CUTOUT = false

rm: il me semble que le FLAG_RAILCOM_IN_CUTOUT pourrait être aussi stocke dans le GPIOR3.
On ne peut pas y placer la valeur microseconds_ticks qui est sur 16bits car le registre est sur 8! On devrait alors combiner avec un autre registre mais ceux ci sont déjà affectés à d autres usages.

En principe cela doit "rouler".

J avais utilisé la fonction (digitalWriteFast(PIN_PC0) && digitalWriteFast(PIN_PC1) pour avoir un temps d exécution le plus court possible pour confirmer la présence des conditions du CUTOUT (timing entre 26us et 32us ET pas de tension sur la voie donc sur une valeur à "1" sur chaque entree DCC.
Cependant cette fonction requiert que les valeurs en  entrée soient des CONSTANTES donc écrit " en dure"... question "portabilité" bof bof!
 La solution que propose Marc va être aussi efficace via le if (IN_portC & 0b00000011) avec une mise en alias sous un #define de cette variable pour supporter les PIN en entrées.
On pourra veiller à ce que les 2 PINS choisies soient idéalement sur le même port pour gagner en efficacité.

Encore quelques lignes à écrire donc puis à tester!

A ce stade ma crainte est que le serial.Write') soit altéré par l ISR de TCB0 et/ou à l inverse que l'émission sur TX face sauter des micocrseconds_ticks ce qui fausserait la précision et donc possiblement le résultat. Mais la c est plus costaud à construire ou à "compenser".

S il y a des idées je suis preneur...

Laurent

 


Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 17, 2023, 09:04:31 pm
Hello

J ai trouve la "commande qui va bien" sur les indications de Trimarco232.

La voici pour bien comprendre sa construction.
Ceux qui la maitrise trouveront cela trivial comme toujours mais il n'est jamais inutile de donner les clés pour bien comprendre chaque étape.

Le if(IN_portX & 0bRSTUVWYZ) == VAL) est en fait une syntaxe sur les AVRx des séries 0/1/2 (et consorts)* de la ligne suivante:

PORTx.IN & 0bQRSTUVWY

PORTx ou  x= A ou B ou C ou D ou E ou F ou G. ( selon ce qui est présent sur le MCU en fonction de son brochage)

QRSTUVWY sont les bits 0 à 7 des PINx de 0 à 7
VAL = 0 ou 1

Si on veut lire le statut de PIN_PA3 on effectue usuellement digitalRead(PIN_PA3)
Si on veut aller plus vite on peut utiliser digitalReadFast(PIN_PA3) car PIN_PA3 est une constante.

Si cette variable ne l'est pas ou "inconnue "on combine donc PORTx.IN & les numéros de()s pin(s) que l on veut lire sur le port en question.

Si dans notre cas on est sur le même port alors la lecture s'effectuant en 1 fois on gagne quelques précieux cycles. A défaut on pourra lire sur des ports différents dans le code proposé

Aussi pour notre cas toujours à titre d exemple sur PIN_PA3 on fait l'équivalent de:
 PORTA.IN & 0b00001000

Dans notre cas nous avons attribué DCC_PIN_RIGHT sur PIN_PC0 et DCC_PIN_LEFT sur PIN_PC1

on irait directement au résultat via la commande suivante afin de lire dans le même cycle les 2 broches 0 et 1 du port C:( rapide efficace mais ... codé en "dure")

PORTC.IN & 0b00000011

mis en forme on a donc in if(PORTC.IN & 0b00000011) ==1) comme condition.

On peut aussi écrire ceci:
if((PORTC.IN & 0b00000001) == 1) && (PORTC.IN & 0b00000010) == 1)) ( au prix de quelques cycles de traitement supplémentaires)

L'avantage de cette seconde structure va être de proposer possiblement des lectures sur des ports différenciés au besoin.

Dans l'initialisation de la CASS_RAILCOM on trouvera donc une fonction qui inclura les 2 PINS sur lesquelles établir la lecture indifféremment de leur port et de leur numéro de broche en entrée  sous réserve toutefois que ces 2 pins puissent être libre d'usage et être déclarées comme INPUT ( pinMode(PIN_PXn, INPUT) voir pinMode(PIN_PXn, INPUT_PULLUP) si nécessaire.

Avec ces éléments on assure (normalement) la portabilité selon les hardwares retenus pour le CPU.

*On parle toujours des familles ATMEGA x08 et x09 ( famille série 0) ( ex Atmega4808, Atmage4809 ( celui du NANO_EVERY), ...

Des AVR DA DB DD EA et EB ( famille des séries suivantes 1 et 2)
Mais aussi des CPU de type" MEGATINY" tels les ATTINY x06 & x07 ( ex Attiny1606 Attiny1607)

Notez toutefois que seuls ceux disposant à minima de 2 timers B pourront alors convenir donc ceux des séries 1 et 2 tels les  Attiny 1616 Attiny1626 ou encore bien encore Attiny 3216 et Attiny3617. Les Attiny de la serie0 ne pourront pas traiter le RAILCOM ( ex Attiny1606 Attiny 1607 ...)

Laurent

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 18, 2023, 02:42:35 am
Bonsoir

Voici ce que ce que cela donne en l'état.

https://we.tl/t-VhMtl2es2j (https://we.tl/t-VhMtl2es2j)

Précisons que ceci a été traite sous PLATFORMIO en ayant précisé les flags suivants dans le fichier. platformio.ini
build_flags = -D MILLIS_USE_TIMERB2 -D DCC_USES_TIMERB1 -D RAILCOM_USES_TIMERB0

Sous l IDE ARDUINO il faudra:
 A jouter dans le fichier  RAILCOM_CONSTANTES.h ceci:

#ifndef RAILCOM_USES_TIMERB0
    #define RAILCOM_USES_TIMERB0
#endif

#ifndef DCC_USES_TIMERB1
    #define DCC_USES_TIMERB1
#endif

 A noter que par défaut si ce n est pas ajouté cela doit "passer" sur les valeurs par defaut avec TCB0 pour traiter RAILCOM et TCB1 pour traiter le signal DCC.

Il faudra renommer le fichier main.cpp en main.ino.
Peut etre aussi ajuster les chemins des fichiers de la librairie ou copier celel ci en lieu et place de celle presente par defaut.

Puis essayer et voir ce que cela donne.

Laurent



Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 18, 2023, 03:34:04 pm
Bonjour

Premier constat sur un test de "portabilité" inter CPU il a fallu compléter par des conditions les modalités d'usage selon définition des ports dans la fonction void RAILCOM::init_RAILCOM_pins(uint8_t dccPin_right, uint8_t dccPin_left)

En effet si certains port ne sont pas définis et présents on aura une erreur à la compilation.

Donc on "conditionne" le tout pour chacun d'entre eux.

Titre: Re : Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 18, 2023, 10:56:20 pm
(...)
A ce stade ma crainte est que le serial.Write') soit altéré par l ISR de TCB0 et/ou à l inverse que l'émission sur TX face sauter des micocrseconds_ticks ce qui fausserait la précision et donc possiblement le résultat. Mais la c est plus costaud à construire ou à "compenser".
Laurent
amha ,
il ne faut plus utiliser TCB0 une fois que l'envoi des bytes railcom a commencé
il ne faut pas non plus utiliser de bibliothèque pour envoyer les bytes , mais le faire manuellement : on se prémunit ainsi des ennuis liés aux interruptions , qu'on aura désactivées au début ; j'imagine la séquence suivante
- désactiver les interruptions
- observer la fin de la tempo pour le début de l'émission railcom , via TIMB0
- écrire le 1er byte du canal 1 dans TXDATA
- écrire le 2ème byte du canal 1 dans TXDATA
- observer une tempo de 40+40+33us , via TIMB0
- écrire le 1er byte du canal 2 dans TXDATA
- écrire le 2ème byte du canal 2 dans TXDATA
- attendre DREIF par polling
- écrire le 3ème byte du canal 2 dans TXDATA
- attendre DREIF par polling
- écrire le 4ème byte du canal 2 dans TXDATA
- attendre DREIF par polling
- écrire le 5ème byte du canal 2 dans TXDATA
- réactiver les interruptions
- attendre TXCIF par polling
- reprendre le décodage des bits DCC

Citer
On pourra veiller à ce que les 2 PINS choisies soient idéalement sur le même port pour
il faudra aussi que ces broches puissent être lues par l'ADC pour les besoins de l'ABC

Edit : 40 + 40 + 33
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 19, 2023, 01:28:30 am
Bonsoir

Oui c est une bonne façon de faire un peu plus "costaude" à construire. JE crois que le code "nippon" construit cela.

Si on est en dehors de l ISR on à toujours une possibilité de s appuyer sur micro() avec les aléas qui vont avec.

J ai légèrement retouché la fonction indiquée plus haut à la suite de tests "debug" qui indiquaient bien une série de corrections à apporter.
A noter l'arrivée d une variable  combo_mask qui pourra servir au besoin.

void RAILCOM :: init_RAILCOM_pins(uint8_t dccPin_right, uint8_t dccPin_left)
{
    pinMode(dccPin_right,INPUT);
    pinMode(dccPin_left,INPUT);

    uint8_t dccpinright = dccPin_right;
    uint8_t dccpinleft = dccPin_left;
   
   
    uint8_t portNumber = 0;
    uint8_t portBitNumber = 0;

    uint8_t tmpval1 = 0;
   
    portNumber = digital_pin_to_port[dccpinright];
portBitNumber = digital_pin_to_bit_position[dccpinright];
     
    switch(portBitNumber)
    {
        case 0:
            tmpval1 = PIN0_bm; //0b00000001;
        break;

        case 1:
            tmpval1 = PIN1_bm; //0b00000010;
        break;

        case 2:
            tmpval1 = PIN2_bm; //0b00000100;
        break;

        case 3:
            tmpval1 = PIN3_bm; //0b00001000;
        break;

        case 4:
            tmpval1 = PIN4_bm; //0b00010000;
        break;

        case 5:
            tmpval1 = PIN5_bm; //0b00100000;
        break;

        case 6:
            tmpval1 = PIN6_bm; //0b01000000;
        break;

        case 7:
            tmpval1 = PIN7_bm; //0b10000000;
        break;

    }

    mask_combo = tmpval1;

   

    switch(portNumber)
    {
        #if defined(PA) && (PA != NOT_A_PORT)
            case PA:
                #define CHECK_IN_PART1 (PORTA.IN & tmpval1)
            break;
        #endif

        #if defined(PB) && (PB != NOT_A_PORT)
            case PB:
                #define CHECK_IN_PART1 (PORTB.IN & tmpval1)
            break;
        #endif

        #if defined(PC) && (PC != NOT_A_PORT)
            case PC:
                #define CHECK_IN_PART1 (PORTC.IN & tmpval1)
            break;
        #endif

        #if defined(PD) && (PD != NOT_A_PORT)
            case PD:
                #define CHECK_IN_PART1 (PORTD.IN & tmpval1)
            break;
        #endif

        #if defined(PE) && (PE != NOT_A_PORT)
            case PE:
                #define CHECK_IN_PART1 (PORTE.IN & tmpval1)
            break;
        #endif 

        #if defined(PF) && (PF != NOT_A_PORT)
            case PF:
                #define CHECK_IN_PART1 (PORTF.IN & tmpval1)
            break;
        #endif
    }

    RAILCOM_CHECK_PIN_RIGHT = CHECK_IN_PART1;

    tmpval1 = 0;

    portNumber = digital_pin_to_port[dccpinleft];
    portBitNumber = digital_pin_to_bit_position[dccpinleft];

    switch(portBitNumber)
    {
        case 0:
            tmpval1 = PIN0_bm; //0b00000001;
        break;

        case 1:
            tmpval1 = PIN1_bm; //0b00000010;
        break;

        case 2:
            tmpval1 = PIN2_bm; //0b00000100;
        break;

        case 3:
            tmpval1 = PIN3_bm; //0b00001000;
        break;

        case 4:
            tmpval1 = PIN4_bm; //0b00010000;
        break;

        case 5:
            tmpval1 = PIN5_bm; //0b00100000;
        break;

        case 6:
            tmpval1 = PIN6_bm; //0b01000000;
        break;

        case 7:
            tmpval1 = PIN7_bm; //0b10000000;
        break;

    }

    mask_combo |= tmpval1;

    switch(portNumber)
    {       
        #if defined(PA) && (PA != NOT_A_PORT)
            case PA:
                #define CHECK_IN_PART2 (PORTA.IN & tmpval1)
            break;
        #endif

        #if defined(PB) && (PB != NOT_A_PORT)
            case PB:
                #define CHECK_IN_PART2 (PORTB.IN & tmpval1)
            break;
        #endif

        #if defined(PC) && (PC != NOT_A_PORT)
            case PC:
                #define CHECK_IN_PART2 (PORTC.IN & tmpval1)
            break;
        #endif

        #if defined(PD) && (PD != NOT_A_PORT)
            case PD:
                #define CHECK_IN_PART2 (PORTD_IN & tmpval1)
            break;
        #endif 

        #if defined(PE) && (PE != NOT_A_PORT)
            case PE:
                #define CHECK_IN_PART2 (PORTE.IN & tmpval1)
            break;
        #endif 

        #if defined(PF) && (PF != NOT_A_PORT)
            case PF:
                #define CHECK_IN_PART2 (PORTF.IN & tmpval1)
            break;
        #endif
    }

    RAILCOM_CHECK_PIN_LEFT = CHECK_IN_PART2;

}
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 19, 2023, 01:50:20 am
@Trimarco

J ai lu que le nombre de cycles nécessaires/utilisés entre les bits en utilisant softwareserial est < 16cyles CPU ;

https://github.com/SpenceKonde/DxCore/blob/master/megaavr/libraries/SoftwareSerial/src/SoftwareSerial.cpp#L286 (https://github.com/SpenceKonde/DxCore/blob/master/megaavr/libraries/SoftwareSerial/src/SoftwareSerial.cpp#L286)

  // 12 (gcc 4.8.2) or 13 (gcc 4.3.2) cycles from start bit to first bit,
  // 15 (gcc 4.8.2) or 16 (gcc 4.3.2) cycles between bits,
  // 12 (gcc 4.8.2) or 14 (gcc 4.3.2) cycles from last bit to stop bit

C est une info précieuse même si on va "construire" surement différemment du coup que via une lib tout faite.

Pas (du tout) s aussi trivial que je l aurai pensé de prime abord mais "défi" intéressant et constructif.

On pourra noter que entre les bits d une trame 8N1 ( avec le start bit en plus donc au total 10bits émis!!)
1 start bit (+12 cycles)
8 bits (7 x 15 = +105 cycles)
1 stop bit (+12 cycles)

donc on a

139 cycles minimum requis entre les bits ( et on a pas les temps pour chacun d entre eux) ce qui vérifie mon hypothèse pessimiste origine entre le "tick" à la us et les multi interruptions liées.

On doit donc composer différèrent comme tu le proposes.
Je ne m étais pas encore aventuré jusque la, c est l'occasion d y plonger  8)

Laurent
Titre: Re : Re : Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 19, 2023, 01:57:06 am
Citer
On pourra veiller à ce que les 2 PINS choisies soient idéalement sur le même port pour
il faudra aussi que ces broches puissent être lues par l'ADC pour les besoins de l'ABC
[/quote]


A ce stade je sélectionne volontairement 2 pins différentes sur le modèle "NIPPON" pour gérer l'ABC tout comme j ai retenu aussi 1 entrée ANA pour la lecture de tension post pont de diodes.

Rien n empêchera de voir comment fusionner ces blocs ensuite mais pour le moment leur gestion différentiée sera plus "simple" à traiter unitairement et rend modulaire la chose puisque qu on peut aussi se passer d'ABC...

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 19, 2023, 02:13:21 am
On va pouvoir aussi s appuyer sur ce doc:

https://ww1.microchip.com/downloads/en/AppNotes/TB3216-Getting-Started-with-USART-90003216A.pdf (https://ww1.microchip.com/downloads/en/AppNotes/TB3216-Getting-Started-with-USART-90003216A.pdf)

Dans lequel on devrait trouver matière à construire.

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 19, 2023, 03:05:18 am
Pour ce qui est des timing indiqués je pense que tu as en tête cette source

https://www.opendcc.de/info/railcom/railcom_f.shtml (https://www.opendcc.de/info/railcom/railcom_f.shtml)

Par contre je ne savais pas  a quoi correspondaient les 40 + 40 + 13 ( ici 80+15)

La reponse ici :

"Durant la pause de transmission un décodeur peut émettre l'information de retour. La transmission de retour est effectuée en série, octet par octet. Ceux-ci sont codés en RS232, paramètres de transmission 250kBaud, 8 bits, 1 bit d'arrêt. A 250 kBaud un bit dure 4μs, et un octet 40μs y compris le bit de départ (= 0) et les bits d'arrêt (= 1)."

source:
https://www.opendcc.de/info/railcom/railcom_f.shtml (https://www.opendcc.de/info/railcom/railcom_f.shtml)

On est bien en format 8N1 de 10bits x4us = 40us. x 2 trames = 80us +15us? ( tempo?)



Finalement on aurait a attendre ce moment de 93/95us par déclanchement de l interruption du TIMERB0 pour "envoyer" ce que l on aura prépare avant (les 2 bytes de data du CH1) 

Cela se ferait par le passage dans la valeur TCB0.CCMP = F_CPU/1000000 * 93 (ou 95) ce qui déclenchera l interruption au moment venu. A ce moment on peut basculer une variable qui autorise l envoi.. ou quelque chose qui y ressemble.
Toutefois pour passer a 193+15 comme on aura eu une interruption qui remettraTCB0.CNT = 0. j imagine qu'on devra les déduire 80 des 193?( mais on a utilement le TCB1.CNT qui continue de compter de son coté a la même vitesse que TCB0... donc on a une valeur auto incrémenté a laquelle on ajoute le timing de l interruption entre 26 et 32...
On bascule alors la valeur CCMP avec ce nouveau nombre ajusté pour bis émission des autres bytes ds le CH2 si requis.

Bon encore un peu à moudre de ce cote la pour tout mettre au claire...

Ltr
Titre: Re : Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 19, 2023, 11:11:09 pm
Pour ce qui est des timing indiqués je pense que tu as en tête cette source
https://www.opendcc.de/info/railcom/railcom_f.shtml (https://www.opendcc.de/info/railcom/railcom_f.shtml)
le mieux est toujours de partir du document officiel , mais ceci est en effet une source sérieuse
Par contre je ne savais pas  a quoi correspondaient les 40 + 40 + 13 ( ici 80+15)
je m'a gouré (pour constater que tu suis 8)) : on a , pour le canal 1 , une tempo de 80us , suivie d'une trame de 80us , ça fait 160us ; pour le canal 2 , la tempo est de 193 us : il faut donc attendre entre les 2 canaux , 193 - 160 = 33us (pas 13 ???)
La réponse ici :
"Durant la pause de transmission un décodeur peut émettre l'information de retour. La transmission de retour est effectuée en série, octet par octet. Ceux-ci sont codés en RS232, paramètres de transmission 250kBaud, 8 bits, 1 bit d'arrêt. A 250 kBaud un bit dure 4μs, et un octet 40μs y compris le bit de départ (= 0) et les bits d'arrêt (= 1)."
source:
https://www.opendcc.de/info/railcom/railcom_f.shtml (https://www.opendcc.de/info/railcom/railcom_f.shtml)

On est bien en format 8N1 de 10bits x4us = 40us. x 2 trames = 80us +15us? ( tempo?)
oui , comme on écrit les 2 octets ensembles , il faut attendre que l'USART les a transmis (40 + 40 = 80us) , tempo à laquelle on ajoute les les 33us

Finalement on aurait a attendre ce moment de 93/95us par déclenchement de l interruption du TIMERB0 pour "envoyer" ce que l'on aura prépare avant (les 2 bytes de data du CH1) (je pense que tu veux dire 193us) : non , car les interruptions doivent être coupées à ce stade , mais aussi oui , car on n'est pas obligé d'arrêter TIMB0 , on peut faire du polling pour voir s'il a atteint les 193us , puis envoyer le canal 2  

Cela se ferait par le passage dans la valeur TCB0.CCMP = F_CPU/1000000 * 93 (ou 95) ce qui déclenchera l interruption au moment venu. A ce moment on peut basculer une variable qui autorise l envoi.. ou quelque chose qui y ressemble.
Toutefois pour passer a 193+15 comme on aura eu une interruption qui remettraTCB0.CNT = 0. j imagine qu'on devra les déduire 80 des 193?( mais on a utilement le TCB1.CNT qui continue de compter de son coté a la même vitesse que TCB0... donc on a une valeur auto incrémenté a laquelle on ajoute le timing de l interruption entre 26 et 32...
On bascule alors la valeur CCMP avec ce nouveau nombre ajusté pour bis émission des autres bytes ds le CH2 si requis. deviendra simple quand on aura compris

Bon encore un peu à moudre de ce cote la pour tout mettre au clair ...

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 20, 2023, 02:44:14 pm
voilà comment je vois la chose :
1) au front montant de la 1ère impulsion du cutout (la 1ère partie du 1er bit du preamble , celle qui sera tronquée à 29us par la station) , TIMB0 provoque une interruption suite à la capture ; on fera toutes les opérations du cutout dans l'ISR correspondante , comme ça on ne sera pas gênés par d'improbables autres activités de l'arduino , pendant toute cette période ; de même , on ne fera appel à aucune instruction de type arduino , pour être certains que celles-ci ne perturbent pas notre timing , un peu critique : cela implique d'écrire directement dans les registres ;
la valeur capturée est mise en ram : uint16_t c = TCB0.CCMP0 ;
on fait aussi les opérations habituelles de décodage , qui permettent de vérifier qu'on est bien au début du cutout
2) il faut à présent attendre le début du cutout , cad. les entrées correspondant aux 2 rails à LOW ; il faut faire un double polling d'abord sur if (PORTx.IN & 0b00100100 == 0) , et aussi sur if ((TCB0.CNT - c) > 80) ;
il faudra aussi vérifier (TCB0.CNT - c) > (80+15) , auquel cas on arrête aussi les frais
si c'est ok , on envoie le canal 1 :
USART0.TXDATA = railcom_canal_1_byte_0 ;
USART0.TXDATA = railcom_canal_1_byte_1 ;
3) faire un polling sur if (PORTx.IN & 0b00100100 == 0) , et sur if ((TCB0.CNT - c) > 193) ;
il faut faire un double polling d'abord sur if (PORTx.IN & 0b00100100 == 0) , et aussi sur if ((TCB0.CNT - c) > 193) ;
il faudra aussi vérifier (TCB0.CNT - c) > (193+15) , auquel cas on arrête les frais
si c'est ok , on envoie le canal 1 :
USART0.TXDATA = railcom_canal_2_byte_0 ;
USART0.TXDATA = railcom_canal_2_byte_1 ;
puis on fait un polling sur la fin d'émission du 1er byte :
if (USART0.TXDATA & DREIF) USART0.TXDATA = railcom_canal_1_byte_2 ;
etc. , jusqu'à l'envoi des 6 bytes
là , les opérations du cutout sont terminées , on peut quitter l'ISR sans autre forme de procès !
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 21, 2023, 12:45:40 am
Bonsoir

Ca semble en effet la construction adéquate.

Je pèche en revanche sur ce que je "connais" et ce qui me "manque".

Ce qui "est connu":
La Lib d AIKO utilise le mode de capture du timer en charge du traitement du signal DCC en mode "Frequency measurement" avec un déclanchement sur "event".

Chaque "détection"  d'un front montant ou descendant introduit une interruption. Une bascule s'opère entre la "montée et la descente via  (EVENTCTRL ^= EDGE) Lors de celle ci et de façon automatique liée à cette implémentation la valeur du compteur du timer TIMERx.CNT est transférée dans le registre TIMERx.CCMP.

On effectue alors une "moulinette" en ayant mis à l échelle des timings avec la vitesse du CPU pour déterminer si on a un "demi 0" , un "demi 1" et bien aussi si on ne "serait pas" dans le cadre d un intervalle de timing de type RAILCOM CUTOUT ( typique 29us (intervalle de 26us à 32us selon les tolérances en vigueur de cette même norme) On a l'idée de vérifier les entrées des PIN DCC venant des deux pôles de la voie. ( 1 serait il suffisant?) ( utilisation de la commande PORTx.IN & "bytes" == "valeur*") (* celle du mask_combo évoquée dans mes précédents messages)

Si pas dans le cutout on assemble ensuite les "1" et les "0" après diagnostic de leur conformité pour constituer les messages DCC. ( ou pas! et alors "reset"!)

Pour RAILCOM on sait donc identifier le cas ou on est dans un CUTOUT:
on a un intervalle de détection conforme ET les entrées des pins DCC sont à "0" puisque il n y a pas de tension dans la voie ( sur les deux rails) ( les valeurs sont plutôt à 1 mais l'absence de tension est un état "0" = OFF) Comme le HARD inverse cette logique on cherchera alors à trouver une valeur 1 sur la lecture des pins

A tout moment on à alors les valeurs TIMERx.CNT et TIMERx.CCMP à dispo qui peuvent être exploitées. puisqu'il il n y aura pas d autre interruption (normalement) avant la reprise des trames DCC post cutout ( donc retour de tension et nouvelle mesure de temps entre 2 fronts de directions opposées) ( dans le cas contraire bye bye railcom et on rebascule en mode "nominal" de traitement des 0 et 1)

Dans mon "analyse" si j ai ces conditions de remplies je "déclenche" seulement le timer du railcom( TIMERy)  et je vais avec celui ci voir si je suis dans les intervalles d émission des canaux 1 et 2 ( si on a active RAILCOM via le bon bit du CV29 et préciser ce que l on émet à l aide des bits du CV28 ( canal 1 et ou canal 2)). Je peux rester dans l ISR générée par le signal DCC.( j ene vois pas comment faire le start du timer RC autrement en mode "periodic interupt")

Donc si je ne suis pas dans l erreur on ajoute le temps  écoulé sur le TIMERx à la valeur CNT du TIMERy utilisé pour la mesure de temps RAILCOM. ( le CCMP0 que tu indiquais avoir mis en mémoire)
Ce timer peut alors être simplement mis en mode "Periodic interrupt" dont on s arrangera pour ne jamais atteindre le seuil haut ou seulement à la fin du temps équivalent au max du timing cutout ( les fameuses 488us après le temps de référence T0 amorcé sur le TIMERx et incrémentés ici en sus à l origine du démarrage de ce TIMERy dédié à railcom.)
Dans le cas d une éventuelle ISR du timer Railcom on aurait alors STOP du timer RC, flag railcom = false, reset de la valeur CNT.

Lors des plages ad hoc (75us 177us) on émet manuellement les "2 bytes du CH1" une tempo puis ceux (les 3 bytes) du CH2 (de 193 à 454us) (CH2 dont il reste à construire aussi la création des contenus)

Ce que je n identifie pas c est "comment"/ "pourquoi" on établirait sur le "front montant"(oui c est le point de depart) l'interruption de démarrage du TIMERy pour RC de façon systématique quitte à faire un reset lors d un front descendant reçu sur le TIMERx si c est dans la plage ouverte et dans les conditions du cutout...

Il faudrait alors une condition qui fasse que uniquement sur les fronts montant on d'éclanche le compteur TIMERy pour RAILCOM depuis  l'interruption générée sur le traitement du signal DCC.( et "reset sur les front descendants)

Certes on s éviterait ainsi les passages de valeur(s) multiples inter timer comme j en avais l idée initialement... whynot!

En quittant l ISR on arrêterait aussi du coup le TIMERy du railcom qui serait en même temps réinitialisé ( TIMERy.CNT =0, TIMERy.CCMP= (valeur a maxima pour 488us), (bitClear(TIMERy.CTRLA,0) pour arreter le timer y.

Le code "NIPPON" formule l usage d envoi des messages sur le CH1 ( senduart(data)) et construit pour cela le paramétrage "complet" de l'uart.

Je ne suis pas du tout familier avec l UART et ses mécanismes mais l'inspiration "est là"

Je pense qu'une petite classe complémentaire RAILCOM_UART va devoir faire son apparition... 8)

Tout laisser dans l ISR parait presque "trivial" des lors que tout est construit "à la main". ( on contourne ainsi l émission sur TX DANS l ISR, ce qui est naturellement impossible avec la lib serial et les bons timings.)

L'autre solution alternative qui me vient en tête serait de rendre prioritaire les interruptions pour émettre les messages RAILCOM sans interruption extérieure dans les conditions requises avant de revenir à un niveau standard. C'est peut être un peu capillotracté et moins judicieux? /ou combinable) ou devenu inutile!... Sauf selon l effet contraire que toute nouvelle interruption sur le signal DCC viendrait obligatoirement faire un reset de "l encours", ce qui, si on est en émission railcom des bytes des CH1 ou 2 et en priorité LVL1 incompatible… On va donc oublier cette fausse bonne idée pour le moment.


Questions: quant tu parles de UART0.TXDATA tu veux parler de UART0.TXDATAL ?
Si j ai bien compris, ce registre contient précisément le Byte a envoyer donc si on n'a pas fini son émission complètement il ne faut pas le rafraichir par son successeur? ( supposition)
donc la close
if (USART0.TXDATA & DREIF) serait (plutôt)  à mettre entre chaque refresh des valeurs ds le registre TXDATAL pour émission. Une fois le byte envoyé refresh etc

Ou alors on stocke les valeurs à envoyer successivement dans un "POOL des BYTES RAILCOM A EMMETTRE" et on avance dans ce pool au fur et à mesure que chaque byte est envoyé un par un. Et ce pool est rafraichi périodiquement si valeurs dynamiques (ou pas si valeurs statiques ex l adresse ne change pas alors que la vitesse elle évolue plus régulièrement)...

A voir donc...

Laurent

Rm: pour ceux qui suivent ce fil et notre échange, ne soyez pas "timide" pour poser vos questions ou apporter votre pierre à l'édifice.






Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 21, 2023, 12:30:19 pm
on a un four , une horloge , alors on va cuire un gateau :
il faut le mettre 10mn à thermostat 7 , puis 20mn à thermostat 3
on le met au four à thermostat 7 , on regarde l'heure il est 11h05 , on s'en souvient
et là on surveille l'horloge de la cuisine :
ah , il est 11h15 (11h05 + 10mn) , on met thermostat 3
et on surveille l'heure , sans se laisser distraire
ah , il est 11h35 (11h05 + 10mn + 20mn) , on sort le gateau
il n'est pas beau mon gateau ? et pourtant je n'ai jamais eu besoin d'une seconde horloge !
ben là c'est pareil , TIMB0 continue de tourner , on fait du polling sur sa valeur pour savoir le temps écoulé depuis la capture (qu'on a sauvegardée) et ça suffit ; si certains parlent d'un second timer , c'est qu'ils n'ont pas compris un truc , où alors c'est moi ...

l'UART a 2 registres , un pour l'écriture TXDATA , et un , à décalage , qui transmet ; quand on écrit dans TXDATA , le byte est immédiatement transféré dans le registre à décalage, qui démarre immédiatement la transmission : on peut donc mettre de suite le 2ème byte dans TXDATA , qui ne sera automatiquement transféré dans le registre à décalage que quand ce dernier aura fini la transmission en cours
par contre , si on veut mettre un 3ème , il faut attendre que la transmission en cours soit finie
alors c'est peut être TXDATAL , ça dépend comment les registres sont définis , je n'ai aps vérifié ça

après relecture il semble bien que la priorité 1 soit une priorité de préemption, c'est à dire qu'elle peut interrompre une ISR en cours , et aussi qu'elle ne risque pas de se faire interrompre à son tour : on a donc une option qui permet(trait) d'éviter d'interdire les interruption pendant l'ISR du cutout ; la question sera aussi de voire comment se comporte le core vis à vis de ces options



Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 21, 2023, 05:19:22 pm
Ca tombe bien j aime bien les gâteaux  ;D

Donc on conserve "exclusivement" la "minuterie du TIMER_DCC ( qui peut être du coup le TIMERB0) et nous allons donc suivre l'évolution de la valeur CNT.

Nous y ajouterons "delta" ( qui est la valeur enregistrée dans CCMP).
Dans notre usage nous ne risquons pas d avoir une valeur  CNT > 65535 ( max de uint16_t donc pas de risque de ce cote la d avoir un reset indésiré)

J ai relu la doc pour l'UART incluant aussi les info du livre de TOM ALMY.
On parle bien d un TXDATA en uint16_t qui est si j ai compris composé de 2 uint8_t ( byte)  TXDATAL et TXDATAH

TXDATAL contient bien nos 8 bits à transmettre
TXDATAH n est utilisé à priori qu'en mode émission sur 9 bits et ne contient qu'un bit de data. Il est a ignoré pour notre cas d usage puisque que nous voulons transmettre en "8N1"

On ne peut donc pas glisser 2 bytes dedans puisque c est un mécanisme de "FIFO" qui s opère avec la partie transmission. ( par morceaux de 8 bits maxi)
Une fois la transmission complète on peut seulement alors pousser un nouveau "byte" à transmettre etc.
C est la lecture des flags qui va orchestrer les séquences.

Ca "fait du monde " à coordonner.

Pour des question de "commodités" autant que de portabilité inter CPU ( AVR, MEGATINY) nous traiterons avec l'UART0 sur les broches par défauts ( ce qui au niveau hardware sera toujours à considérer dans le routage). ( ca tombe bien c est déjà dessiné comme cela d'origine)

Ltr






Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 21, 2023, 08:15:31 pm
Voici le une partie du "squelette" pour ce qui est de la gestion des timings lors de l ISR

//ADD RAILCOM VALUES: LTR 20231210 follow RCN-217: https://normen.railcommunity.de/RCN-217.pdf last updated on 20231123

#define RAILCOM_CUTOUT_MIN_START_TIME   F_CPU/1000000 * 26        //MIN CUTOUT START TIME
#define RAILCOM_CUTOUT_MAX_START_TIME   F_CPU/1000000 * 32        //MAX CUTOUT START TIME

#define RAILCOM_CH1_START_TIME          F_CPU/1000000 * 75        ///MIN CH1 START TIME
#define RAILCOM_CH1_MAX_START_TIME      F_CPU/1000000 * (80+15)   //MAX CH1 SEND START TIME
#define RAILCOM_CH1_END_TIME            F_CPU/1000000 * 177       //MAX CH1 END TIME
#define RAILCOM_CH2_START_TIME          F_CPU/1000000 * 193       //MIN CH2 START TIME
#define RAILCOM_CH2_MAX_START_TIME      F_CPU/1000000 * (193+15)  //MAX CH2 SEND START TIME
#define RAILCOM_CH2_END_TIME            F_CPU/1000000 * 454       //END CH2
#define RAILCOM_CUTOUT_MAX_END_TIME     F_CPU/1000000 * 488       //MAX CUTOUT TIME



//******************************************************************************************************
// 6. The Timer ISR, which implements the DCC Receive Routine
//******************************************************************************************************
// Execution of this DCC Receive code typically takes between 3 and 8 microseconds.
// Select the corresponding ISR
#if (defined(DCC_USES_TIMERB0) && !defined(RAILCOM_USES_TIMERB0))
  ISR(TCB0_INT_vect) {
#elif (defined(DCC_USES_TIMERB1) && !defined(RAILCOM_USES_TIMERB1))
  ISR(TCB1_INT_vect) {
#elif (defined(DCC_USES_TIMERB2) && !defined(RAILCOM_USES_TIMERB2))
  ISR(TCB2_INT_vect) {
#elif (defined(DCC_USES_TIMERB3) && !defined(RAILCOM_USES_TIMERB3))
  ISR(TCB3_INT_vect) {
#else
  // fallback to TCB0 (selected platform must have it)
  ISR(TCB0_INT_vect) {
#endif
 
  TIMER_DCC_CONTROL.EVCTRL ^= TCB_EDGE_bm;                         // Change the event edge at which we trigger
  uint16_t  delta = TIMER_DCC_CONTROL.CCMP;                        // Delta holds the time since the previous interrupt
  uint8_t DccBitVal;

  if(delta < RAILCOM_CUTOUT_MIN_START_TIME)
  {
    //It may be a glitch so cancel elapsed time since last interupt < 26us
    FLAG_RAILCOM_IN_CUTOUT = false;   
    TIMER_DCC_CONTROL.CNT = 0;
    return; //it s a glitch so ignore it and leave ISR
  }

  if(FLAG_RAILCOM_IN_CUTOUT == false)
  { //check if we are in CUTOUT TIMINGS [26us;32us]:
    if( (delta <= RAILCOM_CUTOUT_MAX_START_TIME) && (delta >= RAILCOM_CUTOUT_MIN_START_TIME) )
    { //WE ARE IN CUTOUT START INTERVAL
      //READ PINS STATUS
      /*
      IF A TEMPORIZE TIME IS NEEEDED WE DONT USE delay() into the ISR but a line like "do {} WHILE (TIMER_DCC_CONTROL.CNT < WAIT_TIME);""
      WAIT_TIME is a 16bits variable where F_CPU/1000000 will give 1us ticks to adjust as delay expected
      WAIT_TIME MUST BE STITCLY LOWER THAN (75us-delta) due to match timing with CH1 emission interval, if not it would not be possible to send CH1!
      uint16_t TEMPOVAL;
      uint16_t WAITTIME = (F_CPU/1000000) * TEMPOVAL;
      do {} while (TIMER_DCC_CONTROL.CNT /(F_CPU/1000000) < WAITTIME);
      */
      if( ((railcom.RAILCOM_CHECK_PIN_RIGHT | railcom.mask_combo) == railcom.mask_combo) && ((railcom.RAILCOM_CHECK_PIN_LEFT | railcom.mask_combo) == railcom.mask_combo) )
      { //both CPU PINS ARE AT "1" states so WE ARE IN CUTOUT DUE TO NO VOLT DETECTED ON TRACK
        FLAG_RAILCOM_IN_CUTOUT = true;
      }   
    }
    else //we should receive O or 1 bits:
    {       
      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
          TIMER_DCC_CONTROL.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;
        }
      }   

      #include "sup_isr_assemble_packet.h"
   
    } //END BITS MANAGEMENT
  } //end FLAG RAILCOM == false


  if(FLAG_RAILCOM_IN_CUTOUT) //WE ARE IN RAILCOM CUTOUT
  {   
    /*
    IF A TEMPORIZE TIME IS NEEEDED WE DONT USE delay() into the ISR but a line like "do {} WHILE (TIMER_DCC_CONTROL.CNT < WAIT_TIME);""
    WAIT_TIME is a 16bits variable where F_CPU/1000000 will give 1us ticks to adjust as delay expected
    uint16_t TEMPOVAL;
    uint16_t WAITTIME = (F_CPU/1000000) * TEMPOVAL;
    do { } while (TIMER_DCC_CONTROL.CNT /(F_CPU/1000000) < WAITTIME); //in us
    WAITTIME_es_us = F_CPU/1000000 * TEMPOAL
    do { } while ((TIMER_DCC_CONTROL.CNT < WAITTIME_eq_us ); //general case
    */

    do {} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH1_START_TIME); //WAIT TILL 75us ARRIVED TO START TO SEND BYTE ON UART
 
    if( ((TIMER_DCC_CONTROL.CNT + delta ) >= RAILCOM_CH1_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME) ) //WE ARE IN THE CH1 PERIOD
    {
      if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH1_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO START SENDING CH1 BYTES?
      {
        //TOO LATE TO START SENDING BYTES SO ABORT
        FLAG_RAILCOM_IN_CUTOUT = false;
        TIMER_DCC_CONTROL.CNT = 0;
        return; //LEAVE INTERUPT
      }
     
      //2 BYTES TO SEND IF CH1 AUTORIZED
      //SENDUART(data1); //BYTE0
      //SENDUART(data2); //BYTE1
    }
   
    do {} while ( ((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH1_END_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH2_START_TIME) ); //WE ARE BETWEEN CH1 AND CH2 EMISSION INTERVAL SO WAIT
   
    if( ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) )
    {
      if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO SEND CH2 BYTES?
      {
        //TOO LATE TO START SENDING CH2 SO ABORT
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        return; //LEAVE ISR
      }
     
      //3 BYTES TO SEND IF CH2 EMISSION AUTORISED
      //SENDUARTCH2BYTE0
      //SENDUARTCH2BYTE1
      //SENDUARTCH1BYTE2
   
     
      if(USART0.TXDATAL & bitRead(USART0.STATUS,5))
      {
        //LAST BYTE SENT
        //PROCES FINAL OPERATIONS:     
        TIMER_DCC_CONTROL.CNT = 0; //RESET TIMER_RC VALUE
        FLAG_RAILCOM_IN_CUTOUT = false; //UPDATE FLAG     
        return; //LEAVE ISR
      }
    }
   
    if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CUTOUT_MAX_END_TIME)
    {
      //IF SENDING BYTE RESET SENDIND OPERAITION   
      TIMER_DCC_CONTROL.CNT = 0; //RESET TIMER_RC VALUE
      FLAG_RAILCOM_IN_CUTOUT = false; //UPDATE FLAG   
      return; //LEAVE ISR
    }
   
  }

} //END ISR

Il reste à se pencher sur l'écriture des éléments pour la gestion de l'envoi des bytes sur TX.

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 22, 2023, 12:38:31 pm
Bonjour

Quelques avancées supplémentaires avec la gestion de l émission de "datas" sur TX

Cela prend forme petit à petit.

#include "Arduino.h"

#ifndef _CLASS_RAILCOM_USART_H_
#define _CLASS_RAILCOM_USART_H_


#ifndef RAILCOM_USES_USART0
    #define RAILCOM_USES_USART0
#endif


class RAILCOM_USART
{
    public:

        static void init_RAILCOM_USART();         

        static void enable_USART_RC();

        static void disable_USART_RC();

        static void send_data_on_USART_RC(uint8_t data);


    private:

        static void init_USART_RC_PINS();

        static void init_USART_RC_MODE();

        static void USART_RC_PORTMUX_MAPPING(); 


};


#endif



#include "CLASS_RAILCOM_USART.h"


#define USART_DATABUF_SIZE 10
uint8_t dataBuf[USART_DATABUF_SIZE];
uint8_t dataBufSendPos = 0;
uint8_t dataBufInsertPos = 0;


#if defined(USART0)
    #if !defined(RAILCOM_USES_USART0)       
        #define USART_RC USART0
        #define USART_RC_NB 0
        #define USART_RC_VECTOR USART0_DRE_vect           
    #endif
    #if defined(RAILCOM_USES_USART0)   
        #define USART_RC USART0
        #define USART_RC_NB 0 
        #define USART_RC_VECTOR USART0_DRE_vect     
    #endif
#elif defined(USART1)
    #if defined(RAILCOM_USES_USART1)
        #define USART_RC USART1
        #define USART_RC_NB 1
        #define USART_RC_VECTOR USART1_DRE_vect 
    #endif
#elif defined(USART2)
    #if defined(RAILCOM_USES_UART2)
        #define USART_RC USART2
        #define USART_RC_NB 2
        #define USART_RC_VECTOR USART2_DRE_vect
    #endif
#elif defined(USART3)
    #if defined(RAILCOM_USES_USART3)
        #define UART_RC UART3
        #define USART_RC_NB 3
        #define USART_RC_VECTOR USART3_DRE_vect
    #endif
#else
    #define RAILCOM_USES_USART0
    #define USART_RC USART0
    #define USART_RC_NB 0
    #define USART_RC_VECTOR USART0_DRE_vect
#endif


#define USART_RC_BAUD_RATE(BAUD_RATE) ((float)(F_CPU * 64 / (16 * (float)BAUD_RATE)) + 0.5)


//ISR TO MANAGE TX EMISSION:
ISR(USART_RC_VECTOR)
{
    USART_RC.STATUS |= USART_DREIF_bm; //DATA REGISTER EMPTY FLAG STATE: SET IT EMPTY WITH VAL = 1
    //bitSet(USART_RC.STATUS,5);   

    noInterrupts(); //cli(); //SUSPEND ANY INTERRUPT BEHAVIOR

    USART_RC.TXDATAL = dataBuf[dataBufSendPos]; //PUT THE BYTE TO TRANSFERT INTO DATAL REGISTER
   
    dataBufSendPos++; //NEXT BUFFERED BYTE TO PROCESS AT NEXT INTERRUPT

    if (dataBufSendPos >= USART_DATABUF_SIZE) //ARRIVED AT BUFFER MAX VALUE, RETURN TO 1st POSITION
    {
        dataBufSendPos = 0;
    }

    if (dataBufSendPos == dataBufInsertPos) //TRANSFERT OF CURRENT BYTE IS OVER
    {
        USART_RC.CTRLA &= ~USART_DREIE_bm; //DISABLE DRE_INTERUPT
    }

    interrupts(); //sei(); //LET GLOBAL INTERRUPTS OCCURED

}


void RAILCOM_USART :: send_data_on_USART_RC(uint8_t data)
{
dataBuf[dataBufInsertPos] = data;

dataBufInsertPos++; //NEXT PLACE IN BUFFER FOR NEXT DATA

if (dataBufInsertPos >= USART_DATABUF_SIZE) //AT END OF BUFFER PLACE
    {
        dataBufInsertPos = 0; //START ON 1st BUFFER POOL POSITION
    }

USART_RC.CTRLA |= USART_DREIE_bm; //ENABLE DRE INTERUPT SO CALL ISR

interrupts(); //sei();

}


void RAILCOM_USART :: USART_RC_PORTMUX_MAPPING()
{
    //RAILCOM USART WOULD PREFER USE USART0 ON DEFAULT PORMUX MAPPING:
    switch(USART_RC_NB)
    {
        #if defined(USART0)
            case 0:
                #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
                    bitClear(PORTMUX.CTRLB,0);               
                #else
                    bitClear(PORTMUX.USARTROUTEA,0);
                    bitClear(PORTMUX.USARTROUTEA,1);
                #endif         
            break;
        #endif

        #if defined(USART1)
            case 1:
                #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
                  #error "ONLY 1 USART ON MEGATINY PARTS"                 
                #else
                    bitClear(PORTMUX.USARTROUTEA,2);
                    bitClear(PORTMUX.USARTROUTEA,3);
                #endif 
            break;
        #endif

        #if defined(USART2)
            case 2:
                #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
                    #error "ONLY 1 USART ON MEGATINY PARTS"               
                #else
                    bitClear(PORTMUX.USARTROUTEA,4);
                    bitClear(PORTMUX.USARTROUTEA,5);
                #endif 
            break;
        #endif

        #if defined(USART3)
            case 3:
                #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
                     #error "ONLY 1 USART ON MEGATINY PARTS"               
                #else
                    bitClear(PORTMUX.USARTROUTEA,6);
                    bitClear(PORTMUX.USARTROUTEA,7);
                #endif 
            break;
        #endif

        default:       
            #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
                bitClear(PORTMUX.CTRLB,0);               
            #else
                bitClear(PORTMUX.USARTROUTEA,0);
                bitClear(PORTMUX.USARTROUTEA,1);
            #endif         
        break;
    }
}


void RAILCOM_USART :: init_USART_RC_PINS()
{
    #if defined(_AVR_FAMILY)

        #if defined(__AVR_DA__) || defined(__AVR_DB__) || defined(__AVR_DD__) || defined(__AVR_EA__) || defined(__AVR_EB__)             
            switch(USART_RC_NB)
            {   
                case 0:               
                    //PIN_PA0 AS RAILCOM TX OUTPUT
                    PORTA.DIRSET |= PIN0_bm;
                    //PIN_PA0 HIGH STATE
                    PORTA.OUTSET |= PIN0_bm;
                    #define PORT_TX_INIT_STATE (PORTA.OUTSET |= PIN0_bm)
                 
                break;
            }
        #endif

        #if defined(__AVR_TINY_0__) || defined(__AVR_TINY_1__) || defined(__AVR_TINY_2__)
            //ONLY MEGATINY
            switch(USART_RC_NB)
            {
                case 0:
                    //PIN_PB2 AS RAICLOM TX OUTPUT:
                    PORTB.DIRSET |= PIN2_bm;
                    //PIN_PB2 AS HIGH STATE
                    PORTB.OUTSET |= PIN2_bm;
                    #define PORT_TX_INIT_STATE (PORTB.OUTSET |= PIN2_bm)
                break;
            }
        #endif

    #endif

    #if defined(MEGACOREX) || defined(ARDUINO_AVR_NANO_EVERY)

        switch(USART_RC_NB)
        {
            case 0:   
                #if defined(__AVR_ATmegax08__) && defined(MEGACOREX_DEFAULT_28_PIN_PINOUT) //28PINS ITEMS
                    //PIN_PA0 AS RAILCOM TX OUTPUT
                    PORTA.DIRSET |= PIN0_bm;
                    //PIN_PA0 HIGHT STATE
                    PORTA.OUTSET |= PIN0_bm;
                    #define PORT_TX_INIT_STATE (PORTA.OUTSET |= PIN0_bm)
                #endif

                #if defined(__AVR_ATmegax08__) && defined(MEGACOREX_DEFAULT_32_PIN_PINOUT) //32PINS ITEMS
                    //PIN_PA0 AS RAILCOM TX OUTPUT
                    PORTA.DIRSET |= PIN0_bm;
                    //PIN_PA0 HIGHT STATE
                    PORTA.OUTSET |= PIN0_bm;
                    #define PORT_TX_INIT_STATE (PORTA.OUTSET |= PIN0_bm)
                #endif

                #if defined(__AVR_ATmegax09__) || defined(ARDUINO_AVR_NANO_EVERY) //48PINS ITEMS
                    //PIN_PA0 AS RAILCOM TX OUTPUT
                    PORTA.DIRSET |= PIN0_bm;
                    //PIN_PA0 HIGHT STATE
                    PORTA.OUTSET |= PIN0_bm;
                    #define PORT_TX_INIT_STATE (PORTA.OUTSET |= PIN0_bm)
                #endif

            break;

            default:

                //PIN_PA0 AS RAILCOM TX OUTPUT
                PORTA.DIRSET |= PIN0_bm;
                //PIN_PA0 HIGHT STATE
                PORTA.OUTSET |= PIN0_bm;
                #define PORT_TX_INIT_STATE (PORTA.OUTSET |= PIN0_bm)

            break;
           
        }

    #endif
}


void RAILCOM_USART :: init_USART_RC_MODE()
{
    //AVR ALL SERIES CPU PARTS + MEGATINY CPU PARTS

    //MANAGE PINS ACCORDING PARTS AND PORMUX:

    USART_RC_PORTMUX_MAPPING();

    init_USART_RC_PINS();

    //FIXE BAUD:
USART_RC.BAUD = (uint16_t)USART_RC_BAUD_RATE(250000); //FIXE BAUD

    //SET VALUES:   
    USART_RC.CTRLB =  0 << USART_MPCM_bp       // Multi-processor Communication Mode: disabled
                    | USART_RXMODE_NORMAL_gc // Normal mode
                    | 0 << USART_ODME_bp // Open Drain Mode Enable: disabled                
                    | 0 << USART_SFDEN_bp // Start Frame Detection Enable: disabled
                    | 1 << USART_TXEN_bp // Transmitter Enable: enabled
                    | 0 << USART_RXEN_bp; // Receiver Enable: disabled

    //bitSet(USART_RC.CTRLB,6); //EQUIVALENCE
   
    USART_RC.CTRLC = USART_CHSIZE_8BIT_gc;                // 8N1 form

    //bitSet(USART_RC.CTRLC,0);     //EQUIVALENCE
    //bitSet(USART_RC.CTRLC,1);     //EQUIVALENCE
    //bitClear(USART_RC.CTRLC,2);   //EQUIVALENCE

}



void RAILCOM_USART :: enable_USART_RC()
{
//ALL PARTS FOR AVR or MEGATINY
    USART_RC.CTRLB =  0 << USART_MPCM_bp                // Multi-processor Communication Mode: disabled
                    | USART_RXMODE_NORMAL_gc // Normal mode
                    | 0 << USART_ODME_bp // Open Drain Mode Enable: disabled   
                    | 0 << USART_SFDEN_bp // Start Frame Detection Enable: disabled
                    | 1 << USART_TXEN_bp // Transmitter Enable: enabled
                    | 0 << USART_RXEN_bp; // Receiver Enable: disabled
   
    //bitSet(USART_RC.CTRLB,6); //EQUIVALENCE

}



void RAILCOM_USART :: disable_USART_RC()
{
    //ALL PARTS:
USART0.CTRLB =    0 << USART_MPCM_bp                // Multi-processor Communication Mode: disabled
            | 0 << USART_ODME_bp // Open Drain Mode Enable: disabled
            | USART_RXMODE_NORMAL_gc // Normal mode
            | 0 << USART_SFDEN_bp // Start Frame Detection Enable: disabled
            | 0 << USART_TXEN_bp // Transmitter Enable: disabled
                    | 0 << USART_RXEN_bp; // Receiver Enable: disabled

    // bitClear(USART_RC.CTRLB,6); //EQUIVALENCE

//SET PORT IN READY STATE (HIGH LEVEL)
    PORT_TX_INIT_STATE;
}



void RAILCOM_USART :: init_RAILCOM_USART()
{
    init_USART_RC_MODE();
}

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 25, 2023, 11:55:04 am
il faut tenir compte du fait que la capture doit se faire sur le rail qui va bien : si elle se fait sur le mauvais rail , le bit DCC tronqué à 29us sera désespérément plat , on n'aura pas de top de référence pour les émissions railcom
voici comment je vois l'intérieur de l'AVR :
édit : PRINCIPE POUR LES ANCIENS AVR :
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 25, 2023, 12:12:38 pm
(les 4 0402 amènent les tensions DCC dans le domaine mesurable)
grâce au MUX , l'ADC mesure alternativement le rail gauche et le rail droite , pour voir si on est sur un tronçon ABC
il faut tenir compte du fait que ces mesures perturbent la suite
l'ICP (input capture) utilise le MUX pour fonctionner sur le rail qui détient l'impulsion de 29us : ce rail est déterminé en observant les transitions bit DCC 0 <-> DCC 1 , à la mise sous tension , ou en cours de route , si l'engin passe par une boucle
compte tenu de la disparité des tension admise par la norme , il est possible que les signaux n'atteignent pas les 0.7*VCC nécessaires pour que l'ICP puisse voir un 1 logique : le comparateur y remédie , en employant la référence qui va bien ...
ne sont pas représentés , les différents filtres digitaux , qu'il faudra mettre en oeuvre en selon le MCU utilisé
 
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 26, 2023, 09:17:02 pm
Hello

Partie ABC:
Si on jette jette un œil sur le "code nippon" pour la lecture ABC, celui ci  se fonde sur le delta des impulsions perçues sur/entre les rails de droite et de gauche. Le hard associé y pourvoit par 2 entrées digital "classiques" en lecture. Les paramètres environnementaux indiquent si l'on compte ces impulsions sur le rail de droite, le rail de gauche ou si tout delta est considéré pour l'ABC. On exploite ensuite la mesure. Je trouve cela astucieux.
C'est donc traité " à part" du signal dcc exploité pour la transmission des ordres au prix de quelques broches supplémentaires utilisées. ( mais si on les a...)

RAILCOM:
En effet, comme Trimarco l'indique, le "cut" à 29us d'un bit de valeur 0 ou 1 est indifférencié lors de la capture sur 1 entrée (INPUT) en mode "event capture" et "frequence measurment" comme construit dans la lib d AIKO.
C'est pourquoi je fais ensuite la lecture des 2 ports ( 1 relié à chaque pole de rail) en entrée pour confirmer le statut d une boucle RAILCOM avec l absence de tensions dans les voies. (sinon on est pas dans un contexte railcom puisque toutes les conditions ne sont pas remplies) Il ne me semble pas important à ce stade alors de savoir de quel pole du rail provient cette détection.

Je ne me sans pas "concerné" par le soucis des 0.7v * Vcc pour le signal DCC puisque la lecture dans mon approche hardware se fait sur un pull_up piloté par un NMOSFET (ex BS138) dont la gate est pilotée par le signal DCC.
J ai donc de ce fait toujours un signal très "carré" (0 ou 1) sur l'entrée du CPU selon la bascule du NMOS.( approche similaire à être derrière un OPTO) Le "soucis de seuil" est alors un peu diffèrent car il doit alors être en capacité de faire basculer la gate du NMOSFET.( en DCC no soucis) ( en analogique de toute façon on ne tourne d'au delà de 6V, 6V5 à la voie)

Dans le cas par pont diviseur qu'indique Trimarco pour exploiter à la fois  sur les mêmes broches la lecture du signal DCC et la lecture des tensions présentes ( ou pas)  le contexte différent amène d autres points à considérer.
En ayant séparé les canaux selon les usages désirés (traitement du signal DCC, lecture tension , détection ABC, railcom, …)  je me prémunie ( au moins pour un temps) des effets de bords des uns et des autres en rendant "modulaire" l'association des éléments et à défaut cela permet de disposer d un hardware exploitable pour les fonctions de bases enrichies au fur et à mesure des blocs fonctionnels en question ( et des mises au point des codes associées).

La "fusion" sur un nombre réduit de broches est une ultime étape d optimisation que je n ai pas considéré dans cette approche initiale mais que suggère Trimarco. Elle n'est pas sans intérêt (choix judicieux à faire pour le hard entre autre et l exploitation du hard ensuite) au prix toutefois de quelques settings à combiner et éprouver.

Par ailleurs comme j'avais dans l'idée aussi de faire une lecture sur l'ADC après le pont de diode (donc le VIN type "fil bleu") ramené via un pont diviseur dans une plage compatible [0V;5V] pour être exploité par le CPU, peu m'importait le sens également.
Avec cette détection sur l'ADC je confirmais alors en cas de tension ou non sur la voie la lecture d une valeur pour les deux sens de circulation.( avantage d être derrière le pont)  On pouvait alors sur demande échantillonner la mesure de cette tension et l'exploiter.
Le sens de circulation en analogique étant alors déduit sur la présence ou non d'une tension sur la broche de capture après un timeout dcc. ( absence de trame DCC reçue) et aussi comparé par rapport à la mise sous tension du système ( lors du le setup)
On pourrait aussi au besoin, je pense, exploiter les broches utilisées pour la détection l'ABC sur le modèle que j'ai initialement proposé.

Comme indiqué précédemment il va nous falloir un "hard labo" pour éprouver ces approches. Idéalement le faire fabriquer avant la période du nouvel an chinois pour en disposer d'ici fin janvier au plus tard semble un objectif atteignable.

Qui serait intéressé pour en disposer?

Ce hard labo pourrait contenir sur un plaque proto:
un port de programmation UDPI
un support type SSOP28 pour un AVR (ATMEGA serie 0 ou AVRDx)
ponts diviseurs pour le signal et entrée ADC
circuiterie pour l ABC, le railcom, le signal DCC, la mesure BEMF
Quelques IO pour piloter des leds ou un half-bridge, une extension I2C
RX/TX pour le debug
des broches pour des liaisons filaires entre ces blocs afin de tester des implémentations différenciées

alim via DC DC? externe 5V? LDO type 7805 sur radiateur?


Qu en pensez vous?


Laurent





Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 27, 2023, 01:14:23 am
Bonsoir

Je me suis un peu plus penché sur l'ACn (Analog Comparator n) indiqué précédemment par Trimarco et ce que l ont peut en obtenir.
On y voit donc de suite l'intérêt du pont diviseur en entrée pour les mesures.

A noter qu'à la différence du croquis de Trimarco il n'est pas possible de lier directement en interne ( by software) la sortie de l'AC (out)  et ADC(in).
Je base mon constat sur les vues et options offertes par ATMEL START (cas sur un ATMEGA4809)

https://start.atmel.com/# (https://start.atmel.com/#)

(On ajoutera les composants DIGITAL GLUE LOGIC, EVENT, ANALOG COMPARATOR, ADC, ...) ce qui permettra d obtenir de quoi amorcer notre "setup" dans la parie "code review" une fois les configurations opérées.


La liaison devrait donc s opérer de façon externe pour la sortie de l'AC (PIN_PA7) (sur les AVR) vers le DAC (PIN_Pxy) en reliant ces 2 broches par une piste. ( si je ne me suis pas égaré?)


Le tableau ci joint dresse un aperçu pour des CPU de 20 24 et 32 broches
Les design hardware devront donc considérer ces info.

En vert les "optimums"

Laurent



Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 27, 2023, 11:54:28 am
"A noter qu'à la différence du croquis de Trimarco il n'est pas possible de lier directement en interne ( by software) la sortie de l'AC (out)  et ADC(in)."
mon dessin est juste , si on le lit à l'endroit
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 28, 2023, 01:50:28 pm
Bonjour

Ce que je n arrive pas à comprendre sur le schéma proposé  c'est le fonctionnement de la bascule sur l'ADC PORMUX en entrée.

Sur les séries x08 x09  & MEGATINY A un instant T0 on ne rentre qu'une valeur à la fois de broche de l'ADC MUX car il n y a que des ADCMUXPOS

Donc je ne vois pas ce qui permet de faire cette bascule ( un interruption sur un changement de "Edge" créant un event mais pris à quel endroit? ( hors schéma?)

Seuls les AVR Dx proposent un canal POXMUXPOS et un PORMUXNEG qui permettent de traiter les entrées Positives et Négatives
Les nouveaux EA offre à présent aussi un PGA pour amplifier au besoin le signal en entrée.

Il y a donc une "magie que je n ai pas encore assimilée.

Quelques explications sont nécessaires pour nous éclairer.
Si tu peux nous apporter des précisions on prend :)

Pour les valeurs des résistances je propose 47K (R1 R3) et 12K (R2 R4) ce qui permet de couvrir la plage [0v; 25v] en entrée et ramener dans la plage [0v; 5V] nos lectures.

Laurent

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 28, 2023, 06:16:32 pm
Hello

Retour sur RAILCOM:

D'après les précieuses info lues ici:
https://www.opendcc.de/info/railcom/railcom_f.shtml (https://www.opendcc.de/info/railcom/railcom_f.shtml)

Il est précisé que le CUTOUT se produit à un moment TRES précis qui m'avait jusque la échappé: je cite"  Le signal de la station centrale est coupé 29μs (+ /-3μs) après l'envoi du bit de fin d'un message DCC , puis sur on à nouveau 16μs avant la fin. Ce temps de fonctionnement on/off permet au décodeur de détecter les fronts du signal DCC."

En effet nous mesurions alors uniquement les intervalles de 26 à 32 us sans nous soucier de savoir à quelle étape ils étaient positionnés dans les trames des bits reçus considérant que si une bascule correspondait à cette situation alors nous avions un CUTOUT. Hors pour être conforme on doit être placé au "bon endroit" pour traiter les messages.

Précision importante qui fait qu'il n y a pas que le simple fait d avoir un "timing" de 26 à 32us uniquement mais aussi que celui ci survienne bien à un endroit précis d émission de la centrale et donc du traitement des messages en entrée du décodeur en réception. Après le cutout on repart sur une émission de bits de préambule ( 10 bits mini à 1) pour ensuite "assembler" les bits et former les messages DCC.

Si le dernier bit reçu est bien un 1 qui forme la fin d un message alors sa valeur est de 1.

Si je fais la projection vers la lib d AIKO on sera alors normalement dans un cas ou :

dccrecState == WAIT_PREAMBLE; ( ce qui confirme bien que cela sera un préambule qui sera ensuite attendu une fois le cutout terminé)

alors quand on quitte l'SR en cas de cutout on ne devrait pas avoir à "forcer" le statut de dccrecState = WAIT_PREAMBLE; ( on y est encore) ( mais on peut toujours l'écraser par dccrecState = WAIT_PREAMBLE;)

Par corolaire l'autre option est de vérifier pour confirmer que nous sommes bien dans un CUTOUT "conforme" et placé tel qu'attendu en contrôlant que  dccrecState == WAIT_PREAMBLE avec le "delta" compris entre 26 et 32us.

A défaut on rejetterait le fait d entrer dans le CUTOUT.

A voir si cela affine qualitativement le traitement.

Laurent





Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 29, 2023, 03:47:30 am
Hello


Voici de quoi tester!

RAILCOM est maintenant intégré dans la gestion de l'interruption avec les timing ad hoc gérant ses propres émissions.

Voila ce que cela donne

Modif de la LIB d'AIKO avec ces fichiers:

//******************************************************************************************************
//
// file:      sup_isr.cpp
// purpose:   DCC receiving code for ATmega(X) processors
// author:    Aiko Pras +LTR
// version:   2021-05-15 V1.0.0 ap Initial version
//            2023-12-xx V1.2.1 ADD RAILCOM
//
// Purpose: Select the best DCC capture code for a specific processor and board.
//
// This version of the software runs only on ATmega processors, and not on (for example) the ESP32
//
// For traditional ATmega processors, such as used on the Arduino UNO and MEGA boards, we use an
// approach where a change of the DCC input signal triggers an ISR. The ISR sets a timer to 77us,
// and once the timer fires the DCC input pin's value is read to determine if we have a 0 or a 1.
// See sup_isr_Mega.h for details
//
// For the newer ATMegaX processors, such as the ATmega4808, 4809, AVR128DA and AVR128DB,
// we try to exploit the new Event system peripheral, which can offload  certain task to hardware
// and thereby considerably improves the quality of the captured DCC input signal. Timing has become
// very precise, which means that the code should be able to run in multi-protocol environments and
// conform to the timing requirements as defined by the Rail Community (RCN-210)/
// To exploit these, the MegaCoreX or DxCore boards should be installed by the ARduino IDE:
// https://github.com/MCUdude/MegaCoreX
// https://github.com/SpenceKonde/DxCore
// See sup_isr_MegaCoreX_DxCore.h for details
// 
// If the ATMegaX 4809 processor is used on an Arduino Nano Every, but instead of the MegaCoreX board
// the 'standard' Arduino megaAVR board has been selected in the Arduino IDE, a similar decoding
// approach is used as with the traditional ATmega processors: a change of the DCC input signal
// triggers an ISR; the ISR sets a timer and once the timer fires the DCC input pin's value is read.
// Note that performance of this approach on new processors gives considerably more overhead than on
// the traditional processors. Therefore it is strongly adviced to switch to a MegaCoreX board.
//
//******************************************************************************************************
#include <Arduino.h>

#if defined(__AVR_MEGA__)
  // Only runs on Atmega (AVR) processors
  #if defined(__AVR_XMEGA__)
    // These are the new megaAVR 0, AVR DA and AVR DB processors and MegaTiny     
    #if defined (ARDUINO_AVR_NANO_EVERY)
      // This is the Arduino Nano Every, using an Arduino megaAVR board
      #include "sup_isr_Nano_Every.h"     
    #elif defined(MEGACOREX) && !defined WITH_RAILCOM
      // megaAVR 0
      #include "sup_isr_MegaCoreX_DxCore.h"
    #elif defined(MEGACOREX) && defined WITH_RAILCOM
      // megaAVR 0 & RAILCOM
      #include "sup_isr_MegaCoreX_DxCore_RAILCOM.h" 
    #elif defined(_AVR_FAMILY)
      //AVR DA DB DD (EA)(EB) or MegaTiny CPU Core
      #if !defined WITH_RAILCOM
        #include "sup_isr_MegaCoreX_DxCore.h"
      #else
        #include "sup_isr_MegaCoreX_DxCore_RAILCOM.h"
      #endif
    #endif
  #else
    // These are the traditional ATmega processors
    // Examples are ATmega16A, 328 and 2560
    #include "sup_isr_Mega.h"
  #endif
#else
  #if defined(MIGHTYCORE)
    // The 8535 isn't defined as __AVR_MEGA__, but works
    #include "sup_isr_Mega.h"
  #endif
#endif


Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 29, 2023, 03:50:05 am
La suite en 2 parties (pour s affranchir des limites de 20K caractères)

sup_isr_MegaCoreX_DxCore_RAILCOM.h :
PART 1:
//******************************************************************************************************
//
// file:     sup_isr_MegaCoreX_DxCore_RAILCOM.h
// purpose:  DCC receive code for ATmegaX processors, such as ATmega 4808, 4809, AVR DA, AVR DB, ...
//           using a MegaCoreX or DxCore board
// author:   Aiko Pras + LTR
// version:  2021-09-01 V1.2.0 ap - Uses the Event system to connect the DCC input pin to a TCB timer.
//           2023-12-10 V1.2.2 add RAILCOM support LTR
//
// Result:   1. The received message is collected in the struct "dccrec.tempMessage".
//           2. After receiving a complete message, data is copied to "dccMessage.data".
//           3. The flag "dccMessage.isReady" is set.
//
// Used hardware resources:
//  - DccPin: Any ATmega pin can be used to receive the DCC input signal
//            Polarity of the J/K signal is not important.
//  - Timer:  One TCB timer. Default is TCB0, but the default can be changed by setting one of the
//            #defines (DCC_USES_TIMERB1, DCC_USES_TIMERB2 or DCC_USES_TIMERB3)
//            No dependancies exist with other timers, thus the TCA prescaler is NOT used.
//  - Event:  One of the Event channels available in ATmegaX processors.
//            The software automatically selects an available channel.
//            Not every pin can be connected to every Event channel. If other software has already
//            claimed usage of some channels, it might be necessary to select a DCC input pin on
//            another port. See also: https://github.com/MCUdude/MegaCoreX#event-system-evsys
//
// Howto: This part of the library takes advantage of the Event system peripheral that is implemented
// in the novel ATmegaX processors, and which is supported by MegaCoreX and DxCore.
// The DCC pin is used as input for an Event channel. The output of that Event channel triggers a TCB
// timer in 'Capture Frequency Measurement Mode'. If an event occurs in this Mode, the TCB
// captures the counter value (TCBn.CNT) and stores this value in TCBn.CCMP. The Interrupt flag is
// automatically cleared after the low byte of the Compare/Capture (TCBn.CCMP) register is read.
// The value in TCBn.CCMP is the number of ticks since the previous event, thus the time since the
// previous DCC signal transition. This time determines if the received DCC signal represents (half of)
// a zero or one bit.
// Since we do not want to introduce any dependency between our TCB timer and the TCA prescaler,
// TCB is used at clock speed. This requires us to use TCB in 16 bit mode. If we would have used the
// TCA prescaler, TCB could have been run in 8-bit mode, saving us roughly 8 clock cycli.
// To conform to the RCN-210 standard, we measure the times for both first as well as second half bit.
// Therefore the TCB ISR is called twice for every DCC bit.
// Since the TCB can only trigger on positive or negative edges of the input signal, the trigger
// direction is inverted after each interrupt.
//
// This code uses the Event system of MegaCoreX and DxCore:
// https://github.com/MCUdude/MegaCoreX#event-system-evsys
// https://github.com/SpenceKonde/DxCore
//
// Note: Railcom has now been implemented.
// Timer CNT + CCMP to determine the exact moment when
// the railcom data should be set. The railcom condition occured if conditions meet timings and DCC pins state.
// A UART is started to send the railcom data in RC appropriate periods according CV28 CV29 settings.
//
//
/* IMPLEMENTED BY LTR by adding new define values for RAILCOM

*/
//
//******************************************************************************************************
#include <Arduino.h>
#include <Event.h>
#include "sup_isr.h"

#include "CLASS_RAILCOM_GLOBAL.h"


//******************************************************************************************************
// 1. Declaration of external objects
//******************************************************************************************************
// The dccMessage contains the "raw" DCC packet, as received by the TCB ISR in this file
// It is instantiated in, and used by, DCC_Library.cpp
extern DccMessage dccMessage;

//RAILCOM items:
extern RAILCOM railcom;

//******************************************************************************************************
// 2. Defines that may need to be modified to accomodate certain hardware
//******************************************************************************************************
// Timer to use: TIMERB0 (TCB0), TIMERB1 (TCB1), TIMERB2 (TCB2), TIMERB3 (TCB3)
// In many cases TCB0 or TCB1 are still available for own use.
// The default is TCB0, which is available on all processor variants.
// This can be overruled by setting one of the following defines:
// #define DCC_USES_TIMERB1
// #define DCC_USES_TIMERB2
// #define DCC_USES_TIMERB3


// GPIOR (General Purpose IO Registers) are used to store global flags and temporary bytes.
// For example, in case of dccHalfBit, GPIOR saves roughly 8 clock cycli per interrupt.
// In case the selected GPIORs conflict with other libraries, change to any any free GPIOR
// or use a volatile uint8_t variable
#define dccrecState GPIOR0                     // fast: saves 3 clock cycli, but requires a free GPIOR
// volatile uint8_t dccrecState;               // slow, but more portable
#define tempByte GPIOR1                        // fast
// volatile uint8_t tempByte;                  // slow
#define dccHalfBit GPIOR2                      // fast
// volatile uint8_t dccHalfBit;                // slow

//ADD VARIABLES FOR RAILCOM:

#define FLAG_RAILCOM_IN_CUTOUT GPIOR3          //fast
//volatile bool FLAG_RAILCOM_IN_CUTOUT         //slow


//******************************************************************************************************
// 3. Defines, definitions and instantiation of local types and variables
//******************************************************************************************************
// 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

//ADD RAILCOM VALUES: LTR 20231210 follow RCN-217: https://normen.railcommunity.de/RCN-217.pdf last updated on 20231123

#define RAILCOM_CUTOUT_MIN_START_TIME   F_CPU/1000000 * 26        //MIN CUTOUT START TIME
#define RAILCOM_CUTOUT_MAX_START_TIME   F_CPU/1000000 * 32        //MAX CUTOUT START TIME

#define RAILCOM_CH1_START_TIME          F_CPU/1000000 * 75        //MIN CH1 START TIME
#define RAILCOM_CH1_MAX_START_TIME      F_CPU/1000000 * (80+15)   //MAX CH1 SEND START TIME
#define RAILCOM_CH1_END_TIME            F_CPU/1000000 * 177       //MAX CH1 END TIME
#define RAILCOM_CH2_START_TIME          F_CPU/1000000 * 193       //MIN CH2 START TIME
#define RAILCOM_CH2_MAX_START_TIME      F_CPU/1000000 * (193+15)  //MAX CH2 SEND START TIME
#define RAILCOM_CH2_END_TIME            F_CPU/1000000 * 454       //END CH2
#define RAILCOM_CUTOUT_MAX_END_TIME     F_CPU/1000000 * 488       //MAX CUTOUT TIME



// #define ZERO_BIT_MAX 65535
// Change the defines for ZERO_BIT_MAX to enable (disable) zero-bit stretching.
// To avoid integer overflow, we don't allow 10000 microseconds as maximum, but 65535 (maxint)
// For a 16Mhz clock this is equivalent to 4096 microseconds. This might work on most systems.
// For a discussion of zero bit streching see: https://github.com/littleyoda/sigrok-DCC-Protocoll/issues/4

// Possible values for dccrecState
#define WAIT_PREAMBLE       (1<<0)
#define WAIT_START_BIT      (1<<1)
#define WAIT_DATA           (1<<2)
#define WAIT_END_BIT        (1<<3)

// Possible values for dccHalfBit
#define EXPECT_ZERO         (1<<0)
#define EXPECT_ONE          (1<<1)
#define EXPECT_ANYTHING     (1<<2)

struct {
  uint8_t bitCount;                           // Count number of preamble bits / if we have a byte
  volatile uint8_t tempMessage[MaxDccSize];   // Once we have a byte, we store it in the temp message
  volatile uint8_t tempMessageSize;           // Here we keep track of the size, including XOR
} dccrec;                                     // The received DCC message is assembled here



//******************************************************************************************************
// 4. Initialise timer and event system
//******************************************************************************************************
void DccMessage::initTcb(void) {
  // Step 1: Instead of calling a specific timer directly, we use alias via #defines
  #if defined(DCC_USES_TIMERB0)
    #define TIMER_DCC_CONTROL TCB0 
  #elif defined(DCC_USES_TIMERB1)
    #define TIMER_DCC_CONTROL TCB1
  #elif defined(DCC_USES_TIMERB2)
    #define TIMER_DCC_CONTROL TCB2
  #elif defined(DCC_USES_TIMERB3)
    #define TIMER_DCC_CONTROL TCB3
  #else 
    // fallback to TCB0 (every platform has it)
    #define TIMER_DCC_CONTROL TCB0;
  #endif
  // Step 2: fill the registers. See the data sheets for details
  noInterrupts();
  // Clear the main timer control registers. Needed since the Arduino core creates some presets:
  TIMER_DCC_CONTROL.CTRLA = 0;
  TIMER_DCC_CONTROL.CTRLB = 0;
  TIMER_DCC_CONTROL.EVCTRL = 0;
  TIMER_DCC_CONTROL.INTCTRL = 0;
  TIMER_DCC_CONTROL.CCMP = 0;
  TIMER_DCC_CONTROL.CNT = 0;
  TIMER_DCC_CONTROL.INTFLAGS = 0;
  // Initialise the control registers:
  TIMER_DCC_CONTROL.CTRLA = TCB_ENABLE_bm;                    // Enable the TCB peripheral, clock is CLK_PER (=F_CPU)
  TIMER_DCC_CONTROL.CTRLB = TCB_CNTMODE_FRQ_gc;               // Input Capture Frequency Measurement mode
  TIMER_DCC_CONTROL.EVCTRL = TCB_CAPTEI_bm | TCB_FILTER_bm;   // Enable input capture events and noise cancelation
  TIMER_DCC_CONTROL.INTCTRL |= TCB_CAPT_bm;                   // Enable CAPT interrupts
  interrupts();
}

void DccMessage::initEventSystem(uint8_t dccPin) {
  // Note: this code uses the new Event Library of MegaCoreX, DXCore & MEGATINYCore:
 
  noInterrupts();

  Event& myEvent = Event::assign_generator_pin(dccPin);

  #if defined(DCC_USES_TIMERB0)
    myEvent.set_user(user::tcb0_capt);
  #elif defined(DCC_USES_TIMERB1)
    myEvent.set_user(user::tcb1_capt);
  #elif defined(DCC_USES_TIMERB2)
    myEvent.set_user(user::tcb2_capt);
  #elif defined(DCC_USES_TIMERB3)
    myEvent.set_user(user::tcb3_capt);
  #else
    // fallback to TCB0 (every platform must have it)
    myEvent.set_user(user::tcb0_capt);
  #endif


  //start EVENTS:
  myEvent.start();

  interrupts();
}


//******************************************************************************************************
// 5. attach() / detach()
//******************************************************************************************************
void DccMessage::attach(uint8_t dccPin, uint8_t ackPin) {
  // Initialize the local variables
  _dccPin = dccPin;
  tempByte = 0;
  dccrecState = WAIT_PREAMBLE;
  dccrec.bitCount = 0;
  // initialise the global variables (the DccMessage attributes)
  dccMessage.size = 0;
  dccMessage.isReady = 0;
  // Initialize the peripherals: (TCBx) timer and the Event system.
 
  initTcb();

  initEventSystem(dccPin);
  // Initialise the DCC Acknowledgement port, which is needed in Service Mode
  // If the main sketch doesn't specify this pin, the value 255 is provided as
  // (invalid) default.
  if (ackPin < 255) pinMode(ackPin, OUTPUT);
 
}


void DccMessage::detach(void) {
  noInterrupts();
  // Clear all TCB timer settings
  // For "reboot" (jmp 0) it is crucial to set INTCTRL = 0
  TIMER_DCC_CONTROL.CTRLA = 0;
  TIMER_DCC_CONTROL.CTRLB = 0;
  TIMER_DCC_CONTROL.EVCTRL = 0;
  TIMER_DCC_CONTROL.INTCTRL = 0;
  TIMER_DCC_CONTROL.CCMP = 0;
  TIMER_DCC_CONTROL.CNT = 0;
  TIMER_DCC_CONTROL.INTFLAGS = 0;

  // Stop the Event channel  interrupts();
  interrupts();
 
}

Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 29, 2023, 03:51:01 am
La suite

sup_isr_MegaCoreX_DxCore_RAILCOM.h :
PART2:

//******************************************************************************************************
// 6. The Timer ISR, which implements the DCC Receive Routine
//******************************************************************************************************
// Execution of this DCC Receive code typically takes between 3 and 8 microseconds.
// Select the corresponding ISR
#if defined(DCC_USES_TIMERB0)
  ISR(TCB0_INT_vect) {
#elif defined(DCC_USES_TIMERB1)
  ISR(TCB1_INT_vect) {
#elif defined(DCC_USES_TIMERB2
  ISR(TCB2_INT_vect) {
#elif defined(DCC_USES_TIMERB3)
  ISR(TCB3_INT_vect) {
#else
  // fallback to TCB0 (all platform have it)
  ISR(TCB0_INT_vect) {
#endif
 
  TIMER_DCC_CONTROL.EVCTRL ^= TCB_EDGE_bm;                         // Change the event edge at which we trigger
  uint16_t  delta = TIMER_DCC_CONTROL.CCMP;                        // Delta holds the time since the previous interrupt
  uint8_t DccBitVal;

  if(delta < RAILCOM_CUTOUT_MIN_START_TIME)
  {
    //It may be a glitch or parasit so cancel elapsed time since last interupt < 26us
    FLAG_RAILCOM_IN_CUTOUT = false;   
    TIMER_DCC_CONTROL.CNT = 0;
    dccrecState = WAIT_PREAMBLE;
    dccHalfBit = EXPECT_ANYTHING;
    dccrec.bitCount = 0;
    railcom.stop_TX();

    return; //it s a glitch so ignore it and leave ISR
  }

  if(FLAG_RAILCOM_IN_CUTOUT == false)
  {
    railcom.stop_TX(); //FORCE TX STATE READY
   
    //check if we are in CUTOUT TIMINGS [26us;32us] + last bit received was "1" to set a end of DCC message:
    if( ( (delta <= RAILCOM_CUTOUT_MAX_START_TIME) && (delta >= RAILCOM_CUTOUT_MIN_START_TIME) ) && (dccrecState == WAIT_PREAMBLE))
    { //WE ARE IN CUTOUT START INTERVAL  && LAST "END BYTE" PREVISOULY RECEIVED OK
     
      FLAG_RAILCOM_IN_CUTOUT = true;

    }
    else //we should receive now O or 1 bits:
    {       
      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
          TIMER_DCC_CONTROL.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;
        }
      }   

      #include "sup_isr_assemble_packet.h"
   
    } //END BITS MANAGEMENT
  } //end FLAG RAILCOM == false

  /* /NOT REQUIRED HERE DUE TO EVER TESTED PREVIOUSLY
  if((FLAG_RAILCOM_IN_CUTOUT) && (dccrecState != WAIT_PREAMBLE)) //WE ARE NOT IN RAILCOM CUTOUT CONDITIONS
  {
    FLAG_RAILCOM_IN_CUTOUT = false;
    TIMER_DCC_CONTROL.CNT = 0;
    dccrec.bitCount = 0;
    dccHalfBit = EXPECT_ANYTHING;
    dccrecState = WAIT_PREAMBLE;
   
    return; //LEAVE ISR
   
  }
  */

  if(FLAG_RAILCOM_IN_CUTOUT) ///WE ARE IN RAILCOM CUTOUT AT GOOD POINT
  {     
    if((!railcom.CH1_EMISSION_STATE) && (!railcom.CH2_EMISSION_STATE)) //SEND ANY DATA ON ANY CHANNEL
    {
      //railcom.stop_TX(); //FORCE TX IN WAIT STATE AT LEVEL ON

      do{railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta ) <= RAILCOM_CH2_END_TIME); //WAIT TILL END OF CUTOUT TIMING LEAVING AREA //shoule be an immediate leave too

      //LEAVING AREA OCCURED SO RESET VALUES AND LEAVE ISR
      FLAG_RAILCOM_IN_CUTOUT = false;
      TIMER_DCC_CONTROL.CNT = 0;
      dccrec.bitCount = 0;
      dccrecState = WAIT_PREAMBLE;
      dccHalfBit = EXPECT_ANYTHING;
      railcom.stop_TX(); //SET TX IN WAIT STATE

      return; //LEAVE ISR

    }   
    else if((railcom.CH1_EMISSION_STATE) && (railcom.CH2_EMISSION_STATE)) //CH1 & CH2  EMMISSION AUTHORISED
    {     
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH1_START_TIME); //WAIT TILL 75us ARRIVAL TO START TO SEND BYTE ON UART
   
      if( ((TIMER_DCC_CONTROL.CNT + delta ) >= RAILCOM_CH1_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME) ) //WE ARE IN THE CH1 PERIOD
      {
        if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH1_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO START SENDING CH1 BYTES?
        {
          //TOO LATE TO START SENDING BYTES SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //2 BYTES TO SEND IF CH1 EMISSION AUTORIZED
        railcom.Send_CH1_Messages();
      }

      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH2_START_TIME);  //WE ARE BETWEEN CH1 AND CH2 EMISSION INTERVAL SO WAIT TILL CH2 START TIME if required

      if( ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) ) //WE ARE IN CH2 TIMING AREA
      {
        if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO SEND CH2 BYTES?
        {
          //TOO LATE TO START SENDING CH2 SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;       
          TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //3 BYTES TO SEND IF CH2 EMISSION AUTORISED
        //SENDUARTCH2BYTE0
        //SENDUARTCH2BYTE1
        //SENDUARTCH1BYTE2

        railcom.Send_CH2_Messages();
   
      }

      //SENDING CH2 IS OVER BEFORE CH2 END TIME SO MAY REQUIRE TO WAIT BEFORE LEAVING AREA, this case should theorically never happen!)
      do {railcom.stop_TX();} while ( (TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME);
     
      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_END_TIME) && (TIMER_DCC_CONTROL.CNT + delta <= RAILCOM_CUTOUT_MAX_END_TIME))
      {
        //SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CUTOUT_MAX_END_TIME)) //should never happen
      {
        //CUTOUT AREA IS OVER AND SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

    }
    else if((railcom.CH1_EMISSION_STATE) && (!railcom.CH2_EMISSION_STATE)) //CH1 EMISSION AUTHORISED & CH2 EMMISSION NOT AUTHORISED
    {
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH1_START_TIME); //WAIT TILL 75us ARRIVAL TO START TO SEND BYTE ON UART
   
      if( ((TIMER_DCC_CONTROL.CNT + delta ) >= RAILCOM_CH1_START_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME) ) //WE ARE IN THE CH1 PERIOD
      {
        if(TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH1_MAX_START_TIME) //ARE WE OVER THE TIME LIMIT TO START SENDING CH1 BYTES?
        {
          //TOO LATE TO START SENDING BYTES SO ABORT
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX();

          return; //LEAVE INTERUPT
        }
       
        //2 BYTES TO SEND IF CH1 EMISSION AUTORIZED
        railcom.Send_CH1_Messages();
      }

      //CH1 EMISSION IS OVER BUT MAY BE EARLIER AS CH1 END TIMOUT
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH1_END_TIME);  //WAIT CH1 END AREA if required

      //WE ARE NOW BETWEEN CH1 END TIME AND CH2 END TIME
      do {railcom.stop_TX();} while ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME);  //WAIT CH2 END AREA

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CH2_END_TIME) && (TIMER_DCC_CONTROL.CNT + delta <= RAILCOM_CUTOUT_MAX_END_TIME))
      {
        //SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }

      if((TIMER_DCC_CONTROL.CNT + delta > RAILCOM_CUTOUT_MAX_END_TIME)) //should never happen
      {
        //CUTOUT AREA IS OVER AND SENDING IS OVER NOW: RESET VALUE AND LEAVE ISR
        FLAG_RAILCOM_IN_CUTOUT = false;       
        TIMER_DCC_CONTROL.CNT = 0; //RST TIMER_DCC CNT VALUE
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR

      }

    }   
    else if((!railcom.CH1_EMISSION_STATE) && (railcom.CH2_EMISSION_STATE)) //CH1 EMISSION NOT AUTHORISED & CH2 EMISSION AUTHORISED
    {
      do {railcom.stop_TX();} while((TIMER_DCC_CONTROL.CNT + delta) < RAILCOM_CH2_START_TIME); //WAIT TILL CH1 AREA IS OVER

      if ( ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) )
      {
        if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH2_MAX_START_TIME)
        {
          //TOO LATE TO START SENDING BYTES SO ABORT:
          FLAG_RAILCOM_IN_CUTOUT = false;
          TIMER_DCC_CONTROL.CNT = 0;
          dccrec.bitCount = 0;
          dccrecState = WAIT_PREAMBLE;
          dccHalfBit = EXPECT_ANYTHING;
          railcom.stop_TX(); //SET TX IN WAIT STATE

          return; //LEAVE ISR
        }
       
        //3 BYTES TO SEND IF CH2 EMISSION AUTORISED
        //SENDUARTCH2BYTE0
        //SENDUARTCH2BYTE1
        //SENDUARTCH1BYTE2
        railcom.Send_CH2_Messages();

      }

      //SENDING IS OVER BUT EARLIER AS CH2 END STATE SO WE WAIT A BIT => theorically should never happen
      do {railcom.stop_TX();} while ( ((TIMER_DCC_CONTROL.CNT + delta) <= RAILCOM_CH2_END_TIME) && ((TIMER_DCC_CONTROL.CNT + delta) >= RAILCOM_CH2_START_TIME) ) ; //WAIT TILL END CUTOUT CH2 AREA CONDITIONS

      if(((TIMER_DCC_CONTROL.CNT + delta) <=  RAILCOM_CUTOUT_MAX_END_TIME ) && ((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CH2_END_TIME))
      {
        //CUTOUT AREA TIMING CH2 IS OVER NOW SO UPDATE VALUES:
        FLAG_RAILCOM_IN_CUTOUT = false; //LEAVE CUTOUT STATE
        TIMER_DCC_CONTROL.CNT = 0; //RESET CNT
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE   
       
        return; //LEAVE ISR BETWEEN 454 & 488us //should be leave earlier too but need to wait hten to receive new dcc bits   
      }

      if((TIMER_DCC_CONTROL.CNT + delta) > RAILCOM_CUTOUT_MAX_END_TIME) //should never happen
      {
        //WE ARE OVER THE CUTOUT AREA
        FLAG_RAILCOM_IN_CUTOUT = false; //LEAVE CUTOUT STATE
        TIMER_DCC_CONTROL.CNT = 0; //RESET CNT
        dccrec.bitCount = 0;
        dccrecState = WAIT_PREAMBLE;
        dccHalfBit = EXPECT_ANYTHING;
        railcom.stop_TX(); //SET TX IN WAIT STATE

        return; //LEAVE ISR
      }
    }
  }

} //END ISR

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 29, 2023, 10:42:20 am
au temps pour moi , j'ai indiqué le principe pour des AVR classiques , ce qui t'a confusionné ...
les comparateurs des nouveaux AVR disposent de leur propre MUX d'entrée , donc le principe est le suivant :
PRINCIPE POUR LES NOUVEAUX AVR :
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 29, 2023, 11:08:59 am
la contrainte , c'est qu'il faut choisir 2 pins qui peuvent être reliées à la fois à l'ADC et à un comparateur , mais il y a moult combinaisons possibles , à déterminer lors du dessin du PCB
à vérifier , mais rien ne semble empêcher que les 2 périphériques puissent être reliés simultanément , donc en permanence , aux 2 pins : cela simplifie bien l'analyse
pour que tout le monde comprenne , détaillons un peu  ; le décodeur est aimenté par un pont de Graetz , qui fixe peu ou prou le GND du décodeur à la tension du rail négatif (ce qui fait que du GND du décodeur est également proche du GND de la station DCC)
vu du décodeur , les tensions sur les 2 rails ont donc cette allure :

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 29, 2023, 11:27:24 am
les tensions vues sur le rail de droite sont l'inverse de celles du rail de gauche
j'ai représenté une différence entre les 2 tensions , on est donc sur une section dont l'ABC est actif
l'ADC mesure chaque rail après son front montant , on peut donc déterminer si on est en ABC actif , ou pas

le comparateur va voir la même chose :
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 29, 2023, 11:33:59 am
ici , c'est sur le rail gauche qu'on a l'impulsion tronquée à 29us , dont on va capturer le front montant , qui sert de base aux timings du cutout ; c'est aussi sur ce rail qu'on va devoir vérifier que la tension est bien revenue à 0v , au bout de 29us , pour lancer le canal 1
d'où la nécessité de choisir le "bon" rail , parmi les 2 , en entrée du comparateur
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 29, 2023, 03:01:50 pm
Bonjour

Merci pour ces updates. On voit en effet que c est un peu diffèrent.

Les nouveaux AVR disposent tous à minima d'un ADC. La série 1 des MEGATINY en dispose de 2! ( c est la seul série qui en dispos d autant!).
Toutefois les plus "véloces" ( AVR Dx) ont 2 entrées (une pour pole "négatif" et l'autre pour pole "positif". Ce n'est pas le cas sur les séries plus anciennes comme la série 0 des AVR (ATMEGAx08 et x09) et les MEGATINY des séries 0 et 1.

Ces quelques différences à priori minimes nous imposent donc aussi d'être vigilant sur les besoins vs capacités du hard surtout si l approche se veut d'une solution "transposable" d'un CPU à l'autre.

J ai quand même (encore) un gros point dure. Je ne dois pas être le seul...

Traitons le cas de base avec justement un AVR X08 ou X09 de la série 0. ( ce cas est exploitable sur tous les hard)

A un instant T0 tu n'as qu'avec l'ADCMUX 1 canal de lié au DAC. Si c est la rail de gauche alors on le considère comme "positif" et son voisin de droite est lui un "pseudo GND".
(On pourrait aussi être dans un cas inverse mais il faut bien amorcer dans un sens ou l autre)

Ensuite, dans le temps les "signaux" DCC vont s'inverser.

Il y a donc bien un "fait générateur" qui va modifier la valeur du PORMUX de l'ADC pour connecter alors l'autre broche? ( ou alors tu lis toujours sur la même?) C est la"truc magique" que je ne capte pas!

Je serai tenté de dire que cela pourrait être justement la sortie du COMPARATEUR qui filtre sur les fronts montants chaque changement. ( encore aucune idée de la façon de l'écrire à ce stade ou j essaye de voir les bloc, leurs relations et donc leur liaisons.

Ou alors tu as autre chose en vue mais je n ai pas encore transcrit le concept en solution.


Laurent


Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 29, 2023, 09:21:28 pm
Bonsoir

Au sujet des "poly affectations des broches" rien ne semble l interdire ni non plus le permettre.

ATMEL START ne le permet pas. ( est ce l outils qui est limité?)

MPLAB MCC indique qu'il y a bien un lien avec plusieurs usages.

Je ne sais pas ce que sort ATMEL STUDIO à ce sujet...

C est donc un peu un flou... qu il faut pourtant lever.


Ltr

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le décembre 30, 2023, 05:18:38 pm
oui , il faut faire un petit test pour valider le principe ... par exemple une petite maquette avec une CS qui tourne à une vitesse divisée par 1000 ... on n'y coupera pas
normalement , la capture se fait toujours sur le même rail , mais pour l'ABC , il faut mesurer les 2 rails : on peut par exemple déclencher une mesure après un front montant , puis l'autre après un front descendant
je pense que si on fait cette mesure une seule fois pour chaque packet , ça peut suffire
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 31, 2023, 04:39:14 pm
Bonjour

Je vais essayer de définir la trame de l enchainement des principales étapes sur la base de ma compression actuelle du processus.
Les initialisation des blocs seront traiter en conséquence plus tard une fois que cette trame sera " au carré"

Pre requis:
choisir 2 pins sur le CPU pour y introduire le signal DCC via pont diviseur
ces 2 pins sont idéalement:

Pour une portabilité "optimale" on se reportera au tableau fourni précédemment. ( Pour les AVR le port D est optimal et rempli les conditions posées)

Une fois posées les entrées + et - du comparateur on a donc un état qui permet en sortie de comparateur d identifié si on est à un instant T avec un signal venant du rail de droite ou du rail de gauche.

Rm par CONVENTION avec l'analogique le rail de droite dans le sens normal de la marche est TOUJOURS le pole +.

On s appliquera le même principe ici en définissant SIGN_DCC_R comme le signal, provenant du rail de droite sur l'entrée non inverseuse du comparateur ( +)
Et réciproquement SIGN_DCC_L sur l entrée inverseuse (-) ( pole GND du rail en analogique)

(voir plus tard la table logique)

Ces précisions apportées, exploitons à présent la sortie du comparateur.

Au niveau du comparateur, sur la détection RISING, donc à chaque changement d'état montant du signal en entrée sur le comparateur ( sur chaque pole) dans le cas où le signal DCC est sur le rail de droite alors  la sortie du comparateur = "1",  on peut actualiser  la lecture sur le pole du rail droit relié à  ADC ( ADC0.PORMUX= PIN_SIGN_DCC_R) et inversement lorsque la sortie est sur la valeur opposée.
Si la sortie du comparateur = 0 on pourra procéder a la lecture de l'autre rail.

On doit voir si on fait une lecture simple ou échantillonnée ( 2 lectures? 4? 8 ? ...)

Si on est dans un ISR pour ces mesures on aura tendance à en sortir au plus vite... donc à réduire l échantillonnage à un faible nombre de valeurs.

On comparera alors si les 2 valeurs sont d ordre similaire ( avec une marge seuil bas < val mesurée < seuil haut) ou les seuils bas et hauts seront issus de la lecture de l autre pole mesuré auquel est affecté aussi avec un coefficient de "correction" par exemple seuil bas_rail_droit = 0.8 x val_seuil_mesuré_sur_rail_gauche, en deca de ce seuil alors on serait dans le cas d'un freinage ABC. On appliquerait alors une fonction visant à réduire progressivement la vitesse du moteur ( alors que la valeur reçue et émise par la centrale reste la valeur de vitesse désirée de l engin moteur.)

Lorsque la symétrie du signal DCC est rétablie ( donc que les conditions ayant entrainées le déclanchement du signal ABC ont disparue) alors notre engin doit reprendre son déplacement avec une accélération progressive jusqu'à la vitesse de commande émise par la centrale.

Nous avons donc le mécanisme de base.
Sur un timing DCC on sait que la bascule interviendra proche de 58us pour un demi bit 1 au plus court sinon proche de 29us pour un cutout railcom.

Dans ce cas on en déduit que le temps maxi de la séquence "lecture" devra être contenu en deçà de ces valeurs (sinon impacts et effets de bords)

Ltr





Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 31, 2023, 05:35:14 pm
Phase 2:

Nous avons notre sortie de comparateur qui va donc exploiter soit une sortie physique soit un interruption. ( au choix l'un ou l'autre pas les deux!)

On pourrait exploiter la sortie en la reliant à une entrée liée au timer en charge de la détection des bits des trames DCC. Câblage externe. Mais on se priverait alors d'exploiter un ISR qui pourrait traiter cela plus nativement et inclure aussi plus d'actions diverses ( mais toujours les plus brèves possibles) (dont entre autre les lectures sur les entrées de l ADC).

Cote ABC on aura quelques chose proche de ceci:

uint16_t GET_ABC_VAL()//GIVE RESULT FROM ACTIV INPUT FOR ABC USAGES
{
  if(comparator.read())                     //SELECT INPUT ACCORDING ACTIV PIN
  {
    ADC0.MUXPOS = DCC_PIN_RIGHT;            //RAIL + AS INPUT
  }
  else
  {
    ADC0.MUXPOS = DCC_PIN_LEFT;             //RAIL - AS INPUT
  }

  ADC0.COMAND = ADC_STCONV_bm;                   //START MEASURMENT
 
  while( !(ADC0.INTFLAGS & ADC_RESRDY_bm) )    //WAIT TILL IT IS OVER
  {
    ; //WAIT TILL IT IS IN PROGRESS
  }
 
  ADC0.INTFLAGS = ADC_RESRDY_bm;              //CLEAR INTERRUPT FLAG WRITTING 1
 
  return ABC_IN_VALUE = ADC0.RES;                 // PUSH VALUE
 
  }


Si cette interruption est justement celle qui gère de décodage les bits 0 et 1 en lien avec un TIMERBx on doit avoir le moteur de traitement opérationnel. Comment y parvenir?

Il faut pour cela identifier la maille pour liaisonner ces éléments entre eux. ( l'AC et la capture sur le TIMERB via la broche DCC_IN, pour notre cas liée au rail de droite)

C est le lien du schéma de Trimarco entre la sortie du COMPARATEUR (AC)  et l'entrée du TIMERBn en entrée.

Cela a beau être un "grand mécano" la construction n'est toutefois pas innée pour moi (sorry!)

Reste donc cette liaison à produire.

Ltr



Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le décembre 31, 2023, 07:54:09 pm
Il semble que cette configuration soit en fait "triviale" avec les lignes ci dessous ( soit j'ai encore du grain à moudre :) )

Considérons que les trames DCC sont traitées sur le TIMERB0 mis en mode FREQ (Input Capture Frequency Measurement Mode).

EVSYS_GENERATOR_AC0_OUT_gc est bien la sortie du comparateur ( pas nécessairement la sortie physique mais l'état de sortie de la comparaison réalisée par le composant)

EVSYS.CHANNEL0 = EVSYS_GENERATOR_AC0_OUT_gc;   /* Analog Comparator 0 out */ //On liaisonne le CHANNEL0 à la sortie du comparateur
EVSYS.USERTCB0 = EVSYS_CHANNEL_CHANNEL0_gc;     /* Connect user to event channel 0 */ //On applique au TIMBERB0 le CHANNEL0 comme source

On liaisonne ainsi les états de sortie ( 0 ou 1)   du comparateur comme les trames entrantes dans la capture du TIMERB0 de façon identique au fait qu'elles proviendraient alors d une broche

Dans la lib d AIKO c est la broche  "dccPin" qui traite cela.

Il va donc falloir voir pour ajuster le tout selon ces éléments.

Ltr





Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 03, 2024, 01:13:01 pm
Bonjour

Quelles que news en ce début d année que je souhaite excellente à chacun.

L'intégration de la partie COMPARATEUR est traitée en sus de la partie RAILCOM ( qui inclue l'émission des trames RC sur TX).
Cela compile sur les différents HARD. Il faudra encore tester ensuite et vérifier à l'oscillo. (chaque chose en son temps!)

La partie COMPARATEUR est traitée de façon à être "transparente" pour "s'auto construire" ( en cas de non paramétrage natif) sur les différents hardwares de 20 broches et plus. Il faut cependant OBLIGATOIREMENT  respecter les conditions suivantes d'attribution de broches: (on peut forcer une conf par paramétrage dans les instructions de compilation ( sous platformio) ou via des #define à commenter/décommenter selon les souhaits retenus)



Toutes les autres combinaisons exotiques ne sont pas supportées mais, la solution proposée reste valable. Elle pourra faire l'objet d'évolutions ultérieures à ce niveau au besoin. Elles seraient dans ce cas dictées par des besoins de routage HARDWARE pour faciliter un design ou corriger un bug sur les sélections proposées.

Je suis actuellement penché sur la partie ADC.
J ai quelques lacunes sur son initialisation à combler pour avoir une approche satisfaisante de l'initialisation et une syntaxe efficace.

La multiplicité des versions d ADC des CPU, impose de traiter chaque cas ce qui est un peu long à construire. Cela progresse néanmoins.


Je profite de la circonstance pour poser les bases d'une réflexion pour la mesure de la FCEM et des lectures des entrées ABC.

Utilisation du TIMER RTC avec un intervalle de temps défini? Ou laisser dans la boucle les lectures, ou bien encore profiter du cutout...

A voir
je suis preneur des idées à ce sujet.

Laurent






Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 05, 2024, 11:49:04 am
Bonjour

L'utilisation du TIMER RTC peut être problématique.

En effet nativement un interruption liée au RTC ( ou au PIT) est prioritaire sur celle qui proviennent de la capture de notre TIMERB utilisé par la décodage. Ce qui signifie que lorsque elle se produit alors on ne "voit" pas les inputs du signal DCC qui doit en principe être prioritaire. Elle a donc besoin d'être "aussi brève que possible"

On a donc le choix de rester dans la boucle, quitte à pousser une interruption de type RTC sur une simple bascule de valeur qui ouvrirait un traitement sur la boucle principale via changement d'état d une variable de type BOOL

Autre solution, changer la priorisation des vecteurs d interruption en passant celui lié à la gestion des trames DCC comme étant celui le plus prioritaire.(modif de la valeur CPUINT.LVL1VEC) ( ou la chaine des interruptions CPUINT.CTRLA pour l'activation du mode ROUNDROBIN en ciblant celui qui constitue le plus prioritaire dans la pile)

A voir dans ce cas aussi les effets de bord  si par exemple avec une gestion de PWM sur le TIMERA cela "mouline toujours bien"...

Le cas d'usage la variable dans la boucle globale et de l'ISR semble plus simple ( variable à déclarer comme "volatile bool mavariable;" pour être modifiable dans l ISR et hors ISR sans écueil!)

Le déclanchement de mesure de la BEMF dans la boucle avec modification de la condition de départ toutes les 100ms semble être jouable selon ce mode

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 05, 2024, 12:07:23 pm
Re

J ai achevé la partie de traitement de l'ADC pour les 3 types ( MEGATINY Série 0 et 1 et ATMEGA x8 x9(Type1), AVRDx (type 2), AVR Ex et TINY série 2 (type3)) et pour 2 config d'attribution de broche sur chaque CPU!

Le mode en  lecture simple est retenu pour les mesures.
La vitesse de l'ADC est comprise entre 1 et 1,5Mhz selon les vitesses des CPU et diviseurs applicables ( un choix de cible 1Mhz quasi constant était aussi possible sur de nombreuses implémentations, non retenu pour aller au plus vite selon les cas jusqu'à 1.5Mhz) ( 1.5Mhz @24Mhz 1.250@20Mhz , 1Mhz@16Mhz 1.250@10Mhz et 1.2Mhz@8Mhz)
On reste toutefois sur des optimums pour chaque cas.

La compilation passe!
Les tests à suivre...

Il reste toutefois un point:

La restitution est pour les types 1 et 2 encodée sur 10BITS (dans un uint16_t)
MAIS le type 2 sort sur 12 BITS. ( toujours dans un uint16_t) ( pas de problème de contenant)

Pour une exploitation simplifiée je pense que la mise en forme va devoir être opérée par une "règle de trois" afin de lisser à 10 BITS toutes les valeurs reçues et ensuite appliquer les mêmes paramètres d'utilisation.

Des avis?

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 05, 2024, 08:39:22 pm
Bonsoir

Premiers tests globaux en cours

Premier constat un soucis de compilation avec les AVR EA EB ( lib event en cause à priori) mais ces séries sont encore en support non complet via DX_CORE.

Une solution de "contournement" est de ne pas s'appuyer sur la librairie EVENT fournie et de se "tarter à la mano" les settings, comme j'ai pu le faire pour intégrer l'ARDUINO NANO EVERY ( sans MEGATINYCORE) afin de s'appuyer sur la fonctionnalité EVENTSYS (sur laquelle s'appui EVENT).

A voir donc mais pour le moment c est la seule série de CPU qui se montre rebelle.

Atmega x08 et x09 = OK (MEGACOREX)
NANOEVERY = OK
MEGATINY Série 0 1 2 = OK (MEGATINYCORE)
AVR DA DB DD = OK (DXCORE)
AVR EA EB = KO (DXCORE)


Laurent


Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 06, 2024, 01:06:15 am
Suite des tests

Il semble que le "bug" pour les CPU AVR EA & EB soit sur DXCORE... issue ouverte pour analyse.

En effet la compile "accroche" sur EVENT et COMPARATOR. (pb de { }, de valeur de variables... etc.)
Le fait de rentrer "à la mano "les éléments bloque sur les erreurs contenues dans les fichiers en question.

Peut être une prochaine MAJ de la lib pour corriger le tout. ?
En attendant pas de CPU Ex de dispo pour ce projet.

A noter que leur "cousins" de la série MEGATINY2 ne rencontrent pas le soucis de leur coté.

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 06, 2024, 10:50:07 pm
Bonsoir

Petit update. Les tests se sont poursuivis et le soucis rencontré avec les CPU de type AVR EA et EB est à present resolu.

Toutes les familles sont de nouveau supportées.

A présent d autres tests vont se poursuivre.


Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 08, 2024, 10:54:58 pm
Bonsoir

Les tests se poursuivent bien pour éprouver les nombreuses combinaisons d'options de compilation( avec ou sans RAILCOM, avec ou sans les composants hardware sur les différentes familles de CPU).
J'ai toutefois réduit certaines possibilités pour gagner et garder une certaine cohérence.

J'obtiens de fait "un arbre de décisions multiples" incluant les fichiers concernes pour les combinaisons, rejetant ceux non pris en compte. ( Grace aux directives #if #elif #else et de nombreux #if defined() ou #if !defined().

Avant de passer dans une autre phase de test à l'aide du hardware associé, y a t il des volontaire pour y jeter un oeil?

@Trimarco Peut etre? Mais je te sais aussi tres occupé par ailleurs...

Laurent
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 10, 2024, 11:44:09 am
Bonjour

Nouvelle étape en cours de franchissent.
L initialisation des broches.

Pour memo nous sectionnons 2 broches qui soient adressable simultanément par le comparateur (AC0) et l ADC ( ADC0)

Fixons PD2 et PD3 pour cela pour les AVRx

Sur l ADC on doit par recommandation des datasheet procéder à l annulation de la mise en buffer du mode digital.

On definit au préalable les inputs

PORTD.DIRCLR = PIN2_bm | PIN3_bm; //SET PIN_PD2 and PIN_PD3 as INPUT resp A1 & A0 on NANOEVERY

Qui sont ensuite affinés pour le mode analogique via ces commandes:


                //SET PINS:
                //PIN PD2:
                PORTD.PIN2CTRL &= ~PORT_ISC_gm;
                PORTD.PIN2CTRL |= PORT_ISC_INPUT_DISABLE_gc;

                //PIN PD3:
                PORTD.PIN3CTRL &= ~PORT_ISC_gm;
                PORTD.PIN3CTRL |= PORT_ISC_INPUT_DISABLE_gc;


Cependant le Comparateur AC lui a besoin d avoir 2 inputs.
Pas de soucis pour nos broches PD2 et PD3 deja selctionnées et communes.

Toutefois le fait de désactiver le digital buffer rend impossible ( datasheet à la clé) le lecture d état du port par une instruction de type
PORTx.IN & zzzz est non opérationnel

On devra donc s en passer.

Ce que je n'ai pas encore identifié c est le possible impact sur le comparateur avec ce buffer de désactivé.
Je n'ai rien trouve/lu à ce sujet...

@Trimarco, des avis/idées sur le sujet?

Laurent

Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le janvier 17, 2024, 04:55:51 pm
(https://forum.locoduino.org/index.php?action=dlattach;topic=1628.0;attach=5531)
Bonjour , (désolé pour le silence , j'étais ... ailleurs)
je ne comprends pas bien ta question , il n'y a pas de mode digital ici
c'est normalement le comparateur qui fonctionne (sur le rail qui vabien) , et de temps en temps l'ADC (rapidement sur 1 rail puis sur l'autre)
peux-tu préciser le souci ?
Titre: Re : Décodeur de locomotive multifonctions
Posté par: laurentr le janvier 17, 2024, 07:13:47 pm
Bonsoir

D'après mes lectures des datasheet comme indique ci avant pour l ADC on désactive le buffer digital ce qui a pour effet de rendre inactif la commande PORTx.IN

Je ne sais pas si le comparateur va apprécier ou pas cette configuration.

Rien vu dans les docs à ce sujet.

Ltr
Titre: Re : Décodeur de locomotive multifonctions
Posté par: trimarco232 le janvier 18, 2024, 09:11:44 am
les entrées d'un comparateur analogique sont analogiques