dimanche 30 décembre 2012

programmateur d'eeprom i2c

Pour un projet sur lequel je travaille j'avais besoin d'un programmateur de mémoire eeprom sériel avec interface I2C mais en regardant sur le site de Microchip et celui de digikey.ca le prix m'a fait reculer. Avec les coûts de transport et les taxes j'aurais du débourser plus de 80$ pour un appareil qui ne me servira probablement que très rarement. J'ai donc entrepris de fabriquer mon propre programmateur. Ce programmateur est conçu pour les mémoires eeprom sérielles avec interface I2C de Microchip. Le projet comprend 2 parties, le montage électronique avec le firmware pour le MCU qui contrôle la programmation eeprom et le logiciel hôte qui tourne sur le PC. Pour le logiciel PC j'ai choisi de l'écrire en python pour qu'il puisse être utilisé aussi bien sous Windows que Linux ou même OSX.

Matériel requis

QtNo.Piècedescriptionprix $CANfournisseur
2A100204-NDembases DIL-80,20Digikey.ca
1RB-Ada-30perma-proto 1/48,95/pqt de 3Robotshop.com/ca
3P5148-NDcondensateur électrolytique 10uF/25V0,21digikey.ca
2445-8421-NDcondensateur céramique 100nF0,32digikey.ca
12N3904-APCT-NDtransistor NPN 2N39040,45digikey.ca
12N3906-APCT-NDtransistor PNP 2N39060,45digikey.ca
1PIC12F1822-I/P-NDMicrocontrolleur Micropchip PIC12F18221,50digikey.ca
11N4148-TAPCT-NDdiode 1N41480,25digikey.ca
1P2.0KBACT-NDresistance 2K/0,25Watt0,10digikey.ca
1CF14JT4K70CT-NDresistance 4K7/0,25Watt0,09digikey.ca
3CF14JT10K0CT-NDrésistance 10K/0,25Watt0,09digikey.ca
5609-3466-NDcontact pin0,11digikey.ca

schéma électronique


Le programmateur communique avec l'ordinateur via un port série à 115200 BAUD, 8bits, pas de parité et 1 stop. La partie à droite du schéma, constituée de Q1 et Q2 est un convertisseur de niveaux de tension pour le RS-232. C'est le même circuit que j'ai déjà présenté sur ce blog. Le MCU PIC12F1822 communique donc avec le PC à travers ce circuit et d'autre part avec l'eeprom via les broches 2,3 et 5. La broche 2 est la sortie SCL et la broche 3 est l'E/S pour SDA du protocole I2C. La broche 5 contrôle le WP de l'eeprom et est gardée au niveau haut sauf pendant l'écriture de données dans l'eeprom. Les eeprom 24LCxxxx ont 3 entrées d'addressage A0-A2, qui servent à sélectionner le circuit intégré sur le bus I2C. Puisqu'il y a 3 bits d'adresse on peut mettre jusqu'à 8 I.C. sur le même bus I2C. Sur le schéma du programmateur j'ai mis A2=A0 à Vdd, l'adresse est donc 0b111. Pour les 24LC1025 il faut que la broche A2 soit à Vdd car le bit de la commande qui correspond à A2 dans les eeprom de plus de 64KB est utilisé pour sélectionner le block de 64K, la mémoire étant divisé en 2 block de 64KB.

montage

Pour le montage j'ai utilisé une platine produite par Adafruit et distribuée par Robotshop.com. C'est la première fois que j'utilise ce produit et je suis très satisfait. La qualité est bonne, les oeillets de soudure sont passant donc on peut soudé du côté composant sans avoir à retourner la platine. Le dessus de la platine est une représentation exacte d'une platine sans soudure. Donc pour faire le montage pas besoin de refaire un schéma de montage il suffit de recopier simplement ce qu'on a fait sur la platine sans soudure. Le montage a été plus rapide que si je l'avais fait sur une platine à grille de points 100mil. C'est un produit intéressant que je recommande.
Côté cuivre de la platine entre les contacts TX et RX j'ai coupé la trace du circuit imprimé pour isoler les contacts l'un de l'autre puisqu'il sont montés sur la même rangée.


firmware PIC12F1822

En ce qui concerne le firmware du PIC12F1822 ça a été assé simple. Pour la communication avec le PC comme le MCU a un périphérique USART incorporé le travail au niveau logiciel a été très simple. Le gros du travail c'est fait au niveau de l'interface I2C avec l'eeprom, mais pas de quoi s'arracher les cheveux.

code source firmware PIC12F1822


programme hôte

Comme je l'ai mentionné en introduction j'ai écris le programme en python. Je ne l'ai pas testé sous Linux mais en principe il devrait fonctionner sans modification. Il s'agit d'une application ligne de commande mais l'utilisation est simple.
i2cprog.py port_série mode fichier nombres_octets [-l opp] [-f32]
port_série est le nom du port utilisé pour la communication avec le programmateur.
Sous windows c'est quelque chose comme com3 alors que sous linux ça ressemble à /dev/ttyS0 ou encore /dev/ttyUSB0.
mode est p pour programmer l'eeprom ou r pour lire le contenu de l'eepom.
fichier est le nom du fichier qui contient les données à programmer ou pour le mode r le fichier dans lequel les données seront enregistrées.
nombres_octets est le nombre d'octets à programmer ou lire.
-l opp n'est utilisé que pour la programmation et indique le nombre d'octets par page de l'eeprom. Ce paramètre est essentiel pour la programmation et se retrouve dans le datasheet de l'eeprom utilisée. Par exemple pour 24LC512 ce paramètre est 128.
-f32 n'est utilisé que pour la lecture et sert produire un fichier au format Intel HEX32 plutôt que d'enregistrer les données en binaire brute.
Notez qu'en mode programmation i2cprog.py reconnais les fichiers Intel HEX32 et peut donc en extraire les données pour la programmation. I2cprog.py reconnait aussi les fichiers audio *.WAV 8 et 16bits non compressés. Donc si le nom du fichier se termine par .wav i2cprog.py en extrait le nombre d'octets contenu dans le segment data et l'inscris au début (4 premier octets little indian) ensuite il inscris tous les echantillons dans l'eeprom. J'ai ajouté cette fonctionnalité car c'est exactement ce que j'ai besoin pour mon projet actuel qui sera plublié bientôt sur ce blog.

code source i2cprog.py

tous les fichiers du projet sont disponibles ici.

dimanche 16 décembre 2012

découverte archélogique

Ce soir en fouillant dans le débarras au sous-sol j'ai fait une découverte archéologique. Le 3ième ordinateur personnel que j'ai possédé était un TRS-80 color computer 2 (coco 2). J'ai donné cet ordinateur il y a très longtemps mais j'avais encore en ma possession l'enregistreuse à cassette qui me servait à sauvegarder mes programmes et mes données. Sans surprise après 30+ années d'inactivité elle ne fonctionne plus. Les courroies de catoutchouc du moteur et du cabestan sont éventées. Cependant il y avait aussi une cassette qui a servie à enregistrer des données. Comme l'enregistreuse à un compteur, j'indiquais sur l'index la position de début et fin de chaque enregistrement.

  1. compers 0-6
  2. trie-rapide 10-15
  3. pascal32 20-32

Pour récupérer un enregistrement il fallait faire une avance rapide FAST-F jusqu'à la position désirée avant de peser sur PLAY/CLOAD pour débuter le chargement. Évidemment pour ajouter un enregistrement il fallait dérouler jusqu'après le dernier. Il semble qu'on était pas pressé dans ce temps là.

J'ai encore un lecteur de cassette sur ma chaîne stéréo. J'ai écouté la cassette par curiosité et j'ai reconnu le son caractéristique de ce genre d'enregistrement qui le plus souvent utilisait un standard appellé KCS pour Kansas City Standard. A l'époque il se vendait des cassettes dites numériques qui supposément assurait une meilleure fiabilité des enregistrements, ces dernières coûtaient évidemment plus cher que les cassettes audio standard. Mais comme on peut le voir sur la photo ci-bas. Je me servais de cassettes audio bas de gamme achetées chez Canadian Tire et je n'ai jamais eu de problème. Je suis même confiant que si j'avais encore mon coco 2 je pourrais recharger les données contenue sur celle-ci.





jeudi 13 décembre 2012

premiers pas avec MCU Atmel AVR

Ça faisait déjà plus d'un mois que j'avais acheter un programmeur Polulu AVR. Ajourd'hui j'ai décidé qu'il était temps de m'y mettre en commencant par le plus simple.

La première étape est de télécharger et installer Atmel studio 6.0.
Il faut ensuite installer le logiciel de Polulu pour le programmeur.

Je dois dire que j'avais préalablement acheter et lu le datasheet du AtTiny13A que j'ai utiliser pour programmer une variante de la LED qui clignote.

Atmel studio 6.0

En suivant les instructions du manuel de démarrage du programmeur Polulu. Ça a été simple de me retrouver dans Atmel studio et d'écrire la première version du programme en C. En effet le studio installe le compilateur avr-gcc ce qui permet de programmer en 'C' dès le départ. J'ai donc branché une LED RBG au AtTiny13A comme suit:


et j'ai relié le programmeur au MCU comme ceci:


Le programme que j'ai écris cycle entre les 3 couleurs du LED RGB et le code source est le suivant:

#define F_CPU 9600000
#define DLY 200
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
CLKPR= (1<<7);
CLKPR = 0 ; // désactivation du diviseur
PORTB |= (1<<PORTB5); // pullup sur RESET
DDRB |= (0x11<<DDB3|1); // met PORTB broche 0, 3 et 4 en sortie
PORTB &= ~(0x11<<PORTB3|1) ; // eteint tous les LED
while (1){ //boucle infinie
PORTB |= (1<<PORTB3); // allume le LED sur PB3
_delay_ms(DLY);
PORTB &= ~(1<<PORTB3); // éteint le LED sur PB3
PORTB |= (1<<PORTB4); // allume le led sur PB4
_delay_ms(DLY);
PORTB &= ~(1<<PORTB4); // éteint LED sur PB4
PORTB |= 1; // allume LED sur PB0
_delay_ms(DLY);
PORTB &=0xFE ; // éteint LED sur PB0
}

}


Ce programme compilé occupe 164 octets sur les 1K de mémoire flash du ATTiny13A.
Je voulais comparé ça avec le code écris en assembleur. Comme je n'ai jamais programmé en assembleur pour les AVR j'ai fait une recherche rapide dans google pour trouver des exemples et me suis inspiré de ce que j'ai trouvé.

/*
* BlinkRGB.asm
*
* Created: 2012-12-13 13:10:32
* Author: Jacques
* REF: http://jaxcoder.com/Projects.aspx?id=912541054
* http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=94232
* DESCRIPTION: une LED RGB est branché sur PB0,PB3 et PB4 le programme cycle les 3 couleurs
*/


.NOLIST
.include "tn13adef.inc"
.LIST

.equ DLY = 500 ; 500 msec
.equ F_OSC = 9600000 ; 9.6Mhz
.equ LED1 = PORTB0
.equ LED2 = PORTB3
.equ LED3 = PORTB4


.cseg
.org 0
rjmp init
.org 0x20 ; les 32 première addresses sont réservée aux vecteurs d'interruption.
init:
ldi r16, LOW(RAMEND)
out SPL, r16 ; initialisation du pointeur de pile.
ldi r16, 1<<7
ldi r17, 0
out CLKPR, r16
out CLKPR, r17 ; pas de diviseur sur horloge cpu
ldi r16, 1<<PORTB5
out PORTB, r16 ; pullup sur PORTB5 (reset)
ldi r16, (1<<LED2|1<<LED3|LED1)
out DDRB, r16 ; broche LED1,LED2 et LED3 en sortie
ldi r16, ~(1<<LED2|1<<LED3|LED1)
out PORTB, r16 ; éteint les 3 LEDs

main:
sbi PORTB, LED1 ; allume LED1
rcall delay_ms
cbi PORTB, LED1 ; éteint LED1
sbi PORTB, LED2 ; allume LED2
rcall delay_ms
cbi PORTB, LED2 ; éteint LED2
sbi PORTB, LED3 ; allume LED3
rcall delay_ms
cbi PORTB, LED3
rjmp main

delay_ms:
/* sous-routine de délais
count=(dly/Tboucle)=~(dly/Tcy*nbreCycles)
count=(dly/(nbreCycles/F_OSC))
count=(dly*F_OSC/nbreClycles)
*/
ldi r16, 0xFF & (DLY*F_OSC/4000) ; initialise le compteur délais
ldi r17, 0xFF & (DLY*F_OSC/4000)>>8
ldi r18, 0xFF & (DLY*F_OSC/4000)>>16
dly_loop:
dec r16 ; 1tcy
nop ; 1tcy
brne dly_loop ; 2tcy
dec r17
brne dly_loop
dec r18
brne dly_loop
ret

Le code assembleur occupe 68 octets ce qui représente 41% de la version 'C', mais avec un programme plus gros cet 'overhead' paraîtrait moins coûteux. J'ai examiné le code assembleur résultant du 'C' pour voir la différence. Ça tient principalement au code d'initialisation généré par le compilateur et au fait que le délais est inséré comme une macro plutôt que défini comme une sous-routine comme c'est le cas dans ma version en assembleur. J'observe aussi une différence dans la routine de délais. La macro du programme 'C' est la suivante pour _delay_ms

; r24,r25 et r26 servent de registre 24 bits pour le compteur de délais.
.macro _delay_ms ; voir note 1
ldi r24, LOW(@0) ; octet faible du premier argument, aussi: BYTE1(@0)
ldi r25, HIGH(@0) ; 2ième octet du premier argument, aussi: BYTE2(@0)
ldi r26, BYTE3(@0) ; 3ième octet du premier argument
dly_loop:
subi r24, 0x01 ; soustrait 1 à (r24-r25-r26)
sbci r25, 0x00 ; sustraction en tenant compte du carry bit.
sbci r26, 0x00
brne dly_loop
.endmacro

Cette macro utilise une soustraction sur 24 bits au lieu de décrémenter successivement les compteurs. J'ai modifié mon code assembleur pour utiliser cette méthode et je sauve 6 octets:
; constantes ajoutées au début du fichier
; maintenant on divise par 5000 au lieu de 4000
; car il y a 5 cycles dans la boucle au lieu de 4.
; le 1000 c'est pour les millisecondes DLY=500/1000 sec.
.equ DLY1 = 0xFF & (DLY*F_OSC/5000)
.equ DLY2 = 0xFF & (DLY*F_OSC/5000)>>8
.equ DLY3 = 0xFF & (DLY*F_OSC/5000)>>16

delay_ms:
/*
sous-routine de délais
version améliorée
*/
ldi r16, DLY1 ; initialise le compteur délais
ldi r17, DLY2
ldi r18, DLY3
dly_loop:
subi r16, 1 ; 1tcy
sbci r17, 0 ; 1tcy
sbci r18, 0 ; 1tcy
brne dly_loop ; 2tcy
ret

Comparaison avec MCU PIC

Prenons la sous-routine delay_ms et comparons là avec ce qu'on ferais avec un PIC baseline ou mid-range:

ms_delay
movlw DLY1
movwf dly_cntr
movlw DLY2
movwf dly_cntr+1
movlw DLY3
movwf dly_cntr+2 ; 6 instructions pour initialiser le compteur au lieu de 3.
dly_loop
movlw 1
subwf dly_cntr,F
clrw
skpc
subwf dly_cntr+1, F
skpc
subwf dly_cntr+2, F
skpnc
goto dly_loop ; 9 instructions pour la boucle au lieu de 4
return

Ça prend 2 fois plus d'instructions sur un PIC!!. Essayons avec un enhanced midrange:

ms_delay
movlw DLY1
movwf dly_cntr
movlw DLY2
movwf dly_cntr+1
movlw DLY3
movwf dly_cntr+2 ; aucun gain par rapport aux baseline/midrange
dly_loop
movlw 1
subwf dly_cntr, F
clrw
subwfb dly_cntr+1, F ; instruction disponible seulement
subwfb dly_cntr+2, F ; sur les enhanced et extended.
skpnc
goto dly_loop ; gain de 2 instructions grâce à subwfb
return

Grâce à l'instruction subwfb disponible sur les cores enhanced, on sauve 2 instructions mais on est encore à 14/8 en comparaison avec le AVR. De plus grâce aux 32 registres interne au core AVR a n'a utilisé aucune mémoire RAM alors que les PIC en utilisent 3 pour le compteur.

Beaucoup de points positifs pour le core AVR mais tout n'est pas positif. En effet une instruction AVR occupe 2 octets et certaines en prennent 4. Donc pour le AtTiny13a qui a 1K de flash ça veut dire un maximum de 512 instructions. Il faut en tenir compte lorsqu'on choisi un mcu AVR pour un projet. L'autre point négatif est que l'accès à la RAM prend 2 cycles au lieu de 1 pour les PIC. Par contre un cycle AVR c'est un cycle d'horloge alors qu'un cycle PIC c'est 4 cycles d'horloges. Donc un PIC qui a une horloge interne de 16Mhz comme le PIC10F322 a un cycle d'instruction de 250nsec alors qu'un AVR AtTiny13A avec son horloge à 9.6Mhz a un cycle d'instruction de 104nsec. Donc ce qui semblait-être un point négatif au départ est en fait positif. A fréquence d'horloge égales l'AVR est 4 fois plus rapide pour les opérations arithmétiques et logiques qui se font sur ses registres internes et 2 fois plus rapide pour les accès à la RAM. Par contre s'il doit faire une opération sur une variable dans la RAM il doit d'abord la ramené dans un registre internet faire l'opération et la réécrire dans la RAM. Avec 1 PIC si on veut par exemple incrémenter une variable eu peut le faire en 1 seule instruction et 1 seul cycle. Mais avec ses 32 registres internes au core les AVR tiny peuvent faire pas mal de chemin sans utiliser la RAM.

Conclusion

L'expérience a été intéressante et ce n'est surement la dernière fois que je travaille avec des AVR. Au niveau de l'assembleur la richesse du jeux d'instructions à comparer à la pauvreté du jeux PIC baseline et mid-range rends l'expérience plus agréable. Le fait de pouvoir programmer en 'C' sans avoir à acheter un compilateur coûteux est aussi un point intéressant.



NOTES:
1) contrairement à mpasm avrasm n'utilise pas de noms pour les arguments de macros.
le nombre maximum d'arguments est de 10 et ils sont nommé @0-@9.
Une définition de macro peut se terminée par .endm ou .endmacro
Toutes les directives de l'asembleur commence par un '.'

dimanche 9 décembre 2012

tictactoe 3D, conclusion

Ce projet est maintenant complété. J'ai fait un montage sommaire du circuit sur un morceau de bois qui trainait dans le garage. Comme les modules LED ne tenaient pas bien à la vertical j'ai ajouté un morceau d'acrylique pour les tenirs droit.


J'ai ajouté un petit haut-parleur au circuit de la carte mère pour signaler certains événements aux joueurs. Voici le schéma corrigé.


Schéma des manettes de contrôle:





PIC12F1822

Comme c'est la première fois que j'utilise un PIC12F1822 sur ce blogue je vais en faire une brève présentation. Il s'agit d'un MCU à 8 broches avec un coeur enhanced mid-range avec 2KBi de mémoire flash, 128 octets de RAM et 256 octets EEPROM. Mais ce qui rends intéressant les enhanced mid-range c'est l'adressage indexé relatif via les 2 registres FSR. J'ai profité de cette fonctionnalité pour utiliser une façon différence de programmer. Tout en travaillant en assembleur, j'ai en quelque sorte imité le travail d'un compilateur 'C'. C'est à dire que j'ai créé une pile (stack) pour passer les arguments aux sous-routines et aussi pour les variables locales. J'ai défini un ensemble de macros pour faciliter ce travail avec la pile. Le programme ne fait donc pas usage de variables temporaires autres que celles qui sont empilées. L'ensemble des fichiers du projet sont ici.

fonctionnalités

Il ne s'agit pas seulement d'un jeux de tictactoe, le cube de LED peut-être contrôlé à partir d'un PC grâce à un cable sériel RS-232. les paramètres de transmission sont 19200BAUD/8N1 pas de contrôle de flux. Vous trouverez dans le dossier google docs du projet 3 scripts python à titre d'exemple.

Lorsque le jeux est allumé et avant de démarrer la partie, le PC peut transmettre des commandes au contrôleur maître qui les relais au cube. Cependant lorsque la partie est débutée les commandes ne sont plus relayées.


liste des fichiers source.

fichiercontenu
tictactoe3d.asmfirmware des modules LEDs.
pic10f322_m.incmacros d'usage général pour PIC10F322
tictactoe-master.asmfirmware du contrôleur principal sur la carte-mère.
pic12f1822_m.incmacros d'usage général pour PIC12F1822


difficultés rencontrées

Je dois dire que le développement du firmware a été plus difficile que je l'aurais cru surtout pour le contrôleur maître. En bonne partie du à ma nouvelle façon de travailler avec une pile. Il faut toujours un certain temps pour s'adapter à une nouvelle méthode de travail. Mais cette méthode vaut la peine d'être explorée et améliorée. Vous noterez dans le code source du fichier controleur-maitre.asm la présence de 2 sous-routines qui n'ont pas été compilées dans la version finales. send_to_pc et display_byte n'étaient que des outils de débogage. La première sous-routine envoie un octet vers le PC et l'autre utilise les modules 1 et 4 du cube pour afficher un octet en base 4. Sans ces outils le travail le n'aurais peut-être jamais aboutis. Ce sont deux exemples de la façon d'utiliser des ressources qui sont déjà disponible dans le projet pour faire du débogage.


conclusion

tictactoe-master.asm n'utilise que 51% de la mémoire programme et 12% de la RAM. Tictactoe3D.asm utilise 63% de la mémoire programme et 23% de la RAM il y a donc encore de la place pour apporter des améliorations et nouvelles fonctionnalités au projet.

mise à jours

2016-09-23 ajout d'une vidéo sur youtube suite à une demande.