Skip to content

Commit d8ca240

Browse files
committed
add Arduino LED and Wi-Fi SDKs
Adds two esp32 example projects using the espressif/arduino-esp32 library to demonstrate Wi-Fi scanning and a simple LED blink example
1 parent 3aac684 commit d8ca240

24 files changed

+592
-1
lines changed
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: Build Arduino ESP Examples
2+
3+
on:
4+
push:
5+
branches: ["main"]
6+
pull_request:
7+
branches: ["main"]
8+
schedule:
9+
# Build on Mondays at 9am PST every week
10+
- cron: '0 17 * * 1'
11+
12+
jobs:
13+
build-arduino-esp:
14+
runs-on: ubuntu-24.04
15+
container: espressif/idf:v5.4
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
example: [arduino-esp32-led-blink-sdk, arduino-esp32-wifi-scan-sdk]
20+
swift: [swift-DEVELOPMENT-SNAPSHOT-2025-03-17-a]
21+
22+
steps:
23+
- name: Checkout repo
24+
uses: actions/checkout@v4
25+
26+
- name: Install apt dependencies
27+
run: |
28+
apt-get -qq update
29+
apt-get -qq -y install pkg-config libstdc++6
30+
31+
- name: Install ${{ matrix.swift }}
32+
run: |
33+
wget -q https://download.swift.org/development/ubuntu2404/${{ matrix.swift }}/${{ matrix.swift }}-ubuntu24.04.tar.gz
34+
tar xzf ${{ matrix.swift }}-ubuntu24.04.tar.gz
35+
export PATH="`pwd`/${{ matrix.swift }}-ubuntu24.04/usr/bin/:$PATH"
36+
echo "PATH=$PATH" >> $GITHUB_ENV
37+
swiftc --version
38+
39+
- name: Build ${{ matrix.example }}
40+
run: |
41+
cd $IDF_PATH
42+
. ./export.sh
43+
cd -
44+
cd ${{ matrix.example }}
45+
idf.py set-target esp32c6
46+
idf.py build

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ This repository is a set of demonstration projects of **Embedded Swift**. Embedd
1616
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:
1717

1818
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.
19-
19+
2020
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.
2121

2222
2. Install [`uv`](https://github.com/astral-sh/uv) "an extremely fast Python package and project manager".
@@ -29,6 +29,8 @@ Each example in this repository contains build and deployment instructions, howe
2929
| ---- | -------- | --- | ----------- | ----- |
3030
| [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"> |
3131
| [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"> |
32+
| [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. | |
33+
| [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. | |
3234
| [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"> |
3335
| [nuttx-riscv-blink](./nuttx-riscv-blink) | QEMU | NuttX | Blink a virualized led in QEMU using the Apache NuttX RTOS | |
3436
| [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"> |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(app-template)

arduino-esp32-led-blink-sdk/README.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# arduino-esp32-led-blink-sdk
2+
3+
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).
4+
5+
## Requirements
6+
7+
- 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).
8+
- Make sure you specifically set up development for the RISC-V ESP32-C6, and not the Xtensa based products.
9+
- If you have a different version of ESP-IDF installed, make sure to also delete `~/.espressif` before running `install.sh`
10+
11+
```sh
12+
rm -rf ~/esp-idf ~/.espressif # Remove old installation files
13+
git clone --recurse-submodules https://github.com/espressif/esp-idf.git ~/esp-idf
14+
cd ~/esp-idf
15+
git checkout release/v5.4
16+
git submodule update --init --recursive
17+
./install.sh
18+
idf_tools.py install-python-env
19+
. ./export.sh
20+
```
21+
22+
- 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:
23+
- Try building and running the "get-started/blink" example from ESP-IDF written in C.
24+
25+
## Building
26+
27+
- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support.
28+
- If needed, run export.sh to get access to the idf.py script from ESP-IDF.
29+
- Specify the nightly toolchain to be used via the `TOOLCHAINS` environment variable and the target board type by using `idf.py set-target`.
30+
```sh
31+
cd arduino-esp32-led-blink-sdk
32+
export TOOLCHAINS=...
33+
. <path-to-esp-idf>/export.sh
34+
idf.py set-target esp32c6
35+
idf.py build
36+
```
37+
38+
## Running
39+
40+
- 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.
41+
- 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.
42+
- Use `idf.py` to upload the firmware and to run it:
43+
44+
```sh
45+
idf.py flash
46+
```
47+
48+
- The LED should be blinking now.
49+
50+
### Simulating in VS Code
51+
52+
- Build the project, to generate binaries for simulation
53+
- Install [Wokwi for VS Code](https://docs.wokwi.com/vscode/getting-started/).
54+
- Open the `diagram.json` file.
55+
- Click the Play button to start simulation.
56+
- Click the Pause button to freeze simulation and display states of GPIOs.
57+
+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"version": 1,
3+
"author": "",
4+
"editor": "wokwi",
5+
"parts": [
6+
{
7+
"type": "board-esp32-c6-devkitc-1",
8+
"id": "esp",
9+
"top": 0,
10+
"left": 0,
11+
"attrs": { "builder": "esp-idf" }
12+
},
13+
{
14+
"type": "wokwi-resistor",
15+
"id": "r1",
16+
"top": 119.15,
17+
"left": -76.8,
18+
"attrs": { "value": "1000" }
19+
},
20+
{
21+
"type": "wokwi-led",
22+
"id": "led1",
23+
"top": 25.2,
24+
"left": -111.4,
25+
"attrs": { "color": "red" }
26+
}
27+
],
28+
"connections": [
29+
[ "esp:TX", "$serialMonitor:RX", "", [] ],
30+
[ "esp:RX", "$serialMonitor:TX", "", [] ],
31+
[ "r1:2", "esp:8", "red", [ "v0" ] ],
32+
[ "r1:1", "led1:A", "red", [ "h0" ] ],
33+
[ "led1:C", "esp:GND.1", "black", [ "v0" ] ]
34+
],
35+
"dependencies": {}
36+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
// For some reason swiftc's clang++ defines `__UINT32_TYPE__` as `unsigned int` (g++'s x86 behaviour) not `long unsigned int` (g++'s riscv32 behaviour)
13+
#undef __UINT32_TYPE__
14+
#undef uint32_t
15+
#define __UINT32_TYPE__ long unsigned int
16+
#define uint32_t __UINT32_TYPE__
17+
#define _UINT32_T_DECLARED
18+
19+
#include <stdio.h>
20+
#include <stdint.h>
21+
22+
#include "freertos/FreeRTOS.h"
23+
#include "freertos/task.h"
24+
#include "driver/gpio.h"
25+
#include "sdkconfig.h"
26+
27+
#include <Arduino.h>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Register the app as an IDF component
2+
idf_component_register(
3+
SRCS /dev/null # We don't have any C++ sources
4+
PRIV_INCLUDE_DIRS "."
5+
REQUIRES arduino
6+
)
7+
8+
idf_build_get_property(target IDF_TARGET)
9+
idf_build_get_property(arch IDF_TARGET_ARCH)
10+
11+
if("${arch}" STREQUAL "xtensa")
12+
message(FATAL_ERROR "Not supported target: ${target}")
13+
endif()
14+
15+
# Extract the -march flag and remove any vendor-specific extensions (_x*)
16+
string(REGEX MATCH "-march=[^ ]+" march_flag "${CMAKE_C_FLAGS}")
17+
string(REGEX REPLACE "_x[^ ]*" "" march_flag "${march_flag}")
18+
19+
# Extract the -mabi flag or set a default value if not present
20+
string(REGEX MATCH "-mabi=[^ ]+" mabi_flag "${CMAKE_C_FLAGS}")
21+
if("${mabi_flag}" STREQUAL "")
22+
set(mabi_flag "-mabi=ilp32")
23+
endif()
24+
25+
# Clear the default COMPILE_OPTIONS which include a lot of C/C++ specific compiler flags that the Swift compiler will not accept
26+
get_target_property(var ${COMPONENT_LIB} COMPILE_OPTIONS)
27+
set_target_properties(${COMPONENT_LIB} PROPERTIES COMPILE_OPTIONS "")
28+
29+
# Compute -Xcc flags to set up the C and C++ header search paths for Swift (for bridging header).
30+
set(SWIFT_INCLUDES)
31+
foreach(dir ${CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES})
32+
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ")
33+
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ")
34+
endforeach()
35+
foreach(dir ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES})
36+
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-Xcc ")
37+
string(CONCAT SWIFT_INCLUDES ${SWIFT_INCLUDES} "-I${dir} ")
38+
endforeach()
39+
40+
# Swift compiler flags to build in Embedded Swift mode, optimize for size, choose the right ISA, ABI, etc.
41+
target_compile_options(${COMPONENT_LIB} PUBLIC "$<$<COMPILE_LANGUAGE:Swift>:SHELL:
42+
-target riscv32-none-none-eabi
43+
-Xfrontend -function-sections -enable-experimental-feature Embedded -wmo -parse-as-library -Osize -cxx-interoperability-mode=default
44+
-Xcc ${march_flag} -Xcc ${mabi_flag} -Xcc -fno-pic -Xcc -fno-pie -Xcc -fno-exceptions
45+
46+
-pch-output-dir /tmp
47+
-Xfrontend -enable-single-module-llvm-emission
48+
49+
${SWIFT_INCLUDES}
50+
51+
-import-bridging-header ${CMAKE_CURRENT_LIST_DIR}/BridgingHeader.h
52+
>")
53+
54+
# Enable Swift support in CMake, force Whole Module builds (required by Embedded Swift), and use "CMAKE_Swift_COMPILER_WORKS" to
55+
# skip the trial compilations which don't (yet) correctly work when cross-compiling.
56+
set(CMAKE_Swift_COMPILER_WORKS YES)
57+
set(CMAKE_Swift_COMPILATION_MODE_DEFAULT wholemodule)
58+
set(CMAKE_Swift_COMPILATION_MODE wholemodule)
59+
enable_language(Swift)
60+
61+
# List of Swift source files to build.
62+
target_sources(${COMPONENT_LIB}
63+
PRIVATE
64+
Main.swift
65+
Led.swift
66+
)
67+
68+
add_custom_command(
69+
TARGET ${COMPONENT_LIB}
70+
POST_BUILD
71+
COMMAND ${CMAKE_OBJCOPY} --remove-section .swift_modhash
72+
$<TARGET_FILE:${COMPONENT_LIB}> $<TARGET_FILE:${COMPONENT_LIB}>
73+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# put here your custom config value
2+
menu "Example Configuration"
3+
config LED_BLINK_INTERVAL_MS
4+
int "LED blinking interval / ms"
5+
default 500
6+
help
7+
Interval in milliseconds between turning the LED on/off
8+
endmenu
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
// A simple "overlay" to provide nicer APIs in Swift
13+
struct Led {
14+
var ledPin: UInt8
15+
init(gpioPin: gpio_num_t) {
16+
ledPin = UInt8(gpioPin.rawValue)
17+
pinMode(ledPin, UInt8(OUTPUT))
18+
}
19+
20+
func setLed(value: Bool) {
21+
digitalWrite(ledPin, value ? 1 : 0)
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors.
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
// The code will blink an LED on GPIO8. To change the pin, modify Led(gpioPin: GPIO_NUM_8)
13+
14+
var ledValue: Bool = false
15+
var led: Led?
16+
17+
@_cdecl("_Z5setupv")
18+
func setup() {
19+
print("Hello from Swift on ESP32-C6!")
20+
led = Led(gpioPin: GPIO_NUM_8)
21+
}
22+
23+
@_cdecl("_Z4loopv")
24+
func loop() {
25+
led?.setLed(value: ledValue)
26+
ledValue.toggle() // Toggle the boolean value
27+
delay(UInt(CONFIG_LED_BLINK_INTERVAL_MS))
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#
2+
# Main component makefile.
3+
#
4+
# This Makefile can be left empty. By default, it will take the sources in the
5+
# src/ directory, compile them and link them into lib(subdirectory_name).a
6+
# in the build directory. This behaviour is entirely configurable,
7+
# please read the ESP-IDF documents if you need to do this.
8+
#
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
## IDF Component Manager Manifest File
2+
dependencies:
3+
# # Put list of dependencies here
4+
# # For components maintained by Espressif:
5+
# component: "~1.0.0"
6+
# # For 3rd party components:
7+
# username/component: ">=1.0.0,<2.0.0"
8+
# username2/component2:
9+
# version: "~1.0.0"
10+
# # For transient dependencies `public` flag can be set.
11+
# # `public` flag doesn't have an effect dependencies of the `main` component.
12+
# # All dependencies of `main` are public by default.
13+
# public: true
14+
15+
## Required IDF version
16+
idf: ">=5.3,<5.5"
17+
arduino: # Can't be defined as the espressif/arduino-esp32 shorthand since the library name must be 'arduino' for libraries that depend on it
18+
git: https://github.com/espressif/arduino-esp32.git
19+
version: 3.2.0
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
CONFIG_FREERTOS_HZ=1000
2+
CONFIG_MBEDTLS_PSK_MODES=y
3+
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
4+
CONFIG_AUTOSTART_ARDUINO=y
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Wokwi Configuration File
2+
# Reference: https://docs.wokwi.com/vscode/project-config
3+
[wokwi]
4+
version = 1
5+
firmware = 'build/flasher_args.json'
6+
elf = 'build/main.elf'
7+
# gdbServerPort=3333
8+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# The following lines of boilerplate have to be in your project's
2+
# CMakeLists in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
project(app-template)

0 commit comments

Comments
 (0)