Пролог

При разработке программного обеспечения (особенно для микроконтроллеров) рано или поздно придется столкнуться с необходимостью каким-то образом перенести конфигурации для того или иного программного проекта.

По своему опыту я пришел к выводу, что с точки зрения масштабирования базы кода проще всего передавать конфигурации через переменные среды. Да. Преимущество в том, что переменные среды можно задавать непосредственно в скриптах (Make, CMake и т. д.).

Это выглядит так. Каждая сборка имеет файл config.mk в котором перечислены программные компоненты, из которых должна быть собрана данная конкретная сборка. Содержимое этого файла обычно выглядит следующим образом.


ADC=Y
ADC_ISR=Y
ADT=Y
ALLOCATOR=Y
ARRAY=Y
ASICS=Y

....

TASK=Y
TBFP=Y
TERMINAL=Y
TIME=Y
UART0=Y
UART2=Y
UNIT_TEST=Y
UTILS=Y
UWB=Y

Это просто атомные линии. Здесь устанавливаются переменные среды. Декларативно перечисляет, из какой прошивки следует собирать. Другая сборка имеет собственный декларативный файл config.mk и собственный набор переменных среды.

Эти же переменные среды решают, какие файлы добавить в компиляцию, а какие исключить. Например, переменная среды SD_CARD=Y добавит этот скрипт make в сборку.


ifneq ($(SD_CARD_MK_INC),Y)
    SD_CARD_MK_INC=Y

    $(info + SD card SPI driver)

    SD_CARD_DIR = $(ASICS_DIR)/sd_card
    #@echo $(error SD_CARD_DIR= $(SD_CARD_DIR))

    INCDIR += -I$(SD_CARD_DIR)

    OPT += -DHAS_CRC7
    OPT += -DHAS_CRC16
    OPT += -DHAS_SD_CARD
    OPT += -DHAS_SD_CARD_CRC7
    OPT += -DHAS_SD_CARD_CRC16

    SOURCES_C += $(SD_CARD_DIR)/sd_card_drv.c
    SOURCES_C += $(SD_CARD_DIR)/sd_card_crc.c
    SOURCES_C += $(SD_CARD_DIR)/sd_card_crc16.c

    ifeq ($(DIAG),Y)
        ifeq ($(SD_CARD_DIAG),Y)
            $(info + SD card diag)
            OPT += -DHAS_SD_CARD_DIAG
            SOURCES_C += $(SD_CARD_DIR)/sd_card_diag.c
        endif
    endif

    ifeq ($(CLI),Y)
        ifeq ($(SD_CARD_COMMANDS),Y)
            $(info + SD card commands)
            OPT += -DHAS_SD_CARD_COMMANDS
            SOURCES_C += $(SD_CARD_DIR)/sd_card_commands.c
        endif
    endif
endif

Достаточно внутри config.mk регистр SD_CARD=О а сами сценарии добавят все необходимое для создания кода C: исходный код, пути к исходному коду и директивы препроцессора. Вы изменили символ в сценариях с «Y» на «N», и сценарии make автоматически исключили из выпуска исходный код, исходные пути и директивы препроцессора для этого конкретного программного компонента. Легкий!

ЧИТАТЬ   Психолог дает советы родителям детей с венерическими заболеваниями

Переменные среды в config.mk, обратите внимание: отсортировано! А еще очень удобно сравнивать конфигурации двух разных сборок в утилите WinMerge.

4300fdf443115f305d88ed05eaf6de99

Как известно, компьютерные программы построены иерархически. Например, программный компонент интерфейса командной строки CLI требует, чтобы в программе уже были реализованы такие программные компоненты, как UART, ТАЙМЕР, инструмент распознавания чисел из строки и прочие РАЗНЫЕ мелочи.

В чем проблема?
Проблема в том, что существует множество переменных среды (конфигураций). Если вы пишете сценарий с использованием make, у вас будет много переменных среды для каждой конкретной сборки. Каждый config.mk будет содержать 100….200 строк, и вы можете случайно забыть установить важную переменную среды, которая включает определенные конфигурации. В противном случае прошивка не будет работать должным образом во время выполнения. Вот пример типичного config.mk

ADC=N
ADC_ISR=Y
ALLOCATOR=Y
ARRAY=Y
ASICS=Y
AUDIO=Y
BIN_2_STR=Y
BOARD=Y
BOARD_INFO=Y
BOARD_UTILS=Y
BUTTON=Y
CLI=Y
CLOCK=Y
CMSIS=Y
COMMON=Y
COMPLEX=Y
COMPONENTS=Y
CONNECTIVITY=Y
CORE=Y
CORE_APP=Y
CORE_EXT=Y
CORTEX_M33=Y
CRC16=Y
CRC8=Y
CRC=Y
CSV=Y
CUSTOM_PRINTF=Y
DATA_POC=Y
DEBUG=Y
DEBUGGER=Y
DFT=Y
DIAG=Y
DRIVERS=Y
DSP=Y
DYNAMIC_SAMPLES=Y
FIFO=Y
FIFO_CHAR=Y
FIFO_INDEX=Y
FLASH=Y
FLASH_EX=Y
FLASH_FS=Y
FLASH_FS_WRITE=Y
FLASH_WRITE=Y
GENERIC=Y
GPIO=Y
HEALTH_MONITOR=Y
I2C1=Y
I2C=Y
I2S0=Y
I2S0_MASTER=Y
I2S=Y
I2S_ISR=Y
INDICATION=Y
INTERFACES=Y
LED=Y
LED_MONO=Y
LED_VERIFY=Y
LIMITER=Y
LOG=Y
LOG_COLOR=Y
LOG_DIAG=Y
LOG_TIME_STAMP=Y
LOG_UTILS=Y
MATH=Y
MATH_VECTOR=Y
MCAL=Y
MCAL_NRF5340=Y
MICROCONTROLLER=Y
MISCELLANEOUS=Y
MULTIMEDIA=Y
NORTOS=Y
NRF5340=Y
NRF5340_APP=Y
NRF5340_DK=Y
NRFX=Y
NVIC_COMMANDS=Y
NVS=Y
NVS_WRITE=Y
PARAM=Y
PARAM_SET=Y
PCM_16_BIT=Y
PINS=Y
PROTOCOLS=Y
REAL_SAMPLE_ARRAY=N
SENSITIVITY=Y
SOFTWARE_TIMER=Y
STORAGE=Y
STR2_DOUBLE=Y
STREAM=Y
STRING=Y
STRING_PARSER=Y
SUPER_CYCLE=Y
SW_DAC=Y
SW_DAC_STATIC_SAMPLES=Y
SYSTEM=Y
SYSTICK=Y
SYS_INIT=Y
TABLE_UTILS=Y
TASK=Y
TERMINAL=Y
TEST_HW=Y
TEST_SW=Y
THIRD_PARTY=Y
TIME=Y
TIMER0=Y
TIMER1=Y
TIMER2=Y
TIMER=Y
UART0=Y
UART2=Y
UART=Y
UART_INTERRUPT=Y
UART_ISR=Y
UNIT_TEST=Y
WM8731=Y
WM8731_I2S_SLAVE=Y
WM8731_USB_MODE=Y
WM8731_VERIFY=Y
WRITE_ADDR=Y

В Zephyr Project проблема забытых конфигураций частично решена таким механизмом, как Кконфиг. Если вы не сохранили конфигурацию, то Кконфиг выдаст ошибку сборки или автоматически и автоматически добавит необходимую конфигурацию и продолжит сборку. Однако, к сожалению, не существует отдельной утилиты KConfig.exe, которую можно было бы использовать в любой сборке под Windows, не связанной с проектом Zephyr. Как это…

Отвечать

Очевидно, нам нужно сделать так, чтобы на этапе создания make-скриптов автоматически волшебным образом записывались забытые конфигурации зависимостей программных компонентов, которые мы изначально выбрали в файле. config.mk.

Вы должны убедиться, что конфигурации сохраняются автоматически.

Во-первых, вам необходимо создать для каждого программного компонента отдельный make-файл, который будет содержать информацию о его зависимостях. Иначе как система сборки будет определять, что нужно соединить? Вы можете назвать этот файл xxx_preconfig.mk. Например, вот файл nvram_preconfig.mk. Очевидно, что для работы встроенного кода NVRAM необходимы программные компоненты, такие как CRC8 и MCAL для Flash-устройств. В связи с этим определяются необходимые переменные среды.

ifneq ($(NVRAM_PRECONFIG_INC),Y)
    NVRAM_PRECONFIG_INC=Y

    NVRAM=Y
    FLASH=Y
    NVS=Y
    NVRAM_PROC=Y
    CRC=Y
    CRC8=Y
endif

Если в скриптах сборки работает скрипт nvram_preconfig.mk, то вам не придется писать CRC8=Y, FLASH=Y, NVS=Y и т.д. в файле config.mk. Все, что вам нужно сделать, это написать НВОЗУ=Да. Тогда все остальное появится само.

ЧИТАТЬ   В Самаре загорелся трамвай с пассажирами

А вот предварительная настройка SD-карты в режиме SPI.


ifneq ($(SD_CARD_PRECONFIG_MK_INC),Y)
    SD_CARD_PRECONFIG_MK_INC=Y

    CRC7=Y
    SPI=Y
    GPIO=Y
    CRC16=Y
    SD_CARD=Y
    SD_CARD_CRC7=Y
    SD_CARD_CRC16=Y
endif

На самом деле основная идея этого трюка взята из идеологии CMake. CMake собирает конфигурацию, затем система сборки (make, ninja или IDE) собирает сам проект. Только в этом случае все проще. Конфигурацию и проект собирает сама система сборки! Здесь это делает всеядная утилита make.

Вот упрощенный корневой файл code_base.mk собрать повторно используемый репозиторий

ifneq ($(CODE_BASE_MK),Y)
    CODE_BASE_MK=Y

    include $(WORKSPACE_LOC)/code_base_preconfig.mk

    #preconfig/presets done!

    ifeq ($(CORE),Y)
        include $(WORKSPACE_LOC)/core/core.mk
    endif

    ifeq ($(MICROCONTROLLER),Y)
        include $(WORKSPACE_LOC)/microcontroller/microcontroller.mk
    endif

    ifeq ($(BOARD),Y)
        include $(WORKSPACE_LOC)/boards/boards.mk
    endif

    ifeq ($(THIRD_PARTY),Y)
        include $(WORKSPACE_LOC)/third_party/third_party.mk
    endif

    ifeq ($(APPLICATIONS),Y)
        include $(WORKSPACE_LOC)/applications/applications.mk
    endif

    ifeq ($(MCAL),Y)
        include $(WORKSPACE_LOC)/mcal/mcal.mk
    endif

    ifeq ($(ADT),Y)
        include $(WORKSPACE_LOC)/adt/adt.mk
    endif

    ifeq ($(CONNECTIVITY),Y)
        include $(WORKSPACE_LOC)/connectivity/connectivity.mk
    endif

    ifeq ($(CONTROL),Y)
        include $(WORKSPACE_LOC)/control/control.mk
    endif
    
    ifeq ($(COMPONENTS),Y)
        include $(WORKSPACE_LOC)/components/components.mk
    endif

    ifeq ($(COMPUTING),Y)
        include $(WORKSPACE_LOC)/computing/computing.mk
    endif

    ifeq ($(SENSITIVITY),Y)
        include $(WORKSPACE_LOC)/sensitivity/sensitivity.mk
    endif

    ifeq ($(STORAGE),Y)
        include $(WORKSPACE_LOC)/storage/storage.mk
    endif

    ifeq ($(SECURITY),Y)
        include $(WORKSPACE_LOC)/security/security.mk
    endif

    ifeq ($(ASICS),Y)
        include $(WORKSPACE_LOC)/asics/asics.mk
    endif

    ifeq ($(UNIT_TEST),Y)  
        include $(WORKSPACE_LOC)/unit_tests/unit_test.mk
    endif

    ifeq ($(MISCELLANEOUS),Y)
        include $(WORKSPACE_LOC)/miscellaneous/miscellaneous.mk
    endif
endif

Обратите внимание, что code_base_preconfig.mk

include $(WORKSPACE_LOC)/code_base_preconfig.mk

вызывается до того, как будет построен сам проект. Что такое code_base_preconfig.mk? Это всего лишь скрипт для автоматической организации конфигураций, которые мы забыли при компиляции config.mk.

ifneq ($(CODE_BASE_PRECONFIG_MK),Y)
    CODE_BASE_PRECONFIG_MK=Y

    ifeq ($(BOARD),Y)
        include $(WORKSPACE_LOC)/boards/boards_preconfig.mk
    endif

    ifeq ($(MICROCONTROLLER),Y)
        include $(WORKSPACE_LOC)/microcontroller/microcontroller_preconfig.mk
    endif

    ifeq ($(CORE),Y)
        include $(WORKSPACE_LOC)/core/core_preconfig.mk
    endif

    ifeq ($(MCAL),Y)
        include $(WORKSPACE_LOC)/mcal/mcal_preconfig.mk
    endif

    ifeq ($(ADT),Y)
        include $(WORKSPACE_LOC)/adt/adt_preconfig.mk
    endif

    ifeq ($(CONNECTIVITY),Y)
        include $(WORKSPACE_LOC)/connectivity/connectivity_preconfig.mk
    endif

    ifeq ($(CONTROL),Y)
        include $(WORKSPACE_LOC)/control/control_preconfig.mk
    endif
    
    ifeq ($(COMPONENTS),Y)
        include $(WORKSPACE_LOC)/components/components_preconfig.mk
    endif

    ifeq ($(COMPUTING),Y)
        include $(WORKSPACE_LOC)/computing/computing_preconfig.mk
    endif

    ifeq ($(SENSITIVITY),Y)
        include $(WORKSPACE_LOC)/sensitivity/sensitivity_preconfig.mk
    endif

    ifeq ($(STORAGE),Y)
        include $(WORKSPACE_LOC)/storage/storage_preconfig.mk
    endif

    ifeq ($(SECURITY),Y)
        include $(WORKSPACE_LOC)/security/security_preconfig.mk
    endif

    include $(WORKSPACE_LOC)/asics/asics_preconfig.mk
    
endif

Те же скрипты nvram_preconfig.mk и sd_card_preconfig.mk будут вызываться где-то в Storage_preconfig.mk. И т. д.

ЧИТАТЬ   В шести областях Украины объявлена ​​воздушная тревога.

Итак, ваш исходный config.mk можно упростить, чтобы он выглядел так:

CLI=Y
COMPLEX=Y
CSV=Y
DEBUG=Y
NVRAM=Y
DEBUGGER=Y
DFT=Y
DIAG=Y
DSP=Y
DYNAMIC_SAMPLES=Y
GENERIC=Y
I2C1=Y
I2S0_MASTER=Y
NRF5340_DK=Y
NORTOS=Y
TASK=Y
TIMER0=Y
TIMER1=Y
TIMER2=Y
UART0=Y
UART2=Y
UNIT_TEST=Y
WM8731_I2S_SLAVE=Y
WM8731_USB_MODE=Y

Все остальное будет настроено автоматически! Настройка корня config.mk стала в 10 раз проще! Успех!

Заключение
Как видите, сборка из скриптов предлагает такие бонусы, как возможность автоматической организации конфигураций!

Разработана технология простой автоматической переносимой записи конфигураций зависимостей компонентов программного обеспечения на основе зависимостей, указанных в файлах xxx_preconfig.mk.

Надеюсь, этот текст поможет другим программистам разрабатывать свои программы.

Соединения

Почему важно собирать код из скриптов

Сортировка конфигураций для создания сборок https://habr.com/ru/articles/745244/

Настройка ToolChain(ов) для Win10+GCC+С+Makefile+ARM Cortex-Mx+GDB

Создание прошивки для CC2652 из Makefile

Генерировать зависимости внутри программы

ToolChain: Настройка сборки прошивки для микроконтроллеров Artery из Makefile https://habr.com/ru/articles/792590/

Автоматическое обновление версии прошивки

Source

От admin