-
Notifications
You must be signed in to change notification settings - Fork 62
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
base: main
Are you sure you want to change the base?
Conversation
Provide new examples demonstrating how to run Swift Embedded on the Raspberry Pi 4B and 5 single-board computers, in a baremetal fashion, without an underlying operating system. The provided examples showcase how to blink the onboard green LED using Swift MMIO.
As seen at FOSDEM 2025 Note: ignore formatting for now
Updates to match latest swift-format configuration in swift-mmio.
* Make stm32-blink sample building as both Mach-O and ELF * Use STM_BOARD env var to select which board to target on stm32-blink example * Fix python lint issues in Tools/elf2hex.py
Updates the stm32-uart-echo and stm32-neopixel examples to use a swiftpm toolset.json to specify various compiler and linker flags. Also updates the Makefiles to leverage swiftpm to link the executable instead of manually linking using `ld` directly.
Instead of having users manually manage python venvs this commit migrates the python scripts to use `uv` which can handle installing script dependencies automatically. Additionally it doesn't require sourcing a venv setup script in every shell where you want to build. A further improvement on the swift swift side should also be made to use swiftly to manage swift toolchain versions instead of the `TOOLCHAINS` env variable.
Switches from manually running various compilers and linkers to using SwiftPM for most of the leg work. Additionally switches from -Osize to -O which has notably better runtime performance.
Blink works but I’ve been unable to get WiFi to work. I’m using a seeed studio C6, so perhaps there are some differences. |
Hmm, what errors are you getting? Is it compiling but just not outputting anything? |
The diff looks good, thanks! Could I ask for a new GH workflow to be added so that the code is built in CI? (Just building is good enough, no need to try to run it.) |
I've just written the actions now but there's a dependency issue:
Some options:
|
Not sure what you think is best, but I've done (1) which compiles successfully (example run) |
I didn't realize you were using the hardware serial 😆 I sorta fixed that with this: public typealias ArduinoString = String
extension ArduinoString: CustomStringConvertible {
public var description: Swift.String {
return Swift.String(cString: self.c_str())
}
}
extension ArduinoString: Equatable {
public static func == (lhs: ArduinoString, rhs: ArduinoString) -> Bool {
lhs.equals(rhs)
}
public static func == <RHS: StringProtocol>(lhs: ArduinoString, rhs: RHS) -> Bool {
lhs.equals(String(Swift.String(rhs)))
}
public static func == <LHS: StringProtocol>(lhs: LHS, rhs: ArduinoString) -> Bool {
rhs.equals(String(Swift.String(lhs)))
}
}
extension ArduinoString: Comparable {
public static func < (lhs: ArduinoString, rhs: ArduinoString) -> Bool {
lhs.compareTo(rhs) < 0
}
public static func < <RHS: StringProtocol>(lhs: ArduinoString, rhs: RHS) -> Bool {
lhs.compareTo(String(Swift.String(rhs))) < 0
}
public static func < <LHS: StringProtocol>(lhs: LHS, rhs: ArduinoString) -> Bool {
lhs < rhs.description
}
}
extension ArduinoString: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(description)
}
}
extension ArduinoString: ExpressibleByStringLiteral {
public init(stringLiteral value: Swift.String) {
let cString = Array(value.utf8CString)
self = ArduinoString(cString)
}
}
// MARK: - Operators (+, +=)
extension ArduinoString {
public static func + (lhs: ArduinoString, rhs: ArduinoString) -> ArduinoString {
var newString = lhs
_ = newString.concat(rhs)
return newString
}
/// ArduinoString + SomeString (e.g. String, Substring, etc.)
public static func + <RHS: StringProtocol>(lhs: ArduinoString, rhs: RHS) -> ArduinoString {
ArduinoString(lhs.description + Swift.String(rhs))
}
/// SomeString + ArduinoString
public static func + <LHS: StringProtocol>(lhs: LHS, rhs: ArduinoString) -> ArduinoString {
ArduinoString(Swift.String(lhs) + rhs.description)
}
/// ArduinoString += ArduinoString
public static func += (lhs: inout ArduinoString, rhs: ArduinoString) {
lhs = lhs + rhs
}
/// ArduinoString += SomeString
public static func += <RHS: StringProtocol>(lhs: inout ArduinoString, rhs: RHS) {
lhs = lhs + rhs
}
}
extension Swift.String {
public static func += (lhs: inout Swift.String, rhs: ArduinoString) {
lhs.append(contentsOf: rhs.description)
}
}
extension ArduinoString {
// Access the underlying Swift.String's StringProtocol properties
public var utf8: Swift.String.UTF8View { Swift.String(cString: self.c_str()).utf8 }
public var utf16: Swift.String.UTF16View { Swift.String(cString: self.c_str()).utf16 }
public var unicodeScalars: Swift.String.UnicodeScalarView { Swift.String(cString: self.c_str()).unicodeScalars }
// Common StringProtocol methods
public func hasPrefix(_ prefix: Swift.String) -> Bool {
return Swift.String(cString: self.c_str()).hasPrefix(prefix)
}
public func hasSuffix(_ suffix: Swift.String) -> Bool {
return Swift.String(cString: self.c_str()).hasSuffix(suffix)
}
public func contains(_ other: Swift.Character) -> Bool {
return Swift.String(cString: self.c_str()).contains(other)
}
// Index-based access
public subscript(position: Swift.String.Index) -> Character {
return Swift.String(cString: self.c_str())[position]
}
public subscript(bounds: Range<Swift.String.Index>) -> Swift.Substring {
return Swift.String(cString: self.c_str())[bounds]
}
public var startIndex: Swift.String.Index {
return Swift.String(cString: self.c_str()).startIndex
}
public var endIndex: Swift.String.Index {
return Swift.String(cString: self.c_str()).endIndex
}
public func index(after i: Swift.String.Index) -> Swift.String.Index {
return Swift.String(cString: self.c_str()).index(after: i)
}
public func index(before i: Swift.String.Index) -> Swift.String.Index {
return Swift.String(cString: self.c_str()).index(before: i)
}
} it's not quite StringProtocol conformance, but does allow for the example to use the usb monitor. |
That's very neat - I was using Swift 6.0.3 not 6.1 so didn't realise |
…ve Swift support (apple#99)
68bf7ae
to
5582710
Compare
I had to slightly modify that |
Replaces the register definitions used by the stm32-lcd-logo example to use ones generated by svd2swift leveraging swift-mmio. Additionally refactors much of the example code to have fewer layers of abstraction as they make the code much harder to follow.
Can you elaborate on why we need the ArduinoString extensions at all? I.e. where are those extensions used from? I don't immediately see that in the code. |
Yes they're not used for anything in the example; as @eric-humane suggested it brings Do you think it would be neater to not include them to keep the example more minimal? The only one that's actually needed is the |
That’s a common misconception about CustomStringConvertible actually. String concat won’t work etc. the other issue is it’s sort of “invisible” and hard to understand why it’s occurring. The better thing to do would be to use SWIFT_NAME, probably. But then you’re still having to convert these to swift strings for swift functions and it’s not really clear when or why you have to do that. option: conform to string protocol Either way, it’s a tough problem and really hard to debug. Even writing wrappers you run into this a bit. Edit: I’m also not suggesting adding my code above. But just demonstrating how I fixed the problem. Edit 2: or make arduino lib a proper module (import Arduino), probably best. But I was just going for quick and dirty here. I haven’t spent much time reading all the docs on this stuff here, just happened to have a C6 laying around. |
Interesting - I've only used string formatting in the example which works fine without the other extensions. I can see why
Sorry, should have probably waited for your reply. I'll strip out the extensions then |
it would, it just sucks to have to do that 😆 that said if we keep this really concise i.e. no extra extensions etc, we could land it |
3daba1d
to
1355e7d
Compare
I just realised there was a full arduino-esp32 release 2 weeks ago based on ESP-IDF v5.4 so I've rebased and updated it to use that version |
Adds two esp32 example projects using the espressif/arduino-esp32 library to demonstrate Wi-Fi scanning and a simple LED blink example
Adds two esp32 example projects using the espressif/arduino-esp32 library to demonstrate Wi-Fi scanning and a simple LED blink example
I've also mentioned this in the READMEs: note that these examples require ESP-IDF v5.3.2 since the Arduino releases are paired with specific IDF versions
Resolves #42