Embedded Swift

If one was really excited and wanted to reproduce the example the minute it was possible is this the board? https://www.st.com/en/evaluation-tools/32f746gdiscovery.html

Yup that's the one! In fact if you really really wanted to, you could build a custom stdlib for arm7em with the hermetic seal at link support @kubamracek mentions above, massage it into a swift sdk bundle and use swift package manager to recreate/build that demo.

swift build \
--configuration release \
-Xswiftc -target -Xswiftc armv7em-apple-none-macho \
-Xswiftc -experimental-hermetic-seal-at-link \
-Xswiftc -Xfrontend -Xswiftc -experimental-platform-c-calling-convention=arm_aapcs_vfp \
--experimental-swift-sdk stm32f746 \
--experimental-lto-mode full \
--static-swift-stdlib

Note: this would be the 500kb version of the demo firmware mentioned above.

10 Likes

I wanted to draw some attention to the significant efforts already made over at Swift for Arduino: https://www.swiftforarduino.com

They've already got some great progress in compiling small code. I believe the implementation is more the subset of the language idea mentioned earlier, but I've used it a little myself and was thoroughly impressed.

It would be great to have their efforts mainstreamed, for sure!

16 Likes

RP2040 is my favorite maker chip too. It is really fast, just need to keep the binary sizes and memory use small. I have a few of them sitting on my desk.

6 Likes

To clarify - this should work with which branch(s) of Swift? I'm getting error: Unknown option '--experimental-lto-mode' when I tried to build an empty package (just to see). Do I need a enableExperimentalFeature setting somewhere?

FWIW I also tried a little mini project and swiftc main.swift -o hello_swift_blink -lto=llvm-full -experimental-hermetic-seal-at-link works fine, but the target, xfrontend, and -static-stdlib all seem dependent on getting the sdk linked first (as would be expected).

swift-driver version: 1.87.1 Apple Swift version 5.9 (swiftlang-5.9.0.128.2 clang-1500.0.40.1)
Target: x86_64-apple-macosx14.0

This is all going to be really nice with the C++ interop...

1 Like

Oops! I added the flag in this pr: BuildDescription: Set output path for bc files by rauhul · Pull Request #6611 · apple/swift-package-manager · GitHub but it has not been cherry picked into 5.9 so you will need to use a nightly toolchain until the spm change makes it into a release.

5 Likes

This is amazing! Thank you

We already have ATTiny working with Swift for Arduino. https://www.swiftforarduino.com. You can do it today. :slight_smile:

4 Likes

this is huge! my dreams from 2016 are coming true

2 Likes

You can't fathom the immense joy this brings me.

I have been dreaming about this for quite some time. Next to my iOS and Linux work, I'm doing my development on the ESP (Tensilica + RISCV) family with C(++) ­– being able to use Swift (and possibly share libraries) there would be heaven.

But not only that, I would imagine that this work would also lead to performance improvements on the desktop systems, so I'm all for it!

8 Likes

This is great. One question, in terms of environments the doc states:

Environments where runtime dependencies, implicit runtime calls, and heap allocations are restricted

Could that include real time environments, such as audio processing components consumed within a wider (non-embedded) Swift project?

Could the non-allocating variant be supplemented with a non-locking enforcement, too?

3 Likes

For at least some of these environments, the @noLocks annotation is probably more appropriate (with an asterisk about its current incarnation being overzealous), as in many of these use cases you only need such restrictions on critical sections, rather than the whole binary.

It's worth considering, however.

7 Likes

Wow, I'm thrilled to see this post! What a coincidence. We're gearing up to release our project, which we call "SwiftIO Playground" in the coming weeks.

SwiftIO Playground on CrowdSupply

Let me indulge in a bit of self-promotion first. :slightly_smiling_face:

The demos in this video are written in pure Swift. We've used the SwiftIO package to abstract away microcontroller details and created numerous external drivers and examples based on SwiftIO. While the binary sizes for these example projects range from 2.5MB to 3.5MB, it's not a significant concern for us since we use 16MB Flash (ROM) for storage. This setup allows us to leverage nearly all features of the Swift language.

In past projects, we have employed pure Swift packages like swift-numerics, swift-extras-json, and swift-png. Special thanks to @taylorswift did a lot for optimizing low-level performance. Our experience shows that PNG decoding speed using pure Swift is about 150% as using lodepng, a commonly used PNG library for microcontrollers.

In this demo, we've integrated FreeType2 as a Swift package to enable the use of TrueType fonts. As an embedded developer, I am excited to see this kind of library capability on a microcontroller.

On Topic

The term "embedded" can indeed be confusing; it can refer to either bare-metal microcontroller development or Linux/Android-based hardware development. There's indeed a significant demand for the former, especially for simple sensor-actuator logic controllers where minimizing RAM and ROM usage is critical. It seems that this evolution targets mainly bare-metal microcontroller development.

Besides, modern RTOS providers like Zephyr aim to simplify app development by abstracting low-level details. Our Swift implementation interfaces with Zephyr to exploit high-performance microcontroller features. We plan to introduce concurrency support once the POSIX interface of Zephyr stabilizes.

Implementation Details

Given the complexity of Zephyr (and most RTOS projects), packaging it as a standard Swift package isn't feasible. Here's our approach:

  1. Compile Zephyr source code into ELF object files using GCC.
  2. Use a modified Swift compiler to compile the standard library and runtime into ELF object files.
  3. Use the same compiler to compile the Swift application code into ELF object files.
  4. Link all these parts together using 'ld' to generate an ELF executable.
  5. Convert the ELF executable into a binary file using 'objcopy'.

Open Questions

We pre-compile files from steps 1 and 2 and include them in our SDK. Steps 3-5 occur when developers build their own projects. In this setup, the RTOS serves as a standard C-based static library. I'm curious if there's a way to optimize steps 2 and 3 (something akin to Link-Time Optimization but not at the linking stage) to make the binary size more manageable (perhaps 1MB to 2MB).

26 Likes

To expand on this a bit: I agree that the performance annotations will be more useful in these cases, but I'd like to point out that our implementation of embedded Swift is implemented mostly using the same infrastructure that powers the performance annotations. So the embedded Swift effort will almost certainly benefit and stabilize these annotations indirectly.

The biggest part of this whole effort is likely the library support so that this compiler mode is actually useful. Providing a standard library that works in more constrained environments (and even supports no allocations or locks in some cases) will be very useful (and even necessary) when adding performance annotations to various functions.

9 Likes

Sadly there are non-technical reasons that make working with that project a non-starter for me. If you want to discuss, great! I don't think this thread is the place. I'm sure everyone involved is very well intentioned. :slight_smile:

1 Like

I would like to say that noLocks/noAllocations doesn't necessarily bring us to a great real time environment/programming model. Specifically these two constraints can allow a programmer to reason about how fast code will roughly run, but do not allow a programmer to ensure a function meets a particular cycle count requirement or time deadline for the specific hardware they are targeting.

Very excited for this! I’ve been doing embedded development for 30 years and am amazed at the high-level languages becoming available now on microcontrollers. I can’t wait for Swift’s modern language features to be officially available for MCUs.

7 Likes

I’m excited for this prospective vision for Embedded Swift.

I have been working on a commercial product using @carlos42421's tool chain that relies on swift working on very small microcontrollers. Cost is important and limiting to only the largest microcontrollers, or on the more extreme end ROTS systems, completely eliminates huge categories of products and systems that can benefit from Swift.

I’m a little disappointed that there has been so much radio silence since the Call for interest by Ted Kremenek. I hope that with this vision document we can start a small workgroup or collaboration where we can bring in all of the great work that has been done by so many such as @andyliu and @carlos42421 among countless others to make sure that Swift can be used on the smallest of systems up to the largest servers and powerful handheld devices.

As a point of perspective, I personally helped someone get a simple blink program for an ATtiny that compiled to 372 bytes, or about 24 times smaller than the best achieved by this proposal. It is possible, I can’t say how excited I am to have people internal to Apple working on this but fear that without the community involvement promised over a year ago and touted on Swift.org we could cut off a large portion of the use case.

10 Likes

I'm not sure it will ever make sense for the programming language to try to directly enforce that a function stays within an exact time/cycle budget. That would require a lot of invasive special-case language mechanics and library annotations. It makes a lot more sense for languages to provide stable and predictable performance, at the very least within specially-identified critical sections, and then let programmers working within these budgets take advantage of that stability to carefully optimize their code.

8 Likes

Some hardware interfaces require some pretty precision timing diagrams. Do you see that being handled by a C or C++ library instead? That would be a disappointment.

3 Likes