Skip to content

add Arduino LED and Wi-Fi SDKs #98

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .github/workflows/build-arduino-esp.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Build Arduino ESP Examples

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]
schedule:
# Build on Mondays at 9am PST every week
- cron: '0 17 * * 1'

jobs:
build-arduino-esp:
runs-on: ubuntu-24.04
container: espressif/idf:v5.4
strategy:
fail-fast: false
matrix:
example: [arduino-esp32-led-blink-sdk, arduino-esp32-wifi-scan-sdk]
swift: [swift-DEVELOPMENT-SNAPSHOT-2025-03-17-a]

steps:
- name: Checkout repo
uses: actions/checkout@v4

- name: Install apt dependencies
run: |
apt-get -qq update
apt-get -qq -y install pkg-config libstdc++6

- name: Install ${{ matrix.swift }}
run: |
wget -q https://download.swift.org/development/ubuntu2404/${{ matrix.swift }}/${{ matrix.swift }}-ubuntu24.04.tar.gz
tar xzf ${{ matrix.swift }}-ubuntu24.04.tar.gz
export PATH="`pwd`/${{ matrix.swift }}-ubuntu24.04/usr/bin/:$PATH"
echo "PATH=$PATH" >> $GITHUB_ENV
swiftc --version

- name: Build ${{ matrix.example }}
run: |
cd $IDF_PATH
. ./export.sh
cd -
cd ${{ matrix.example }}
idf.py set-target esp32c6
idf.py build
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This repository is a set of demonstration projects of **Embedded Swift**. Embedd
Each example in this repository contains build and deployment instructions, however there are a couple common steps needed for many of the examples included below:

1. Install the latest downloadable 'main' [Development Snapshot](https://www.swift.org/install/macos/#development-snapshots) from swift.org to use Embedded Swift. Public releases of Swift do not yet support Embedded Swift.

You can follow the [tutorial here](https://apple.github.io/swift-matter-examples/tutorials/swiftmatterexamples/setup-macos/) for instructions on installing and using nighly Swift toolchains.

2. Install [`uv`](https://github.com/astral-sh/uv) "an extremely fast Python package and project manager".
Expand All @@ -29,6 +29,8 @@ Each example in this repository contains build and deployment instructions, howe
| ---- | -------- | --- | ----------- | ----- |
| [esp32-led-blink-sdk](./esp32-led-blink-sdk) | ESP32-C6-Bug | ESP-IDF SDK | Blink an LED repeatedly with Swift & the ESP-IDF. | <img width="300" src="esp32-led-blink-sdk/assets/images/ledon.jpg"> |
| [esp32-led-strip-sdk](./esp32-led-strip-sdk) | ESP32-C6-DevKitC-1 | ESP-IDF SDK | Control NeoPixel LEDs with Swift & the ESP-IDF. | <img width="300" src="https://github.com/apple/swift-embedded-examples/assets/1186214/15f8a3e0-953e-426d-ad2d-3902baf859be"> |
| [arduino-esp32-led-blink-sdk](./arduino-esp32-led-blink-sdk) | ESP32-C6-Bug | ESP-IDF SDK | Blink an LED repeatedly with Swift, the ESP-IDF and the Arduino libraries. | |
| [arduino-esp32-wifi-scan-sdk](./arduino-esp32-wifi-scan-sdk) | ESP32-C6-DevKitC-1 | ESP-IDF SDK | Blink an LED repeatedly with Swift, the ESP-IDF and the Arduino libraries. | |
| [nrfx-blink-sdk](./nrfx-blink-sdk) | nRF52840-DK | Zephyr SDK | Blink an LED repeatedly with Swift & Zephyr. | <img width="300" src="https://github.com/apple/swift-embedded-examples/assets/1186214/ae3ff153-dd33-4460-8a08-4eac442bf7b0"> |
| [nuttx-riscv-blink](./nuttx-riscv-blink) | QEMU | NuttX | Blink a virualized led in QEMU using the Apache NuttX RTOS | |
| [pico-blink-sdk](./pico-blink-sdk) | Raspberry Pi Pico, Pico 2 | Pico SDK | Blink an LED repeatedly with Swift & the Pico SDK. | <img width="300" src="https://github.com/apple/swift-embedded-examples/assets/1186214/f2c45c18-f9a4-48b4-a941-1298ecc942cb"> |
Expand Down
6 changes: 6 additions & 0 deletions arduino-esp32-led-blink-sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(app-template)
57 changes: 57 additions & 0 deletions arduino-esp32-led-blink-sdk/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# arduino-esp32-led-blink-sdk

This example demonstrates how to integrate with the ESP-IDF SDK via CMake and how to use the Arduino GPIO library to control an LED from Swift. This example is specifically made for the RISC-V MCUs from ESP32 (the Xtensa MCUs are not currently supported by Swift).

## Requirements

- Set up **version v5.4** (required for this `arduino-esp32` version) of the [ESP-IDF](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32/) development environment. Follow the steps in the [ESP32-C6 "Get Started" guide](https://docs.espressif.com/projects/esp-idf/en/v5.4/esp32c6/get-started/index.html).
- Make sure you specifically set up development for the RISC-V ESP32-C6, and not the Xtensa based products.
- If you have a different version of ESP-IDF installed, make sure to also delete `~/.espressif` before running `install.sh`

```sh
rm -rf ~/esp-idf ~/.espressif # Remove old installation files
git clone --recurse-submodules https://github.com/espressif/esp-idf.git ~/esp-idf
cd ~/esp-idf
git checkout release/v5.4
git submodule update --init --recursive
./install.sh
idf_tools.py install-python-env
. ./export.sh
```

- Before trying to use Swift with the ESP-IDF SDK, make sure your environment works and can build the provided C/C++ sample projects, in particular:
- Try building and running the "get-started/blink" example from ESP-IDF written in C.

## Building

- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support.
- If needed, run export.sh to get access to the idf.py script from ESP-IDF.
- Specify the nightly toolchain to be used via the `TOOLCHAINS` environment variable and the target board type by using `idf.py set-target`.
```sh
cd arduino-esp32-led-blink-sdk
export TOOLCHAINS=...
. <path-to-esp-idf>/export.sh
idf.py set-target esp32c6
idf.py build
```

## Running

- Connect the Esp32-C6-Bug board (or any other board with integrated LED on GPIO pin 8) over a USB cable to your Mac. Alternatively you can just connect external LED to GPIO pin 8 on any other board.
- Connect RX pin of USB-UART converter to TX0 pin of your board if you need serial output. You may also need to connect GND converter pin to the GND pin of the board.
- Use `idf.py` to upload the firmware and to run it:

```sh
idf.py flash
```

- The LED should be blinking now.

### Simulating in VS Code

- Build the project, to generate binaries for simulation
- Install [Wokwi for VS Code](https://docs.wokwi.com/vscode/getting-started/).
- Open the `diagram.json` file.
- Click the Play button to start simulation.
- Click the Pause button to freeze simulation and display states of GPIOs.

36 changes: 36 additions & 0 deletions arduino-esp32-led-blink-sdk/diagram.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"version": 1,
"author": "",
"editor": "wokwi",
"parts": [
{
"type": "board-esp32-c6-devkitc-1",
"id": "esp",
"top": 0,
"left": 0,
"attrs": { "builder": "esp-idf" }
},
{
"type": "wokwi-resistor",
"id": "r1",
"top": 119.15,
"left": -76.8,
"attrs": { "value": "1000" }
},
{
"type": "wokwi-led",
"id": "led1",
"top": 25.2,
"left": -111.4,
"attrs": { "color": "red" }
}
],
"connections": [
[ "esp:TX", "$serialMonitor:RX", "", [] ],
[ "esp:RX", "$serialMonitor:TX", "", [] ],
[ "r1:2", "esp:8", "red", [ "v0" ] ],
[ "r1:1", "led1:A", "red", [ "h0" ] ],
[ "led1:C", "esp:GND.1", "black", [ "v0" ] ]
],
"dependencies": {}
}
27 changes: 27 additions & 0 deletions arduino-esp32-led-blink-sdk/main/BridgingHeader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

// For some reason swiftc's clang++ defines `__UINT32_TYPE__` as `unsigned int` (g++'s x86 behaviour) not `long unsigned int` (g++'s riscv32 behaviour)
#undef __UINT32_TYPE__
#undef uint32_t
#define __UINT32_TYPE__ long unsigned int
#define uint32_t __UINT32_TYPE__
#define _UINT32_T_DECLARED

#include <stdio.h>
#include <stdint.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"

#include <Arduino.h>
73 changes: 73 additions & 0 deletions arduino-esp32-led-blink-sdk/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Register the app as an IDF component
idf_component_register(
SRCS /dev/null # We don't have any C++ sources
PRIV_INCLUDE_DIRS "."
REQUIRES arduino
)

idf_build_get_property(target IDF_TARGET)
idf_build_get_property(arch IDF_TARGET_ARCH)

if("${arch}" STREQUAL "xtensa")
message(FATAL_ERROR "Not supported target: ${target}")
endif()

# Extract the -march flag and remove any vendor-specific extensions (_x*)
string(REGEX MATCH "-march=[^ ]+" march_flag "${CMAKE_C_FLAGS}")
string(REGEX REPLACE "_x[^ ]*" "" march_flag "${march_flag}")

# Extract the -mabi flag or set a default value if not present
string(REGEX MATCH "-mabi=[^ ]+" mabi_flag "${CMAKE_C_FLAGS}")
if("${mabi_flag}" STREQUAL "")
set(mabi_flag "-mabi=ilp32")
endif()

# Clear the default COMPILE_OPTIONS which include a lot of C/C++ specific compiler flags that the Swift compiler will not accept
get_target_property(var ${COMPONENT_LIB} COMPILE_OPTIONS)
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_OPTIONS "")

# Compute -Xcc flags to set up the C and C++ header search paths for Swift (for bridging header).
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()
foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ")
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ")
endforeach()

# Swift compiler flags to build in Embedded Swift mode, optimize for size, choose the right ISA, ABI, etc.
target_compile_options(${COMPONENT_LIB} PUBLIC "$<$<COMPILE_LANGUAGE:Swift>:SHELL:
-target riscv32-none-none-eabi
-Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library -Osize -cxx-interoperability-mode=default
-Xcc ${march_flag} -Xcc ${mabi_flag} -Xcc -fno-pic -Xcc -fno-pie -Xcc -fno-exceptions

-pch-output-dir /tmp
-Xfrontend -enable-single-module-llvm-emission

${SWIFT_INCLUDES}

-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
>")

# Enable Swift support in CMake, force Whole Module builds (required by Embedded Swift), and use "CMAKE_Swift_COMPILER_WORKS" to
# skip the trial compilations which don't (yet) correctly work when cross-compiling.
set(CMAKE_Swift_COMPILER_WORKS YES)
set(CMAKE_Swift_COMPILATION_MODE_DEFAULT wholemodule)
set(CMAKE_Swift_COMPILATION_MODE wholemodule)
enable_language(Swift)

# List of Swift source files to build.
target_sources(${COMPONENT_LIB}
PRIVATE
Main.swift
Led.swift
)

add_custom_command(
TARGET ${COMPONENT_LIB}
POST_BUILD
COMMAND ${CMAKE_OBJCOPY} --remove-section .swift_modhash
$<TARGET_FILE:${COMPONENT_LIB}> $<TARGET_FILE:${COMPONENT_LIB}>
)
8 changes: 8 additions & 0 deletions arduino-esp32-led-blink-sdk/main/Kconfig.projbuild
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# put here your custom config value
menu "Example Configuration"
config LED_BLINK_INTERVAL_MS
int "LED blinking interval / ms"
default 500
help
Interval in milliseconds between turning the LED on/off
endmenu
23 changes: 23 additions & 0 deletions arduino-esp32-led-blink-sdk/main/Led.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

// A simple "overlay" to provide nicer APIs in Swift
struct Led {
var ledPin: UInt8
init(gpioPin: gpio_num_t) {
ledPin = UInt8(gpioPin.rawValue)
pinMode(ledPin, UInt8(OUTPUT))
}

func setLed(value: Bool) {
digitalWrite(ledPin, value ? 1 : 0)
}
}
28 changes: 28 additions & 0 deletions arduino-esp32-led-blink-sdk/main/Main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift open source project
//
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

// The code will blink an LED on GPIO8. To change the pin, modify Led(gpioPin: GPIO_NUM_8)

var ledValue: Bool = false
var led: Led?

@_cdecl("_Z5setupv")
func setup() {
print("Hello from Swift on ESP32-C6!")
led = Led(gpioPin: GPIO_NUM_8)
}

@_cdecl("_Z4loopv")
func loop() {
led?.setLed(value: ledValue)
ledValue.toggle() // Toggle the boolean value
delay(UInt(CONFIG_LED_BLINK_INTERVAL_MS))
}
8 changes: 8 additions & 0 deletions arduino-esp32-led-blink-sdk/main/component.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
19 changes: 19 additions & 0 deletions arduino-esp32-led-blink-sdk/main/idf_component.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## IDF Component Manager Manifest File
dependencies:
# # Put list of dependencies here
# # For components maintained by Espressif:
# component: "~1.0.0"
# # For 3rd party components:
# username/component: ">=1.0.0,<2.0.0"
# username2/component2:
# version: "~1.0.0"
# # For transient dependencies `public` flag can be set.
# # `public` flag doesn't have an effect dependencies of the `main` component.
# # All dependencies of `main` are public by default.
# public: true

## Required IDF version
idf: ">=5.3,<5.5"
arduino: # Can't be defined as the espressif/arduino-esp32 shorthand since the library name must be 'arduino' for libraries that depend on it
git: https://github.com/espressif/arduino-esp32.git
version: 3.2.0
4 changes: 4 additions & 0 deletions arduino-esp32-led-blink-sdk/sdkconfig.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CONFIG_FREERTOS_HZ=1000
CONFIG_MBEDTLS_PSK_MODES=y
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
CONFIG_AUTOSTART_ARDUINO=y
8 changes: 8 additions & 0 deletions arduino-esp32-led-blink-sdk/wokwi.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Wokwi Configuration File
# Reference: https://docs.wokwi.com/vscode/project-config
[wokwi]
version = 1
firmware = 'build/flasher_args.json'
elf = 'build/main.elf'
# gdbServerPort=3333

6 changes: 6 additions & 0 deletions arduino-esp32-wifi-scan-sdk/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)

include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(app-template)
Loading
Loading