<M9names[m]>
> Or sacrificing a pico to become a debug probe
<M9names[m]>
i would choose this option if you already have a spare pico. quick, convenient, cheap.
<M9names[m]>
everything the rp2040 template projects expects debugging via probe-rs, you don't have to change anything to keep working as you have with the microbit
<JaminMartin[m]>
Awesome! thanks for this! that is good news. I definitely do have a spare one - I will start soldering some headers! Do I still leave the boot2 sections in the memory.x file? or when using SWD can you just specify the memory part just like the microbit, as I presume this bypasses the boot loader? or is that still critical?
<M9names[m]>
you keep boot2 - the program you flash via SWD runs exactly the same whether you're debugging it or not.
<M9names[m]>
as above: the memory.x in the templates is already set up for you. you don't need to change it
<JaminMartin[m]>
Ah I see! Thank you, im looking foward to using the pi-picos with probe-rs! glad it can be done with little changes. Ill definitely make the most of these templates!
psukys has left #rust-embedded [Leaving]
emerent has quit [Ping timeout: 252 seconds]
emerent has joined #rust-embedded
enaut[m] has quit [Quit: Idle timeout reached: 172800s]
sroemer has quit [Ping timeout: 265 seconds]
flippette[m] has quit [Quit: Idle timeout reached: 172800s]
cinemaSundays has joined #rust-embedded
rainingmessages has joined #rust-embedded
barafael[m] has quit [Quit: Idle timeout reached: 172800s]
cinemaSundays has quit [Quit: Connection closed for inactivity]
korken89[m] has joined #rust-embedded
<korken89[m]>
Does anyone here have experience with creating both sync and async implementations? When writing drivers I'm always torn between async and not, and re-implementing the same functionality two times does not really feel valuable. I tried once to make a script which copies the async implementation and remove all `async`/`.await` which worked quite OK for simple stuff but still not ideal.
<korken89[m]>
The feature based approach of `maybe-async` of course breaks if 2 dependencies expect enabled/disabled features which is not ideal and adds weird dependencies between crates.
<korken89[m]>
* good minimum extra work/minimum yank
<korken89[m]>
The script based copy-paste approach is my current go-to, but are there more interesting ways people have attacked this?
<korken89[m]>
It seems from blogs I've read that copy-paste and maybe-async seems to be the major goto solutions for now.
ivmarkov[m] has joined #rust-embedded
<ivmarkov[m]>
You could try the `maybe-async` crate, however keep in mind that the `is-sync` and `is-async` features of that crate are very controversial and should be avoided.
<ivmarkov[m]>
I've been successful in avoiding those by using the `duplicate` crate trick, as described [here](https://github.com/rust-embedded-community/embedded-sdmmc-rs/pull/154#issuecomment-2440095378). However, the three drivers I have implemented so far with this approach are each 840, 1200 and 1200 lines of code. not sure how much that method would scale (if at all) for codebases of 10K LOCs.
<ivmarkov[m]>
* You could try the `maybe-async` crate, however keep in mind that the `is-sync` and `is-async` features of that crate are very controversial and should be avoided.
<ivmarkov[m]>
I've been successful in avoiding those by using the `duplicate` crate trick, as described [here](https://github.com/rust-embedded-community/embedded-sdmmc-rs/pull/154#issuecomment-2440095378). However, the three drivers I have implemented so far with this approach are each 840, 1200 and 1200 lines of code. Not sure how much that method would scale (if at all) for codebases of 10K+ LOCs.
<Socke>
vollbrecht[m]: whats the difference between esp_idf::svc::{sys::esp_restart(), hal::reset::restart()}?
<Socke>
s/esp_idf::svc/esp_idf_svc/
<ivmarkov[m]>
(Answering for Vollbreht) Nothing except that the sys one is unsafe, I think?
<Socke>
k
marmrt[m] has quit [Quit: Idle timeout reached: 172800s]
wwwwwwww[m] has joined #rust-embedded
<wwwwwwww[m]>
<Socke> "vollbrecht: whats the difference..." <- pretty cool
silverhorn[m] has quit [Quit: Idle timeout reached: 172800s]
<ivmarkov[m]>
One restriction of this crate is that it can only duplicate inline modules, declared with the mod {} syntax. That's why I'm saying, not sure how that would scale for a larger code-base. Might be possible, haven't tried myself though.
<korken89[m]>
Yeah I see what you mean, it's maybe no ideal but seems OK
<korken89[m]>
s/no/not/
<korken89[m]>
Right, it needs to inspect the internal of the mod, so it gets the same limitations as RTIC's app macro
czarop[m] has quit [Quit: Bridge terminating on SIGTERM]
vollbrecht[m] has quit [Quit: Bridge terminating on SIGTERM]
joelsa[m] has quit [Quit: Bridge terminating on SIGTERM]
korken89[m] has quit [Quit: Bridge terminating on SIGTERM]
JaminMartin[m] has quit [Quit: Bridge terminating on SIGTERM]
ivmarkov[m] has quit [Quit: Bridge terminating on SIGTERM]
thejpster[m] has quit [Quit: Bridge terminating on SIGTERM]
whitequark[cis] has quit [Quit: Bridge terminating on SIGTERM]
explodingwaffle1 has quit [Quit: Bridge terminating on SIGTERM]
GrantM11235[m] has quit [Quit: Bridge terminating on SIGTERM]
_catircservices has quit [Quit: Bridge terminating on SIGTERM]
dirbaio[m] has quit [Quit: Bridge terminating on SIGTERM]
RockBoynton[m] has quit [Quit: Bridge terminating on SIGTERM]
VincenzoMarturan has quit [Quit: Bridge terminating on SIGTERM]
JamesMunns[m] has quit [Quit: Bridge terminating on SIGTERM]
ryan-summers[m] has quit [Quit: Bridge terminating on SIGTERM]
Lumpio[m] has quit [Quit: Bridge terminating on SIGTERM]
snorkman[m] has quit [Quit: Bridge terminating on SIGTERM]
M9names[m] has quit [Quit: Bridge terminating on SIGTERM]
diondokter[m] has quit [Quit: Bridge terminating on SIGTERM]
wwwwwwww[m] has quit [Quit: Bridge terminating on SIGTERM]
n_vl[m] has quit [Quit: Bridge terminating on SIGTERM]
_catircservices has joined #rust-embedded
Lumpio[m] has joined #rust-embedded
<Lumpio[m]>
For my own one-off projects I end up hardcoding stuff like wifi credentials (or semi-hardcoding e.g. read from a config file at flashing time). I wonder if there's some kind of ready-made "IoT device settings framework" I could use to make things actually configurable without having to write a whole lot of code 🤔
<Lumpio[m]>
And by a whole lot of code I mean writing an entire web server or mobile app or whatever just to input two strings into a device that doesn't have a keyboard
<Lumpio[m]>
I keep thinking about making some kind of protocol that can run simple methods over webusb/webbluetooth/even a one off mobile app or something similar that I could then use for that, but it'd probably end up being used in one of my own projects and that's it
ivmarkov[m] has joined #rust-embedded
<ivmarkov[m]>
Lumpio[m]: Wouldn't it'd been nice if Google and Apple did embrace the DPP (Wifi Easy Connect) protocol and just put two such apps in their phones? :(
<ivmarkov[m]>
... instead of me - as we speak - re-inventing a Captive Portal for my own firmware... Probably invented for the 100th time...
JamesMunns[m] has joined #rust-embedded
<JamesMunns[m]>
Do the devices y'all are using have real USB?
<Lumpio[m]>
Some do some don't
<JamesMunns[m]>
yeah, figured :/
<Lumpio[m]>
Got some great idea for real USB?
<JamesMunns[m]>
I mean I'm working on making "plug and play usb devices" a thing with postcard-rpc and my upcoming poststation tool
<JamesMunns[m]>
so it could be more reasonable to have many devices that support a common "set wifi credentials" endpoint that you could write a single win/mac/linux tool to support
<Lumpio[m]>
What's a poststation heh
<JamesMunns[m]>
Unreleased "pro tools" for postcard-rpc :)
<JamesMunns[m]>
But yeah, the plan is to have something between OpenAPI and bluetooth characteristics:
<JamesMunns[m]>
You have "endpoints" you can enumerate, and if the key of the endpoint is one you know about, you know you can talk to the device that way.
<JamesMunns[m]>
so you can detect it's a USB device that has postcard-rpc services, ask what services it has, and if it has a common "enroll wifi credentials" service, you can talk to it on that endpoint
<Lumpio[m]>
ah
<JamesMunns[m]>
even if it does 10 other things you don't know about
<Lumpio[m]>
I've been playing with the idea of some kind of transport agnostic text based menu protocol that could even be used via a serial terminal if that's all you had, but also go over USB/BLE/whatever
<JamesMunns[m]>
Lumpio[m]: postcard-rpc has somewhat similar goals, but it's binary comms instead of a text UI. So you would need some kind of desktop app, but it wouldn't have to be rewritten or customized for every device. Poststation also has/will have some tools for manually "poking" endpoints with a GUI and/or console, but that's more aimed at devs
<shilga[m]>
JamesMunns[m]: That is what I also thought about. But that means that I have to reinitialize the sd card, as I can't share the sd card
<JamesMunns[m]>
JamesMunns[m]: it probably depends on what drivers and libraries you are using, but usually you will need to "tear down" the things you create in the first stage, then figure out how to pass things on.
<JamesMunns[m]>
Or, use some kind of mutex or static storage that is safe to use across cores
<shilga[m]>
The thing is, it was working all fine with the two cores, as long I was using ExclusiveDevice. But as I want to now use a second spi device in the first phase, it fails now because of the RefCellDevice. I could use RefCellDevice in the first phase, and ExclusiveDevice in the second. But that would mean I have to reinitialize the sd card again. And it probably needs a lot of code space as the whole sd card library is used
<shilga[m]>
with two different spi device implementantions
<JamesMunns[m]>
JamesMunns[m]: You'd need to use a critical section mutex across cores
<shilga[m]>
JamesMunns[m]: From what I have seen in the documentation I don't think any of the mutexes can be used cross-core. But it is not so bad for me, as I actually don't use the SPI at the same time on the two cores.
<JamesMunns[m]>
shilga[m]: I'm pretty sure you can, as long as you use the right critical section impl (e.g. the one from the embassy-rp crate), since it synchronizes across cores
<JamesMunns[m]>
JamesMunns[m]: on the rp2 chips, it uses a hardware semaphore to be safe to use across cores. The critical section is only held while locking and unlocking the mutex (not the whole time you have the mutex locked)
<shilga[m]>
<JamesMunns[m]> "hmm, embassy-embedded-hal has an..." <- thx for that. I somehow was not able to find that on my own. I will see if I can work with that.
<shilga[m]>
JamesMunns[m]: that sounds like it does not have much have much (in my case unnecessary) overhead to do the core synchronisation.
<shilga[m]>
s/much/that/, s/have//
<JamesMunns[m]>
shilga[m]: Yeah, it's a bit of a bummer you have to pay for it, but if you need to keep "the same device" (e.g. not re-initialize it), the way you share it needs to be consistent
<JamesMunns[m]>
JamesMunns[m]: It might be possible to add an unsafe "skip initialization and use this config" API to your sdcard library maybe? That way you could move the peripheral by ownership, and not pay multicore cost for it. But I don't know how reasonable that is.
<shilga[m]>
In the second phase I would not mind the overhead as it's not time critical. In the first phase the overhead could be noticeable, as accessing the sd card gets slower. And at that point the second core is actually not even started. Kinda bad, but I will test. Thanks for your input. That was really helpful.
<JamesMunns[m]>
JamesMunns[m]: But I'd definitely try the CriticalSectionRawMutex option - in my experience it's unlikely to be noticable overhead unless you can't handle any (even very short) critical sections that might delay your interrupts a couple dozen cycles.
<JamesMunns[m]>
but yeah, locking/unlocking the mutex really should only be a couple dozen cycles in total, at most.
<JamesMunns[m]>
by the way, back on the topic of "maybe async":
<JamesMunns[m]>
For people who WANT non-async drivers, how are you writing your code? I feel like doing anything non-trivial with blocking code requires SOME kind of concurrency, like RTIC, or an RTOS, or hand writing your own interrupts + state machines, etc. Are there really people who are writing things like that? And if so, how are you making that portable at all? Or am I underestimating how effective a single blocking "executive loop" is?
<JamesMunns[m]>
like, for desktop where you have real threads, I think I understand it more. But for single threaded embedded, I'm confused how you would reliably get things done without some kind of pre-emption (RTOS threads, RTIC interrupt tasks), or cooperative scheduling (async)
<thejpster[m]>
* Neotron OS and its various BIOSes do nothing of the sort. Nor do most Arduino programs. Nor do things running under MS-DOS.
<thejpster[m]>
If you want a thing to happen, you do it, and wait until it is finished. You don't generally worry about other things happening whilst you are waiting - you will get around to them once you are done waiting. If you aren't chasing battery life, and the things you do don't usually take that long, this can be quite reasonable.
<thejpster[m]>
The smart tag I wrote (where I was chasing battery life), would wake up, check a list of things in a fixed order, and then go back to sleep. The state machines were written by hand, and weren't that difficult to put together.
<shilga[m]>
On the same topic, I really like the video of The Rusty Bits about async. He starts with doing everything with StateMachines and ends it with embassy async while doing all the steps in between by hand. https://www.youtube.com/watch?v=wni5h5vIPhU
<ivmarkov[m]>
Yes but using (manual) state machines is one thing, using blocking read/write/IO on a machine which does not have threads is another, James is right here. I also struggle to understand how embedded-hal can even be considered without a traditional pre-emptive scheduler running underneath.
<JamesMunns[m]>
I mean I'm sympathetic to very simple programs, like "read sensor, set servo position" loops, for sure
<JamesMunns[m]>
I just feel like it breaks down very quickly, productivity wise, if you do have to write it all by hand.
<ivmarkov[m]>
Well, I think it breaks down either (a) due to latency issues as some of the stuff is blocking in the absence of scheduling or (b) it breaks down due to complexity even if your stuff is non-blocking, due to the complexity of writing them manual state machines
<ivmarkov[m]>
JamesMunns[m]: But you know my favourite example? The Matter C++ SDK. It is single-threaded non-blocking all the way, yet they wrote it with manual state machines. A bit Arduinop style. An effort worth admiring! :)
<JamesMunns[m]>
I just wanted to calibrate that I'm not entirely out of touch of what most people are doing when it comes to writing firmware in Rust.
<ivmarkov[m]>
s/Arduinop/Arduino/
<JamesMunns[m]>
Like - maybe I'm just self-selecting because I do projects that usually ARE doing multiple things at a time - waiting for comms, reading multiple sensors, etc.
<JamesMunns[m]>
I mean "need" is relative
JamesSizeland[m] has joined #rust-embedded
<JamesSizeland[m]>
Anything with networking stacks, like Bluetooth, needs async right?
<JamesMunns[m]>
like ivmarkov said, with enough effort, anything is possible
<JamesMunns[m]>
I personally wouldn't attempt to do it without async, but that's not saying it's impossible
<JamesMunns[m]>
Though for example, I have no plan to have a non-async version of postcard-rpc
<JamesMunns[m]>
it's just not reasonable imo to write a non-async version of it that is likely to be portable and maintainable
<JamesSizeland[m]>
Target agnostic Async is one of the big strengths of embedded Rust, I feel
dirbaio[m] has joined #rust-embedded
<dirbaio[m]>
It's pretty much impossible to get tcp/ip or Bluetooth working in a *true* blocking fashion.
<dirbaio[m]>
Hand - written state machines is still async, it's just hand-written async.
<JamesMunns[m]>
yeah, it's impossible without concurrency, and async is only one way of doing concurrency, not the only way.
<dirbaio[m]>
The old "nb" crate is also handwritten async
<JamesMunns[m]>
yep, nb, rticv1, hand written interrupt state machines, all concurrency for sure
<ivmarkov[m]>
dirbaio[m]: ... except there was no way for you to know when you could poll again. Terribly inefficient...
<JamesMunns[m]>
It's just challenging because I feel like I can't even reasonably recommend rust without async or some external rtos. Things like sharing timers, communicating between thread mode and interrupts, etc., are just missing "easy to use and reasonable" libraries and tools, IMO.
<ivmarkov[m]>
But why do you need to recommend Rust without either async or a preemptive scheduler? One of these should be there, else - dead end.
<JamesMunns[m]>
like, for experts that know how to do those things, or how to avoid structuring your program in a way that won't run into issues - sure.
<JamesMunns[m]>
ivmarkov[m]: I mean, *I* don't. But there are people that come here wanting to do non-trivial projects, and are also not interested in async
<ivmarkov[m]>
I think the other problem is that even if you use a pre-emptive scheduler, there are jst no drivers that would take advantage of it, isnt't? I mean, the hals (esp-rs included) that implement the blocking embedded-hal are not pre-emptive scheduler friendly, as they do busy-looping, which is exactly the thing you should not do if you have a scheduler...
<ivmarkov[m]>
* I think the other problem is that even if you use a pre-emptive scheduler, there are jst no drivers that would take advantage of it, isnt't? I mean, the hals (esp-rs included) that implement the blocking embedded-hal traits are not pre-emptive scheduler friendly, as they do busy-looping, which is exactly the thing you should not do if you have a scheduler...
<JamesMunns[m]>
I mean that's pre-emption
<JamesMunns[m]>
if you busy loop, you'll get descheduled
<ivmarkov[m]>
eventually
<JamesMunns[m]>
you could do a better job explicitly yielding, but you don't have to
<ivmarkov[m]>
But the point is, you should not busy loop, you should wait on a mutex or other scheduler primitive
<ivmarkov[m]>
otherwise, you are wasting cpu cycles
<ivmarkov[m]>
for example, the esp idf "hal" never busy loops. it waits on mutexes, queues, semaphoes, whatever which are then signaled from the irq handlers
<ivmarkov[m]>
but then the drivers should be aware of these sync primitives and use them. and the embedded-hal baremetal crates don't?
<ivmarkov[m]>
Maybe I'm not doing myself a service calling the scheduler a "scheduler". It is a scheduler but then also a bunch of blocking synchronization primitives. But then, these come together, as the scheduler must be aware of the sync primitves, so as - for example - not to schedule tasks which are blocked on a mutex.
<adamgreig[m]>
it makes it a lot easier to analyse things like WCET and give bounded latencies, and the strictly linear program flow can be easier to reason about too. but the tradeoff of having to write a bunch of manual state machines for each thing being polled is definitely a big pita
<adamgreig[m]>
you could probably do a blocking executive loop that polled a bunch of async tasks... though i'm not sure what the point would be
<JamesMunns[m]>
If you're worried about WCET, are you using off the shelf drivers anyway?
<adamgreig[m]>
no, I expect not
igiona[m] has joined #rust-embedded
<igiona[m]>
In embassy (nrf), Is there a why to "convert" a spim::Spim<'_, peripherals::SERIAL1> into a embedded_hal::spi::SpiDevice ?
<igiona[m]>
As far as I can see, embedded_hal::spi::SpiDevice trait is not implemented in the nrf spim
<igiona[m]>
I could prob. wrap spim into MySpim and then implement the embedded_hal::spi::SpiDevice trait, but maybe there is already something "built-in" ?
<dirbaio[m]>
it impements SpiBus
<dirbaio[m]>
because it has no CS pin
<dirbaio[m]>
you have to wrap it with something that pairs it with the CS pin, which does impl SpiDevice
<igiona[m]>
In fact I'm not going to have to share the bus, so the Exclusive device sounds like what I need!
<igiona[m]>
Cool, thanks!
<dirbaio[m]>
does anyone know why PACs copy device.x to the out dir and add that to rustc-link-search?
<dirbaio[m]>
instead of adding the crate dir to rustc-link-search?
<dirbaio[m]>
so the linker finds device.x automatically, no file copy needed?
<dirbaio[m]>
s/automatically/there/
<JamesMunns[m]>
I feel like it's a thing to do for hals that provide multiple options, and then everyone copy and pasted it, or it was just like that in the defmt app template?
<JamesMunns[m]>
(the real answer is I don't know for sure tho)
<JamesMunns[m]>
Oh wait device-x and not memory-x
<JamesMunns[m]>
Then I definitely don't know
<thejpster[m]>
cortex-m-rt does it because it changes the file
<thejpster[m]>
I guess svd2rust just copied it, but no longer changes the file
<thejpster[m]>
does cargo have an environment variable for "the directory this crate is in"?
<thejpster[m]>
the fact that the line in svd2rust's output imports std::path::PathBuf but only std::env, and has the same comment above it, implies it was a copy-paste job
anton_star has quit [Quit: Client closed]
<dirbaio[m]>
<thejpster[m]> "does cargo have an environment..." <- CARGO_MANIFEST_DIR, yep