IMA3/IMA4 2019/2021 P1+ : Différence entre versions
(→Préparation du projet) |
(→Entrées USB) |
||
(94 révisions intermédiaires par 2 utilisateurs non affichées) | |||
Ligne 1 : | Ligne 1 : | ||
− | |||
<br style="clear: both;"/> | <br style="clear: both;"/> | ||
Ligne 28 : | Ligne 27 : | ||
Une première tentative de porter micro-python sur une carte ATXMEGAC3-XPLD [https://wiki-ima.plil.fr/mediawiki//index.php/Micro-ordinateur_pour_la_p%C3%A9dagogie a déjà été faite par Xuelu YAN en 2020]. Je base donc mes efforts sur les siens. | Une première tentative de porter micro-python sur une carte ATXMEGAC3-XPLD [https://wiki-ima.plil.fr/mediawiki//index.php/Micro-ordinateur_pour_la_p%C3%A9dagogie a déjà été faite par Xuelu YAN en 2020]. Je base donc mes efforts sur les siens. | ||
+ | |||
+ | De plus, il existe un [https://github.com/slavaza/micropython-avr8 port de micropython sur AVR]. | ||
==Cahier des charges== | ==Cahier des charges== | ||
Ligne 44 : | Ligne 45 : | ||
** Prise en main de la carte ATXMEGAC3-XPLD | ** Prise en main de la carte ATXMEGAC3-XPLD | ||
** Porter micro-python sur la carte ATXMEGAC3-XPLD | ** Porter micro-python sur la carte ATXMEGAC3-XPLD | ||
− | * | + | ** OU créer un OS "maison" |
+ | *** Gestion entrée/sortie | ||
+ | *** Gestion capteurs | ||
+ | *** Gestion périphérique de sauvegarde | ||
+ | * Créer un module USB (pour brancher un clavier) | ||
** Choisir les composants | ** Choisir les composants | ||
** Concevoir le circuit | ** Concevoir le circuit | ||
** L'imprimer et y souder les composants | ** L'imprimer et y souder les composants | ||
− | ** | + | ** Porter la bibliothèque LUFA de commande USB |
− | ** | + | ** Coder l'interaction avec l'ATXMEGAC3 |
==Calendrier prévisionnel== | ==Calendrier prévisionnel== | ||
Ligne 56 : | Ligne 61 : | ||
==Prologue== | ==Prologue== | ||
− | ==Semaine 1== | + | ==Semaine 1 : Aventures avec micropython== |
− | ==Semaine 2== | + | |
+ | ===Exploration du code source de micropython=== | ||
+ | |||
+ | J'ai d'abord commencé par explorer le code de micropython; je me suis dans un premier temps penché sur le port "avr8-dummy", qui est un exemple très basique (et générique) d'une implémentation de micro-python sur AVR. | ||
+ | |||
+ | On y voit un ''main.c'', avec une fonction main qui ressemble à ça : | ||
+ | |||
+ | int main() | ||
+ | { | ||
+ | ... | ||
+ | pyexec_event_repl_init(); | ||
+ | for(;;) { | ||
+ | usb_vcp_handling(); // = LUFA_USB_Handling() | ||
+ | int c = mp_hal_stdin_rx_chr(); | ||
+ | if (pyexec_event_repl_process_char(c)) { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | pyexec_friendly_reply(); | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | Il semble que <code>mp_hal_stdin_rx_chr</code> serve à lire un caractère sur l'entrée standard, et <code>mp_hal_stdout_tx_strn</code> écrive sur la sortie standard. Une question se pose alors : qu'est-ce que l'entrée/sortie standard sur une Arduino ? | ||
+ | |||
+ | En cherchant un peu, j'ai trouvé le fichier ''mphalports.h'', qui définit ces deux fonctions, ainsi que la fonction <code>usb_vcp_handling</code>. Il me faut maintenant modifier la définition pour utiliser le port série. C'est ici que rentre en jeu la [http://www.fourwalledcubicle.com/LUFA.php bibliothèque LUFA]. | ||
+ | |||
+ | ===Exploration du code source de LUFA=== | ||
+ | |||
+ | LUFA est une librairie USB pour les microcontrolleurs AVR. Elle permet notamment de créer une connexion série entre un ordi et la carte. | ||
+ | |||
+ | Pour faciliter la tâche, on peut utiliser l'exemple VirtualSerial. | ||
+ | |||
+ | En modifiant légèrement le code du port micropython, on peut modifier les fonctions de façon à ce que les ''read'' et les ''print'' se fassent sur le port série. | ||
+ | |||
+ | En regardant un peu la documentation, on voit que la fonction <code>LUFA_USB_Handling</code> doit être appelée au minimum toutes les 30ms afin (entre autres) de relancer périodiquement la connexion USB à l'hôte. Or, avec la boucle que nous avons dans le main, nous risquons de rater cette échéance. Dans certaines boards Arduino, la connexion USB est réalisée via un deuxième microcontrôleur. Ainsi, il y a de grandes chances qu'il faille, à un moment ou un autre, réaliser un bouclier pour notre Arduino permettant de gérer cettte connexion USB. | ||
+ | |||
+ | ===Fusion de micropython et de LUFA=== | ||
+ | |||
+ | En ajoutant la bibliothèque LUFA dans le projet micropython, on peut maintenant interagir avec l’Arduino via le port série avec <code>minicom</code>. On peut interagir avec l'invite de commandes, mais.. | ||
+ | |||
+ | [[File:Ordinateur_minicom_erreurs_mp.png|400px]] | ||
+ | |||
+ | On peut voir que micropython n'a pas l'air de très bien savoir ce qu'on veut de lui. Par conséquent, c'est le moment de plonger plus loin dans le code de micropython. | ||
+ | |||
+ | ===Replonger dans micropython=== | ||
+ | |||
+ | La fonction la plus intéressante dans <code>main</code> est <code>pyexec_event_repl_process_char</code>. Cette fonction appelle les fonctions suivantes (seules les fonctions les plus intéressantes (selon moi) sont renseignées) : | ||
+ | |||
+ | FONCTIONS DEFINITIONS | ||
+ | pyexec_event_repl_process_char (lib/utils/pyexec.c:345) | ||
+ | └ pyexec_friendly_repl_process_char (lib/utils/pyexec.c:232) | ||
+ | └ parse_compile_execute (lib/utils/pyexec.c:62) | ||
+ | ├ mp_lexer_new_from_str_len (py/lexer.c:706) | ||
+ | │ └ mp_lexer_new (py/lexer.c:670) | ||
+ | ├ mp_parse (py/parse.c:832) | ||
+ | ├ mp_compile (py/compile.c:3527) | ||
+ | │ ├ mp_compile_to_raw_code (py/compile.c:3364) | ||
+ | │ └ mp_make_function_from_raw_code (py/emitglue.c:122) | ||
+ | └ mp_call_function_0 (py/runtime.c:601) | ||
+ | └ mp_call_function_n_kw (py/runtime.c:617) | ||
+ | └ mp_obj_get_type (py/obj.c:40) | ||
+ | └ type->call (py/obj.h:481) | ||
+ | On apprend déjà que micropython ''compile'' les instructions qu'on lui donne ; ce qui est assez surprenant car Python est un language typiquement interprété. | ||
+ | |||
+ | En résumé, l'erreur peut venir de l'une des 4 étapes suivantes : | ||
+ | * lexing | ||
+ | * parsing | ||
+ | * compilation | ||
+ | * exécution | ||
+ | |||
+ | Pour l'instant, je n'ai pas envie de toucher aux parties lexing-parsing-compilation ; je vois d'abord la partie exécution. Je m’intéresse donc à la fonction <code>mp_call_function_n_kw</code>. La première fonction appelée par cette dernière est <code>DEBUG_OP_printf</code>, qui imprime des informations sur la fonction exécutée ; il suffit de definir MICROPY_DEBUG_VERBOSE = 1 pour activer l'affichage des printf de déverminage. J'ai également rajouté l'affichage de la mémoire utilisée, afin de déverminer de ce côté aussi. Malheureusement, je n'ai rien trouvé. | ||
+ | |||
+ | ==Semaine 2 : Un OS maison== | ||
+ | |||
+ | Après l'échec avec micropython, je passe alors à l'option "créer mon propre OS". Puisque j'aime bien les fleurs, je décide de le nommer "fleurOS". | ||
+ | |||
+ | ===fleurOS=== | ||
+ | |||
+ | ====Documentation==== | ||
+ | |||
+ | Je vois que je ne suis pas le premier à avoir travaillé sur ce projet, et je pense que je ne serai pas le dernier. C'est pourquoi il est important de laisser une bonne documentation pour les pauvres âmes qui reprendront derrière moi. | ||
+ | |||
+ | La pluspart du code que j'ai écrit est documenté; pour voir la doc, il suffit d'exécuter <code>make docs</code>, qui produit la page ''doxygen/index.html''. Bonne lecture ! | ||
+ | |||
+ | ====shell==== | ||
+ | |||
+ | Dans un premier temps, je crée une invite de commandes : | ||
+ | |||
+ | [[Fichier:FleurOS_shell_1.png]] | ||
+ | |||
+ | Cet invite de commande permet d'entrer une ligne de caractères. Lorsqu'on appuie sur Entrée, la ligne est exécutée. | ||
+ | |||
+ | TODO : mettre photos. | ||
+ | |||
+ | La ligne est divisée en arguments (penser <code>argv[]</code>). Puisque j'évite au possible d'utiliser des allocations dynamiques, j'utilise un tableau alloué statiquement (Note à moi-même : utiliser <code>alloca()</code>) de taille <code>N_ARGS_MAX</code>. | ||
+ | |||
+ | Dans un shell réél, l'exécution est faite de deux façons; soit la commande entrée est cherchée dans le <code>$PATH</code> et le fichier binaire correspondant est exécuté, soit on exécute directement une commande [https://www.gnu.org/software/bash/manual/html_node/Shell-Builtin-Commands.html builtin] du shell. Je commence alors dans un premier temps par implémenter cette fonctionnalité, puisque je n'ai pas encore accès au système de fichiers de la carte SD. Par exemple, la fonction echo : | ||
+ | |||
+ | [[Fichier:Shell_Demo.png]] | ||
+ | |||
+ | ''Note : Les indications de debug peuvent être enlevées en mettant l'option <code>DEBUG = 0</code>.'' | ||
+ | |||
+ | Voir la commande <code>help</code>. | ||
+ | |||
+ | ====Pilotes==== | ||
+ | |||
+ | Qu'est-ce qu'un OS sans ses pilotes ? En plus du pilote USB implémenté par la LUFA, j'ai écrit quelques pilotes pour contrôler les LEDs, les boutons, et le bus SPI (ce dernier pilote a été fortement inspiré d'un pilote écrit par ATMEL). | ||
+ | |||
+ | Le pilote pour les LEDs présente une interface via le shell grâce à la commande <code>ledctrl</code>. | ||
+ | |||
+ | J'ai également essayé de faire des pilotes pour la carte SD et l'écran OLED, mais je pense que mon implémentation du bus SPI est erronée.. | ||
+ | |||
+ | ====Résultat==== | ||
+ | |||
+ | fleurOS est un squelette d'un système d'exploitation pour l'ATMEGAC3. J'ai essayé de créer un projet le plus modulaire possible, avec des drivers génériques. La configuration physique de la carte est faite dans ''board.c''. Dans ''config.h'', différents flags peuvent être définis pour modifier la compilation. | ||
+ | |||
+ | ==Semaines 3-6 : Bouclier d'entrées/sorties== | ||
+ | |||
+ | Comme vu précédemment, la LUFA présente quelques contraintes. De plus, l'objectif étant d'avoir un ordinateur semblable à ceux des années 80, il serait judicieux de trouver une alternative autre que de passer par <code>minicom</code>, et de pouvoir brancher un clavier sur la board. Pour résoudre les problèmes de la LUFA, et permettre de brancher un clavier sur notre carte, je vais alors faire un bouclier. | ||
+ | |||
+ | ===Design du bouclier USB=== | ||
+ | |||
+ | [[File:PCB Bouclier USB Microordinateur.png|thumb|Design du PCB du bouclier]] | ||
+ | |||
+ | [[File:Ordinateur_Bouclier_USB.jpg|thumb|600px|PCB enfiché sur l'ATXMEGAC3-XPLD]] | ||
+ | |||
+ | Le bouclier USB doit pouvoir s'enficher sur la XMEGAC3-XPLD et lui permettre de gérer une sortie série (encore <code>minicom</code>..) et d'accepter une entrée USB. | ||
+ | |||
+ | Ainsi, ce bouclier est en deux parties : | ||
+ | * Gestion de la sortie série. | ||
+ | * Gestion des entrées USB. | ||
+ | |||
+ | ====Sortie série==== | ||
+ | |||
+ | Pour gérer la sortie série, il nous faut gérer un périphérique USB. Pour cela, on utilise un ATMEGA8U2. Il recevra les caractères à afficher via la liaison RX de son USART, et les renverra à l'odinateur via un port micro-USB. | ||
+ | |||
+ | ====Entrées USB==== | ||
+ | |||
+ | Pour gérer les entrées USB (clavier, peut-être même souris), il nous faut un microcontrôleur capable d'assurer le rôle de maître USB. On utilise pour cela un AT90USB647. Il enverra les caractères reçus via la liaison TX de son USART. | ||
+ | |||
+ | Pour la connexion aux périphériques, on ajoute un port USB-A (femelle). (Note : il aurait été judicieux d'ajouter également un port mini-USB afin de pouvoir programmer le microcontrôleur via sa liaison USB.) | ||
+ | |||
+ | ===Troubleshooting=== | ||
+ | |||
+ | ====Sortie série==== | ||
+ | |||
+ | [[Fichier:Utilisation oscilloscope.png|thumb|600px|Sortie de l'oscillateur telle que vue sur l'interface de Louis]] | ||
+ | |||
+ | Nous avons fait imprimer les PCB à l'extérieur. Une fois les circuits reçus, j'ai commencé par souder les composants de la partie "sortie". Une fois chose faite, j'ai branché la carte à un PC en regardant la sortie de <code>dmesg -w</code>. Et là.. rien. Multimètre à la main, j'ai testé les tensions aux bornes des pattes du microcontrôleur; tout allait bien de ce côté. Un des composants qui avait le plus de chances de poser problème était le quartz. Pour tester les sorties de ce composant, il me fallait un oscilloscope. J'ai donc fait appel à mon camarade qui travaillait sur le projet [[IMA3/IMA4 2019/2021 P11+|TP à distance - Interface de visualisation]] (merci Louis <3). Évidemment, le quartz était mal soudé. Après une petite retouche de soudure, j'ai branché la carte au PC, et victoire ! Le périphérique est détecté comme un bootloader DFU. | ||
+ | |||
+ | Le lendemain, je rebranche mon PCB à l'ordinateur.. Et patatras, ça ne marche plus ! Je remarque que lorsque j'appuie sur la patte du micro-contrôleur liée au quartz, la connexion au PC se fait; c'est donc qu'il est mal soudé (pas étonnant..). Je passe chez M.Flamen, qui m'explique mes erreurs et me donne de quoi rattraper le truc. Grâce à quoi, mon micro-contrôleur est reconnu à chaque fois. Je peux le programmer facilement avec le dfu-programmer. | ||
+ | |||
+ | Je note également que j'ai placé les pins TX et RX à l'envers sur l'en-tête de broches. En enfichant la carte sur l'en-tête J4, on peut en utiliser les pins TX et RX - mais on bloque les boutons et l'écran OLED du XMEGAC3-XPLD. | ||
+ | |||
+ | ====Entrées USB==== | ||
+ | |||
+ | Après avoir soudé les composants de cette partie (et résolu les problèmes liés à ça), j'essaie de brancher mon PCB à un ordi. Premier soucis : je n'ai pas prévu de port USB-B pour permettre de brancher cette partie en tant que périphérique (note pour le futur, si une nouvelle carte est tirée : rajouter un port USB de programmation n'est pas une mauvaise idée). On a tout de même trouvé un câble USB-A - USB-A, avec lequel je connecte le PCB au PC. Sur la sortie de <code>dmesg -w</code>, plein d'erreurs s'affichent; le périphérique n'est pas reconnu.. | ||
+ | |||
+ | Heureusement, il me reste la possibilité de programmer via l'ICSP. Dans un premier temps, j'écris un simple programme pour tester la carte, qui fait simplement clignoter la LED TX (note pour le futur, si une nouvelle carte est tirée : rajouter des LEDs et des boutons pour tester la carte n'est pas une mauvaise idée). Bingo, ça marche :) | ||
+ | |||
+ | ===Programmation=== | ||
+ | |||
+ | Il faut maintenant programmer les deux micro-controleurs pour leur permettre de gérer leurs connexions USB. Et qui dit USB sur Arduino, dit LUFA ! | ||
+ | |||
+ | Je reprends deux démos de la librairie : ''VirtualSerial'' pour l'ATMEGA8U2 et ''KeyboardHost'' pour l'AT90USB647. | ||
+ | |||
+ | Il me faut également programmer l'entrée/sortie USART de l'ATXMEGAC3. | ||
+ | |||
+ | ====Sortie Série==== | ||
+ | |||
+ | Dans un premier temps, je crée un petit programme qui ne fait qu'envoyer une chaîne de caractères via la liaison série, pour tester la connexion USB. Les caractères envoyés sont bien reçus par <code>minicom</code> sur l'ordinateur, tout a l'air de fonctionner. En testant, je remarque tout de moins que lorsque je débranche le câble USB, l'ATMEGA16U2 se remet en mode DFU.. | ||
+ | |||
+ | Pour tester mon programme, vu que je n'ai pas encore rédigé la partie transmission de l'ATXMEGAC3-XPLD, je simule une connexion en reliant brièvement le pin RX du micro-contrôleur à VCC. Ça fonctionne ! | ||
+ | |||
+ | =====Entrées USB===== | ||
+ | |||
+ | J'écris un petit programme pour tester la sortie série dans un premier temps. En essayant d'écrire sur TX, rien ne se passe.. Je cherche un peu, et horreur ! Je vois que le pin que j'utilise -PD3- n'est pas le bon; j'ai inversé les pins TX et RX. Un petit coup de cutter, un fil et un peu de soudure et le tour est joué, ma LED clignote correctement. | ||
+ | |||
+ | Je passe à la LUFA : je reprends la démo ''KeyboardHost'', j'y rajoute un peu de code pour permettre l'utilisation de l'USART. Malheureusement, lorsque je connecte le clavier à la carte, j'obtiens cette erreur : | ||
+ | |||
+ | [[Fichier:Pipe_Error.png]] | ||
+ | |||
+ | Et encore plus malheureusement, c'est la fin des 6 semaines. Je suis contraint de m'arrêter là. | ||
+ | |||
+ | =Documents= | ||
− | + | [https://archives.plil.fr/aflorea/micro-ordinateur-pour-la-pedagogie sources] (archives.plil.fr) |
Version actuelle datée du 25 juin 2021 à 14:25
Sommaire
Présentation générale
- Nom du projet : Micro-ordinateur pour la pédagogie
- Stagiaire : Andrei FLOREA
- Encadrant : Xavier REDON
- Durée : 6 semaines (17 Mai - 25 Juin 2021)
Description
Concevoir et réaliser un ordinateur du même type que les ordinateurs familiaux des années 1980. L'ordinateur sera à base de micro-contrôleur mais avec clavier, écran et périphérique de sauvegarde.
Objectifs
Le but de ce projet est de réaliser un ordinateur peu puissant mais en le concevant de A à Z. Concernant le matériel :
- Le coeur doit être un micro-contrôleur, un processeur étant trop complexe à maîtriser, même si un AVR est envisageable, il serait préférable de partir vers un Cortex-M pour bénéficier d'une mémoire plus importante ;
- Pour les périphériques d'entrée, il faut utiliser un clavier USB et éventuellement une souris USB, ce qui implique de choisir un micro-contrôleur avec gestion USB ;
- Plusieurs choix sont possibles pour l'écran, un choix est de partir sur la génération de signaux VGA, il semble même envisageable d'utiliser une puce HDMI et enfin il existe le choix de l'écran LCD avec contrôleur intégré, choix fait par les concepteurs de la calculatrice NumWorks ;
- Pour le stockage, une carte micro-SD semble adaptée ;
- Une interface réseau est probablement indispensable qu'elle soit Ethernet ou WiFi.
Le système d'exploitation de l'ordinateur peut être basé sur micro-python avec ajout d'options spécifiques
Préparation du projet
Une première tentative de porter micro-python sur une carte ATXMEGAC3-XPLD a déjà été faite par Xuelu YAN en 2020. Je base donc mes efforts sur les siens.
De plus, il existe un port de micropython sur AVR.
Cahier des charges
Choix techniques : matériel et logiciel
- Matériel :
- Carte ATXMEGAC3-XPLD pour le prototypage
- Logiciel :
Liste des tâches à effectuer
- Première partie : Prototypage
- Prise en main de la carte ATXMEGAC3-XPLD
- Porter micro-python sur la carte ATXMEGAC3-XPLD
- OU créer un OS "maison"
- Gestion entrée/sortie
- Gestion capteurs
- Gestion périphérique de sauvegarde
- Créer un module USB (pour brancher un clavier)
- Choisir les composants
- Concevoir le circuit
- L'imprimer et y souder les composants
- Porter la bibliothèque LUFA de commande USB
- Coder l'interaction avec l'ATXMEGAC3
Calendrier prévisionnel
Réalisation du Projet
Prologue
Semaine 1 : Aventures avec micropython
Exploration du code source de micropython
J'ai d'abord commencé par explorer le code de micropython; je me suis dans un premier temps penché sur le port "avr8-dummy", qui est un exemple très basique (et générique) d'une implémentation de micro-python sur AVR.
On y voit un main.c, avec une fonction main qui ressemble à ça :
int main() { ... pyexec_event_repl_init(); for(;;) { usb_vcp_handling(); // = LUFA_USB_Handling() int c = mp_hal_stdin_rx_chr(); if (pyexec_event_repl_process_char(c)) { break; } } pyexec_friendly_reply(); ... }
Il semble que mp_hal_stdin_rx_chr
serve à lire un caractère sur l'entrée standard, et mp_hal_stdout_tx_strn
écrive sur la sortie standard. Une question se pose alors : qu'est-ce que l'entrée/sortie standard sur une Arduino ?
En cherchant un peu, j'ai trouvé le fichier mphalports.h, qui définit ces deux fonctions, ainsi que la fonction usb_vcp_handling
. Il me faut maintenant modifier la définition pour utiliser le port série. C'est ici que rentre en jeu la bibliothèque LUFA.
Exploration du code source de LUFA
LUFA est une librairie USB pour les microcontrolleurs AVR. Elle permet notamment de créer une connexion série entre un ordi et la carte.
Pour faciliter la tâche, on peut utiliser l'exemple VirtualSerial.
En modifiant légèrement le code du port micropython, on peut modifier les fonctions de façon à ce que les read et les print se fassent sur le port série.
En regardant un peu la documentation, on voit que la fonction LUFA_USB_Handling
doit être appelée au minimum toutes les 30ms afin (entre autres) de relancer périodiquement la connexion USB à l'hôte. Or, avec la boucle que nous avons dans le main, nous risquons de rater cette échéance. Dans certaines boards Arduino, la connexion USB est réalisée via un deuxième microcontrôleur. Ainsi, il y a de grandes chances qu'il faille, à un moment ou un autre, réaliser un bouclier pour notre Arduino permettant de gérer cettte connexion USB.
Fusion de micropython et de LUFA
En ajoutant la bibliothèque LUFA dans le projet micropython, on peut maintenant interagir avec l’Arduino via le port série avec minicom
. On peut interagir avec l'invite de commandes, mais..
On peut voir que micropython n'a pas l'air de très bien savoir ce qu'on veut de lui. Par conséquent, c'est le moment de plonger plus loin dans le code de micropython.
Replonger dans micropython
La fonction la plus intéressante dans main
est pyexec_event_repl_process_char
. Cette fonction appelle les fonctions suivantes (seules les fonctions les plus intéressantes (selon moi) sont renseignées) :
FONCTIONS DEFINITIONS pyexec_event_repl_process_char (lib/utils/pyexec.c:345) └ pyexec_friendly_repl_process_char (lib/utils/pyexec.c:232) └ parse_compile_execute (lib/utils/pyexec.c:62) ├ mp_lexer_new_from_str_len (py/lexer.c:706) │ └ mp_lexer_new (py/lexer.c:670) ├ mp_parse (py/parse.c:832) ├ mp_compile (py/compile.c:3527) │ ├ mp_compile_to_raw_code (py/compile.c:3364) │ └ mp_make_function_from_raw_code (py/emitglue.c:122) └ mp_call_function_0 (py/runtime.c:601) └ mp_call_function_n_kw (py/runtime.c:617) └ mp_obj_get_type (py/obj.c:40) └ type->call (py/obj.h:481)
On apprend déjà que micropython compile les instructions qu'on lui donne ; ce qui est assez surprenant car Python est un language typiquement interprété.
En résumé, l'erreur peut venir de l'une des 4 étapes suivantes :
- lexing
- parsing
- compilation
- exécution
Pour l'instant, je n'ai pas envie de toucher aux parties lexing-parsing-compilation ; je vois d'abord la partie exécution. Je m’intéresse donc à la fonction mp_call_function_n_kw
. La première fonction appelée par cette dernière est DEBUG_OP_printf
, qui imprime des informations sur la fonction exécutée ; il suffit de definir MICROPY_DEBUG_VERBOSE = 1 pour activer l'affichage des printf de déverminage. J'ai également rajouté l'affichage de la mémoire utilisée, afin de déverminer de ce côté aussi. Malheureusement, je n'ai rien trouvé.
Semaine 2 : Un OS maison
Après l'échec avec micropython, je passe alors à l'option "créer mon propre OS". Puisque j'aime bien les fleurs, je décide de le nommer "fleurOS".
fleurOS
Documentation
Je vois que je ne suis pas le premier à avoir travaillé sur ce projet, et je pense que je ne serai pas le dernier. C'est pourquoi il est important de laisser une bonne documentation pour les pauvres âmes qui reprendront derrière moi.
La pluspart du code que j'ai écrit est documenté; pour voir la doc, il suffit d'exécuter make docs
, qui produit la page doxygen/index.html. Bonne lecture !
shell
Dans un premier temps, je crée une invite de commandes :
Cet invite de commande permet d'entrer une ligne de caractères. Lorsqu'on appuie sur Entrée, la ligne est exécutée.
TODO : mettre photos.
La ligne est divisée en arguments (penser argv[]
). Puisque j'évite au possible d'utiliser des allocations dynamiques, j'utilise un tableau alloué statiquement (Note à moi-même : utiliser alloca()
) de taille N_ARGS_MAX
.
Dans un shell réél, l'exécution est faite de deux façons; soit la commande entrée est cherchée dans le $PATH
et le fichier binaire correspondant est exécuté, soit on exécute directement une commande builtin du shell. Je commence alors dans un premier temps par implémenter cette fonctionnalité, puisque je n'ai pas encore accès au système de fichiers de la carte SD. Par exemple, la fonction echo :
Note : Les indications de debug peuvent être enlevées en mettant l'option DEBUG = 0
.
Voir la commande help
.
Pilotes
Qu'est-ce qu'un OS sans ses pilotes ? En plus du pilote USB implémenté par la LUFA, j'ai écrit quelques pilotes pour contrôler les LEDs, les boutons, et le bus SPI (ce dernier pilote a été fortement inspiré d'un pilote écrit par ATMEL).
Le pilote pour les LEDs présente une interface via le shell grâce à la commande ledctrl
.
J'ai également essayé de faire des pilotes pour la carte SD et l'écran OLED, mais je pense que mon implémentation du bus SPI est erronée..
Résultat
fleurOS est un squelette d'un système d'exploitation pour l'ATMEGAC3. J'ai essayé de créer un projet le plus modulaire possible, avec des drivers génériques. La configuration physique de la carte est faite dans board.c. Dans config.h, différents flags peuvent être définis pour modifier la compilation.
Semaines 3-6 : Bouclier d'entrées/sorties
Comme vu précédemment, la LUFA présente quelques contraintes. De plus, l'objectif étant d'avoir un ordinateur semblable à ceux des années 80, il serait judicieux de trouver une alternative autre que de passer par minicom
, et de pouvoir brancher un clavier sur la board. Pour résoudre les problèmes de la LUFA, et permettre de brancher un clavier sur notre carte, je vais alors faire un bouclier.
Design du bouclier USB
Le bouclier USB doit pouvoir s'enficher sur la XMEGAC3-XPLD et lui permettre de gérer une sortie série (encore minicom
..) et d'accepter une entrée USB.
Ainsi, ce bouclier est en deux parties :
- Gestion de la sortie série.
- Gestion des entrées USB.
Sortie série
Pour gérer la sortie série, il nous faut gérer un périphérique USB. Pour cela, on utilise un ATMEGA8U2. Il recevra les caractères à afficher via la liaison RX de son USART, et les renverra à l'odinateur via un port micro-USB.
Entrées USB
Pour gérer les entrées USB (clavier, peut-être même souris), il nous faut un microcontrôleur capable d'assurer le rôle de maître USB. On utilise pour cela un AT90USB647. Il enverra les caractères reçus via la liaison TX de son USART.
Pour la connexion aux périphériques, on ajoute un port USB-A (femelle). (Note : il aurait été judicieux d'ajouter également un port mini-USB afin de pouvoir programmer le microcontrôleur via sa liaison USB.)
Troubleshooting
Sortie série
Nous avons fait imprimer les PCB à l'extérieur. Une fois les circuits reçus, j'ai commencé par souder les composants de la partie "sortie". Une fois chose faite, j'ai branché la carte à un PC en regardant la sortie de dmesg -w
. Et là.. rien. Multimètre à la main, j'ai testé les tensions aux bornes des pattes du microcontrôleur; tout allait bien de ce côté. Un des composants qui avait le plus de chances de poser problème était le quartz. Pour tester les sorties de ce composant, il me fallait un oscilloscope. J'ai donc fait appel à mon camarade qui travaillait sur le projet TP à distance - Interface de visualisation (merci Louis <3). Évidemment, le quartz était mal soudé. Après une petite retouche de soudure, j'ai branché la carte au PC, et victoire ! Le périphérique est détecté comme un bootloader DFU.
Le lendemain, je rebranche mon PCB à l'ordinateur.. Et patatras, ça ne marche plus ! Je remarque que lorsque j'appuie sur la patte du micro-contrôleur liée au quartz, la connexion au PC se fait; c'est donc qu'il est mal soudé (pas étonnant..). Je passe chez M.Flamen, qui m'explique mes erreurs et me donne de quoi rattraper le truc. Grâce à quoi, mon micro-contrôleur est reconnu à chaque fois. Je peux le programmer facilement avec le dfu-programmer.
Je note également que j'ai placé les pins TX et RX à l'envers sur l'en-tête de broches. En enfichant la carte sur l'en-tête J4, on peut en utiliser les pins TX et RX - mais on bloque les boutons et l'écran OLED du XMEGAC3-XPLD.
Entrées USB
Après avoir soudé les composants de cette partie (et résolu les problèmes liés à ça), j'essaie de brancher mon PCB à un ordi. Premier soucis : je n'ai pas prévu de port USB-B pour permettre de brancher cette partie en tant que périphérique (note pour le futur, si une nouvelle carte est tirée : rajouter un port USB de programmation n'est pas une mauvaise idée). On a tout de même trouvé un câble USB-A - USB-A, avec lequel je connecte le PCB au PC. Sur la sortie de dmesg -w
, plein d'erreurs s'affichent; le périphérique n'est pas reconnu..
Heureusement, il me reste la possibilité de programmer via l'ICSP. Dans un premier temps, j'écris un simple programme pour tester la carte, qui fait simplement clignoter la LED TX (note pour le futur, si une nouvelle carte est tirée : rajouter des LEDs et des boutons pour tester la carte n'est pas une mauvaise idée). Bingo, ça marche :)
Programmation
Il faut maintenant programmer les deux micro-controleurs pour leur permettre de gérer leurs connexions USB. Et qui dit USB sur Arduino, dit LUFA !
Je reprends deux démos de la librairie : VirtualSerial pour l'ATMEGA8U2 et KeyboardHost pour l'AT90USB647.
Il me faut également programmer l'entrée/sortie USART de l'ATXMEGAC3.
Sortie Série
Dans un premier temps, je crée un petit programme qui ne fait qu'envoyer une chaîne de caractères via la liaison série, pour tester la connexion USB. Les caractères envoyés sont bien reçus par minicom
sur l'ordinateur, tout a l'air de fonctionner. En testant, je remarque tout de moins que lorsque je débranche le câble USB, l'ATMEGA16U2 se remet en mode DFU..
Pour tester mon programme, vu que je n'ai pas encore rédigé la partie transmission de l'ATXMEGAC3-XPLD, je simule une connexion en reliant brièvement le pin RX du micro-contrôleur à VCC. Ça fonctionne !
Entrées USB
J'écris un petit programme pour tester la sortie série dans un premier temps. En essayant d'écrire sur TX, rien ne se passe.. Je cherche un peu, et horreur ! Je vois que le pin que j'utilise -PD3- n'est pas le bon; j'ai inversé les pins TX et RX. Un petit coup de cutter, un fil et un peu de soudure et le tour est joué, ma LED clignote correctement.
Je passe à la LUFA : je reprends la démo KeyboardHost, j'y rajoute un peu de code pour permettre l'utilisation de l'USART. Malheureusement, lorsque je connecte le clavier à la carte, j'obtiens cette erreur :
Et encore plus malheureusement, c'est la fin des 6 semaines. Je suis contraint de m'arrêter là.
Documents
sources (archives.plil.fr)