Programmation embarquée

Révision de 21 mars 2014 à 17:14 par Cedric (discussion | contributions) (compilation)

Révision de 21 mars 2014 à 17:14 par Cedric (discussion | contributions) (compilation)

Sommaire

résumé

le TP de la semaine de la fabacademy consiste à se familiariser avec la programmation de microcontroleurs et processeurs.

je vais commencer par programmer les deux circuits que j'ai réalisé : le FabISP et le helloWorld


premiers pas

La première étape est de finir mon travail en retard sur le fabISP : comme j'attendais l'arrivée des composants, je n'ai pas eu le temps de programmer le circuit à temps. De plus je ne comprenais pas bien la logique d'alimentation du circuit : je croyais que le programmateur alimentait la puce cible alors qu'il fallait qu'elle le soit séparément...

cette fois ça marche en suivant le protocole du tutoriel

make -f hello.ftdi.44.echo.c.make avr-objcopy -O ihex hello.ftdi.44.echo.out hello.ftdi.44.echo.c.hex;\ avr-size --mcu=attiny44 --format=avr hello.ftdi.44.echo.out AVR Memory Usage


Device: attiny44

Program: 776 bytes (18.9% Full) (.text + .data + .bootloader)

Data: 64 bytes (25.0% Full) (.data + .bss + .noinit)


cedric@cedric-Inspiron-5520 ~/fabacademy/electronicDesign/programming $ make -f hello.ftdi.44.echo.c.make program-avrisp2-fuses avr-objcopy -O ihex hello.ftdi.44.echo.out hello.ftdi.44.echo.c.hex;\ avr-size --mcu=attiny44 --format=avr hello.ftdi.44.echo.out AVR Memory Usage


Device: attiny44

Program: 776 bytes (18.9% Full) (.text + .data + .bootloader)

Data: 64 bytes (25.0% Full) (.data + .bss + .noinit)


avrdude -p t44 -P usb -c avrisp2 -U lfuse:w:0x5E:m

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9207 avrdude: reading input file "0x5E" avrdude: writing lfuse (1 bytes):

Writing | ################################################## | 100% 0.01s

avrdude: 1 bytes of lfuse written avrdude: verifying lfuse memory against 0x5E: avrdude: load data lfuse data from input file 0x5E: avrdude: input file 0x5E contains 1 bytes avrdude: reading on-chip lfuse data:

Reading | ################################################## | 100% 0.00s

avrdude: verifying ... avrdude: 1 bytes of lfuse verified

avrdude: safemode: Fuses OK

avrdude done. Thank you.

$ make -f hello.ftdi.44.echo.c.make program-avrisp2 avr-objcopy -O ihex hello.ftdi.44.echo.out hello.ftdi.44.echo.c.hex;\ avr-size --mcu=attiny44 --format=avr hello.ftdi.44.echo.out AVR Memory Usage


Device: attiny44

Program: 776 bytes (18.9% Full) (.text + .data + .bootloader)

Data: 64 bytes (25.0% Full) (.data + .bss + .noinit)


avrdude -p t44 -P usb -c avrisp2 -U flash:w:hello.ftdi.44.echo.c.hex

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.00s

avrdude: Device signature = 0x1e9207 avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed

        To disable this feature, specify the -D option.

avrdude: erasing chip avrdude: reading input file "hello.ftdi.44.echo.c.hex" avrdude: input file hello.ftdi.44.echo.c.hex auto detected as Intel Hex avrdude: writing flash (776 bytes):

Writing | ################################################## | 100% 0.27s

avrdude: 776 bytes of flash written avrdude: verifying flash memory against hello.ftdi.44.echo.c.hex: avrdude: load data flash data from input file hello.ftdi.44.echo.c.hex: avrdude: input file hello.ftdi.44.echo.c.hex auto detected as Intel Hex avrdude: input file hello.ftdi.44.echo.c.hex contains 776 bytes avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.23s

avrdude: verifying ... avrdude: 776 bytes of flash verified

avrdude: safemode: Fuses OK

avrdude done. Thank you.



Par contre, le programme ne répond pas par le port série.

en explorant les différents codes, j'ai trouvé dans http://academy.cba.mit.edu/classes/embedded_programming/hello.ftdi.44.echo.interrupt.c

un commentaire de neil : "set lfuse to 0x7E for 20 MHz xtal"

or dans la makefile que j'ai utilisé, le fuse est seté à 0x5E

j'essaye de comprendre le datasheet pour résoudre ce probleme...

Dans le datasheet, il est question de la calibration de l'oscilateur: "...OSCCAL = 0x7F gives a higher frequency than OSCCAL = 0x80..."


je n'ai pas réussi à décoder exactement le code pour comprendre à quoi correspond ce setting mais je vois qu'il est question de selectionner l'external clock et le multiple de l'horloge.

En tous cas, le circuit fonctionne : je peux commencer à essayer de la programmer

il suffit de modifier le makefile en remplaçant :


program-avrisp2-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c avrisp2 -U lfuse:w:0x5E:m


par


program-avrisp2-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c avrisp2 -U lfuse:w:0x7F:m



en assembleur

j'ai choisi la facilité : au lieu d'écrire en hexadécimal, je vais utiliser l'assembleur...

En partant de l'exemple de Neil, je vais essayer de faire un clignoter ma led.

je commence à lire le programme et je trouve :

ldi temp, (1 << CLKPCE) ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0)

en lisant le datasheet, je comprends que :

'ldi = load immediate


(p30) CLKPCE=1 : Clock Prescaler Change Enable

(0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0) : Clock prescaler select : Clock division factor = 1

donc logiquement, le systeme doit fonctionner à la fréquence du quarts (qui est l'orloge externe : 20mhz)

compilation

il faut avoir téléchargé le compilateur gavrasm

Une fois décompressé dans le dossier (ou installé) on peut compiler un programme avec la commande :

./gavrasm <fichier_source_asm>

par exemple dans mon cas :

./gavrasm hello.ftdi.44.blink.asm

j'arrive à compiler mon code, mais la led ne clignote pas...

quelques pistes sur l'assembleur

http://www.unixgarden.com/index.php/gnu-linux-magazine/coder-pour-atmel-attiny


le guide assembleur AVR


des histoires d'horloge

voici ma boucle de délai :

delai:

  ;ldi temp, 255; max
  ;clr temp
  delay_loop:
     dec temp 
     clr temp1  
     delay_loop2:
       dec temp1
       clr temp2

delay_loop3:

         dec temp2
         brne delay_loop3 
       brne delay_loop2 
     brne delay_loop
  ret


malgré une boucle de délai conséquente (255^3), je ne voyais pas la led clignoter.

pourtant 255*255*255=16581375 cycles

et l'horloge tourne à 20Mhz, soit un cycle toutes les 1/20000000=0,00000005 sec

donc logiquement ma boucle devrai faire :

16581375*0,00000005=0,8s

or je ne vois pas le clignotement.

Par contre en changeant le diviseur de l'horloge à 256

ldi temp, (1 << CLKPCE) ldi temp1, (1 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);/256 out CLKPR, temp out CLKPR, temp1

le clignotement est apparent et dure à peu près la durée prévue. J'ai donc fait des erreurs de calcul?


désynchronisation

J'ai enfin réussi à faire clignoter la led, mais depuis, j'ai perdu mon tiny !

si j'essaye de le reprogrammer, j'ai :

make -f hello.ftdi.44.blink.asm.make program-avrisp2 avrdude -p t44 -P usb -c avrisp2 -U flash:w:hello.ftdi.44.blink.hex

avrdude: stk500v2_command(): command failed avrdude: stk500v2_program_enable(): bad AVRISPmkII connection status: Unknown status 0x00 avrdude: initialization failed, rc=-1

        Double check connections and try again, or use -F to override
        this check.


avrdude done. Thank you.

make: *** [program-avrisp2] Erreur 1

Sur les conseils de Neil, j'essaye d'utiliser l'option "-i" de avrdude , qui spécifie la délai en microsecondes entre chaque changement de bit.

-i delay
                  For bitbang-type programmers, delay for approximately delay
                  microseconds between each bit state change.  If the host
                  system is very fast, or the target runs off a slow clock
                  (like a 32 kHz crystal, or the 128 kHz internal RC oscilla‐
                  tor), this can become necessary to satisfy the requirement
                  that the ISP clock frequency must not be higher than 1/4 of
                  the CPU clock frequency.


Si je continue mes mauvais calculs :

l'horloge tourne à 20mhz mais est divisée par 256, donc elle fait 20000000/256=78125 cycles/sec

donc un cycle dure = 1/78125 = 0,0000128 sec = 12,8 microsecondes

Finalement l'option "-i" ne donne rien, mais j'ai fini par trouver une solution ici : utiliser l'option -B 1024 pour effacer le programme

ouf !

patience et longueur de temps

J'ai remis l'horloge à son timing d'origine.

Mais diable ! comme il est difficile de faire patienter cette horloge qui tourne à l'allure vertigineuse de 20 millions de cycles par secondes !!!

j'ai finalement trouvé une solution plus ou moins élégante, en utilisant deux registres couplés (sous forme de words) qui au lieu de plafonner à 255, atteignent 65535 : ça fait déjà plus de cycles.

delai: mov r16,temp outer_loop:; duration ~


ldi r26, 0; set r26 to zero ldi r27, 0; set r27 to zero delay_loop:;~262143*65535+3= 17179541508 cycles adiw r26, 1; add 1 to r26 and r27 ldi r28, 0; set r28 to zero ldi r29, 0; set r29 to zero delay_loop1:;~4*65535+3= 262143 cycles adiw r28, 1; add 1 to r28 and r29; 2 cycles brne delay_loop1; if no overflow loop; 1 or 2 cycles brne delay_loop; if no overflow loop

dec r16; dcrement R16 brne outer_loop; if no overflow loop ret

Expérimentalement, j'ai trouvé que cette boucle tourne environ en une centiseconde.

C'est à dire que si on set le registre "temp" à 100, le délai durera une seconde :

ldi temp,100;delay 1 sec

       rcall delai; delay