ATTiny13 - avr-gcc Hello World utilise plus de 100 octets?

9

J'essaie d'écrire un programme pour ATTiny13. Mon problème est qu'il a d'énormes contraintes de taille. Eh bien, lors de la création de mon premier programme Hello World, il a fallu 100 octets d'espace de programme juste pour allumer et éteindre une lumière! Y a-t-il des options que je peux donner à avr-gcc pour réduire cette taille? De plus, que contient le crt0? Je ne suis pas trop passionné par l'assemblage AVR donc je ne le comprends pas beaucoup ..

Je ne veux pas avoir à passer à l'assemblage pour ce projet ..

Earlz
la source
En guise de petite note, certaines personnes appellent cela un programme "Blinky".
Johan
1
@Johan et je ne savais pas comment épeler "blinkenlights"
Earlz

Réponses:

9

crt0 est la routine de démarrage de l'UC. Les routines effectuent la configuration des registres ainsi que l'initialisation des données.

Les 100 octets incluent-ils la table des vecteurs d'interruption? Je ne suis pas sûr de l'Attiny13 mais l'Attiny25 / 45/85 a 15 vecteurs d'interruption. Cela prendrait 30 octets.

gcc a une option pour lier dans votre crt0. Vous pouvez prendre le fichier AVR crt0.S et le modifier. Ce n'est pas très long donc ça ne devrait pas être difficile à faire.

jluciani
la source
Je n'arrive pas à trouver la source crt0, mais dans crt1 il y a ce qui semble être une table de vecteurs d'interruption. Peut-être que c'est ça
Earlz
Je ne le trouve pas non plus sur mon système :( J'ai compilé tous les outils à partir des sources, donc je pensais que ce serait là. Si vous recherchez "crt0.S atmel" sur Google, quelques notes d'application Atmel sur le démarrage, crt0 et gcc optimisation à venir. Peut-être qu'il y a des indices dans ces documents.
jluciani
@jlu J'essaie de comprendre la différence entre les deux, mais je n'ai encore rien obtenu de bon sur Stack Overflow: stackoverflow.com/questions/2709998/…
Earlz
2
avr-libc a un CRT différent pour chaque type de puce AVR, et les distributions avr-libc standard incluent uniquement la version .o du fichier. Celui pour ATtiny13 est situé à [avr-libc-path] /avr-3/lib/crttn13.o
todbot
@todbot hmm. Ah, ok oui, je l'ai/avr-libc-1.6.7/avr/lib/avr2/attiny13/crttn13.S
Earlz
19

Vous pouvez utiliser avr-objdump -d .elf pour voir ce qui est généré:

Analysons-le un peu:

[jpc@jpc ~] avr-objdump -d avr.elf | sed -e 's/^/    /' | pbcopy

avr.elf:     file format elf32-avr

Disassembly of section .text:

00000000 <__vectors>:
   0:   09 c0           rjmp    .+18        ; 0x14 <__ctors_end>
   2:   0e c0           rjmp    .+28        ; 0x20 <__bad_interrupt>
   4:   0d c0           rjmp    .+26        ; 0x20 <__bad_interrupt>
   6:   0c c0           rjmp    .+24        ; 0x20 <__bad_interrupt>
   8:   0b c0           rjmp    .+22        ; 0x20 <__bad_interrupt>
   a:   0a c0           rjmp    .+20        ; 0x20 <__bad_interrupt>
   c:   09 c0           rjmp    .+18        ; 0x20 <__bad_interrupt>
   e:   08 c0           rjmp    .+16        ; 0x20 <__bad_interrupt>
  10:   07 c0           rjmp    .+14        ; 0x20 <__bad_interrupt>
  12:   06 c0           rjmp    .+12        ; 0x20 <__bad_interrupt>

Tableau vectoriel d'interruption de 20 octets (au moins certaines des entrées pourraient être omises si vous insistiez et promettiez de ne jamais activer les interruptions correspondantes).

00000014 <__ctors_end>:
  14:   11 24           eor r1, r1
  16:   1f be           out 0x3f, r1    ; 63
  18:   cf e9           ldi r28, 0x9F   ; 159
  1a:   cd bf           out 0x3d, r28   ; 61
  1c:   02 d0           rcall   .+4         ; 0x22 <main>
  1e:   05 c0           rjmp    .+10        ; 0x2a <_exit>

Efface SREG (je ne suis pas sûr que ce soit vraiment nécessaire), écrit 0x9f (RAMEND) dans SPL (le pointeur de pile) et passe à main. Le dernier rjmp est un peu redondant. (vous pourriez promettre de ne jamais revenir du principal)

00000020 <__bad_interrupt>:
  20:   ef cf           rjmp    .-34        ; 0x0 <__vectors>

Procédure d'interruption par défaut pour les interruptions qui n'en ont pas écrasées en C. (mêmes règles que pour __vectors)

00000022 <main>:
  22:   bb 9a           sbi 0x17, 3 ; 23
  24:   c3 9a           sbi 0x18, 3 ; 24
  26:   c3 98           cbi 0x18, 3 ; 24
  28:   fd cf           rjmp    .-6         ; 0x24 <main+0x2>

Votre proc principal. Serré.

0000002a <_exit>:
  2a:   f8 94           cli

0000002c <__stop_program>:
  2c:   ff cf           rjmp    .-2         ; 0x2c <__stop_program>

Ces deux ne sont pas très utiles. _exit est probablement requis par la norme C et __stop_program est nécessaire pour qu'il fonctionne comme il se doit.

jpc
la source
16

Quelle est votre éventuelle candidature? Un ATtiny13 a 1 Ko de flash et vous pouvez faire beaucoup avec cela en C. Le crt0 est le runtime avr-libc C. Il contient des éléments comme la gestion de la pile afin que vous puissiez utiliser des fonctions avec des arguments et des valeurs de retour.

100 octets pour la configuration C intégrée n'est pas trop mal, et sa taille est constante. Doubler les lignes de la logique du programme ne fera pas nécessairement 200 octets. À quel niveau d'optimisation compilez-vous? Vous devriez être à "-O". Et comment compilez-vous cela? Les Makefiles dans les projets de démonstration disponibles sur le site avr-libc sont assez bons et complets.

Le programme simple d'activation / désactivation des LED ci-dessous prend 62 octets sur un ATtiny13 avec "-Os" sur le avr-gcc 4.3.3. de CrossPack-AVR:

#include <avr / io.h>
#include <avr / delay.h>

int main (void)
{
    DDRB | = _BV (PB3);
    tandis que (1) { 
        PORTB | = _BV (PB3);
        _delay_ms (200);
        PORTB & = ~ _BV (PB3);
        _delay_ms (200);
    }
}

La suppression des appels _delay_ms () lui fait 46 octets.

Un plus grand exemple sur l'ATtiny13 sont mes prototypes Smart LED . Ce code contient un logiciel PWM à 3 canaux, une conversion des couleurs HSV en RVB, une machine d'état et lit deux boutons. Il n'est pas particulièrement bien écrit et arrive à 864 octets. Sous avr-gcc 3.x, il était encore plus petit. (pour une raison quelconque, avr-gcc 4 a fait croître presque tous les programmes de quelques octets)

todbot
la source
avr-gcc -std=c99 -Wall -Os -mmcu=attiny13 -o hello.out helloworld.cest la ligne pertinente dans mon makefile (auto-créé). et j'utilise un code presque identique sauf pour retourner la LED que j'utilise PORTB &= ~(1 << LED);et autres
Earlz
Et oui, la taille est constante, mais même 46 octets semblent un peu lourds si tout ce qu'il a à faire est de configurer un stackframe
Earlz
2

Si vous manquez d'espace, essayez IAR's Embedded Workbench - leur version gratuite 'kickstart' a une limite de taille de code de 4K, donc beaucoup pour ATTiny, et probablement une meilleure optimisation que gcc

mikeselectricstuff
la source
1
Les comparaisons d'optimisation sont un sujet de forte controverse. Je n'irais pas là-bas.
Tyblu
1
@tyblu Je suis d'accord, mais IAR est connu pour produire des binaires plus petits que avr-gcc par exemple .. Je serais également d'accord avec mikeselectricstuff et je pense que c'est un bon conseil.
Morten Jensen
1

De tels périphériques sont souvent programmés dans l'assembleur, ce qui entraîne des exécutables plus petits. Cela vaut la peine de faire l'effort et d'apprendre à l'utiliser.

Leon Heller
la source
1
Je serais d'accord, mais à mon humble avis, le but n'est pas de programmer des appareils entiers en assemblage (je sais que cela se fait fréquemment et je l'ai fait aussi), mais de pouvoir décoder et vérifier ce que le compilateur C fait derrière votre dos. Cela signifie également que vous pourrez fréquemment deviner le compilateur et optimiser le code que vous écrivez en C pour obtenir une petite taille exécutable.
jpc