Создание встраиваемого приложения для микроконтроллера
Исходный код этого руководства можно найти на GitHub
В этом руководстве мы будем использовать Raspberry Pi Pico в качестве встраиваемого устройства, на котором будет выполняться наше приложение Swift. Если у вас его нет, не волнуйтесь! Вы всё равно можете запустить приложение в онлайн-эмуляторе.
Установка Swift
Если у вас не установлен Swift, установите его сначала. Поскольку Embedded Swift — экспериментальная функция, доступная только в предварительных инструментах, убедитесь, что установлена инструментальная цепочка «Development Snapshot» (main), а не инструментальная цепочка выпуска (6.0). Если вы используете компьютер macOS, вам необходимо убедиться, что Xcode установлен и выбран, выполнив xcode-select -p и проверив, что он указывает на путь к установке Xcode. Далее убедитесь, что установленная инструментальная цепочка «Development Snapshot» выбрана как активная, например, путём экспорта переменной среды TOOLCHAINS:
$ export TOOLCHAINS=org.swift.59202405011a
Чтобы проверить установку Swift, выполните swift --version из вашего терминала. Должно отобразиться значение «6.0-dev», что означает, что у вас установлена инструментальная цепочка «Development Snapshot».
Установка зависимостей для разработки встраиваемых систем
Установите SDK Raspberry Pi Pico и инструментальную цепочку Arm Embedded, следуя руководству Getting Started With Pico. Экспортируйте три переменные среды, чтобы соответствовать вашей настройке и оборудованию:
$ export PICO_BOARD=pico
$ export PICO_SDK_PATH=... # location to your Pico SDK
$ export PICO_TOOLCHAIN_PATH=... # location to the Arm Embedded Toolchain
Если у вас есть Wi-Fi-модуль Pico W вместо обычного Pico, обратите внимание, что вам понадобится немного другая настройка, описанная в проекте Pico W, и просто указание PICO_BOARD=pico_w не сработает.
Установите CMake 3.29 или более позднюю версию.
Чтобы проверить, что все необходимые компоненты установлены, вы можете выполнить следующие команды в терминале:
$ swift --version
Apple Swift version 6.0-dev (LLVM b66077aefd3be08, Swift 84d36181a762913)
$ cmake --version
cmake version 3.29.2
$ echo $PICO_BOARD
pico
$ ls $PICO_SDK_PATH
CMakeLists.txt README.md external/ pico_sdk_version.cmake tools/
CONTRIBUTING.md cmake/ lib/ src/
LICENSE.TXT docs/ pico_sdk_init.cmake test/
$ ls $PICO_TOOLCHAIN_PATH
13.2.Rel1-darwin-arm64-arm-none-eabi-manifest.txt include/ share/
arm-none-eabi/ lib/
bin/ libexec/
Сборка приложения «blinky» для встраиваемых систем
Стандартным «Привет, мир!» в разработке встраиваемых систем является программа, которая периодически мигает светодиодом. Давайте создадим такую программу. Данную настройку также можно найти в swift-embedded-examples, но ниже мы покажем, что вам нужны только три файла. Давайте создадим новую пустую директорию и подготовим простую структуру для проекта CMake, который можно использовать поверх Pico SDK:
embedded-swift-tutorial
├── BridgingHeader.h
├── CMakeLists.txt
└── Main.swift
В файлах Main.swift и BridgingHeader.h изначально может быть следующий базовый контент:
// Main.swift
let led = UInt32(PICO_DEFAULT_LED_PIN)
gpio_init(led)
gpio_set_dir(led, /*out*/true)
while true {
gpio_put(led, true)
sleep_ms(250)
gpio_put(led, false)
sleep_ms(250)
}
// BridgingHeader.h
#include "pico/stdlib.h"Для сборки поверх поддержки CMake в Pico SDK нам понадобится немного больше логики CMake в файле CMakeLists.txt:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.29)
include($ENV{PICO_SDK_PATH}/external/pico_sdk_import.cmake)
set(CMAKE_Swift_COMPILATION_MODE wholemodule)
set(CMAKE_Swift_COMPILER_WORKS YES)
project(blinky)
pico_sdk_init()
enable_language(Swift)
add_executable(blinky Main.swift)
set_target_properties(blinky PROPERTIES LINKER_LANGUAGE CXX)
# Clear the default COMPILE_OPTIONS which include C specific compiler flags that the Swift compiler will not accept
# Instead, set those options to only apply when compiling C code.
set_target_properties(pico_standard_link PROPERTIES INTERFACE_COMPILE_OPTIONS "")
target_compile_options(pico_standard_link INTERFACE "$<$<COMPILE_LANGUAGE:C>:SHELL: -ffunction-sections -fdata-sections>")
set(SWIFT_INCLUDES)
foreach(dir ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES})
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ")
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ")
endforeach()
target_compile_options(blinky PUBLIC "$<$<COMPILE_LANGUAGE:Swift>:SHELL:
-enable-experimental-feature Embedded
-target armv6m-none-none-eabi -Xcc -mfloat-abi=soft -Xcc -fshort-enums -Xfrontend -function-sections
-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
${SWIFT_INCLUDES}
>")
target_link_libraries(blinky pico_stdlib hardware_uart hardware_gpio)
pico_add_extra_outputs(blinky)
Теперь мы готовы сконфигурировать и собрать этот прошивку для Pico. Выполните следующие команды:
$ cmake -B build -G Ninja . # configure step
$ cmake --build build # build step
Сборка должна пройти успешно и создать прошивку в нескольких форматах (ELF, HEX, UF2), включая некоторые файлы отчётов (DIS, ELF.MAP):
$ ls -al build/blinky*
-rwxr-xr-x 1 kuba staff 8.0K Jan 1 12:00 build/blinky.bin*
-rw-r--r-- 1 kuba staff 145K Jan 1 12:00 build/blinky.dis
-rwxr-xr-x 1 kuba staff 30K Jan 1 12:00 build/blinky.elf*
-rw-r--r-- 1 kuba staff 222K Jan 1 12:00 build/blinky.elf.map
-rw-r--r-- 1 kuba staff 23K Jan 1 12:00 build/blinky.hex
-rw-r--r-- 1 kuba staff 16K Jan 1 12:00 build/blinky.uf2
Запуск прошивки на устройстве
Если у вас есть Raspberry Pi Pico, мы сейчас загрузим собранную прошивку и запустим её. Если у вас его нет, переходите к следующему разделу и запустите тот же файл прошивки в эмуляторе вместо этого.
Подключите Raspberry Pi Pico к вашему компьютеру через USB-кабель и убедитесь, что он находится в режиме загрузки прошивки через USB-массовое хранилище. Обычно это так, если вы ещё никогда не загружали прошивку — Pico загружается в режим загрузки прошивки, если его память не содержит никакой действительной прошивки. После загрузки действительной прошивки устройство запустит эту прошивку после подключения. Чтобы вернуться в режим загрузки прошивки, удерживайте кнопку BOOTSEL при подключении платы.
Pico должен отобразиться как подключённый том в /Volumes (в данном случае как RPI-RP2):
$ ls -al /Volumes
lrwxr-xr-x 1 root wheel 1B Jan 1 12:00 Macintosh HD@ -> /
drwx------ 1 kuba staff 16K Dec 31 1969 RPI-RP2/
Скопируйте файл UF2 в этот том:
$ cp build/blinky.uf2 /Volumes/RPI-RP2
Это позволит Pico автоматически установить прошивку, перезагрузиться и запустить прошивку.
Теперь зелёный светодиод должен периодически мигать. Ура! Наше первое приложение Embedded Swift запущено на встраиваемом устройстве!
Запуск прошивки в эмуляторе
Если у вас нет физического Pico или если вы хотите быстро итерировать, Wokwi — это бесплатный онлайн-эмулятор различных встраиваемых микроконтроллеров, включая Raspberry Pi Pico. Он выполняет ту же двоичную прошивку, которую вы обычно загружаете на физическое устройство, и эмулирует одну инструкцию за раз.
Откройте новый проект Pico в Wokwi. Вместо использования редактора кода для написания кода C, нажмите F1 и выберите «Загрузить прошивку и начать симуляцию». Затем выберите файл UF2, который произвел наш процесс сборки.
После загрузки файла UF2 в Wokwi симуляция начнется, и светодиод начнёт периодически мигать. Ура! Наше первое приложение Embedded Swift запущено в эмуляторе!
Бонус: Сборка простого приложения для вашей хост-ОС с помощью Embedded Swift
Хотя настольные операционные системы, такие как macOS и Linux, не являются типичными целевыми платформами для Embedded Swift, вы абсолютно можете создать для них код, используя режим Embedded Swift. Это полезно для экспериментов, тестирования Embedded Swift или быстрого воплощения идей кода, которому физическое устройство не нужно для работы.
Самое простое приложение в Embedded Swift — это обычное «Hello, World»:
// HelloEmbedded.swift
print("Hello, Embedded Swift 😊")
И сборка его в исполняемый файл может быть выполнена вызовом компилятора swiftc напрямую, но мы хотим добавить флаги для включения Embedded Swift и также Whole Module Optimization.
$ swiftc HelloEmbedded.swift -o HelloEmbedded -enable-experimental-feature Embedded -wmo
Это создаст обычный исполняемый двоичный файл, но обратите внимание, что он очень мал по размеру и что он фактически не зависит от среды выполнения Swift в ОС (все двоичные файлы Embedded Swift содержат зависимости среды выполнения + stdlib внутри):
$ ls -al
-rwxr-xr-x 1 kuba staff 18K May 16 17:19 HelloEmbedded*
-rw-r--r-- 1 kuba staff 59B May 16 17:16 HelloEmbedded.swift
$ otool -L HelloEmbedded
HelloEmbedded:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1000.0.0)
Давайте запустим его:
$ ./HelloEmbedded
Hello, Embedded Swift 😊
Ура! Наше первое приложение Embedded Swift для хост-системы работает!
Что делать дальше
- Документ Embedded Swift Vision предоставит обзор подходов и целей Embedded Swift, а также что именно входит в подмножество языка Embedded Swift.
- Коллекция примеров проектов Embedded Swift на GitHub показывает, на каких встраиваемых устройствах Swift может работать сегодня, а примеры также могут быть использованы как шаблоны для ваших собственных проектов.
- Руководство пользователя Embedded Swift описывает, как использовать режим компиляции Embedded Swift и взаимодействовать с компилятором.
- На странице Инструменты есть руководства по настройке интеграции Swift в ваш редактор, чтобы включить функции, такие как индексирование, автодополнение, переход к определению и другие.
- Форумы Swift — лучшее место для задавания вопросов, предоставления отзывов или показа ваших интересных проектов.
Исходный код этого руководства можно найти на GitHub
The Swift Programming Language, Copyright © 2014-2025 Apple Inc.
Swift and the Swift logo are trademarks of Apple Inc.
Documentation for Swift 6.0.3
https://www.swift.org/getting-started/embedded-swift/