samedi 30 mars 2013

pixdel: plus complexe qu'il n'y paraît

l'idée du pixdel a émergée dans mon esprit au début de juin 2012 puis après quelques expérimentations je l'ai mis de côté. Dernièrement je l'ai repris et j'ai réécris le code au complet sans regarder ce que j'avais fait l'an passé. J'espérais pouvoir augmenter la vitesse de transmission des commandes qui dans la version 2 était à 9600 BAUD. Mes premières réécritures m'ont permis de monter la vitesse à 38400 BAUD mais le résultat n'était pas acceptable à mes yeux. Ce problème est plus complexe qu'il en a l'air. Dans cette chronique je vais faire une analyse détaillé du problème et de la solution que j'ai trouvé. Solution qui cependant ne permet pas une vitesse de transmission supérieure à 14400 BAUD.

Description du pixdel

L'idée de départ est d'utiliser le plus économique des MCU disponibles actuellement sur le marché soit le PIC10F200 pour contrôler une LED RGB dans le but de créer un bus de LED dont chaque élément peut-être contrôler individuellement. Pour que l'idée soit intéressante il faut que le MCU soit vraiment à petit prix. Actuellement le PIC10F200T-I/OTCT-ND est à 0,422CAN$ chez Digikey.ca ce qui est le même prix qu'une LED RGB économique. Donc en achetant ces éléments en quantité on peut fabriquer un pixdel pour environ 1,00CAN$ l'unité.

Le pixdel présentente 3 avantages par rapport à un système de LEDs multiplexés. Le premier est que le contrôleur principal est décharger de la responsabilité de contrôler la couleur et l'intensité de chaque LED. Le deuxième est qu'il n'y a pas de multiplexage donc l'intensité de chaque PIXDEL est maximale. Et finalement le 3ième avantage est la simplicité des interconnections, il s'agit d'un simple bus à 3 fils, V+, V-, communication.

La complexité du multi-tâche en temps réel.

Le PIC10F200 n'a pas de périphérique RS-232 ni de PWM, tout doit donc être fait en software. Pour la réception des commandes RS-232 il faut un contrôle précis du timing sinon la lecture sera erronnée. Pour le contrôle d'intensité PWM des composantes rouge,verte et bleu il faut aussi un timing précis sinon il y aura une fluctuation de l'intensitée et de la couleur de la LED. Hors ces 2 tâches doivent partager le temps MCU sans se nuire l'une l'autre. Il s'agit d'un problème multi-tâche en temps réel. Prise individuellement chacune de ces tâches est très simple à implémenter mais les faire fonctionner ensemble sur ce petit MCU qui ne supporte pas les interruptions est beaucoup plus complexe car aucune de ces tâches ne tolère une pause. Les 2 tâches doivent-être imbriquées l'une dans l'autre en respectant toutes les contraintes de timing.

Calcul des contraintes de timing

La broche GP3 est utilisée pour la réception des commandes mais il n'y a pas de support d'interruption qui permet de déclencher une ISR lorsque cette broche passe du niveau Vdd à Vss qui indique le bit de démarrage. En conséquence il faut vérifier l'état de cette broche à un intervealle inférieur ou égal à la moitié de la durée d'un bit. A 9600 BAUD un bit dure 104usec. Donc il faut vérifier l'état de GP3 à toute les 52usec sinon le MCU peut manquer un réception. Une fois qu'un start bit est détecté, il faut échantillonné GP3 à un intervalle précis de 104uSec pour faire une lecture correcte de l'octet.

En ce qui concerne le PWM le fait qu'il est en software ne change rien à son fonctionnement. Un compteur est incrémenté à intervalle régulier et à chaque incrément la valeur de ce compteur est comparée avec la valeur de seuil du rapport cyclique des 3 canaux PWM rouge, vert, bleu. si le seuil est dépassé la sortie du canal est remise à zéro. Dans le cas du pixdel is s'agit d'un compteur 8 bits, donc il retourne à zéro après 256 incrément. La période PWM est donc:
période= Tc*256
Tc étant l'intervalle entre chaque incrément. Pour que l'oeil ne percoive pas de scintillement de la LED il faut que cette période soit au maximum 1/70Hz=14msec. Donc Tc doit-être <=0,014/256=55uSec.

Donc la durée d'un demi-bit à 9600 BAUD est de 52usec et l'intervalle maximal pour pwm_clock=55uSec. On peut donc prendre la valeur de 52uSec comme durée de la boucle du céduleur de tâches et s'assurer que chaque cycle s'exécute en exactement 52uSec.

La tâche pwm_clock s'exécute à chaque cycle du céduleur et est suivit d'une autre tâche. Au début de la boucle le TIMER0 est réinitialisé pour qu'il revienne à zéro au bout de 52uSec. Ensuite pwm_clock qui est définit comme une macro, s'exécute (12uSec), après quoi le céduleur effectue un compute goto vers la tâche à exécuter pour ce cycle. Finalement la boucle se termine par idle_loop qui attend que le TIMER0 termine son compte de 52uSec avant de revenir au départ. Chaque tâche détermine quel sera la tâche à exécuter dans la boucle suivante.

A 9600 BAUD il faut ~1msec pour recevoir un octet il n'est donc pas question d'interrompre le PWM pour s'occuper exclusivement de la réception de cet octet. C'est pourquoi la réception RS-232 est découpée en tranche (tâche) dont la durée est suffisamment courte pour ne pas perturber le cycle principal de 52uSec.
Boucle principale (projet au complet ici)

Il y a 8 tâches qui se partage le temps CPU dont 2 s'exécutent à chaque cycle.

  • T0: pwm_clock, s'exécute à chaque cycle et incrémente le compteur PWM et vérifie les seuils pour chaque composante RGB.
  • T1: task_wait_sync_start, attend le bit de démarrage pour réception de l'octet de synchronisation. Lorsque ce start bit est détecté commute vers la tâche task_sync.
  • T2: task_sync, réception de l'octet de synchronisation et vérification de sa validité. Si l'octet reçu est valide commute vers la tâche task_wait_start_bit, sinon retourne à la tâche task_wait_sync_start
  • T3: task_wait_start_bit, attend le bit de démarrage pour les 4 octets de la commande. Lorsque ce bit est détecté commute vers la tâche task_cmd_rcv.
  • T4: task_cmd_rcv, reçoit un octet de commande. Lorsque la réception d'un octet est complétée, vérifie si tous les octets ont été reçus. Si tous reçus commute vers task_chk_id, sinon retourne à la tâche task_wait_start_bit en attente de la réception de l'octet suivant.
  • T5: task_chk_id, vérifie si la commande en est une de diffusion (id=0) ou si l'id correpond à ce pixdel. Si la commande est acceptée la prochaîne tâche sera task_cmd sinon ce sera task_wait_sync_start.
  • T6: task_cmd, mais à exécution la commande reçu, c'est à dire modifie les valeurs du rapport cyclique de chaque canal au nouvelles valeurs reçues. La prochaine tâche à exécuter sera task_wait_sync_start.
  • T7: idle_loop, cette tâche s'exécute à la fin de chaque boucle et s'assure que la durée totale de la boucle est fixée à 52uSec.

Une seule des tâches task_* est exécutée par cycle de 52uSec. Le temps total d'exécution de pwm_clock+task_* doit-être inférieur au délais programmé dans TIMER0 pour que le système fonctionne correctement. Tout délais supplémentaire se traduira par une erreur de réception des octets de commandes et par une variation du cycle PWM.

Script python de test

Dans le dépôt github il y a un script python qui sert à vérifier le bon fonctionnement du pixdel. En autre même si le bus de commandes est saturé de commandes l'intensité ou la couleur du PIXDEL ne doit pas fluctuer.

Les tests que j'ai fait montre que cette version du firmware est meilleure que celle que j'avais créer l'an passé. La version 2 avait tendance à se désynchroniser et parfois le pixdel ne répondais plus aux commandes du contrôleur. J'ai modifier la stucture des commandes. Dans la version 4 les commandes sont précédées par un octet de synchronisation 0xFF, cette valeur ne doit pas être utilisée autrepart dans le paquet de donnée transmis sinon le système de synchronisation ne fonctionnera plus. Mais si on respecte cette règle le pixdel même s'il rate une réception se resynchronise rapidement avec le contrôleur.

augmentation de la vitesse des commandes

Mon objectif principal qui consistait à augmenter la vitesse de transmission n'a cependant pas été atteint. La contrainte principale est la durée d'un demi-bit pour un BAUD donné. A 9600 BAUD comme mentionné précédemment cette durée est de 52uSec. A 14400 BAUD on tombe à 35uSec hors dans la version actuelle certains cycles requièrent plus de 35uSec pour clore la boucle.

J'ai réussi à augmenter la vitesse RS-232 à 14400 BAUD en overclockant le mcu à 4,619Mhz (+15%). J'ai choisi cette valeur car elle correspond à un multiple entier de la durée d'un demi-bit pour 14400 BAUD. (1/14400)/2/40~=(1/4,619Mhz)/4. On dispose donc de 40 Tcy par boucle et cette durée corresponds précicément à 1 demi-bit pour 14400 BAUD.


liens

vendredi 22 mars 2013

carillon électronique

Voici un carillon électronique réalisé sur PIC10F202. Ce carillon imite le son des sonnettes à lames de métal percutées sauf qu'il permet de jouer un ringtone. Je n'ai pas fait de montage final de ce projet car il ne s'agissait pour moi que de tester l'usage d'un transistor 2N7000 pour contrôler le voltage de sortie d'une fréquence audio générée sur sortie numérique. Les notes jouées sont amortie selon une courbe exponentielle conforme la l'attéunation naturelle d'une lame vibrante. Tous les fichiers du projet sont sur https://github.com/pictatout/carillon

Schéma

Fonctionnement

GP1 est utilisé comme sortie des notes et GP2 contrôle le volume de sortie par le transistor Q1. Au début de chaque note C3 est chargée à Vdd à travers D3 et R1. le temps de charge est déterminé par la constante de temps R1*C3. Après l'expiration du temps défini par la constante ATTACK, GP1 est remis à Vss et C3 commence à se décharger à travers R2. Le temps de décharge est donc déterminé par la constante de temps R2*C3. Lorsque le voltage sur le gate de Q1 diminu le transistor conduit moins et en conséquence le voltage au bornes de R3 diminu. Voici une capture de la forme du signal à l'oscilloscope.

vendredi 15 mars 2013

vérificateur de transistor

Voici un circuit simple pour vérifier les transistors bi-jonction. Il utilise 1 PIC10F202 et 2 LEDs pour indiquer l'état du transistor. Ce projet pourrait-être réalisé sur n'importe quel petit MCU et ne nécessite que 3 E/S. Ce serait d'ailleur un bon exercice de débutant sur atTiny13A. l'ensemble du projet est sur https://github.com/Picatout/transistor-tester.

Matériel

  • 1 PIC10F202-I/P
  • 1 LED rouge 3mm
  • 1 LED verte 3mm
  • 1 bouton momentaté
  • 1 résitance 56K, (valeur non critique)
  • 1 résitance 33K, (valeur non critique)
  • 1 condenstateur céramique 100nF
  • 1 pile au lithium CR2032
  • 1 support pour pile CR2032
  • 1 petite platine de montage, exemple perma-proto 1/4 de Adafruit
Plan du montage sans soudure

Fonctionnement

GP0 est utilisé pour contrôler le courant de la base du tansistor. GP1 est branché sur l'émetteur et GP2 sur le collecteur en passant par les 2 LEDs connectées en opposition. Lorsque GP0 est configuré en entrée haute impédance, aucun courant ne devrait circuler entre le collecteur et l'émetteur en conséquence les 2 LEDs sont éteintes. Si on met GP1 à Vss et GP2 à Vdd et que GP0 est configuré en sortie à Vdd le transistor doit conduire dans le sens qui allume la LED verte. Donc cette LED va allumé si le transistor est un NPN. Aucune LED n'allume si c'est un PNP.

Si on inverse la polarité des voltages. C'est à dire GP0 en sortie à Vss, GP1 à Vdd et GP2 à Vss. La LED rouge doit allumée si le transistor est un PNP. Aucune LED n'allume si c'est un NPN.

En passant d'une configuration des GPIO à l'autre avec un délais de 250milli-secondes entre chaque il en résulte que si un transistor bi-jonction en bon état est branché, la LED verte clignote si c'est un NPN et au contraire c'est la rouge si c'est un PNP.

Si les 2 LEDs clignotes en alternance il y a un court-circuit entre émetteur et collecteur. Si rien n'allume soit le transistor est défectueux ou bien ce n'est pas un transistor bi-jonction.

Si le transistor est branché à l'envers, c'est à dire le collecteur et l'émetteur étant inversé, une LED va clignoté quand même mais à plus faible intentisé. Ce n'est pas du à une défectuosité du transistor mais plutôt à la symétrie des 2 jonctions, base-collecteur et base-émetteur qui fait que le transistor a quand même un certain gain lorsque c'est 2 électrodes sont inversées. Ce phénomène est particulièrement apparent sur certains transistors de commutation comme les ZTX649 (NPN) et ZTX749 (PNP).

Code source

Le code source est très simple, il n'occupe que 57 instructions sur le PIC10F202.

jeudi 7 mars 2013

pixdel version 3

2013-03-23
mise à jour firware pixdel à la version 4. Vitesse de réception des commandes augmenté à 38400 BAUD.
https://github.com/Picatout/pixdel4


Pour commencer je vous informe que j'ai créé un dépot github.com/Picatout. Désormais tous les fichiers associés à un projet seront sur github.com/Picatout. C'est beaucoup plus pratique que google docs.

J'ai retravailler sur mon concept de pixdel. J'ai simplifié le firmware. Il s'agit de la version 3 de ce projet. Un pixdel est un module miniature composé d'un petit MCU au format sot23-6 et d'un LED RGB qui reçoit des commandes par interface RS-232 à niveau TTL. L'idée est d'utiliser le MCU le plus petit et le plus économique sur le marché. J'ai donc choisi le PIC10F202 pour les versions antérieurs et le PIC10F200 pour cette version. La différence entre les 2 tiens simplement à la quantité de FLASH et de RAM. 256i flash pour le 200 et 512 pour le 202. 14 octets RAM pour le 200 et 24 pour le 202. Étant donnée que cette version simplifiée du pixdel occupe seulement 154 instructions et utilise 12 octets RAM, le PIC10F200 peut remplacé le 202.

différences avec la version 2

La vitesse de communication est passée de 9600 baud à 19200.
Il n'y a qu'une seule commande, qui sert à contrôler l'intensité des 3 composantes couleurs.
Le protocole de communication a été modifié. Maintenant le paquet comprend 5 octets.
0xAA pixdel_id r_level g_level b_level

  1. 0xAA octet de synchronisation
  2. pixdel_id identifiant pixdel, 0 pour diffusion, 1-255 pour identifiant unique.
  3. r_level intensité du rouge 0-255
  4. g_level intensité du vert 0-255
  5. b_level intensité du bleu 0-255

La vitesse de communication est limitée par le fait que les PIC10F20x ne supporte pas les interruptions il faut donc sonder continuellement GP3 pour détecter la présence d'un start bit. Pour ne pas manquer de start bit il faut que l'intervalle entre 2 vérifications de GP3 soit inférieur à la moitié de la durée d'un bit rs-232. En simplifiant le code du contrôleur PWM j'ai ramené cette durée à 23 micro-secondes alors qu'à 19200 baud la durée d'un demi-bit est de 26 micro-secondes. 19200 baud est donc la vitesse maximale de communication.

Vous noterez que dans le fichier pixdel3.asm j'ai commenté la constante PIXDEL_ID. Il est plus partique de définir cette constante sur la ligne de commande de mpasm.exe que d'avoir à ouvrir le projet à chaque fois qu'un veut programmer un MCU avec un nouvel id.

Tous les fichiers du projet sont sur githup.com/Picatout/pixdel