Embedded Swift Example Projects for ARM and RISC-V Microcontrollers

That was a great link! I've added to my "good links to recommend" cache.

A learning embedded for Swift Developers and a learning Swift for embedded developers wiki/repo/shared annotated bibliography would be awesome. I am working on my own greatest hits page, but then, by definition, that only has resources that I know about.

For example anyone have a "Biggest gotchas in switching to Clang/CMake for people who know GCC/Make" talk they like? I'm using them because of Swift actually, but I have a lot to learn.

For those who like books the second edtion of the below is hot of the press

The author is one of the hosts of https://embedded.fm which interviews a lot of people in the biz. I haven't read it but they do have a 2016 series based on the ti MSP430 that on initial review looks pretty comprehensive and well beyond the teach a 6th grader to blink an LED level without requiring calculous - Embedded Software Engineering 101 — Embedded

In case anyone is interested, I transformed the stm32-blink example to compile on Linux. It works with the nightly-jammy Docker image, and the only additional required package is binutils-arm-none-eabi.

I'm still getting familiar with this stuff, so it may not be perfect, but my LED is blinking!

6 Likes

Excellent! I love how the changes are really minimal, and looking at them, most are pretty self-explanatory (e.g. you needed to add a linker script to produce a correctly laid out ELF file instead of a Mach-O file). I think we should be able to eliminate the need for these stubs:

void posix_memalign(void) {
    while (1) {}
}

void __stack_chk_fail(void) {
    while (1) {}
}

void __stack_chk_guard(void) {
    while (1) {}
}

void free(void *ptr) {
    while (1) {}
}

(1) If you disable stack protectors (-disable-stack-protector swiftc flag), I'd expect __stack_chk_fail and __stack_chk_guard to not be needed anymore. See https://github.com/apple/swift/blob/main/docs/EmbeddedSwift/UserManual.md#external-dependencies. But of course, stack protectors are generally useful.
(2) I think that asking the compiler to place functions into separate sections (-Xfrontend -function-sections, the equivalent of Clang's/GCC's -ffunction-sections) should enable dead-code stripping, and then the posix_memalign and free dependencies will go away because you don't use any allocations in the example. I am actually trying to pursue enabling this behavior by default on ELF, see https://github.com/apple/swift/pull/70788.

6 Likes

Thanks! I was indeed wondering how we could get rid of these stubs. As it turns out, using -function-sections is enough to get rid of all of them in this case. I pushed an update for that.

One strange thing I found is that I had to 'clean' the build (removing blink.o is enough). Otherwise, for some reason it doesn't have any effect when enabling (or disabling) -function-sections, even though everything is recompiled.

I pushed similar changes for the stm32-lcd-logo example, so that one can be compiled on Linux as well now.

1 Like

Experimenting with stm32-uart-echo with Swift 6 toolchain

No luck:

% export TOOLCHAINS='Swift Development Snapshot'
admin@mbam1 stm32-uart-echo % make
fatal: not a git repository (or any of the parent directories): .git
compiling...
/Library/Developer/Toolchains/swift-DEVELOPMENT-SNAPSHOT-2024-04-22-a.xctoolchain/usr/bin/swift-build
--configuration release
--verbose
--triple armv7em-apple-none-macho
-Xcc -D__APPLE__ -Xcc -D__MACH__
-Xswiftc -Xfrontend -Xswiftc -disable-stack-protector
Planning build
Building for production...

... here starting for long long time when compiling SwiftSyntax stuff...
... then stop here:

....
-o /Users/admin/Documents/atwork/swift-embedded-examples-main/stm32-uart-echo/.build/armv7em-apple-none-macho/release/Application.build/USART1.swift.o
make: *** [build] Error 1

Any idea?
Must we use a specific toolchain to experiment with Swift embedded?

1 Like

Can you post the entire log? I think the error message is cut off.

Actually, I was able to reproduce the failure, and I think I've been able to fix it with: Fix calling convention on putchar (silgen_name -> cdecl) by kubamracek · Pull Request #10 · apple/swift-embedded-examples · GitHub

Can you try it now?

Success with your patch and latest toolchain.
Thanks !

Do you happen to know if Clang support for Xtensa is in progress? Any active issues/PRs that I can follow along with?

See discussion in this thread: Is there support for Xtensa LX7 cores?

I'm trying to get some basic network functionality working, and running into trouble. I've built the wifi modules in pico-examples for pico_w to verify my dev setup, but when pulling over some of that code into Swift, I'm having trouble.

I suspect the issue is with the CMakeLists.txtfile, although I'm not sure.

I've modified the necessary target link libraryentry to properly set CYW43_LWIP, but now I'm getting other errors:

In file included from /Users/willwalker/Developer/pico-swift/pico-sdk/lib/lwip/src/core/mem.c:59:
/Users/willwalker/Developer/pico-swift/pico-sdk/lib/lwip/src/include/lwip/sys.h:95:10: fatal error: arch/sys_arch.h: No such file or directory
   95 | #include "arch/sys_arch.h"
      |          ^~~~~~~~~~~~~~~~~
compilation terminated.
[84/180] Building C object CMakeFiles/swift-pico.dir/pico-sdk/lib/tinyusb/src/common/tusb_fifo.c.obj
ninja: build stopped: subcommand failed.

Here is my full project: GitHub - willswire/pico-swift at implement-networking

Your lwipopts.h file is empty, if you want to actually use lwip, you have to use that file to "configure it". See e.g. this example config from the official Pico Examples repo: pico-examples/pico_w/wifi/lwipopts_examples_common.h at master · raspberrypi/pico-examples · GitHub

1 Like

Oh duh!! That was it. Thanks so much!! :smiley:

For posterity's sake, I just brought over all of those definitions and interpolated them into my lwipopts.h file and it's working great now.

1 Like

I just tried using a #define in Swift by creating a function in the bridging header that returns me that value. (It's a pointer to a c struct)
But if I try to use it I get following error:

lib/gcc/arm-none-eabi/13.3.1/../../../../arm-none-eabi/bin/ld: _swiftcode.o: in function `$ss17swift_allocObject8metadata12requiredSize0E13AlignmentMaskSpys04HeapC0VGSpys13ClassMetadataVG_S2itF':
_swiftcode.o:(.text.$ss17swift_allocObject8metadata12requiredSize0E13AlignmentMaskSpys04HeapC0VGSpys13ClassMetadataVG_S2itF+0x4e): undefined reference to `posix_memalign'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

For me it seems like swift tries to use posix_memalign form the c-stdlib available on desktop but not in the ARM embedded toolchain. Does this make sense or is it an issue on my side?

Depending on the libc you're using, posix_memalign might not be available. You might need to provide it yourself -- if you have aligned_alloc available instead then it's pretty simple: swift-embedded-examples/nrfx-blink-sdk/Stubs.c at fc1942bc094947bb2c73fe194d3fc1d207cb418d · apple/swift-embedded-examples · GitHub

1 Like

Thanks, by providing my own posix_memalign implementation I was able to solve it.
I also had an issue with the unicode stuff but found the library mentioned in the swift github. The only problem I have with this approach is that it seems to be a runtime requirement. So I had to manually include the whole lib because the linker would otherwise just exclude it.

target_link_options(SwiftDMA PRIVATE
    -Wl,--whole-archive ${SWIFT_EMBEDDED_UNICODE_LIB} -Wl,--no-whole-archive
)

So i was wondering if there is recommended approach from the Swift community or is this the only option I have?

That's surprising to me. Are you saying that just adding the library via -L/-l doesn't work? Can you post the resulting linker error and the linker command?