Embedded Swift running on the Raspberry Pi Pico

It works! I'm watching a blinking led :green_circle:

Apparantly, after installing the correct toolchain, I had to delete the build folder and recreate the build folder. Before, even after installing the toolchain and setting the correct ID, it still defaulted to the Xcode provided one. Lesson learned. ;)

Thank you for your help. You swiftc example command really helped find the problem. :pray:t2:

6 Likes

@maartene Glad that you got it working!

2 Likes

Congrats. Would like to read a tutorial showing all the steps, if you have the time to write one.

1 Like

Yeah, I’m definitely considering this.

However i do need to get a better grasp on it all. Don’t think I can write reliable tutorial just yet.

Also, I created two milestones to tackle first:

  • Understand which Swift features are available and which ones are not. At least how to work with strings and arrays;
  • Get serial communication working.
1 Like

Arrays (and even classes) are available when you provide an allocator, you'll see which C symbols to define in a linker error as soon as you try adding those into your codebase.

I also found that with latest snapshots even constant array literals don't require an allocator, apparently those get optimized into the .rodata section. It's dynamic arrays (re)allocation (or use of UnsafeBufferPointer.allocate, which is good substitute for arrays when you need to manage allocations manually) when it starts requiring a defined allocator.

You can also get quite far with StaticString, but string interpolation is much trickier. Assuming you have arrays working, one could come up with a #utf8 or even #ascii macros that transform string literals into [UInt8] literals. Similarly, macros for string interpolation would be needed. At that point you'd be working with byte strings, and of course no Unicode handling, unless you're ready to roll with your own Unicode support.

3 Likes

There are some interesting approaches in reduced usage cases:

For example if it is known that the interpolation will just be emitted via printing to a UART line or something like that you can still conform to the protocols for string interpolation. But instead of allocating, you can use the side effect of construction to emit the values on said printing output. This is obviously not a general purpose mechanism but can make some forward progress.

Instead we probably would want to have some sort of method to use the information in the compiler to build up an expected size and then use a stack allocation to pass down into each interpolated element (via some sort of alternative interpolation protocol) and have each element write itself into that buffer.

The more wide-spread issue for String proper is that it ends up requiring some relatively large data tables for normalization.

Here is a non-exhaustive list of things that have dependencies or are removed:

  • Existentials - e.g. any Thing are not allowed because they require type metadata. This also makes as? not as important and should be avoided even in class cases.
  • Embedded swift does not bring any runtime functions to the table - so things like allocating heap objects (Ala class) you end up needing to provide your own posix_memalign. Likewise for ref counting, you need to provide your own atomic primitives
  • String requires both heap allocations AND also needs NFC/NFD tables for Unicode normalization. We avoided bringing in String because even if someone provides the posix_memalign for the heap allocations that strings may use, they still need to have the normalization tables for things as simple as == or hash(into:). This is a known pain point and is something that probably should be investigated and iterated upon designing a method where folks can opt-in to using strings
  • crt0 and other bootstrapping from a entry point is not provided; this is a bring-your own type thing because it is very chip specific on how the setup must be done.
  • hardware interfaces are not something that is brought to the table by the compiler or swift stdlib - however the interfaces can be generated via swift-mmio and that can lead to a way to convert from register definitions to a hardware specific interface
  • hardware abstraction layers are also something that must be brought to the table . Working with a broad range of chips is something that the community will have to build.
  • Swift Concurrency is not something that will work out of the box.

The rest of Swift as a language and as the standard library should work; structures, enumerations, protocols, integer types, static strings all work without a hitch, classes, array, dictionary, set all require heap allocation and therefore need the memory allocation.

4 Likes

So, some progress. I got printing to serial working. So that’s great.

The use case I want to explore is this: you connect the box to serial and then you can interact with it while it runs some sort of (text based) game.

The “string interpolation by side effect” @Philippe_Hausler proposed is actually an interesting approach that might just work here.

@Max_Desiatov I guess for my use case missing strings is probably the biggest issue. I can define rooms using structs and static strings. And put them in an array literal.

It’s interesting working around the limitations here. :blush:

3 Likes