Fabriquer un programmeur (ISP) AVR hybride pour ATTiny et ATMega

Pour la programmation de mes microcontrôleurs, j’ai toujours trouvé plus commode de disposer d’une plaque sur laquelle sont soudés quelques broches et un support ZIF pour faciliter les manipulations. Il est aisé ensuite de brancher cette plaque sur un Arduino.

Au début, j’avais simplement soudé ces broches avec un support à  8 pattes, ce qui me permettait de programmer les microcontrôleurs de ce format (ATTiny85 ou ATTiny45).

Puis je suis passé à l’ATMega, et j’ai donc fabriquer un nouveau support avec les broches adéquates, sur 28 pattes. J’étais néanmoins obligé de changer de plaque à chaque fois que je passais d’un ATMega à un ATTiny.

Il y a peu, j’ai reçu des ATTiny4313. Ce microcontrôleur utilise un nouveau format, à 20 broches, ce qui aurait impliqué de fabriquer une nouvelle plaque dédiée.

C’est quand même bien foutu !

J’ai décidé de réfléchir un peu et je me suis rendu compte d’une chose : les broches utilisées pour la programmation sont placées exactement de la même façon. Seule la position des broches d’alimentation et de réinitialisation (RESET) varie.

ATMEGA168details
Broches d’un ATMega168
attiny85details
Broches d’un ATTiny85
ATTINY4313details

Broches d’un ATTiny4313

En rouge, les broches SCK (Horloge), MISO et MOSI (entrée/sortie du mode SPI), sont positionnées toutes 3 dans le même ordre pour chacun des microcontrôleurs.

Les broches en vert sont mobiles, mais on retrouve cependant les mêmes positions des VCC et RESET pour les deux versions d’ATTiny.

Factorisons tout ça !

Maintenant que nous avons la position des broches, on peut rapidement comparer ce qui se passe si on superpose les 3 microcontrôleurs. Magie ! Aucune broche « sous-tension » (VCC ou GND) n’interfère avec les broches RESET, SCK, MISO ou MOSI. Ce qui veut dire que l’on peut  brancher le tout comme ceci :

universalisp_bbPour rappel, voici les branchements à faire avec un Arduino :

Microcontrôleur Arduino
VCC VCC
SCK 13
MISO 12
MOSI 11
RESET 10
GND GND

Introduction aux crypto-monnaies

Depuis quelques années maintenant, Internet puis les médias se sont emparés d’un sujet intéressant : les crypto-monnaies.

En quoi cela consiste ?

Il s’agit de monnaie établie non pas au sein d’une banque centrale (comme peuvent l’être l’euro, le dollar, et toutes les autres monnaies officielles), mais de « jetons » et transactions que s’échangent les nœuds d’un réseau. Les transactions s’effectuent grâce à la cryptographie asymétrique.

Pour saisir les avantages et inconvénients, voici quelques schémas.

 Comment fonctionne une transaction traditionnelle ?

Dans notre économie actuelle, les banques sont le maillon de confiance qui permet d’effectuer des transactions en toute sérénité. Voici un exemple simple, où une transaction à lieu entre un émetteur E et un bénéficiaire B, d’un montant de 5 M (monnaie arbitraire).

cryptomonnaie-Diapositive1

  1. E et B se mettent d’accord sur l’échange d’un bien ou d’un service d’une valeur de 5M.
  2. E envoie une demande de transaction à sa banque. Celle-ci peut prendre plusieurs formes :
    • un virement bancaire (par Internet par exemple)
    • un paiement par carte (par terminal de paiement électronique)
  3. La banque de E valide ou refuse la transaction, en fonction du contrat qui la lie avec son client (autorisation de découvert, …). Si elle la valide, elle débitera le compte de la somme de 5M.
  4. Une fois la transaction validée, la banque de E envoie une transaction à la banque de B, qui lui retournera un accusé de réception (notez que  cette étape n’est pas forcement synchrone et peut avoir lieu plus tard, dans des « lots » de transactions entre les deux banques).
  5. La banque de E transmet ainsi une preuve de transaction, à B ou à E suivant la forme de celle-ci :
    • pour un paiement par carte, il s’agira d’un ticket
    • pour un virement bancaire, d’un numéro de transaction
  6. Parallèlement, la banque de B créditera le compte de B de 5M.
  7. B pourra faire valoir sa preuve de transaction auprès de sa banque, afin de s’assurer que la transaction s’est bien réalisée.
  8. Dans le cas où tout s’est bien passé, B pourra profiter de la somme de 5M envoyée par E.

La transaction complète peut durer entre 2 jours et plusieurs mois suivant la somme et le mode utilisée. Par ailleurs, celle-ci peut être mise à mal par plusieurs facteurs :

  • Carte bancaire corrompue ou détournée
  • Banque douteuse
  • etc.

Je ne vais pas faire ici un cours complet sur les méthodes qui permettent d’affaiblir ce système, je ne crois pas en avoir la compétence et ce n’est absolument pas le but de cet article.

Étudions maintenant le fonctionnement d’une crypto-monnaie

Pour pouvoir effectuer une transaction, il est nécessaire de disposer d’un couple clef publique/clef privée. La clef publique est utilisée comme adresse lors de la transaction.

cryptomonnaie-Diapositive2

  1. E et B se mettent d’accord sur l’échange d’un bien ou d’un service d’une valeur de 5C. Ils échangent leur adresse (clef publique).
  2. E émet une transaction, qu’il signe avec sa clef privée. Étant le seul en possession de cette clef, il est l’unique personne sur le réseau à pouvoir signer une transaction, qui correspondra à sa clef publique (son adresse).
  3. Cette transaction est ensuite diffusée sur le réseau, en pair-à-pair (P2P ou peer-to-peer). Le réseau agit ainsi comme un livre de compte gigantesque, où chaque transaction du réseau est enregistrée sur chaque nœud du réseau.
  4. La transaction se réplique sur le réseau, tour à tour, les nœuds ont vent de celle-ci et l’enregistre. Ainsi, F, G, H et I enregistrent la transaction, et la mettent à disposition. Chaque nœud « valide » ainsi la transaction.
  5. Finalement, la transaction arrive chez B, et la somme est créditée par le logiciel sur son portefeuille bbbbbbb.

La réalisation de ces étapes prend entre quelques secondes et plusieurs heures, en fonction du nombre de nœuds sur le réseau (plus il y a de nœuds, plus il est performant). La plupart du temps, une transaction n’est considérée comme sûre qu’après un certain nombre de validations (entre 4 et 200 pour les plus paranoïaques).

Mettre en défaut une crypto-monnaie est un exploit presque impossible à réaliser, puisque pour cela, il est nécessaire de « casser » la clef privée d’un portefeuille pour émettre des transactions en son nom et ainsi récupérer son contenu.

Les crypto-monnaies face au système actuel

Quels sont les avantages des crypto-monnaies sur les transactions traditionnelles ?

  • La mise à disposition d’un portefeuille est immédiate, ne nécessite aucun contrat et n’engendre aucun frais direct (contrairement à l’établissement d’un compte bancaire).
  • Il est possible de disposer d’autant d’adresses qu’on le désire, chacune étant liée à une clef privée distincte. Ceci permet d’augmenter la sécurité de vos transactions, et de réduire leur traçabilité.
  • Les transactions sont beaucoup plus rapides.
  • En cas de panne d’un nœud, le réseau n’est pas altéré et continue de fonctionner. Le nœud rattrapera son retard lors de sa reconnexion, contrairement à une panne d’un élément de la chaine d’une transaction traditionnelle (panne de courant, indisponibilité du terminal de paiement électronique, indisponibilité de la banque, …).
  • Il est possible d’imprimer sa crypto-monnaie sous la forme d’une adresse à usage unique, rendant la transaction indépendante de la présence d’un réseau.
  • En chiffrant son portefeuille, il est impossible de « voler » la monnaie, même en étant un proche (sauf dans le cas des sites hébergeant des portefeuilles). Rien n’empêche techniquement un banquier de vider votre compte et de s’en servir comme il l’entend (néanmoins, un cadre légal très strict prévient ces pratiques en Europe).

Et quels sont les inconvénients ?

  • Aucune autorité légale (comme une banque centrale) ne régule le marché de la crypto-monnaie. Elle est donc susceptible de connaitre des variations violentes, à la hausse comme à la baisse.
  • Aucune loi ne protège l’épargnant ou l’utilisateur d’une crypto-monnaie. Il est ainsi très facile de créer un service en ligne pour former un système de Ponzi ou simplement une loterie truquée. La crypto-monnaie n’ayant aucune valeur légale, peut-on continuer à parler d’arnaque ?
  • La perte de votre clef privée entraîne la perte pure et simple de tous les revenus attachés. Il n’y a aucun moyen de récupérer un clef privée autrement qu’en restaurant une sauvegarde.
  • Le vol de votre clef privée entraîne la possibilité d’émettre des transaction en votre nom. Ainsi, en volant un téléphone disposant de ces clefs privés, il est possible de vider votre portefeuille ! Bien entendu, aucune banque, assurance ou autorité ne couvrira la perte de ces revenus, et je suis certain qu’aucune enquête ne sera officiellement demandée pour trouver le voleur et recouvrer vos biens. Cependant, il est possible est surtout vivement recommandé de chiffrer sa clef privée en utilisant un mot de passe complexe.
  • La sécurité, et donc la valeur de la crypto-monnaie résident dans la force de son algorithme de chiffrement. Si celui-ci venait à être cassé ou simplement à montrer des faiblesses, le cours de la crypto-monnaie pourrait s’effondrer, là où une banque serait couverte par une assurance ou par l’État. Ce scénario est toutefois improbable puisque les algorithmes couramment utilisés sont réputés sûrs, et leur code source est disponible librement.

Attention à ces fausses vérités à propos des crypto-monnaies

  • Il est faux de croire que les transactions réalisées sur le réseau d’une crypto-monnaie sont anonymes. Comme dit plus tôt, la transaction est réalisée entre deux adresses, et est publiquement disponible sur l’ensemble du réseau. Il existe même pour chaque crypto-monnaie des sites permettant de suivre à la trace chaque transaction entre chaque adresse. Si vous utilisez la même adresse pour commander votre journal ou pour louer un botnet, soyez sûrs que les autorités finiront par mettre la main sur vous, si vous êtes amené à réaliser l’attaque du siècle avec ledit botnet.
  • Il est dangereux de croire que votre portefeuille est en sécurité si vous l’hébergez sur un serveur distant. Gardez à l’esprit qu’avoir accès à votre clef privée donne l’accès à vos revenus. Je vous déconseille donc fortement l’utilisation de plateformes en ligne, quelque soit leur réputation, et quelque soit le rendement d’épargne qu’elles peuvent proposer. Évitez ainsi de stocker de la crypto-monnaie sur une machine dont vous n’avez pas le contrôle absolu et exclusif. Les cas de serveurs qui disparaissent dans la nature avec les clefs privées des utilisateurs se multiplient, et il est difficile de déterminer s’il s’agit de piratages, ou d’actions délibérées de la part des administrateurs. Bien entendu, les autorités, si elles daignent s’y intéresser, n’auront un champ d’actions que très limité.
  • Jusqu’à maintenant, aucune crypto-monnaie n’a montré de faiblesse dans sa sécurité. Beaucoup d’articles relatent des cas de « piratage » de crypto-monnaies. En fait, il s’agit de vols ou de pertes de portefeuilles, que les utilisateurs ont mis en ligne, ignorant les avertissements quant aux dangers de cette pratique. Encore une fois : les crypto-monnaies ne sont pas conçues pour être utilisées depuis des serveurs distants. Il est important de considérer votre portefeuille comme vos clefs de voiture. Aussi, si vous confiez celles-ci à un tiers, ne vous plaignez pas si celui-ci se fait voler votre voiture ou s’il disparait avec.
  • Il est impossible d’annuler une transaction réalisée en crypto-monnaie. En effet, une fois diffusée sur le réseau, si celle-ci est validée, elle sera répliquée de nœud en nœud et gravée pour toujours. Ceci lui donne un caractère irrévocable, ce qui est une bonne chose, car avec la vitesse à laquelle est diffusée la transaction, il pourrait être gênant de pouvoir l’annuler aussi rapidement. Ceci permettrait d’acheter un bien ou un service, d’attendre la confirmation de son expédition, et d’annuler son paiement.
  • Les tentatives de régulations sur ces monnaies sont vaines. Un état qui chercherait à établir la liste des revenus d’un citoyen pour lui réclamer des impôts pourrait se heurter à d’énormes difficultés, tant sur un plan technique que juridique. Il lui est en effet totalement impossible de faire geler un avoir, comme pourrait le réaliser une banque lors d’une suspicion de fraude ou de blanchiment. Un individu inquiété par l’origine de ses revenus pourrait aisément séparer son solde sur plusieurs centaines voire milliers de portefeuilles, rendant toute investigation fastidieuse et pratiquement impossible à démêler.

Comment obtient-on de la crypto-monnaie ?

Quelque soit la crypto-monnaie désirée, il existe deux façons de l’obtenir :

  • l’échanger contre une autre crypto-monnaie ou une monnaie traditionnelle
  • l’extraire (ou la « miner »)

L’échange

Pour l’échanger, il existe une multitude de plateforme d’échanges (appelés Exchange en anglais). Il suffit de chercher « Exchange » avec le nom de la monnaie qui vous intéresse pour trouver votre bonheur.

Les plateformes d’échange « Exchanges »

Évidemment, ces services ne sont pas gratuits, et chaque transaction se voit agrémentée de frais à payer (entre 0,01% et 5%). Dans l’ensemble, cela fonctionne comme une place d’échange classique. Vous devez faire un versement initial qui doit être confirmer par un nombre important de pairs (au moins 10) et vous pourrez ensuite faire vos achats. Des adresses de portefeuilles temporaires vous seront fournies, cependant, ne laissez pas de sommes importantes dormir sur ces comptes.

Attention aux annonces en ligne !

Par ailleurs, vous trouverez sur beaucoup de forums spécialisés, ou même sur des sites d’enchères en ligne, des annonces d’achat ou de vente. Si les tarifs sont souvent alléchants (vente en dessous du prix du marché, ou achat surévalué), il est important de se méfier de ces annonces ; en effet le caractère irrévocable d’une transaction en crypto-monnaie n’est pas compatible avec les moyens de paiement garantis par des banques ou des entreprises.

Ainsi, si je réponds à une offre d’achat d’une quantité importante de crypto-monnaie contre de l’argent réel, à un prix qui me semble intéressant, il est fort possible qu’une fois la transaction effectuée, la personne annule son paiement, ou dénonce un achat frauduleux. Les crypto-monnaies n’ayant pas vraiment la cote auprès des établissements traditionnels, il est fort probable que le paiement ne soit jamais honoré. Cette plainte sera d’autant plus valable qu’elle aura lieu quelques heures voire quelques minutes après la transaction, appuyant l’argument d’un achat non autorisé.

L’extraction « Mining »

Extraire une crypto-monnaie est une tâche fastidieuse, qui demande un investissement continu à mesure que la monnaie prend de la maturité. Certaines crypto-monnaies sont pré-extraites en partie, afin d’en distribuer les montants suivants des règles précises.

L’analogie avec les métaux précieux

La grande particularité des crypto-monnaies est qu’elles sont construites sur le modèle des métaux précieux :

  • Au tout début, personne ne les connait, et à fortiori, personne n’en veut. La valeur est donc nulle.
  • Les premiers prospecteurs s’y intéressent et en trouvent en relative abondance, puisque personne n’y a touché jusqu’ici.
  • Ceux-ci en parlent à leurs proches, et une fraction de ceux-ci vont s’y intéresser également, grossissant petit à petit le nombre de personnes concernées. Cette nouvelle ressource s’échange modestement car personne n’a conscience de sa rareté.
  • La popularité croissante provoque une fièvre qui incite chacun à extraire plus que ses pairs, accélérant ainsi l’appauvrissement des gisements.
  • La quantité de ressources faciles d’accès étant épuisée, il devient nécessaire de s’équiper en conséquence pour continuer l’enrichissement. De la même façon, la ressource devenant difficile à obtenir pousse les prix à la hausse.
  • De nouvelles techniques apparaissent, permettant de chercher plus loin et donc de ramener plus de ressources. Le prix de celles-ci freine les plus modestes à s’équiper. En même temps, ces techniques toujours plus performantes réduisent de façon exponentielle la quantité de ressources disponibles.
  • Une fois tous les gisements épuisés, cette ressource atteint une valeur élevée relativement stable.

Petit lexique du mineur débutant

l’empreinte « hash »

Le hash est le résultat d’un algorithme de somme de contrôle particulier. Cet algorithme permet de calculer une empreinte propre à une série de données. Ainsi, si on calcule deux fois l’empreinte pour la même série de données, celle-ci sera identique. Si on change ne serait-ce qu’un bit de ces données, quelque soit la taille, l’empreinte deviendra radicalement différente. Ceci rend totalement imprévisible le résultat de la fonction à la seule vue des données. Par ailleurs, il n’est pas possible de retrouver les données depuis une empreinte. Cette fonction est primordiale dans beaucoup de domaines en informatique (cryptographie, vérification d’authenticité, …).

Pour l’extraction, lorsque l’on réalise un hash, on calcule l’empreinte d’un ensemble de données, comprenant l’entête du dernier bloc établi, et des données arbitraires. Si ce hash est « gagnant » ( plus petit qu’une valeur cible « target »), alors un nouveau bloc est établi. Le reste des hashes est « jeté ».

L’extraction est donc une sorte de loterie, où on parie à chaque hash que le résultat sera inférieur à la cible.

le bloc « block »

C’est un ensemble de transactions, qui une fois que le bloc suivant est établi, valide définitivement les transactions qu’il contient. Un bloc est identifié par le hash « gagnant »

la cible « target »

La cible est un nombre dépendant de la difficulté du réseau. Celle-ci représente la valeur maximale d’un hash pour qu’il soit considéré comme « gagnant » et qu’un nouveau bloc commence. Plus la difficulté augmente, plus la cible sera petite.

la difficulté « difficulty »

Il s’agit d’un ajustement qui garantit une extraction à vitesse constante dans le temps. Plus il y a de hash, plus la probabilité qu’un hash « gagnant » soit trouvé rapidement augmente, et plus la difficulté augmente. Un peu comme pour la recherche de métaux précieux : plus on est nombreux à chercher au même endroit, et plus il est difficile d’en trouver.

La difficulté augmente généralement, mais peut aussi se réduire, lorsque le nombre de mineurs diminue.

la chaîne de blocs « blockchain »

La blockchain est la liste complète des blocs trouvés, rangés dans un ordre précis. Chaque blocs contenant les transactions, on peut ainsi déterminer l’historique et donc le solde de chaque compte de la crypto-monnaie.

le taux d’empreintes « hashrate »

Le taux d’empreintes permet de calculer les performances d’un équipement. Il existe différentes organisations pour extraire de la crypto-monnaie. La difficulté augmentant avec le nombre de mineurs, le hashrate doit suivre la cadence pour pouvoir rester profitable. Il est généralement exprimé en kilohash/s, megahash/s, gigahash/s voire terahash/s et exahash/s. En ordre de grandeur voici les performances que l’on peut attendre des différents équipements :

Équipement hashrate
Processeur 0-50 khash/s
Carte graphique 100khash/s – 1Mhash/s
Puce ASIC 300khash/s – 5Ghash/s

Si certaines monnaies sont encore au stade des cartes graphiques, d’autres sont déjà passées aux puces ASIC (Application Specific Integrated Circuit : circuit intégré pour application dédiée). Il s’agit de puces spécialement conçues pour l’extraction de crypto-monnaie. Celles-ci sont pour la plupart très chères, et ont donc eu pour effet d’exclure les mineurs les plus modestes.

un pool

Un pool est un rassemblement de mineurs dans le but de trouver des blocs plus facilement. Il existe différents types de pool, mais la plupart proposent de partager la crypto-monnaie issue de ces blocs au prorata de la quantité de hashes générés par chacun.

le round

Un round est une période entre deux blocs. Généralement, une difficulté s’applique à un round entier. L’ajustement de la difficulté permet d’assurer une durée globalement constante au round.

 

Fonctionnement et émulation USB d’une télécommande infrarouge pour LED RGB (Partie 2)

Dans l’épisode précédent, nous avons vu comment récupérer les codes émis par une télécommande, pour les implémenter dans un micro-contrôleur.

L’idée est maintenant de transformer ce montage en clef USB, puis de la lier à un web-service pour pouvoir utiliser la télécommande depuis n’importe où.

Dans mon article sur l’USB, je décris en détail les étapes qui permettent d’utiliser la bibliothèque V-USB. Voici le montage à faire :

ir_rgb_schémaLe code est disponible ici : RGB remote.7z.

Compiler et installer la commande

Dans le chapitre sur l’utilisation de l’USB, on réalise une commande  send  qui envoie des commande au micro-contrôleur. Nous allons nous servir de cette commande, que nous placeront dans  /usr/local/bin  et que nous appellerons set-led .

Créer le web service

Je vais créer deux pages en PHP (je n’aime pas trop ce langage, mais c’est pratique pour faire des petites pages rapidement) :

  • index.php  contiendra les boutons de la télécommande
  • command.php  sera appelé dès qu’un bouton sera appuyé

N’utilisez pas ce code sur une machine accessible depuis Internet ; je n’ai pas assaini les entrées GET et POST, et il est probablement possible d’injecter du code à une invite de commandes.

J’utilise Bootstrap et JQuery dedans. Il y a surement moyen de faire plus simple et plus propre, mais il s’agit d’un simple test alors ne soyez pas trop regardant sur la qualité de mon code.

Les sources du web-service sont disponibles ici : rgbremote-ws.tar.gz.

Une règle POV commandée par une application Android

Mais c’est quoi ?

Une règle POV (Persistence of vision : Persistance rétinienne) est une petite barre de 8 diodes (ou plus (ou même moins)) qui clignotent suivant un schéma précis. En déplaçant rapidement la règle, ce scintillement « dessine » des points qui permettent alors d’écrire un petit texte.

Il y a une foule d’exemples sur Internet ; motorisés, montés sur un ventilateur, une roue de vélo, un chien, un nunchaku, …

Voici ce que ça donne :

DSC01560-1920x1080Oui, ceci est une photographie, sans aucun montage ni aucune retouche (hormis le recadrage). Il suffit d’ouvrir l’obturateur (mode BULB), de faire son dessin, puis de le refermer. Il est nécessaire de disposer d’une télécommande pour cela.

J’ai choisi d’en fabriquer une simple, dont on peut changer le texte en utilisant un smartphone Android, par Bluetooth.

Fabriquer sa règle POV

Un peu de réflexion

Puisque les diodes représentent une colonne d’un caractère à un instant précis, il est nécessaire de « traduire » les caractères en colonnes de diodes. J’ai choisi ici de fixer la taille des caractères à 4 colonnes. Chaque colonne sera ainsi représentée par un nombre de 8-bits, le pixel du bas étant le bit de poids faible, et le pixel du haut le bit de poids fort.

Avec un tableur et une petite demie-heure, on peut dessiner pixel par pixel chaque caractères, pour les convertir en 4 nombres de 8-bits.

lettreOn construit de cette façon le tableau suivant de 380 octets, contenant tous les caractères ASCII affichables :

Calibrer le délai

Une étape importante lors du développement du programme est de choisir un délai entre deux colonnes d’un caractère. S’il est trop long, le caractère sera plat. S’il est trop court, le caractère sera étroit.

Une expérience simple permet de calibrer ce délai. Il suffit d’un chronomètre, et de votre bras :

  1. Chronométrez vous pendant un temps défini (10 secondes par exemple) et comptez des mouvements avec votre bras, comme si vous utilisiez cette règle. Par exemple, basculez le de 60 degrés puis revenez à votre position.
  2. Pour ma part, en 10 secondes, je fais 30 mouvements aller et retour, soit 60 trajets.
  3. Estimez le nombre de caractères que doit comporter un trajet. J’ai choisi 20.
  4. Maintenant, appliquer la formule suivante :
    D\'{e}lai = \frac{Temps_{total}}{Nombre_{trajets} \times Nombre_{caract\'{e}res}  \times Nombre_{colonnes}} = \frac{10}{60 \times 20 \times 4} \approx 2 ms

Le schéma

pov_bb

Le montage est trivial, même si, j’utilise un registre à décalage pour économiser des broches sur mon micro-contrôleur. Cela parait idiot puisqu’il y a largement de quoi faire avec les broches présentes sur un ATMega.

Pour le module Bluetooth, il s’agit d’un modèle chinois basé sur la puce BC417. Il n’y a aucune documentation officielle disponible, mais en cherchant « linvor » on trouve quelques informations utiles. Pour le configurer, je l’ai connecté au port série d’un PC, puis je lui ai envoyé les commandes AT suivantes :

 

 Le code pour le microcontrôleur

Je n’ai pas ajouter de commentaires, il est relativement lisible.

 L’application Android

Ici, j’ai triché un peu ; je me suis servi d’AppInventor du MIT. Il s’agit d’un outil en ligne permettant de fabriquer une application Android sans connaissance particulière.

pov_appJe vous fourni le fichier installable (APK), ainsi que le projet « source ». Il n’y a aucune garantie livrée avec ceux-ci.

Notez qu’il est nécessaire d’appairer votre smartphone avec le module Bluetooth avant de démarrer l’application.

Mise à jour: J’ai modifié mon code pour qu’il écrive le message reçu depuis le port série en mémoire, pour pouvoir le charger au redémarrage.

AVR – Chapitre 9 – Créer son périphérique USB

L’usine à gaz USB

L’Universal Serial Bus est une norme de transfert de données en série (c’est à dire que les données sont transmises les unes à la suite des autres ; à opposer au mode parallèle où les données sont transmises via plusieurs canaux). Créé en 1994 par un consortium de constructeurs, l’USB est maintenant incontournable depuis le début des années 2000. Tout fonctionne maintenant par USB : claviers, souris, stockages de données, caméras, imprimantes, protocoles sans fil,.. L’idée de pouvoir rejoindre cette communauté doit vous sembler excitante !

Il est important de saisir certains concepts avant de se jeter à l’eau. Par ailleurs, je ne traiterai ici que des périphériques de version USB 1.1. Cette limitation est due aux caractéristiques techniques des micro-contrôleurs.

Les caractéristiques du bus

L’USB 1 et 2, se déploit sur quatre fils :

  • L’alimentation +5V VCC en rouge (parfois orange)
  • Le câble « données » D- en blanc (parfois jaune)
  • Le câble « données » D+ en vert
  • et la masse GND en noir (parfois bleu)

Communément, un périphérique USB 1.x peut être alimenté par un courant de 150mA (500mA pour l’USB 2.0). Si vous avez besoin de plus de puissance, il sera nécessaire de prévoir votre propre source de courant (batteries, alimentation, …).

Les connecteurs à chaque bout peuvent avoir différentes formes, les plus courants étant les suivantes :

Broches Type A Type B Mini-A Mini-B Micro-A Micro-B
VCC 1 1 1 1 1 1
D- 2 2 2 2 2 2
D+ 3 3 3 3 3 3
GND 4 4 5 5 5 5

La topologie

Le bus se dessine suivant une topologie en arbre, l’hôte étant la racine. Il est possible de connecter jusqu’à 127 périphériques, sur 5 niveaux (derrière des hubs).

L’USB peut fonctionner jusqu’à 3 mètres et même au-delà en utilisant des répétiteurs alimentés (ceci est néanmoins déconseillé).

Les identifiants

Chaque périphérique s’identifie grâce à deux codes :

  • le code fournisseur (vendor ID) sur 2 octets (soit 65536 possibilités). Ce code est distribué par l’USB Implementers Forum. Il est nécessaire de payer entre 2500 et 5000 US$ pour disposer du sien de façon officielle. Heureusement, il existe des codes pour les « bricoleurs » comme nous.
  • le code produit (product ID) sur 2 octets  (soit 65536 possibilités). Ce code est défini par le fournisseur à sa guise. Généralement, tous les produits d’une même génération partagent le même code produit.

On les représente communément sous forme hexadécimale, sur 4 chiffres, en les séparant par un deux-points. Voici quelques exemples :

  • Appareil photo Sony NEX-5R : 054c:066e
  • Téléphone Nexus 4 : 18d1:4ee1

Ce couple ne permettent pas d’identifier de manière unique un individu, seulement sa nature. Pour l’identifier précisément, il sera nécessaire de le prévoir de manière logicielle, ou en utilisant son chemin de connexion dans le réseau (par exemple, hub 2 > hub 2.1> hub 2.1.4 > port 2.1.4.5).

Par ailleurs, il existe une identification textuelle représentée par une chaîne de caractères.

Les classes USB

Vue la myriade de possibilités qu’offre la norme USB, il est nécessaire de regrouper les périphériques par classes, afin de factoriser l’effort à fournir pour le support de nouveaux matériels.

Ainsi, les souris, claviers, joysticks, etc. sont syndiqués sous la classe « Human interface device » (HID): 0x03. Les périphériques de stockage sont sous la classe « Mass storage » : 0x08. Cette page (en anglais) résume les classes officiellement déclarées.

Suivant la classe, les systèmes d’exploitation ont bâti des pilotes (drivers) afin de rendre plus ou moins transparente l’intégration des périphériques USB. Ainsi, la plupart des périphériques de classe HID sont supportés sans la nécessité de fournir des pilotes. C’est cette classe qui va nous intéresser, car il s’agit de la plus simple à mettre en œuvre.

Le « Report Descriptor »

Dans le cas de la classe HID, il est nécessaire de fournir un « report descriptor ». Il s’agit d’une chaîne d’entiers qui décrit le format de données que le périphérique va retourner à l’hôte.

Prenons l’exemple d’une souris ; celle-ci doit retourner les informations suivantes :

  • l’état de ses boutons (gauche, droite, milieu, molette vers le haut et molette vers le bas)
  • un mouvement sur l’axe X
  • un mouvement sur l’axe Y

La classe HID « mouse »

Voici une façon de représenter ces données, sur 3 octets :

octet bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
Boutons -     -     -     molette bas molette haut clic droit clic milieu clic gauche
Axe X entier relatif entre -128 et 127
Axe Y entier relatif entre -128 et 127

Voici à quoi correspond le rapport :

 

Pour aider à la rédaction de ce rapport, il est possible d’utiliser HID Descriptor Tool disponible ici. Voici à quoi cela ressemble :

HIDtoolJe ne vais pas  vous faire un cours sur le contenu détaillé de ces rapports. Il suffit simplement de savoir qu’ils existent et à quoi ils servent. Pour plus de détails, voici une bonne introduction (en anglais).

La classe HID « Custom »

Dans mon tutoriel, je vais utiliser une version allégée qui n’utilise pas de donnée formatée :

L’utilisation d’un tel rapport permet de s’affranchir des limitations du format HID, tout en étant facile à « installer » sur l’hôte. Cependant, il devient nécessaire d’utiliser un logiciel sur l’hôte pour se servir du périphérique.

La bibliothèque V-USB

AVR-GCC ne fournit pas de méthode pour utiliser l’USB, et ce n’est pas son but.

Il est donc nécessaire de charger une bibliothèque (library) tierce. V-USB est une bibliothèque qui propose une implémentation logicielle de la norme USB 1.1 pour les micro-contrôleurs AVR.

Celle-ci est proposée sous double licence : GPL version 2 ou commerciale. Cela implique que vos projets qui incluent cette bibliothèque doivent être publiés en accord avec la GPL (et donc avec distribution des sources), ou nécessite l’achat d’une licence commerciale (9.90€ pour une licence « Hobbyiste », 500€ pour une licence professionnelle).

Il existe des alternatives, mais la plupart nécessitent des micro-contrôleurs « puissants » ou des contrôleurs USB matériel. V-USB est utilisable sur des micro-contrôleurs modestes, dont l’ATTiny85.

Que contient-elle ?

La version actuelle (20121206) contient le répertoire usbdrv, dans lequel vous trouverez (entre autres) :

usbdrv.h les définitions nécessaires
usbdrv.c le cœur du pilote
usbdrvasm.S code assembleur utilisé par le pilote
usbdrvasm*.inc fichier appelé depuis usbdrvasm.S
asmcommon.inc fichier appelé depuis usbdrvasm.S
oddebug.c fournit plusieurs fonction de débogage
oddebug.h Les définitions requises par oddebug.c
usbportability.h Des définitions utilisés par le compilateur
usbconfig-prototype.h un exemple de fichier de configuration

Pour le bon fonctionnement du projet, il est important de copier l’intégralité du répertoire dans vos sources.

Comment fonctionne la bibliothèque ?

La configuration

Toute la configuration se trouve dans le fichier usbconfig.h, que vous devez ajouter à vos sources. Pour cela, vous pouvez copier le fichier usbconfig-prototype.h. Voici les points importants à adapter à votre projet :

Macro Description Exemple
USB_CFG_IOPORTNAME Port du microcontrôleur utilisé pour la communication en USB B
USB_CFG_DMINUS_BIT Numéro de broche utilisé par D- 0
USB_CFG_DPLUS_BIT Numéro de broche utilisé par D+ 2
USB_CFG_IS_SELF_POWERED Indique si votre périphérique dispose de sa propre source (0 : Non/ 1 : Oui) 0
USB_CFG_MAX_BUS_POWER Courant maximum que consomme votre périphérique (en mA) 50
USB_CFG_IMPLEMENT_FN_WRITE Indique si vous souhaitez utiliser la fonction usbFunctionWrite() ou non 0
USB_CFG_IMPLEMENT_FN_READ Indique si vous souhaitez utiliser la fonction usbFunctionRead() ou non 0
USB_CFG_LONG_TRANSFERS Indique si vous souhaitez faire des transferts de plus de 254 octets 0
USB_CFG_VENDOR_ID Octet faible et octet fort qui définissent l’identifiant fournisseur 0xc0, 0x16
USB_CFG_PRODUCT_ID Octet faible et octet fort qui définissent l’identifiant produit 0xdc, 0x05
USB_CFG_VENDOR_NAME Nom du fournisseur (il est demandé d’y mettre un nom de domaine) ‘c’,’i’,’c’,’a’,’t’,’r’,’i’,’c’,’e’,’.’,’e’,’u’
USB_CFG_VENDOR_NAME_LEN Taille de la macro fournisseur 12
USB_CFG_DEVICE_NAME Nom du produit ’I’,’R’,’-‘,’L’,’e’,’d’
USB_CFG_DEVICE_NAME_LEN Taille de la macro produit 6

Bien entendu, il reste beaucoup de macros, je vous laisse découvrir leur utilité dans les commentaires du code.

Les callbacks

V-USB implémente plusieurs « callbacks » (fonctions de retour), qui sont appelées à la suite d’événements précis. Cela ressemble à des interruptions, sauf que celles-ci sont purement logicielles :

  • usbFunctionSetup  : appelée à l’arrivée d’une requête ; c’est ici que vous définirez ce qu’il doit se passer au niveau du micro-contrôleur.
  • usbFunctionWrite  (nécessite USB_CFG_IMPLEMENT_FN_WRITE à 1) Cette fonction est appelée quand la fonction usbFunctionSetup retourne USB_NO_MSG et si la requête est de type USBRQ_HID_SET_REPORT (0x09).
  • usbFunctionRead  (nécessite USB_CFG_IMPLEMENT_FN_READ à 1) Cette fonction est appelée quand la fonction usbFunctionSetup retourne USB_NO_MSG et si la requête est de type USBRQ_HID_GET_REPORT (0x01).

Il y en a d’autres mais ce sont les principales. Ce diagramme résume l’utilisation que vous pouvez faire de ces méthodes.

USBlibs

La bibliothèque LibUSB

Comme je l’ai indiqué lors du chapitre sur les « report descriptors », nous allons avoir besoin d’un programme sur la machine hôte qui se chargera de dialoguer avec le micro-contrôleur branché en USB. Je vais utiliser ici libusb.

Ne voulant pas m’embêter avec la signature des pilotes sous Windows (obligatoire depuis la version 8) j’ai décidé de tout faire sous Linux (j’utilise une Fedora 20).

LibUSB est une bibliothèque dont le but est de fournir des méthodes de gestion et d’accès aux périphériques branchés en USB.

Le programme se découpe en deux parties :

  • une partie d’initialisation, où l’on cherche le périphérique USB qui nous intéresse
  • une partie d’exécution, où l’on effectue les actions nécessaires, notamment grâce à la méthode  libusb_control_transfer()  que vous avez pu apercevoir dans mon diagramme plus haut.

La structure du projet

Pour mon exemple, je vais utiliser un petit projet qui permet à mon PC de servir de télécommande pour une bande de LED RGB.

Aperçu

Voici comment doit se présenter votre projet :

  \dirtree{% .1 projet. .2 commands. .3 send.c. .3 Makefile. .2 usbdrv. .3 .... .2 Makefile. .2 remote.c. .2 requests.h. .2 usbconfig.h. }

Vous verrez dans beaucoup d’exemples que les fichiers remote.c , requests.h ,  usbconfig.h  et Makefile (celui du micro-contrôleur) se trouvent dans un répertoire firmware. Vous pouvez ranger ces fichiers comme bon vous semble, l’important est que cette structure soit claire pour vous.

Le schéma

Avant de parler du code, voici un exemple de branchements :ir_rgb_schémaIl n’y a pas grand chose à dire sur ce schéma. Les deux diodes Zener doivent limiter la tension à 3.3V.

 

Les définitions

usbconfig.h

Comme décrit plus tôt, il s’agit de la configuration pilote V-USB. Celui est chargé automatiquement, à partir du moment où votre projet inclus le fichier usbdrv.h . Il sera également inclus lors de la compilation du programme hôte.

 

requests.h

Ce fichier contient les requêtes USB personnalisées. Comme pour le fichier précédent, il sera inclus lors de la compilation.

 

Le programme du micro-contrôleur

remote.c

Il s’agit du code principal, qui sera envoyé sur le micro-contrôleur.

 

Makefile

Ici il faut faire quelques ajouts, pour prendre en compte la bibliothèque. J’ai mis en surbrillance les lignes qui diffèrent par rapport à d’habitude.

 

Le programme hôte

Ici, tout se passe sur une machine sous Fedora 20.

commande-hote.c

Comme vous pouvez le voir, ce code à besoin d’inclure les fichiers  ../requests.h  et ../usbconfig.h .

Makefile

Je ne sais pas ce qu’il en ait quant à l’outil pkg-config en dehors de Fedora, mais celui est plutôt pratique puisqu’il génère les options tout seul.

Utiliser un ATTiny85

Le problème que pose l’utilisation d’un ATTiny, est qu’il faut utiliser une horloge cadencée au minimum à 12MHz. Or l’ATTiny ne fonctionne correctement à 8MHz maximum. On va utiliser une astuce pour le passer à 16.5MHz sans cristal externe : la PLL (Phase-Locked Loop : boucle à verrouillage de phase).

Sans entrer dans les détails, il s’agit d’un dispositif qui permet d’augmenter la fréquence d’un micro-contrôleur (basée sur un cristal), au prix de sa stabilité. Il est ainsi possible de faire fonctionner un ATTiny au delà de 80MHz ! Mais dans notre cas, 16.5MHz suffiront.

Pour cela il est nécessaire d’harmoniser la fréquence au début de l’exécution. Ceci se fait en définissant un « hook » dans le ficher usbconfig.h , en y ajoutant la fonction hadUsbReset() , qui s’occupera d’appeler une autre fonction ( calibrateOscillator() ), qui calibrera l’oscillateur PLL.

L’exemple donné dans cet article prend déjà en compte ces modifications.

Dans le cas d’un micro-contrôleur capable d’utiliser une horloge à 16.5MHz, il n’y a pas besoin de ce dispositif, et donc des fonctions hadUsbReset() ,  calibrateOscillator()  ainsi que des lignes suivantes dans usbconfig.h  :

 

 Et voilà !

Voici les sources du projet : RGB remote (fichier 7z).

Lorsque vous branchez votre périphérique, les messages suivants doivent apparaitre dans dmesg.

Une fois le programme hôte compilé, vous pouvez envoyer des commandes au micro-contrôleur avec les commandes suivantes :

 

Fonctionnement et émulation USB d’une télécommande infrarouge pour LED RGB (Partie 1)

En traînant un peu sur le net, je suis tombé sur des bandes de diodes RGB (rouge/vert/bleu) contrôlées par télécommande (44 boutons) pour une trentaine d’euros les dix mètres. Il s’agit d’un clone chinois des lampes Living Colors de Phillips.

Après l’avoir installé et joué un peu avec l’éclairage, j’ai cherché à savoir comment celui-ci fonctionne ; l’idée étant de pouvoir contrôler le tout depuis un PC.

J’aurais pu démonter le boitier de commande de la bande de diodes, mais cela m’aurait forcer à tirer un second câble (en plus de l’alimentation) du PC jusqu’à la bande de diode, ce qui n’est pas pratique. Alors pour le défi, j’ai cherché à savoir comment fonctionne la télécommande, et comment émuler ses fonctions.

Télécommande RGB

S’équiper à moindre frais

Si vous disposez d’un PC avec une entrée pour micro, vous n’aurez pas besoin d’investir dans beaucoup de matériel. Prenez une prise jack mâle, une diode infrarouge réceptrice, une résistance de 4.7kΩ et un peu de fil.

irda_schema

Puis, téléchargez le logiciel Audacity (open-source). Il s’agit d’un éditeur de signal sonore, dont l’interface est un peu rude, mais il est très simple à utiliser.

Il suffit maintenant de choisir la bonne source de son, et de démarrer la capture. Un petit clic sur un des boutons de la télécommande, et hop !

irda_large

C’est quoi ce bazar ?!

Ici, on récupère le signal émis par la télécommande, mais seulement, celui-ci est échantillonné a 44100Hz. C’est bien pour « lire » le signal, mais ceci ne suffit pas à l’émuler.

Il est nécessaire de comprendre comment fonctionne, en théorie, le signal infrarouge.

La théorie (oui, il en faut un peu tout de même)

L’infrarouge est un signal très rudimentaire, qui à la fâcheuse tendance d’être sensible à la chaleur. En effet, toute source de chaleur (corps vivant, soleil, ampoule, …) émet naturellement des rayonnements infrarouges. Cela peut interférer avec le transfert d’un signal. Il n’est donc pas possible de considérer la présence d’un rayonnement comme un [ccie]1[/ccie] et l’absence comme un [ccie]0[/ccie].

On va alors utiliser un signal pulsé à une fréquence particulière. Ainsi, un [ccie]1[/ccie] sera un signal pulsé d’une durée déterminée, tandis qu’un [ccie]0[/ccie] sera un silence de même durée. Ceci implique de synchroniser le signal sur une fréquence particulière.

Rendered by QuickLaTeX.com

Pour déterminer cette fréquence, la méthode du microphone atteint ses limites ; il faudrait ici un oscilloscope avec une fréquence d’échantillonnage d’au moins une centaine de kilohertz. À défaut, il faut chercher un peu.

Prenons le signal acquis, et observons le. On a :

  • une longue crête de ~9ms
  • une longe crête de ~4.5ms
  • 4 paquets de 16 crêtes de ~0.5ms ou ~1.5ms

En fouillant, je suis tombé sur cet article (en anglais). Il s’agit du protocole infrarouge NEC.

On y est presque !

Le protocole NEC

Il s’agit d’un code, utilisant une fréquence de 38kHz (soit une modulation de 26.3µs) et dont le protocole est :

  • initialisation par un signal pulsé de 9ms (342 modulations), suivi d’un silence de 4.5ms
  • adresse du matériel (ici 0x00) sur 8 bits
  • inverse de l’adresse sur 8 bits
  • commande (ici 0x02 pour « POWER ») sur 8 bits
  • inverse de la commande sur 8 bits

Pour la transmission de l’adresse et de la commande, on code chaque bit de la façon suivante (le bit fort en premier) :

  • un signal pulsé de 560µs (21 modulations), suivi d’un silence de même durée pour [ccie]0[/ccie]
  • un signal pulsé de 560µs, suivi d’un silence de 1690µs pour [ccie]1[/ccie]

Voici ce que donne donc la trame qui permet l’allumage (ou l’extinction) des diodes :

Rendered by QuickLaTeX.com

Mettons cela en pratique

Il suffit de prendre un microcontrôleur (un ATTiny85 peut suffire, mais j’ai préféré prendre un ATMega168 pour ajouter une connexion série par la suite) et d’y brancher une diode infrarouge (émettrice cette fois).

Voici un code minimaliste qui se contente d’allumer et d’éteindre toutes les secondes. Vous y trouverez également les commandes disponibles en macro.

[cce_c]
#include <avr/io.h>
#include <util/delay.h>
#include <avr/sleep.h>

#define IR_PORT    PORTD
#define IR_DDR     DDRD
#define IR_PIN    PD2

#define SIGNAL_BOTTOM()    IR_PORT |= (1<<IR_PIN)
#define SIGNAL_TOP()    IR_PORT &= ~(1<<IR_PIN)
//38kHz
#define PULSE()        {SIGNAL_TOP();_delay_us(13.2);SIGNAL_BOTTOM();_delay_us(13.2);}

#define CMD_UP        0x3A
#define CMD_DOWN    0xBA
#define CMD_PLAY    0xB2
#define CMD_POWER    0x02

#define CMD_RED        0x1A
#define CMD_GREEN    0x9A
#define CMD_BLUE    0xA2
#define CMD_WHITE    0x22

#define CMD_DEEPORANGE    0x2A
#define CMD_LIGHTGREEN    0xAA
#define CMD_DEEPBLUE    0x92
#define CMD_HOTWHITE    0x12

#define CMD_ORANGE    0x0A
#define CMD_LIGHTBLUE    0x8A
#define CMD_PURPLE    0xB2
#define CMD_WARMWHITE    0x32

#define CMD_BROWN    0x38
#define CMD_TURQUOISE    0xB8
#define CMD_PINK    0x78
#define CMD_COLDWHITE    0xF8

#define CMD_YELLOW    0x18
#define CMD_CYAN    0x98
#define CMD_MAGENTA    0x58
#define CMD_ICEWHITE    0xD8

#define CMD_RED_UP    0x28
#define CMD_GREEN_UP    0xA8
#define CMD_BLUE_UP    0x68
#define CMD_QUICK    0xE8

#define CMD_RED_DOWN    0x08
#define CMD_GREEN_DOWN    0x88
#define CMD_BLUE_DOWN    0x48
#define CMD_SLOW    0xC8

#define CMD_DIY1    0x30
#define CMD_DIY2    0xB0
#define CMD_DIY3    0x70
#define CMD_AUTO    0xF0

#define CMD_DIY4    0x10
#define CMD_DIY5    0x90
#define CMD_DIY6    0x50
#define CMD_FLASH    0xD0

#define CMD_JUMP3    0x20
#define CMD_JUMP7    0xA0
#define CMD_FADE3    0x60
#define CMD_FADE7    0xE0

void init_sequence(){
uint8_t i;
for(i = 0; i<255; i++) PULSE();
for(i = 0; i<88; i++) PULSE(); //too lazy too swap to uint_16t (love your memory)
_delay_us(4500);
}

void send(uint8_t bit){
int8_t i;
for(i = 0; i<21; i++) PULSE();
if (bit & 0x01) _delay_us(1130);
_delay_us(560);
}

void send_command(uint8_t address, uint8_t command){
init_sequence();
int8_t i;
for(i=7;i>=0;i–) send(address >> i);
for(i=7;i>=0;i–) send(~address >> i);
for(i=7;i>=0;i–) send(command >> i);
for(i=7;i>=0;i–) send(~command >> i);

}

int main(){
IR_DDR = (1<<IR_PIN);
for(;;){
send_command(0x00,CMD_POWER);
_delay_ms(1000);
}
}
[/cce_c]

Ou quelque chose de plus funky :

[cce_c]
int main(){
IR_DDR = (1<<IR_PIN);
for(;;){
send_command(0x00,CMD_TURQUOISE);
_delay_ms(100);
send_command(0x00,CMD_ORANGE);
_delay_ms(100);
send_command(0x00,CMD_PURPLE);
_delay_ms(100);
}
}
[/cce_c]

AVR – Chapitre 6 – Lire des valeurs analogiques (ADC)

Analogique vs. numérique

Les valeurs analogiques sont à opposer aux valeurs discrètes et logiques. Voici quelques comparaisons entre les deux mondes, avec des exemples pratiques :

Vision analogique Vision logique (numérique)
la porte est à peine ouverte (0.01) la porte est ouverte (1)
le réservoir est presque vide (0.1) le réservoir contient de l’essence (1)
le premier a parcouru 99% du chemin (0.99) le premier n’est pas encore arrivé (0)
il reste 17% de batterie (0.17) il reste de la batterie (1)

Oui, il est frustrant de ne pas atteindre le niveau de détails qui nous semble trivial au quotidien, au sein d’un programme purement logique.

L’ADC

Pour palier à ce manque, il a été ajouté aux microcontrôleurs un ou plusieurs canaux convertisseurs analogique vers numérique. Ceux-ci sont représentés par les broches ADC d’un microcontrôleur, pour « Analog to Digital Converter ».

L’ATTiny85 peut supporter jusqu’à 4 canaux ADC, chacun ayant une résolution de 10 bits, soit 1024 valeurs. Comme pour les PWM (Modulation de signal pulsé), leur utilisation dépend d’une horloge et d’un diviseur.

La théorie

Du point de vue de l’exécution, il s’agit d’approximer une tension inconnue (Vin) contenue entre 0 et une tension de référence (Vref).

Ainsi, le résultat est retourné sous la forme d’un entier entre 0 et 1023 :

ADC = [\frac{V_{IN} \times 1024}{V_{REF}}]

La configuration

Les registres de configuration de l’ADC sont ADMUX, ADCSRA et ADCSRB. Je vais faire l’impasse sur le registre ADCSRB, il permet des options avancées non essentielles pour le moment. Bien entendu, vous retrouverez tous ces registres dans la documentation (À partir de la page 134).

Le registre ADMUX

Bit 7 6 5 4 3 2 1 0
ADMUX REFS1 REFS0 ADLAR REFS2 MUX3 MUX2 MUX1 MUX0

Les bits REFS 2 à 0 déterminent la tension de référence Vref utilisée pour la comparaison.

REFS2 REFS1 REFS0 Vref
0 0 0 Vcc (i.e. la tension d’alimentation fournie au microcontrôleur)
0 0 1 Aref (i.e. tension externe fournie sur la broche Aref/PB0 du microcontrôleur)
0 1 0 1.1V
0 1 1 réservé (ne pas utiliser)
1 1 0 2.56V sans condensateur de découplage sur Aref/PB0
1 1 1 2.56V avec condensateur de découplage sur Aref/PB0

Les bits MUX 3 à 0 indiquent quel canal sélectionné (je ne parlerai ici que des canaux simples).

MUX3 MUX2 MUX1 MUX0 Canal
0 0 0 0 ADC0/PB5
0 0 0 1 ADC1/PB2
0 0 1 0 ADC2/PB4
0 0 1 1 ADC3/PB3
1 1 1 1 ADC4 il s’agit d’un capteur de température interne. Surprise !

Enfin le bit ADLAR indique l’alignement du résultat (1 pour gauche, 0 pour droite).

Le registre ADCSRA

Il s’agit du registre de contrôle, qui va permettre de démarrer la conversion et de savoir quand celle-ci est terminée.

Bit 7 6 5 4 3 2 1 0
ADCSRA ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0

Les bits ADPS 2 à 0 configure le diviseur (page 136 de la documentation). Le bit ADEN doit être à 1 pour que la conversion puisse fonctionner, mais ceci ne la démarre pas.

Passer le bit ADSC à 1 démarre la conversion. Il repasse à zéro dès que celle-ci est finie.

Le bit ADIE permet de déclencher une interruption lors de la fin d’une conversion, et le bit ADIF témoigne de la fin de la conversion. Dans le cas d’une utilisation sans interruption il est important de le positionner à 1 à la fin de la boucle, sinon la lecture restera bloquée sur la même valeur. Lors de l’utilisation de l’interruption, le chargement de sa procédure réinitialisera automatiquement ADIF, il n’y a donc plus besoin d’y toucher.

Le résultat

Puisqu’il s’agit d’un convertisseur 10 bits, il n’est pas possible de rendre le résultat sur un seul registre de 8 bits. Il y a donc deux façons d’organiser le résultat :

  • aligné à gauche (ADLAR = 1) : les 8 bits les plus forts sont dans le registre haut, et les 2 derniers bits dans le registre bas
    Bit 7 6 5 4 3 2 1 0
    ADCH ADC9 ADC8 ADC7 ADC6 ADC5 ADC4 ADC3 ADC2
    ADCL ADC1 ADC0 -   -     -    -     -      -
  • aligné à droite (ADLAR = 0) : les 2 bits les plus forts sont dans le registre haut, et les 8 derniers bits dans le registre bas
    Bit 7 6 5 4 3 2 1 0
    ADCH -   -     -    -     -      -    ADC9 ADC8
    ADCL ADC7 ADC6 ADC5 ADC4 ADC3 ADC2 ADC1 ADC0

Pour choisir quelle format vous sied le mieux, l’alignement à gauche permet de comparer rapidement le résultat sur 8 bit avec une précision moyenne, alors que l’alignement à droite offre une meilleure précision mais contraint à l’utilisation d’un entier codé sur 16 bits (cf. exemple plus loin).

 Un exemple simple : la photorésistance

Comme vous le savez surement, la photorésistance est un composant électronique à deux pôles, dont la résistance dépend de la luminosité ambiante. Voici un schéma pour la mettre en œuvre :

adc_schem

La résistance R3 est à prévoir en fonction de la photorésistance R1. Celles-ci étant montées en diviseur de tension, on mesurera donc une tension comprise entre :

\frac{R_3}{R_{1}_{MAX} + R_{3}} \times V_{REF} et \frac{R_3}{R_{1}_{MIN} + R_{3}} \times V_{REF}

Pour ma part, j’ai utilisé une résistance R3 de 4,7kΩ et une résistance R1 de 20kΩ, sur un circuit de 5V soit :

\frac{4.7k}{20k + 4.7k} \times 5 \simeq 1V et \frac{4.7k}{0 + 4.7k} \times 5 = 5V

Ainsi, la valeur retournée par l’ADC devrait être comprise entre 205 et 1023.

Le but ici est d’activer la diode dès que la photorésistance R1 atteint un certain seuil (i.e. dès qu’il fait trop sombre), et de l’éteindre dès qu’on y voit suffisamment clair, à la manière de l’éclairage public qui s’allume à la tombée de la nuit, et s’éteint quand le soleil brille. On laissera une marge entre les deux pour éviter un va-et-vient lors de la pénombre. Il faudra veiller également à ce que la diode ne soit pas orienté vers la résistance pour ne pas fausser sa mesure.

 

Pour aller plus loin

Je n’ai présenté ici l’utilisation que pour un seul canal simple, mais il est assez facile d’en utiliser plusieurs à la suite ; le choix du canal se faisant avec le registre ADMUX, il est facile de reconfigurer les bits 3 à 0 en fonction du canal désiré, à la fin de l’interruption (juste avant la ligne ADCSRA |= (1 << ADSC); ).

Il est également possible de ne pas utiliser les interruptions. Dans ce cas, il est nécessaire d’ajouter la ligne suivante une fois la valeur lue, au risque de voir la conversion retourner toujours le même résultat :

 

Supprimer le bruit d’un chargeur QI XCSource

Possédant un Nexus 4, je cherchais un chargeur QI (La technologie QI permet de recharger un appareil compatible, sans contact, grâce à l’induction) pour en finir avec les câbles. Je suis tombé sur cette référence chez Amazon : à 20€, là où les autres sont généralement vendus entre 30 et 80€, j’ai voulu faire le test.

Je ne connais pas la marque XCSource, les avis étaient peu nombreux au moment de commander, mais maintenant, tout le monde s’accorde sur le fait que le bruit émis au moment de la mise en charge est insupportable.

Un bip, ca va deux bips…

D’autant plus, lors de la fin de la charge, celui-ci s’arrête automatiquement, ce qui autorise la décharge de la batterie du téléphone qui va de nouveau enclencher le cycle du chargeur, lequel poussera fièrement son cri strident, malgré l’heure (3h du mat) ou le lieu (au bureau).

J’ai donc souhaité l’ouvrir, et faire taire cette bête une fois pour toute.

Ouvrons la bête !

Un tournevis fin et plat suffit à démonter la coque du chargeur, le long de son arête. Voici ce qu’on y trouve.

XSource - entraille 1

En dessous de la puce centrale, vous pouvez apercevoir un capot où se cache ce maudit buzzer.Une flèche sur celui-ci vous indique où insérer votre tournevis pour l’ouvrir.

XSource - entraille 2

Une fois ouvert, vous trouverez un petit disque de métal. C’est lui qui émet ce bruit insupportable en vibrant. Il suffit donc de l’enlever. Ce qui laissera apparaitre la bobine.XSource - entraille 3

Une fois le disque retiré, vous pouvez remettre le capot, et refermer le chargeur.

Vous pouvez maintenant profiter d’un rechargement sans fil et en silence !

 

AVR – Chapitre 7 – Passer à l’ATMega

L’ATTiny85 est une plateforme parfaite pour bien débuter en programmation AVR, mais ses fonctionnalités et ses broches sont en nombre limité. Je vous propose maintenant de passer à une série de microcontrôleur AVR plus performante : l’ATMega.

Présentation de l’ATMega

Il s’agit toujours d’un microcontrôleur fabriqué par Atmel. Il y a beaucoup de variantes d’ATMega, la version que je vais présenter ici est l’ATMega168. Si vous disposez d’un ATMega328 (comme les cartes Arduino), la configuration sera quasi identique.

L’ATMega168 dispose d’une horloge fonctionnant jusqu’à 20Mhz, de 16ko de mémoire Flash, 512octets d’EEPROM, 1ko de RAM, et 28 broches.

Coté fonctionnalités, l’ATMega168 fournis deux compteurs 8bits, un compteur 16bits, et surtout une liaison USART (Universal Synchronous & Asynchronous Receiver & Transmitter : Récepteur/Émetteur Universel, Synchrone & Asynchrone), nous verrons cela plus tard.

Il fonctionne avec une tension comprise entre 1,8 et 5,5V.

Comment programmer un ATMega168 ?

Les branchements

Comme pour l’ATTiny85, il est facile de créer une carte de programmation pour l’ATMega168, à partir d’un Arduino. Je vous conseille d’utiliser un support ZIF ; ce sera plus facile à manipuler qu’un simple support pour circuit intégré.

arduino_as_ISP_atmega_bb

Notez que le quartz et les deux condensateurs en bas à droite du schéma ne sont utiles que si l’on souhaite utiliser une horloge externe.

Les ajustements

Rien de bien compliqué ici, il suffit simplement d’indiquer au compilateur et au logiciel de programmation la nouvelle cible. Voici les modifications que j’ai apportées à mon Makefile :

 

 

Compilation croisée d’un noyau pour Raspberry Pi

Pourquoi compiler un noyau, et pourquoi faire une compilation croisée ?

Il arrive parfois que l’on ait besoin d’ajouter le support d’un protocole, ou d’un périphérique, et il n’est pas toujours possible d’utiliser un module pour cela (besoin de ressource spécifique, …). Il n’y a d’autre choix alors que de compiler un noyau.

La compilation d’un noyau Linux est une étape qui demande une bonne quantité de ressources, notamment en temps d’exécution. Je me rappelle avoir laisser une machine compiler un noyau pendant toute une nuit lorsque j’étais étudiant.

Les processeurs ont bien changé depuis, et il est maintenant possible de compiler un noyau en quelques minutes, surtout en s’aidant des nouveaux processeurs à plusieurs cœurs.

Mais toutes nos machines n’ont pas cette puissance ; le Raspberry Pi est capable de compiler ses propres noyaux, mais cela prend un temps abominable lorsque l’on veut exécuter une série de tests par la suite. Il est frustrant d’attendre plusieurs heures que la compilation se termine, pour échouer lamentablement à un test trivial.

Alors pour accélérer cette tâche nous allons avoir recours à la compilation croisée (Cross-compilation en anglais).

Installer les bons outils

Je me sers ici d’une distribution Fedora (version 19, je pense qu’il n’y aura que très peu de variations pour une version plus récente). Je l’ai installé avec l’assistant par défaut, avec le mode « Infrastructure Server » ; il s’agit d’une configuration minimaliste, sans interface graphique ni service particulier (sauf SSH). Veillez cependant à disposer de quelques gigaoctets d’espace libre, et d’un gigaoctet de RAM.

J’installe les outils dont j’ai besoin ici : le compilateur (gcc), le gestionnaire de sources (git) et un outil sympathique pour exécuter des commandes en tâches de fond (screen).

[cce_bash]yum install -y gcc-arm-linux-gnu screen git ncurses-devel[/cce_bash]

Télécharger les sources pour Raspberry Pi

Les sources du noyau Linux destiné au Raspberry Pi sont hébergées dans un depôt Git. Il s’agit d’un gestionnaire de version, capable de fonctionner de façon décentralisée. Dans un premier temps il est nécessaire de cloner ce dépôt.

[cce_bash]
mkdir -p ~/rpikernel/
cd ~/rpikernel/
git  clone http://github.com/raspberrypi/linux.git
cd linux
[/cce_bash]

Le téléchargement des sources commence et peut prendre un long moment (~1 gigaoctet de données).

La commande [cci]git branch[/cci] vous donnera la version actuelle des sources du noyau (à cette date, 3.10). Si cette version vous satisfait, vous pouvez continuer le tutoriel ; sinon, [cci]git branch -r[/cci] vous indiquera les versions disponibles. Si la 3.12 vous intéresse, entrez alors ces commandes :

[cce_bash]git branch rpi-3.12.y origin/rpi-3.12.y
git checkout rpi-3.12.y[/cce_bash]

Une fois votre version choisie, nous pouvons passer à l’étape de la configuration de la compilation.

Générer sa configuration

Il y a trois moyens de générer la configuration de la compilation :

  • depuis zéro, en saisissant un à un les choix proposés par l’assistant [cci]make config[/cci] (non recommandé)
  • en utilisant le fichier de configuration par défaut, que l’on trouve dans arch/arm/configs/bcmrpi_defconfig dans le répertoire des sources. Il suffit de copier ce fichier à la racine, et de le renommer « .config ». On utilisera ensuite l’assistant de configuration de la compilation (voir plus loin).
  • en exploitant un fichier de configuration existant, que l’on peut extraire avec la commande [ccie]zcat /proc/config.gz > .config[/ccie] (sur un Raspberry Pi). On copie ensuite ce fichier à la racine du répertoire des sources (fichier nommé .config). C’est la façon la plus correcte lorsque l’on sait précisément ce que l’on souhaite modifier.

Pour éditer ce fichier de configuration, il est plus confortable d’utiliser l’assistant dédié :

[cce_bash]make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnu- menuconfig[/cce_bash]

Notez l’ajout des termes ARCH=arm (pour spécifier l’architecture cible) et CROSS_COMPILE=/usr/bin/arm-linux-gnu- (pour spécifier les outils de compilation à utiliser). Ces déclarations sont indispensables pour indiquer au compilateur que l’on est en train de compiler un noyau pour une autre architecture.

En exécutant la commande menuconfig, vous découvrirez un menu permettant de configurer votre noyau à votre guise. Libre à vous de le modifier.

Enfin, vous pouvez donner un petit nom à votre noyau, en renseignant les variables EXTRAVERSION et NAME du Makefile à la racine. EXTRAVERSION sera notamment visible à l’aide de la commande [cci]uname -r[/cci].

Lancer la compilation

Ici, il n’y a rien de plus simple :

[cce_bash]make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnu-[/cce_bash]

Vous pouvez profiter même des capacités multi-coeurs de votre machine avec l’option -j pour indiquer le nombre de coeurs à utiliser

[cce_bash]make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnu- -j 4[/cce_bash]

Et n’oubliez pas de compiler les modules ensuite !

[cce_bash]make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnu- modules[/cce_bash]

Installer votre nouveau noyau

Pour ne pas trop se fatiguer, on va utiliser SSHFS pour monter le noyau fraichement compiler, et ainsi installer les modules très facilement. Installons d’abord SSHFS sur le Raspberry Pi (je suppose que vous utilisez une Raspbian, vous trouverez aisément la façon de le faire si ce n’est pas le cas) :

[cce_bash]sudo su –
aptitude install -y sshfs[/cce_bash]

Puis, toujours depuis le Raspberry Pi, montons les sources du noyau (remplacez crosscompilemachine par l’IP de votre machine qui sert pour la compilation) :

[cce_bash]mkdir -p /mnt/rpikernel
sshfs root@crosscompilemachine:~/rpikernel /mnt/rpikernel[/cce_bash]

Rendons nous maintenant dans ce répertoire et installons les modules ainsi que le noyau :

[cce_bash]cd /mnt/rpikernel/linux
make modules_install
cp arch/arm/boot/Image /boot/kernel.img
[/cce_bash]

Après un redémarrage de votre Raspberry Pi, vous devriez avoir un noyau tout neuf !

Cet article est inspiré de celui-ci, en anglais.