ATTiny13 - ¿avr-gcc Hello World utiliza más de 100 bytes?


9

Estoy tratando de escribir un programa para el ATTiny13. Mi problema es que tiene grandes limitaciones de tamaño. Bueno, cuando hice mi primer programa Hello World, ¡tomó 100 bytes de espacio en el programa solo para encender y apagar la luz! ¿Hay alguna opción que pueda darle a avr-gcc para reducir este tamaño? Además, ¿qué hay en el crt0? No estoy muy interesado en el ensamblaje AVR, así que no lo entiendo mucho ...

No quiero tener que ir al ensamblaje para este proyecto.


Como pequeña nota al margen, algunas personas lo llamarían un programa "Blinky".
Johan

1
@Johan bueno, no estaba seguro de cómo deletrear "luces intermitentes"
Earlz

Respuestas:


9

crt0 es la rutina de inicio para el uC. Las rutinas realizan la configuración de los registros y también la inicialización de los datos.

¿Los 100 bytes incluyen la tabla de vectores de interrupción? No estoy seguro sobre el ATtiny13 pero el ATtiny25 / 45/85 tiene 15 vectores de interrupción. Esto tomaría 30 bytes.

gcc tiene una opción para vincular en su crt0. Puede tomar el archivo AVR crt0.S y modificarlo. No es muy largo, por lo que no debería ser difícil de hacer.


Parece que no puedo encontrar la fuente crt0, pero en crt1 existe lo que parece ser una tabla de vectores de interrupción. Quizás eso es todo
Earlz

Tampoco puedo encontrarlo en mi sistema :( Compilé todas las herramientas de la fuente, así que pensé que estaría allí. Si buscas en Google "crt0.S atmel", un par de notas de la aplicación Atmel sobre inicio, crt0 y gcc
surge la

@jlu Estoy tratando de descubrir la diferencia entre los dos, pero todavía no he conseguido nada bueno en Stack Overflow: stackoverflow.com/questions/2709998/…
Earlz

2
avr-libc tiene un CRT diferente para cada tipo de chip AVR, y las distribuciones estándar de avr-libc solo incluyen la versión .o del archivo. El del ATtiny13 se encuentra en [avr-libc-path] /avr-3/lib/crttn13.o
todbot el

@todbot hmm. Ah, está bien, sí, lo tengo en/avr-libc-1.6.7/avr/lib/avr2/attiny13/crttn13.S
Earlz

19

Puede usar avr-objdump -d .elf para ver lo que se genera:

Analicémoslo un poco:

[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>

Tabla de vectores de interrupción de 20 bytes (al menos algunas de las entradas podrían omitirse si insiste y promete que nunca habilitará las interrupciones correspondientes).

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>

Borra SREG (no estoy seguro de que esto sea realmente necesario), escribe 0x9f (RAMEND) en SPL (el puntero de la pila) y salta a main. El último rjmp es algo redundante. (podría prometer que nunca volverá de main)

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

Procedimiento de interrupción predeterminado para esas interrupciones que no tienen una sobrescrita en C. (mismas reglas que para __vectores)

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>

Tu proceso principal. Apretado.

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

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

Estos dos no son muy útiles. _exit es probablemente requerido por el estándar C y __stop_program es necesario para que funcione como debería.


16

¿Cuál es su eventual aplicación? Un ATtiny13 tiene 1kB de flash y puede hacer mucho con eso en C. El crt0 es el tiempo de ejecución C avr-libc. Contiene cosas como el manejo de la pila para que pueda usar funciones con argumentos y valores de retorno.

100 bytes para la configuración de C incrustado no es tan malo, y es de tamaño constante. Duplicar las líneas de la lógica del programa no necesariamente lo convertirá en 200 bytes. ¿En qué nivel de optimización está compilando? Deberías estar en "-Os". ¿Y cómo estás compilando esto? Los Makefiles en los proyectos de demostración disponibles en el sitio avr-libc son bastante buenos y completos.

El simple programa de encendido / apagado de LED a continuación toma 62 bytes en un ATtiny13 con "-Os" en el avr-gcc 4.3.3. de CrossPack-AVR:

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

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

Eliminar las llamadas _delay_ms () hace 46 bytes.

Un ejemplo más amplio en el ATtiny13 son mis prototipos Smart LED . Este código contiene un software PWM de 3 canales, una conversión de color HSV a RGB, una máquina de estado y lee dos botones. No está escrito particularmente bien y viene en 864 bytes. Bajo avr-gcc 3.x era aún más pequeño. (por alguna razón, avr-gcc 4 ha hecho que casi todos los programas crezcan unos pocos bytes)


avr-gcc -std=c99 -Wall -Os -mmcu=attiny13 -o hello.out helloworld.ces la línea relevante en mi archivo MAKE (auto creado). y uso un código casi idéntico, excepto para voltear el LED que uso PORTB &= ~(1 << LED);y tal
Earlz

Y sí, el tamaño es constante, pero incluso 46 bytes parece un poco pesado si todo lo que tiene que hacer es configurar un stackframe
Earlz

2

Si tiene poco espacio, pruebe el banco de trabajo integrado de IAR: su versión 'kickstart' gratuita tiene un límite de tamaño de código de palabra 4K, por lo que es suficiente para ATTiny y probablemente una mejor optimización que gcc


1
Las comparaciones de optimización son un tema de gran controversia. Yo no iría allí
tyblu

1
@tyblu Estoy de acuerdo, pero IAR es conocido por producir binarios más pequeños que avr-gcc, por ejemplo. Sin embargo, también estaría de acuerdo con mikeselectricstuff y creo que es un buen consejo.
Morten Jensen

1

Dispositivos como ese a menudo se programan en ensamblador, lo que resulta en ejecutables más pequeños. Vale la pena hacer el esfuerzo y aprender a usarlo.


1
Estoy de acuerdo, pero en mi humilde opinión, el objetivo no es programar dispositivos completos en ensamblaje (sé que esto se hace con frecuencia y yo también lo hice), sino poder decodificar y verificar lo que el compilador de C está haciendo a sus espaldas. También significa que con frecuencia podrá adivinar el compilador y optimizar el código que escribe en C para obtener un tamaño ejecutable pequeño.
jpc
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.