Introduccion
En un
artículo anterior , se describió el proceso de convertir Qt Creator en un IDE completo para proyectos en la plataforma Arduino. Los pasos se describieron en detalle, pero sin una descripción del significado de lo que está sucediendo, por lo que el efecto de dicho artículo es pequeño. En cada caso, pueden surgir varios matices y es difícil comprenderlos sin comprender cómo se organiza el proyecto.
Por lo tanto, en este artículo entenderemos la estructura y la configuración del proyecto.
1. Arduino Core y función main ()
Como sabe, la ejecución de cualquier programa en C / C ++ comienza con la función main (), incluido el firmware del microcontrolador. De una forma u otra, esta función está presente en cualquier proyecto. Para crear un proyecto en el IDE de Arduino, inmediatamente se nos ofrece un archivo de boceto (también con una estúpida extensión * .ino), que oculta la ubicación del punto de entrada al desarrollador.
En Arch, las fuentes Arduino Core se encuentran a lo largo de la ruta
/ usr / share / arduino / hardware / archlinux-arduino / avr / cores / arduino y contienen lo siguiente
Lista de archivos Arduino Core$ ls -l 320 -rw-r--r-- 1 root root 1222 3 2017 abi.cpp -rw-r--r-- 1 root root 7483 3 2017 Arduino.h -rw-r--r-- 1 root root 11214 3 2017 binary.h -rw-r--r-- 1 root root 8078 9 2017 CDC.cpp -rw-r--r-- 1 root root 1529 3 2017 Client.h -rw-r--r-- 1 root root 2605 3 2017 HardwareSerial0.cpp -rw-r--r-- 1 root root 2315 3 2017 HardwareSerial1.cpp -rw-r--r-- 1 root root 1975 3 2017 HardwareSerial2.cpp -rw-r--r-- 1 root root 1975 3 2017 HardwareSerial3.cpp -rw-r--r-- 1 root root 7743 3 2017 HardwareSerial.cpp -rw-r--r-- 1 root root 5262 3 16:57 HardwareSerial.h -rw-r--r-- 1 root root 4469 3 2017 HardwareSerial_private.h -rw-r--r-- 1 root root 1142 3 2017 hooks.c -rw-r--r-- 1 root root 2851 3 2017 IPAddress.cpp -rw-r--r-- 1 root root 2861 3 2017 IPAddress.h -rw-r--r-- 1 root root 1372 3 2017 main.cpp -rw-r--r-- 1 root root 1027 3 2017 new.cpp -rw-r--r-- 1 root root 979 3 2017 new.h -rw-r--r-- 1 root root 2725 3 2017 PluggableUSB.cpp -rw-r--r-- 1 root root 2063 3 2017 PluggableUSB.h -rw-r--r-- 1 root root 1335 3 2017 Printable.h -rw-r--r-- 1 root root 5442 3 2017 Print.cpp -rw-r--r-- 1 root root 2963 3 16:57 Print.h -rw-r--r-- 1 root root 963 3 2017 Server.h -rw-r--r-- 1 root root 8804 3 17:23 Stream.cpp -rw-r--r-- 1 root root 6060 3 17:23 Stream.h -rw-r--r-- 1 root root 15022 3 2017 Tone.cpp -rw-r--r-- 1 root root 4363 18 16:52 Udp.h -rw-r--r-- 1 root root 6261 3 16:57 USBAPI.h -rw-r--r-- 1 root root 20086 18 16:52 USBCore.cpp -rw-r--r-- 1 root root 8435 3 2017 USBCore.h -rw-r--r-- 1 root root 1519 3 2017 USBDesc.h -rw-r--r-- 1 root root 4576 3 2017 WCharacter.h -rw-r--r-- 1 root root 9409 3 2017 WInterrupts.c -rw-r--r-- 1 root root 7850 3 2017 wiring_analog.c -rw-r--r-- 1 root root 12024 3 2017 wiring.c -rw-r--r-- 1 root root 4978 3 2017 wiring_digital.c -rw-r--r-- 1 root root 2255 3 2017 wiring_private.h -rw-r--r-- 1 root root 3435 3 2017 wiring_pulse.c -rw-r--r-- 1 root root 6022 3 2017 wiring_pulse.S -rw-r--r-- 1 root root 1550 3 2017 wiring_shift.c -rw-r--r-- 1 root root 1641 3 2017 WMath.cpp -rw-r--r-- 1 root root 16989 3 2017 WString.cpp -rw-r--r-- 1 root root 9910 3 2017 WString.h
La función main () se encuentra en el archivo main.cpp y tiene este aspecto
#include <Arduino.h> // Declared weak in Arduino.h to allow user redefinitions. int atexit(void (* /*func*/ )()) { return 0; } // Weak empty variant initialization function. // May be redefined by variant files. void initVariant() __attribute__((weak)); void initVariant() { } void setupUSB() __attribute__((weak)); void setupUSB() { } int main(void) { init(); initVariant(); #if defined(USBCON) USBDevice.attach(); #endif setup(); for (;;) { loop(); if (serialEventRun) serialEventRun(); } return 0; }
Se puede ver que no hay nada sobrenatural en el boceto: las funciones setup () y loop () se llaman directamente desde main (). El archivo led-blink.cpp que
creamos anteriormente contiene definiciones de estas funciones. Si eliminamos este archivo del proyecto
# #INCLUDEPATH += ./include #HEADERS += $$files(./include/*.h) # #SOURCES += $$files(./src/*.cpp)
obtenemos un error de enlazador lógico

Por lo tanto, todos los módulos que agreguemos al proyecto estarán vinculados con el núcleo Arduino, que implementa la funcionalidad básica. Aquí hay una breve descripción de los encabezados Arduino Core:
- Arduino.h: el encabezado básico, incluidos los encabezados de la biblioteca C estándar, las definiciones de la interfaz del programa con los registros del controlador AVR, las definiciones macro básicas utilizadas en la programación
- binary.h: definiciones de macro para escribir números del 0 al 255 en forma binaria
- Client.h: clase de cliente Ethernet
- HardwareSerial.h, HardwareSerial_private.h - biblioteca para trabajar con hardware UART
- IPAddress.h: funciona con direcciones IP de protocolos Ethernet
- new.h: implementación de los operadores C ++ nuevos y eliminados
- PluggableUSB.h, USBAPI.h, USBCore.h, USBDesc.h: biblioteca para implementar dispositivos USB
- Print.h, Printable.h, Stream.h: bibliotecas para trabajar con flujos de datos simbólicos, incluidos los transmitidos a través de UART
- Server.h: una clase que implementa el servidor Eternet
- Udp.h: implementación del protocolo UDP
- WCharacters.h, WString.h: clases para trabajar con caracteres y cadenas
- cableado_privado.h - la biblioteca de la plataforma Wiring , sobre la base de la cual se construye el Arduino Core. Esta biblioteca implementa una interfaz de nivel relativamente alto para los recursos del sistema de los microcontroladores.
Por lo tanto, incluso en el programa de parpadeo de LED más simple, se incluye una gran cantidad de código innecesario. Este es el precio por la facilidad de desarrollo y el bajo umbral de entrada. Sin embargo, hablando de esto, soy astuto: el ejemplo que se muestra en el último artículo no corresponde a lo que se obtiene después del ensamblaje en el IDE de Arduino.
2. Cortar la grasa del firmware
En Arduino, el IDE Core se ensambla en un núcleo estático separado. Una biblioteca, que luego se vincula con los archivos de objetos de croquis en un binario listo para usar. Haremos lo mismo en Qt Creator.
Cree un proyecto central con la siguiente estructura

El script qmake para este proyecto se presenta a continuación:
core.pro # DESTDIR = ../../lib TARGET = core # INCLUDEPATH += $$ARDUINO_DIR/cores/arduino INCLUDEPATH += $$ARDUINO_DIR/variants/standard INCLUDEPATH += $$ARDUINO_DIR/libraries INCLUDEPATH += /usr/avr/include # C QMAKE_CC = /usr/bin/avr-gcc QMAKE_CFLAGS += -c -g -Os -w -ffunction-sections -fdata-sections QMAKE_CFLAGS += -MMD -mmcu=$$ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU QMAKE_CFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU QMAKE_CXXFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR files($$ARDUINO_DIR/cores/arduino/*.h) HEADERS += $$files($$ARDUINO_DIR/variants/standard/*.h) files($$ARDUINO_DIR/cores/arduino/*.c) SOURCES += $$files($$ARDUINO_DIR/cores/arduino/*.cpp)
El proyecto contiene exclusivamente el código Arduino Core. Su ensamblaje da libcore.a salida de la biblioteca
Ahora a continuación para crear un proyecto de firmware que contenga el código de boceto

blink.pro # # Arduino Core ARDUINO_DIR=/usr/share/arduino/hardware/archlinux-arduino/avr/ # (Arduino Uno, Nano, Mini) ARDUINO_MCU=atmega328p # ARDUINO_FCPU = 16000000L # , Qt ! QT -= gui core CONFIG -= qt # - , ELF TEMPLATE = app # DESTDIR = ../../bin TARGET = blink # INCLUDEPATH += $$ARDUINO_DIR/cores/arduino INCLUDEPATH += $$ARDUINO_DIR/variants/standard INCLUDEPATH += $$ARDUINO_DIR/libraries INCLUDEPATH += /usr/avr/include # C QMAKE_CC = /usr/bin/avr-gcc QMAKE_CFLAGS += -c -g -Os -w -ffunction-sections -fdata-sections QMAKE_CFLAGS += -MMD -mmcu=$$ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU QMAKE_CFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR ARDUINO_MCU -DF_CPU=$$ARDUINO_FCPU QMAKE_CXXFLAGS += -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR # QMAKE_LINK = /usr/bin/avr-gcc QMAKE_LFLAGS = -w -Os -Wl,ARDUINO_MCU QMAKE_LIBS = -lm # QMAKE_POST_LINK += /usr/bin/avr-objcopy -O ihex -j .text -j .data -S ${TARGET} ${TARGET}.hex LIBS += -L../../lib -lcore # INCLUDEPATH += ./include HEADERS += $$files(./include/*.h) files(./src
blink.h #ifndef LED_BLINK_H #define LED_BLINK_H #include <Arduino.h> #endif // LED_BLINK_H
blink.cpp #include "blink.h" #define LED_STAND_PIN 13 unsigned long time = 0; unsigned long DELAY = 1000000; bool on = false;
Recopilaremos ambos proyectos juntos utilizando el tipo de proyecto "subdirectorios" disponible en qmake
led-blink2.pro TEMPLATE = subdirs SUBDIRS += ./core SUBDIRS += ./blink
Ensamblamos el proyecto, lo ejecutamos en el tablero y miramos el registro de firmware
Registro de firmware de Blink.hex avrdude: AVR device initialized and ready to accept instructions Reading |
Aquí prestamos atención a la cantidad de memoria ocupada.
avrdude: verifying ... avrdude: 1040 bytes of flash verified
Sí, el firmware ya tiene 1040 bytes contra 2838 en el proyecto del último artículo. Pero aún así, un boceto similar en el IDE de Arduino toma 882 bytes. Habiendo estudiado cuidadosamente el registro de compilación del entorno Arduino, agregamos claves del compilador de C a los proyectos principales y de parpadeo
QMAKE_CFLAGS += -flto -fno-fat-lto-objects
y claves del compilador C ++
QMAKE_CXXFLAGS += -fpermissive -flto -fno-devirtualize -fno-use-cxa-atexit
Reconstruimos, cosimos, lanzamos y ...
avrdude: verifying ... avrdude: 882 bytes of flash verified
Ok, codiciados 882 bytes logrados. ¿Qué hace que esto suceda?
Primero, echemos un vistazo a los archivos ELF obtenidos durante el ensamblaje de los proyectos actuales y anteriores, es decir, prestaremos atención a la información simbólica, lo que dará una idea de que a partir de las funciones y clases del núcleo Arduino termina en el binario. Dar una orden
$ avr-objdump -t led-blink
Tabla de caracteres de parpadeo de led led-blink: elf32-avr SYMBOL TABLE: 00800100 ld .data 00000000 .data 00000000 ld .text 00000000 .text 00800122 ld .bss 00000000 .bss 00000000 ld .stab 00000000 .stab 00000000 ld .stabstr 00000000 .stabstr 00000000 ld .comment 00000000 .comment 00000000 ld .note.gnu.avr.deviceinfo 00000000 .note.gnu.avr.deviceinfo 00000000 ld .debug_info 00000000 .debug_info 00000000 ld .debug_abbrev 00000000 .debug_abbrev 00000000 ld .debug_line 00000000 .debug_line 00000000 ld .debug_str 00000000 .debug_str 00000000 l df *ABS* 00000000 WInterrupts.c 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000112 l F .text 00000002 nothing 00800100 l O .data 00000004 intFunc 00000000 l df *ABS* 00000000 HardwareSerial.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000000 l df *ABS* 00000000 IPAddress.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 0000078a l F .text 00000016 _GLOBAL__sub_I_IPAddress.cpp 008001c8 l O .bss 00000006 _ZL11INADDR_NONE 00000000 l df *ABS* 00000000 Tone.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 0080011c l O .data 00000001 _ZL9tone_pins 000000b8 l O .text 00000001 _ZL21tone_pin_to_timer_PGM 00000000 l df *ABS* 00000000 led-blink.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000000 l df *ABS* 00000000 wiring_digital.c 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000304 l F .text 00000052 turnOffPWM 00000000 l df *ABS* 00000000 HardwareSerial0.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000694 l F .text 0000005a _GLOBAL__sub_I_HardwareSerial0.cpp 00000000 l df *ABS* 00000000 _clear_bss.o 000000ea l .text 00000000 .do_clear_bss_start 000000e8 l .text 00000000 .do_clear_bss_loop 00000000 l df *ABS* 00000000 wiring.c 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00800122 l O .bss 00000001 timer0_fract 00000000 l df *ABS* 00000000 main.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 00000000 l df *ABS* 00000000 Print.cpp 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 0000081e l F .text 0000001e _ZN5Print5writeEPKc.part.2 00000000 l df *ABS* 00000000 _udivmodsi4.o 00000ac6 l .text 00000000 __udivmodsi4_ep 00000aac l .text 00000000 __udivmodsi4_loop 00000000 l df *ABS* 00000000 _exit.o 00000af2 l .text 00000000 __stop_program 00000000 l df *ABS* 00000000 hooks.c 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 0000010e w .text 00000000 __vector_22 00800127 g O .bss 00000004 timer0_overflow_count 0000094a g F .text 0000002a _Z6noToneh 00000772 g F .text 00000018 _ZN9IPAddressC1Ehhhh 000000ae g O .text 0000000a port_to_mode_PGM 00000114 g F .text 0000004e __vector_1 0000ffa0 g *ABS* 00000000 __DATA_REGION_LENGTH__ 00800123 g O .bss 00000004 timer0_millis 00000442 g F .text 0000001c _ZN14HardwareSerial4peekEv 0000084a g F .text 00000098 _ZN5Print11printNumberEmh 000007c4 g F .text 0000005a _ZN5Print5writeEPKhj 00000068 g .text 00000000 __trampolines_start 008001cf g O .bss 00000002 timer2_pin_port 00000af4 g .text 00000000 _etext 0000042a g F .text 00000018 _ZN14HardwareSerial9availableEv 0000010e w .text 00000000 __vector_24 00000a34 g F .text 0000006c loop 000004c0 g F .text 00000042 _ZN14HardwareSerial17_tx_udr_empty_irqEv 0000010e w .text 00000000 __vector_12 000007a0 w F .text 00000002 initVariant 000006ee g F .text 00000084 _ZNK9IPAddress7printToER5Print 00000542 g F .text 0000008e _ZN14HardwareSerial5writeEh 0000010e g .text 00000000 __bad_interrupt 00000b16 g *ABS* 00000000 __data_load_end 0000010e w .text 00000000 __vector_6 008001d5 g O .bss 00000001 on 00000068 g .text 00000000 __trampolines_end 0000010e w .text 00000000 __vector_3 000003ce g F .text 0000005c digitalWrite 00000356 g F .text 00000078 pinMode 00000090 g O .text 00000014 digital_pin_to_port_PGM 0000010e w .text 00000000 __vector_23 00000af4 g *ABS* 00000000 __data_load_start 000000be g .text 00000000 __dtors_end 008001da g .bss 00000000 __bss_end 00000400 g *ABS* 00000000 __LOCK_REGION_LENGTH__ 0000010e w .text 00000000 __vector_25 0000090a g F .text 00000040 _Z12disableTimerh 0000010e w .text 00000000 __vector_11 00000486 g F .text 0000001e _ZN14HardwareSerial17availableForWriteEv 000000be w .text 00000000 __init 000008fc g F .text 0000000e _ZN5Print5printEhi 00000772 g F .text 00000018 _ZN9IPAddressC2Ehhhh 000004a4 w F .text 0000001c _Z14serialEventRunv 00000502 g F .text 00000040 _ZN14HardwareSerial5flushEv 0000010e w .text 00000000 __vector_13 0000010e w .text 00000000 __vector_17 00000634 g F .text 0000004c __vector_19 00000974 g F .text 000000b8 __vector_7 0080012b g O .bss 0000009d Serial 00800104 w O .data 00000012 _ZTV14HardwareSerial 000000e0 g .text 00000010 .hidden __do_clear_bss 0000083c g F .text 0000000e _ZN5Print5printEc 00000680 g F .text 00000014 _Z17Serial0_availablev 00810000 g .stab 00000000 __eeprom_end 0000007c g O .text 00000014 digital_pin_to_bit_mask_PGM 00800116 w O .data 00000006 _ZTV9IPAddress 00000000 g .text 00000000 __vectors 00800122 g .data 00000000 __data_end 00000000 w .text 00000000 __vector_default 0000010e w .text 00000000 __vector_5 00000400 g *ABS* 00000000 __SIGNATURE_REGION_LENGTH__ 00000ae4 g .text 0000000c .hidden __tablejump2__ 0000028e g F .text 00000076 init 000000ba g .text 00000000 __ctors_start 000000ca g .text 00000016 .hidden __do_copy_data 0080011d g O .data 00000004 DELAY 00800122 g .bss 00000000 __bss_start 000007a2 g F .text 00000022 main 0000010e w .text 00000000 __vector_4 008001d6 g O .bss 00000004 time 00000244 g F .text 0000004a micros 008001ce g O .bss 00000001 timer2_pin_mask 00000000 w *ABS* 00000000 __heap_end 0000010e w .text 00000000 __vector_9 00000162 g F .text 0000004e __vector_2 00000400 g *ABS* 00000000 __USER_SIGNATURE_REGION_LENGTH__ 0000010e w .text 00000000 __vector_21 0000010e w .text 00000000 __vector_15 000000a4 g O .text 0000000a port_to_output_PGM 000008e2 g F .text 0000001a _ZN5Print5printEmi 00000a2c g F .text 00000008 setup 008001da g .stab 00000000 __heap_start 000000be g .text 00000000 __dtors_start 000000be g .text 00000000 __ctors_end 000008ff w *ABS* 00000000 __stack 00800122 g .data 00000000 _edata 008001da g .stab 00000000 _end 0000010e w .text 00000000 __vector_8 00000068 g O .text 00000014 digital_pin_to_timer_PGM 00000af0 w .text 00000000 .hidden exit 0000045e g F .text 00000028 _ZN14HardwareSerial4readEv 00000aa0 g .text 00000044 .hidden __udivmodsi4 00010000 g *ABS* 00000000 __EEPROM_REGION_LENGTH__ 00000af0 g .text 00000000 .hidden _exit 0000010e w .text 00000000 __vector_14 0000010e w .text 00000000 __vector_10 008001d1 g O .bss 00000004 timer2_toggle_count 000001b0 g F .text 00000094 __vector_16 00800100 g .data 00000000 __data_start 000005d0 g F .text 00000064 __vector_18 00000400 g *ABS* 00000000 __FUSE_REGION_LENGTH__ 00020000 g *ABS* 00000000 __TEXT_REGION_LENGTH__ 0000010e w .text 00000000 __vector_20 000000f0 g .text 00000016 .hidden __do_global_ctors
Ahora compara con el segundo proyecto
Tabla de caracteres de parpadeo blink: elf32-avr SYMBOL TABLE: 00800100 ld .data 00000000 .data 00000000 ld .text 00000000 .text 00800100 ld .bss 00000000 .bss 00000000 ld .comment 00000000 .comment 00000000 ld .note.gnu.avr.deviceinfo 00000000 .note.gnu.avr.deviceinfo 00000000 ld .debug_info 00000000 .debug_info 00000000 ld .debug_abbrev 00000000 .debug_abbrev 00000000 ld .debug_line 00000000 .debug_line 00000000 ld .debug_str 00000000 .debug_str 00000000 l df *ABS* 00000000 0000003e l *ABS* 00000000 __SP_H__ 0000003d l *ABS* 00000000 __SP_L__ 0000003f l *ABS* 00000000 __SREG__ 00000000 l *ABS* 00000000 __tmp_reg__ 00000001 l *ABS* 00000000 __zero_reg__ 000000e0 l F .text 00000038 pinMode.constprop.1 000000a4 l O .text 00000014 digital_pin_to_bit_mask_PGM 00000090 l O .text 00000014 digital_pin_to_port_PGM 00000086 l O .text 0000000a port_to_mode_PGM 0000007c l O .text 0000000a port_to_output_PGM 00000118 l F .text 00000090 digitalWrite.constprop.0 00000068 l O .text 00000014 digital_pin_to_timer_PGM 000001a8 l F .text 00000076 init 0000021e l F .text 0000004a micros 00800105 l O .bss 00000004 timer0_overflow_count 0080010a l O .bss 00000004 time 00800109 l O .bss 00000001 on 00800101 l O .bss 00000004 timer0_millis 00800100 l O .bss 00000001 timer0_fract 00000000 l df *ABS* 00000000 _clear_bss.o 000000ce l .text 00000000 .do_clear_bss_start 000000cc l .text 00000000 .do_clear_bss_loop 00000000 l df *ABS* 00000000 _exit.o 00000370 l .text 00000000 __stop_program 000000dc w .text 00000000 __vector_22 000000dc w .text 00000000 __vector_1 0000ffa0 g *ABS* 00000000 __DATA_REGION_LENGTH__ 00000068 g .text 00000000 __trampolines_start 00000372 g .text 00000000 _etext 000000dc w .text 00000000 __vector_24 000000dc w .text 00000000 __vector_12 000000dc g .text 00000000 __bad_interrupt 00000372 g *ABS* 00000000 __data_load_end 000000dc w .text 00000000 __vector_6 00000068 g .text 00000000 __trampolines_end 000000dc w .text 00000000 __vector_3 000000dc w .text 00000000 __vector_23 00000372 g *ABS* 00000000 __data_load_start 000000b8 g .text 00000000 __dtors_end 0080010e g .bss 00000000 __bss_end 00000400 g *ABS* 00000000 __LOCK_REGION_LENGTH__ 000000dc w .text 00000000 __vector_25 000000dc w .text 00000000 __vector_11 000000b8 w .text 00000000 __init 000000dc w .text 00000000 __vector_13 000000dc w .text 00000000 __vector_17 000000dc w .text 00000000 __vector_19 000000dc w .text 00000000 __vector_7 000000c4 g .text 00000010 .hidden __do_clear_bss 00810000 g .comment 00000000 __eeprom_end 00000000 g .text 00000000 __vectors 00000000 w .text 00000000 __vector_default 000000dc w .text 00000000 __vector_5 00000400 g *ABS* 00000000 __SIGNATURE_REGION_LENGTH__ 000000b8 g .text 00000000 __ctors_start 00800100 g .bss 00000000 __bss_start 000002fc g F .text 00000072 main 000000dc w .text 00000000 __vector_4 00000000 w *ABS* 00000000 __heap_end 000000dc w .text 00000000 __vector_9 000000dc w .text 00000000 __vector_2 00000400 g *ABS* 00000000 __USER_SIGNATURE_REGION_LENGTH__ 000000dc w .text 00000000 __vector_21 000000dc w .text 00000000 __vector_15 000000b8 g .text 00000000 __dtors_start 000000b8 g .text 00000000 __ctors_end 000008ff w *ABS* 00000000 __stack 00800100 g .data 00000000 _edata 0080010e g .comment 00000000 _end 000000dc w .text 00000000 __vector_8 0000036e w .text 00000000 .hidden exit 00010000 g *ABS* 00000000 __EEPROM_REGION_LENGTH__ 0000036e g .text 00000000 .hidden _exit 000000dc w .text 00000000 __vector_14 000000dc w .text 00000000 __vector_10 00000268 g F .text 00000094 __vector_16 000000dc w .text 00000000 __vector_18 00000400 g *ABS* 00000000 __FUSE_REGION_LENGTH__ 00020000 g *ABS* 00000000 __TEXT_REGION_LENGTH__ 000000dc w .text 00000000 __vector_20
La diferencia es obvia. Se puede ver que al compilar el núcleo en una biblioteca separada, el compilador incluye solo partes del núcleo que realmente se usan en el firmware. En particular, en ninguno de los casos usamos UART, sin embargo, en el primer firmware hay clases para trabajar con él. La reducción del volumen de firmware con las claves del compilador se debe analizar por separado, al igual que las claves mismas
3. Claves del compilador y enlazador
Opciones del compilador:
- -flto : habilita la optimización del diseño. Las funciones en los archivos de objetos vinculados se vinculan como si estuvieran dentro de la misma unidad de traducción
- -fno-fat-lto-objects : no crea archivos de objetos "gordos" que contengan un lenguaje intermedio, excepto el código de objeto. Actúa en conjunción con la clave anterior.
- -fpermisivo : reduce algunos errores del compilador al nivel de advertencias. Puede conducir a la generación incorrecta de código
- -fuse-cxa-aexit - usa la función __cxa-atexit () en lugar de atexit () en destructores de objetos
- -ffunction-secciones, -fdata-secciones : coloque cada función y datos en secciones separadas, para la optimización durante el diseño posterior. Permite que el vinculador incluya solo funciones reales en el archivo de salida.
- -fno-threadsafe-statics : no utilice métodos seguros para subprocesos para trabajar con miembros de clase estáticos. Tiene sentido porque los controladores AVR tienen un solo hilo de ejecución
- -fno-excepciones - no use manejo de excepciones
- -fno-devirtualize - no use "virtualización". Si el compilador conoce el tipo de objeto, puede llamar a sus métodos virtuales directamente, sin usar una tabla de funciones virtuales. Esta opción deshabilita este mecanismo.
- -MMD : generación de reglas de ensamblaje separadas para cada unidad de traducción, con la creación de una lista de dependencias en el archivo * .d (cada archivo * .c / *. Cpp corresponde a un archivo con el mismo nombre y la extensión * .d que contiene las rutas de dependencia)
- -DARDUINO_AVR_UNO, -DARDUINO_ARCH_AVR : crea durante el preprocesamiento de las definiciones de macro ARDUINO_AVR_UNO y ARDUINO_ARCH_AVR, activando las direcciones necesarias para la compilación condicional de las fuentes.
Opciones de vinculador:
- -w : deshabilita todas las advertencias
- -Os : optimice para el tamaño del archivo final
- -Wl, - gc-secciones - activa el diseño de función selectiva. Solo las funciones utilizadas se incluyen en el archivo final
- -mmcu - modelo de controlador usado
Como puede ver, todas las configuraciones se reducen a apagar las lociones utilizadas en la programación de aplicaciones y aumentar la seguridad del código, así como a minimizar la cantidad de firmware final.
Conclusiones
Espero que este texto ponga todos los puntos en la "i". No hay nada sobrenatural en la plataforma Arduino. Su arquitectura tiene como objetivo ocultar a un desarrollador novato todos los mecanismos, cuyo uso es bastante común para aquellos que usan C o ensamblador puro para desarrollar software para AVR.
Además, los trabajadores arduino basados en Linux pueden trabajar con comodidad: este y otros artículos anteriores, con la mejor elocuencia y la competencia de su autor, resaltan la cuestión del uso de un IDE conveniente al desarrollar uno normal.
Espero que esta información sea útil. En el próximo artículo, probablemente hablaremos sobre las posibilidades de depurar proyectos AVR en Qt Creator
PD: el código fuente del proyecto de ejemplo del artículo
se puede tomar aquí