Почему использование serial.readBytes увеличивает размер программы на 10 КБ?

Если я добавлю это в свою программу Arduino, в main.cpp, у меня внезапно закончится память для размера флэш-программы:

  if(msgSize > 2) {
    //sr::sequentialRead(&serialRead, newTram.hash);
    uint8_t bytes[4];
    Serial.readBytes(&bytes[0], 2);

  }

Без этого я вижу это:

avr-size -C --mcu=atmega328p connections_display.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:   26348 bytes (80.4% Full)
(.text + .data + .bootloader)

Data:        598 bytes (29.2% Full)
(.data + .bss + .noinit)

Но если я использую Serial.readBytes, я получаю:

avr-size -C --mcu=atmega328p connections_display.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:   36404 bytes (111.1% Full)
(.text + .data + .bootloader)

Data:        601 bytes (29.3% Full)
(.data + .bss + .noinit)

Я попробовал это и в пустом скетче Arduino, и там такой проблемы не возникло, значит, дело в моих командах сборки.

Это мой CMake:

cmake_minimum_required(VERSION 3.11)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_SYSTEM_NAME  Generic)
# Project name
project("MyProject" VERSION 0.1 LANGUAGES CXX C)

# Product filename (name of the compiled file)
set(PRODUCT_NAME connections_display)

set(ARDUINO_BOARD "UNO")
## AVR Chip Configuration
# 8Mhz, this should match the crystal on your board,
# I use 8Mhz and 3.3V for the lowest power consumption
set(F_CPU 16000000L)
# CPU, you can find the list here:
# https://gcc.gnu.org/onlinedocs/gcc/AVR-Options.html
set(MCU atmega328p)

# The programmer to use, read avrdude manual for list
# avrispmkII
set(ARDUINO_PROGRAMMER_TYPE arduino)
set(ARDUINO_PROGRAMMER_COM_ID "COM6")
set(ARDUINO_PROGRAMMER_BAUD 115200)

# AVR Fuses, must be in concordance with your hardware and F_CPU
# http://eleccelerator.com/fusecalc/fusecalc.php?chip=atmega328p
set(E_FUSE 0xfd)
set(H_FUSE 0xda)
set(L_FUSE 0xfd)
set(LOCK_BIT 0xff)

# set(CMAKE_AVR_TOOL_COMPILERS "%APPDATA%\\..\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7\\bin")
set(ARDUINO_TOOLKIT "%APPDATA%/../Local/Arduino15/packages/arduino")
set(ARDUINO_COMPILERS "${ARDUINO_TOOLKIT}/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin")
set(ARDUINO_AVRDUDE "${ARDUINO_TOOLKIT}/tools/avrdude/6.3.0-arduino17/bin")
set(ARDUINO_AVR_DIRECTORY "${ARDUINO_TOOLKIT}/hardware/avr/1.8.6")
set(ARDUINO_LIBRARIES_HOME "${ARDUINO_AVR_DIRECTORY}/libraries")
set(ARDUINO_CORES_HOME "${ARDUINO_AVR_DIRECTORY}/cores")

get_filename_component(ARDUINO_COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)

set(AVR_STRIP_COMMAND ${ARDUINO_COMPILER_DIR}/avr-strip)
set(AVR_OBJCOPY_COMMAND ${ARDUINO_COMPILER_DIR}/avr-objcopy)
set(AVR_SIZE_COMMAND ${ARDUINO_COMPILER_DIR}/avr-size)
set(AVR_AVRDUDE_COMMAND ${ARDUINO_AVRDUDE}/avrdude)
set(AVR_AVRDUDE_CONFIG ${ARDUINO_AVRDUDE}/../etc/avrdude.conf)

# Pass defines to compiler
add_definitions(
    -DF_CPU=${F_CPU}
    -DBAUD=${BAUD}
    -DARDUINO=10607
    -DARDUINO_AVR_UNO
    -DARDUINO_ARCH_AVR
    # disable some extra display functions
    -DENA_SCR_DIA=0
    -DENA_MISC=0
    -DENA_OPNCLS=0
    -DENA_GROW=0
)
# mmcu MUST be passed to bot the compiler and linker, this handle the linker
set(CMAKE_EXE_LINKER_FLAGS
    -mmcu=${MCU}
)

add_compile_options(
    -mmcu=${MCU} # MCU
    -Os # optimize
    -Wall # enable warnings
    -Wno-main
    -Wundef
    -pedantic
    -Wno-error=expansion-to-defined
    -Wno-expansion-to-defined
    -Wno-error=cpp
    -Wno-cpp
    -Wl,--relax,--gc-sections
    -g
    -gdwarf-2
    -fno-threadsafe-statics
    -funsigned-char # a few optimizations
    -funsigned-bitfields
    #-fpack-struct
    -fshort-enums
    -ffunction-sections
    -fdata-sections
    #-fno-split-wide-types
    -fno-tree-scev-cprop
)
file(GLOB SRC_FILES "src/*.cpp" "src/*.c") # Load all files in src folder

# Create one target
add_executable(${PRODUCT_NAME} ${SRC_FILES})
target_include_directories(${PRODUCT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include/display_controller)
target_include_directories(${PRODUCT_NAME} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/)

# Rename the output to .elf as we will create multiple files
set_target_properties(${PRODUCT_NAME} PROPERTIES OUTPUT_NAME ${PRODUCT_NAME}.elf)

target_link_libraries(${PRODUCT_NAME} PRIVATE
    ArduinoCore
)

# Strip binary for upload
add_custom_target(avr_strip_hex ALL ${AVR_STRIP_COMMAND} ${PRODUCT_NAME}.elf DEPENDS ${PRODUCT_NAME})

# Transform binary into hex file, we ignore the eeprom segments in the step
add_custom_target(avr_create_hex ALL ${AVR_OBJCOPY_COMMAND} -O ihex -R .eeprom ${PRODUCT_NAME}.elf ${PRODUCT_NAME}.hex DEPENDS avr_strip_hex)
# Transform binary into hex file, this is the eeprom part (empty if you don't
# use eeprom static variables)
add_custom_target(eeprom ${AVR_OBJCOPY_COMMAND} -O ihex -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0  ${PRODUCT_NAME}.elf ${PRODUCT_NAME}.eep DEPENDS avr_strip_hex)

add_custom_target(avr_calc_size_two ALL ${AVR_SIZE_COMMAND} -A --mcu=${MCU} ${PRODUCT_NAME}.elf DEPENDS avr_create_hex)
add_custom_target(avr_calc_size ALL ${AVR_SIZE_COMMAND} -C --mcu=${MCU} ${PRODUCT_NAME}.elf DEPENDS avr_calc_size_two)

# Upload the firmware with avrdude
add_custom_target(upload_to_arduino ${AVR_AVRDUDE_COMMAND} -v -V -C${AVR_AVRDUDE_CONFIG} -c${ARDUINO_PROGRAMMER_TYPE} -p${MCU} -P${ARDUINO_PROGRAMMER_COM_ID} -b${ARDUINO_PROGRAMMER_BAUD} -U flash:w:${PRODUCT_NAME}.hex DEPENDS avr_create_hex)
set_target_properties(upload_to_arduino PROPERTIES EXCLUDE_FROM_ALL TRUE)

# Clean extra files
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PRODUCT_NAME}.hex;${PRODUCT_NAME}.eeprom;${PRODUCT_NAME}.lst")

add_subdirectory("../lib/arduino_libs/ArduinoCore" "${CMAKE_BINARY_DIR}/lib/arduino_libs/ArduinoCore")

Это зависит от другой библиотеки ядра Arduino:

ArduinoCore/CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(ArduinoCore VERSION 1.0 LANGUAGES CXX)

# Set the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(THIS_LIBRARY_HOME "${ARDUINO_CORES_HOME}/arduino/")
file(GLOB SRC_FILES "${THIS_LIBRARY_HOME}/*.cpp" "${THIS_LIBRARY_HOME}/*.c")

# Add the executable
add_library(${PROJECT_NAME} ${SRC_FILES})

# Include directories
target_include_directories(${PROJECT_NAME} PUBLIC ${THIS_LIBRARY_HOME})
# include pin definitions
if(ARDUINO_BOARD STREQUAL "UNO")
    set(PIN_HEADERS "${ARDUINO_AVR_DIRECTORY}/variants/standard/")
else()
    message(FATAL_ERROR "Unsupported ARDUINO_BOARD value: ${ARDUINO_BOARD}")
endif()

target_include_directories(${PROJECT_NAME} INTERFACE ${PIN_HEADERS})
target_include_directories(${PROJECT_NAME} PRIVATE ${PIN_HEADERS})


unset(THIS_LIBRARY_HOME)
unset(SRC_FILES)

Кажется, я использую неправильные флаги компиляции, и это каким-то образом приводит к взрывному увеличению размера ядра Arduino при вызове этой функции. Даже если я удалю весь код и оставлю этот простой тест main.cpp, проблема всё равно останется:

#include "Arduino.h"
void setup() {
  // инициализируем последовательный порт:
  Serial.begin(9600);
}


uint8_t bytes[10];
int i = 0;
void loop() {
  if (Serial.available() >= 10) {
    Serial.readBytes(&bytes[0], 10);
    i = 10;
  }
  if(i >= 10) {
    i = 0;
    for(int iout = 0; iout < 10; ++iout) {
      Serial.write(bytes[i]);
    }
  }
}

Вывод avr-size:

[3/5] avr-size -A --mcu=atmega328p connections_display.elf
connections_display.elf  :
section                     size      addr
.data                         52   8388864
.text                      15354         0
.bss                         185   8388916
.comment                      17         0
.note.gnu.avr.deviceinfo      64         0
Total                      15672


[4/5] avr-size -C --mcu=atmega328p connections_display.elf
AVR Memory Usage
----------------
Device: atmega328p

Program:   15406 bytes (47.0% Full)
(.text + .data + .bootloader)

Data:        237 bytes (11.6% Full)
(.data + .bss + .noinit)

, 👍1


1 ответ


Лучший ответ:

3

Проблема заключалась в том, что флаги компоновщика передавались неправильно. Часть -Wl в add_compile_options не передавалась компоновщику.

Вместо этого мне пришлось расширить CMAKE_EXE_LINKER_FLAGS:

set(CMAKE_EXE_LINKER_FLAGS
    "-mmcu=${MCU} -Wl,--relax,--gc-sections,-Os,-g,--strip-discarded,--stats"
)

Теперь у меня получился такой же размер, как с Arduino IDE.

,