<re_irc_>
<@dirbaio:matrix.org> (embassy-nrf doesn't really use stm32-metapac, it uses the normal nrf pacs, but it ignores the pac singletons. it's a better example because all the stm32 stuff is autogenerated so I can't link to any code, but it works the same way as nrf)
<re_irc_>
<@dirbaio:matrix.org> `peripherals!` defines the singletons and a Peripherals struct containing them all
<cr1901>
yea I'm looking for the macro impl now
<re_irc_>
<@dirbaio:matrix.org> `embassy_nrf::init()` returns the `Peripherals`, it's the equivalent of `pac::Peripherals::take()`
<re_irc_>
<@dirbaio:matrix.org> the singletons are similar to what the PAC would have, with a few differences:
<re_irc_>
<@dirbaio:matrix.org> - GPIO pins already come split
<re_irc_>
<@dirbaio:matrix.org> - SPI0, SPIM0, SPIS0, TWI0, TWIM0, TWIS0 becomes just TWISPI0 so you can only use one at a time
<re_irc_>
<@dirbaio:matrix.org> - GPIOTE channels already come split
<re_irc_>
<@dirbaio:matrix.org> - PPI channels and groups already come split
<cr1901>
Okay, so each peripheral has a steal() method
<cr1901>
(and an unborrow() method, however that works)
<re_irc_>
<@dirbaio:matrix.org> normal usage is to get the peripherals from `embassy_nrf::init()`, you can optionally unsafely steal them
<cr1901>
(Well take is implemented in terms of steal, so I was thinking of that)
<cr1901>
Since PACs write everything in terms of the peripherals struct, not sure it's possible for me to extract singletons out of it per pin. Mulling over how to do my code golf without rewriting swaths of register blocks
hifi has quit [Remote host closed the connection]
hifi_ has joined #rust-embedded
<re_irc_>
<@dirbaio:matrix.org> yeah.. embassy-nrf does it by unsafely stealing the pac singletons
<re_irc_>
<@dirbaio:matrix.org> since it has the hal singletons to enforce ownership of stuff, it's fine
<re_irc_>
<@dirbaio:matrix.org> and embassy-stm32 uses stm32-metapac which simply doesn't have pac singletons :P
<cr1901>
>since it has the hal singletons to enforce ownership of stuff, it's fine
<cr1901>
So, AFAIU right now, this only works (safely) because you return all the hal singletons at once, in a single function (in other words, thread)
<re_irc_>
<@dirbaio:matrix.org> yep
<re_irc_>
<@dirbaio:matrix.org> the idea of the singletons is exactly the same, except they're defined in the HAL instead of the PAC
<cr1901>
Well, you might get away with a bit more granularity, but the idea is if you could safely get one singleton in one thread, another singleton in another, and they share registers
<cr1901>
congrats, you got a data race
<re_irc_>
<@dirbaio:matrix.org> yeah
<re_irc_>
<@dirbaio:matrix.org> nrf's gpio is very well designed, pins never "share" registers
<cr1901>
I don't get that luxury
<re_irc_>
<@dirbaio:matrix.org> you can use P0_01 from thread A and P0_02 from thread B without races
<re_irc_>
<@dirbaio:matrix.org> stm32's gpio is not that well designed, and there's similar issues with RCC
<cr1901>
Single thread data race is possible (iterator invalidation), but does that apply to a singleton data structure?
<cr1901>
I can't visualize it if yes
<re_irc_>
<@dirbaio:matrix.org> currently embassy-stm32 ensures atomicity with critical sections, there's plans to move to bitbanding or atomics wherever possible
<re_irc_>
<@dirbaio:matrix.org> hm not sure what you mean, the singletons are zero-sized, they don't contain actual data
<cr1901>
I... don't really understand how it works. I was told "single thread data races in Rust are possible"
<cr1901>
i.e. "the same memory location can be used mutably by two different locations in your code in a single thread"
<cr1901>
in the case of these singletons, that would be writing to the same register in two different locations
<re_irc_>
<@dirbaio:matrix.org> yep, so you have to ensure these writes are protected with critical sections or atomics or whatever
<re_irc_>
<@thalesfragoso:matrix.org> are singleton Sync ?
<cr1901>
But that protects two different threads :P
<re_irc_>
<@thalesfragoso:matrix.org> the ones from the pac, I mean
<cr1901>
I'm asking about a data race in a single thread
<cr1901>
(i.e. interrupts off for your entire program, for instance)
<re_irc_>
<@dirbaio:matrix.org> within a single thread you won't be touching P0_02 and P0_03 at the same time
<re_irc_>
<@dirbaio:matrix.org> you'll be first configuring one, then the next
<re_irc_>
<@thalesfragoso:matrix.org> cr1901: how do you get those ?
<re_irc_>
<@dirbaio:matrix.org> unless you do weird stuff in the hal
<re_irc_>
<@thalesfragoso:matrix.org> calling that race is stretchering
<cr1901>
Do you have a more concrete example?
<re_irc_>
<@adamgreig:matrix.org> `let x = moder.read(); moder.set_pin5_output(); x |= 5; moder.write(x);`
<cr1901>
well you can do that from safe code... so that's technically UB?
<re_irc_>
<@adamgreig:matrix.org> it's not UB because rust doesn't prevent all race conditions
<re_irc_>
<@dirbaio:matrix.org> it's not UB, it's just wrong
<re_irc_>
<@adamgreig:matrix.org> only data races which it's not
<cr1901>
Oh, I thought that is a single-thread data race
<re_irc_>
<@adamgreig:matrix.org> calling it a race condition is definitely a stretch too really
<cr1901>
like the ones mentioned in the blog posts
<re_irc_>
<@adamgreig:matrix.org> I'm not sure you can ever have a single-thread data race
<re_irc_>
<@dirbaio:matrix.org> its behavior is perfectly defined, it's just the wrong behavior :D
<re_irc_>
<@adamgreig:matrix.org> the blog post does not describe data races
<re_irc_>
<@adamgreig:matrix.org> just other forms of memory unsafety that would be caused by multiple aliasing mutable references
<re_irc_>
<@adamgreig:matrix.org> for a "data race" you need concurrency, e.g. not single thread
<re_irc_>
<@adamgreig:matrix.org> (and rust prevents data races, so they cannot occur in safe code and are ub in unsafe code)
<cr1901>
Well in the context of GPIO pins, at least in STM32 HAL land, they are accessed via pointer deref, not a reference
<re_irc_>
<@adamgreig:matrix.org> i don't _think_ that's a material difference
<cr1901>
so I guess the mutable reference problem doesn't apply
<cr1901>
oh
<re_irc_>
<@adamgreig:matrix.org> also they are accessed by reference in stm32 hal land iirc
<re_irc_>
<@adamgreig:matrix.org> (because they are accessed by calling methods that receive `&self` on a RegisterBlock)
<cr1901>
yes, but they use interior mutability
<cr1901>
(... oh, which would allow that aliasing)
<re_irc_>
<@adamgreig:matrix.org> yes
<re_irc_>
<@adamgreig:matrix.org> but note Cell allows mutability at the cost of not being Sync and so you can't use it from multiple threads and therefore it doesn't let you data race
<re_irc_>
<@adamgreig:matrix.org> UnsafeCell (inside registers in mmio embedded stuff) requires you to use `unsafe` and promise you have exclusive access, to the same effect
<re_irc_>
<@adamgreig:matrix.org> so it basically works out
<cr1901>
exclusive access being distinct (but related) to "shared mutation"
<re_irc_>
<@adamgreig:matrix.org> I guess I'd say the &mut system is one way of ensuring exclusive access
<re_irc_>
<@adamgreig:matrix.org> where 'exclusive' here means "won't be contested/raced by any other thread"
<cr1901>
You mean static mut?
<cr1901>
(I thought that was really screwy and upstream isn't even sure it works or SHOULD work)
<re_irc_>
<@adamgreig:matrix.org> I think the concern with static mut is that it's extremely difficult to actually use safely
<re_irc_>
<@adamgreig:matrix.org> but I don't think it makes a difference to this discussion about single-threaded racing
<cr1901>
Basically I'm not sure how these two msgs are related:
<cr1901>
(8:53:32 PM) re_irc_: <@adamgreig:matrix.org> where 'exclusive' here means "won't be contested/raced by any other thread"
<cr1901>
(8:53:18 PM) re_irc_: <@adamgreig:matrix.org> I guess I'd say the &mut system is one way of ensuring exclusive access
<cr1901>
If you taking something by &mut, chances are it's only visible to a single function (and thus thread)
<cr1901>
And MMIO opted to use Cells
<re_irc_>
<@adamgreig:matrix.org> ah, I meant "if you know you currently have exclusive access to some memory, then you know you cannot have a data race", and "if you have &mut to memory, that counts as having exclusive access"
<cr1901>
Ahhh
<re_irc_>
<@adamgreig:matrix.org> but there are other ways that count, like "being inside a critical section [on a single-core mcu]", and "having a Cell, since it's not Sync so can't be accessed by any other threads anyway", and "being the only thread in the whole system, regardless of the data, because there are no other threads"
<cr1901>
Hmmm, sounds good
<cr1901>
This was a good convo, even tho I wrote basically zero code today. Go figure...
<re_irc_>
<@adamgreig:matrix.org> rust provides a ton of powerful guarantees here that other languages do not
<re_irc_>
<@adamgreig:matrix.org> which is why it can promise 'no data races in safe rust'
<re_irc_>
<@adamgreig:matrix.org> unfortunately this leaves us trying to fit interrupts and critical sections etc into rust's execution model :P
<cr1901>
(right, but anything useful ultimately requires unsafe somewhere, unless you want to want to do a math calculation and store it in RAM forever.)
<cr1901>
adamgreig: I don't think the impedance mismatch of interrupts and critical sections vs OS threads is that dire.
starblue2 has joined #rust-embedded
<cr1901>
(i.e. I wouldn't use "unfortunately")
<re_irc_>
<@adamgreig:matrix.org> yea, theoretically it seems fine, I guess I just mean rust doesn't already do it internally
<cr1901>
Well, no surprises there. The general gist I got of Rust's attitude towards embedded- besides those doing embedded- is "since it's no GC, the ppl who aren't writing for Linux, Mac, or Windoze, will figure it out")
<re_irc_>
<@adamgreig:matrix.org> cr1901: idk, you could be operating on a Rust Machine that literally doesn't need any unsafe anywhere else and just provides a safe I/O api
<cr1901>
how's the I/O being done safely? :)
<re_irc_>
<@adamgreig:matrix.org> who cares, the Rust Machine datasheet says it's fine :p
<re_irc_>
<@yatekii:matrix.org> adamgreig: i'd pay for this to happen :D
starblue1 has quit [Ping timeout: 265 seconds]
<re_irc_>
<@adamgreig:matrix.org> or the bits of unsafe code you need to rely on from stdlib could be formally proven to provide the same guarantees
<re_irc_>
<@adamgreig:matrix.org> of course a library you depend on could just do something wildly unsound in an unsafe block and ruin everything, lol
<re_irc_>
<@yatekii:matrix.org> couldn't you make an architecture where certain memory access is just atomic and volatile (for peripherals) and then you gucci?
<re_irc_>
<@yatekii:matrix.org> (not sure about the perf implications etc (guess there must be some otherwise all MCUs would do this??))
<re_irc_>
<@nihal.pasham:matrix.org> quick question - is anyone using an apple m1 based machine for embedded-rust development? If yes, I'd like to know what works and what doesnt?
<re_irc_>
<@nihal.pasham:matrix.org> more specifically - was wondering if `probe-rs` drivers for the usual probes (such as j-link, cmsis-dap, stlink) work well or if there is something that we need to be aware of
<re_irc_>
<@tiwalun:matrix.org> I haven't noticed any issues with probe-rs and M1 based machines so far.
<re_irc_>
<@therealprof:matrix.org> dirbaio: It's a different tradeoff, not necessarily better or worse.
<re_irc_>
<@jamesmunns:matrix.org> As a firmware developer, it's certainly a lot less complicated to work with.
<re_irc_>
<@jamesmunns:matrix.org> There's a reason we use nrf52s in all our training material, even without wireless stuff.
<astroanax>
Is a precompiled version of the rust toolchain for the esp32 available somewhere?
<re_irc_>
<@jamesmunns:matrix.org> If I had to explain global clock trees and pin muxes, I'd have to spend a ton more time
<re_irc_>
<@jamesmunns:matrix.org> But "here, in the gpio you turn it on, set mode, and good to go" is so nice
<re_irc_>
<@jamesmunns:matrix.org> astroanax: not afaik, atm you need to build it from source.
<re_irc_>
<@therealprof:matrix.org> jamesmunns: Yes, I agree.
<cr1901>
I thought of something while trying to sleep yesterday... if you imported two semver-incompatible versions of a crate, but they still have the same Peripherals singletons, haven't you just "safely" gotten access to the same memory locations from two threads w/o synchronization?
<cr1901>
That works (as long as CORE_PERIPHERALS/DEVICE_PERIPHERALS isn't changed between semver-incompat versions).
tokomak has joined #rust-embedded
<re_irc_>
<@jordens:matrix.org> Due to `no_mangle` it will cause a linker name collision in any case where there are two of them.
<cr1901>
Oooh, the comment "used here to prevent linking different minor versions" also implies "used here to prevent linking different major versions"
<cr1901>
meaning if a backwards-incompat changed removed that static, nothing good will happen
<re_irc_>
<@adamgreig:matrix.org> All the recent releases also use the cargo.toml links key which stops cargo even trying to link multiple versions together, except for our special semver hack versions which re-export peripherals from later releases to allow cross version compatibility
<cr1901>
adamgreig: I suppose I should ask my real question
<cr1901>
If I have a Peripherals struct from a PAC, with peripheral-level granularity for GPIO (not pin level), is the only recourse I have to safely get pin-level granularity to consume the peripheral and use GPIO::ptr() accesses from with the pin-level struct?
<cr1901>
This is what STM32 does. I'd much rather code my own struct using the register block directly, but AFAICT, the minute I try to create a separate static that aliases registers from another struct, I can create data races
<cr1901>
(and the Peripherals abstract gets around the data race problem by forcing you to take all peripherals at once in a single thread)
<re_irc_>
<@adamgreig:matrix.org> Have you seen the split() methods in lots of HALs?
<re_irc_>
<@adamgreig:matrix.org> Basically yes, by convention ownership of the GPIO struct instance implies exclusive access to the registers, so your new struct should somehow consume the PAC struct (eg in new) to prevent two existing at once
<re_irc_>
<@adamgreig:matrix.org> But after consuming it you could use the unsafe ptr methods to access fields so long as you do something else for synchronisation (like bitbanding or only using atomic registers (bit set etc) or critical sections)
<cr1901>
Or using it from a single thread only :)
<re_irc_>
<@adamgreig:matrix.org> Indeed (with no interrupts ever allowed to access it, and the structs made not sync)
<re_irc_>
<@adamgreig:matrix.org> I guess also not send in this case
<cr1901>
>and the structs made not sync
<cr1901>
That's the default IIRC
<cr1901>
and not send, I'm not sure... the peripherals themselves implement Send. Althought notably, Parts doesn't
<cr1901>
adamgreig: Also, I forgot this, but... Deref for peripherals is implemented in terms the PTR. It's just that if you consume the peripheral, you have no way of returning a pin-level abstraction using Deref (because lifetimes for the pin regs will exceed the GPIO peripheral lifetime)
<cr1901>
So you have to use the pointer/unsafe
fabic has joined #rust-embedded
<re_irc_>
<@wcpannell:matrix.org> Can I solicit a little advice for my HAL API? Basically, on my MCU the gpiox::into_analog equivalent functionality is controlled by the ADC peripheral. That peripheral must have its clock gated to it (handled by Adc<Disabled>::enable) before touching it, otherwise any read/write of the peripheral's registers...
<re_irc_>
... triggers a HardFault.
<re_irc_>
<@wcpannell:matrix.org> I'm looking at either leaving into_analog in the gpiox modules and checking if the Adc is enabled at runtime (effectively try_into_analog), or providing something like channel_to_analog in the impl Adc<Enabled> section. The former is a little gross. The latter feels pretty different from what all the other...
<re_irc_>
... HALs do.
<cr1901>
What does the "PhantomData<*const ()>" in peripherals actually do? One thing I can think of is to prevent derivation of Send/Sync. But what else is it for?
<re_irc_>
<@firefrommoonlight:matrix.org> I'd go with hardware consistency, and let the ADC configure the pin as Analog in its constructor or other setup fn.
<re_irc_>
<@firefrommoonlight:matrix.org> I feel like letting the Gpio module do it would be surprising to people used to the MCU
<re_irc_>
<@wcpannell:matrix.org> Thanks, that makes a lot of sense
<re_irc_>
<@yruama_lairba:matrix.org> hi, i'd like to know correpondance between a rust toolchain and a MPU/MCU
<re_irc_>
<@yruama_lairba:matrix.org> specifically, i'd like to know wich toolchain i should use if i want to use a pi zero in a "bare metal" way
<re_irc_>
<@firefrommoonlight:matrix.org> Dude - I love probe-rs. Thank you for making the Rust embedded ecosystem as nice as it is. Probe-rs and Cargo-flash are outstanding critical infrastructure that make it such a nice experience
<re_irc_>
<@firefrommoonlight:matrix.org> Also, thank you to the Knurling team for building probe-run on top of it
<cr1901>
So by default, the STM32 HALs return GPIO parts (from split()) in Input<Floating> mode. How does the HAL guarantee that any time split() is called, the pins will, in fact, be in that mode?
<re_irc_>
<@dirbaio:matrix.org> Theyre in that mode from cold boot
<re_irc_>
<@thalesfragoso:matrix.org> cr1901: Now that made me remember of one question, does reset in RCC really reset all registers to the reset values ?
<re_irc_>
<@thalesfragoso:matrix.org> cr1901: probably just for that
tokomak has quit [Read error: Connection reset by peer]
<re_irc_>
<@yatekii:matrix.org> firefrommoonlight: thanks! we try hard :)
<re_irc_>
<@jamesmunns:matrix.org> Also reminder, if you are looking for a rust-embedded job, POST ABOUT IT ON TWITTER AND TAG THE `@rustembedded` account so I can retweet it!
<re_irc_>
<@jamesmunns:matrix.org> (or: if your company is *looking* to hire rust-embedded devs, make a job posting that mentions Rust, and tag rustembedded so I can retweet it!)
<re_irc_>
<@jamesmunns:matrix.org> I don't have a good solution for folks that can't make that info public (but I am open to ideas!), or for folks that don't have twitter, but if I can help, I'm always happy to.
<re_irc_>
<@jamesmunns:matrix.org> DMs always open (on twitter or here on Matrix), if you'd like to chat.
<re_irc_>
<@jamesmunns:matrix.org> Also, leaking information on twitter, as I am want to do:
<re_irc_>
<@dirbaio:matrix.org> Thanks for the heads up, posted :)
<re_irc_>
<@dirbaio:matrix.org> gonna post it here too, in case someone is interested!
<re_irc_>
<@dirbaio:matrix.org> At Akiles (https://akiles.app/en) we're just now opening our first Rust firmware dev position. Remote, ideally EU timezone. We're a tiny team (3 engineers, all remote), you'd be the first firmware-only developer. DM me for details!
<cr1901>
>dirbaio Theyre in that mode from cold boot
<cr1901>
What prevents a user from changing the mode _before_ creating a HAL instance from split()? (Also, you can't get the original register block back once you split?)
<re_irc_>
<@dirbaio:matrix.org> hmmm
<re_irc_>
<@dirbaio:matrix.org> ....nothing?
<re_irc_>
<@dirbaio:matrix.org> 🤣
<re_irc_>
<@dirbaio:matrix.org> yeah you can totally use the raw regblock to change the mode, then do .split() and you get the pins in the wrong mode
<cr1901>
Well, that's "safe" I guess, but feels rather undesirable :P
<cr1901>
(And what if there's a hardware peripheral you could damage by the HAL assuming it's in one mode, but isn't actually in that mode? :P)
<re_irc_>
<@jamesmunns:matrix.org> Hanno Braun feels more strongly on this topic
<re_irc_>
<@jamesmunns:matrix.org> He basically thinks the hal should be responsible for taking periphs for this reason
<re_irc_>
<@dirbaio:matrix.org> hehe, what embassy does
<re_irc_>
<@dirbaio:matrix.org> who'd have thought
<cr1901>
but you can certainly still write code that opts-in to the problem described :P
<re_irc_>
<@braincode:matrix.org> jamesmunns: Last commits from espressif/esp32-rust-example repo they were dockerizing it for easier DX, IIRC
<re_irc_>
<@braincode:matrix.org> nihal.pasham: Works for me on stlink v2 cheap Aliexpress probe
<re_irc_>
<@braincode:matrix.org> dirbaio: Cool product! Did you send a sample to the lockpicking lawyer? One of my recent favourite channels :P
<re_irc_>
<@dirbaio:matrix.org> hahaha
<re_irc_>
<@dirbaio:matrix.org> it has no keyholes to pick, it's electronic only
<re_irc_>
<@dirbaio:matrix.org> not sure if he picks suck things too
<re_irc_>
<@braincode:matrix.org> He does too, low sec rfid access IIRC and thumbprint and Bluetooth ones too
<re_irc_>
<@dirbaio:matrix.org> ooh
<re_irc_>
<@hanno:braun-odw.eu> dirbaio: Good to know I'm not the only one feeling the need to re-invent that particular wheel 😁
<re_irc_>
<@hanno:braun-odw.eu> I really need to take a close look at embassy. I never took the time, but I keep hearing bits and pieces I totally agree with. Interrupts being something that an be owned, for example. Been saying that for years 😄
nohit has quit []
nohit has joined #rust-embedded
<re_irc_>
<@yruama_lairba:matrix.org> hello, i there a trick to know parameters of a generic type ?
<re_irc_>
<@yruama_lairba:matrix.org> i mean i'm starting to use RTIC and i want to share a resource where the type is a big generic
<re_irc_>
<@dirbaio:matrix.org> assign it to a u32 variable or something
<re_irc_>
<@dirbaio:matrix.org> then try to compile
<re_irc_>
<@dirbaio:matrix.org> rust will print the full type in the compile error
<re_irc_>
<@yruama_lairba:matrix.org> ;( it's too ugly, it's take almost three lines
<re_irc_>
<@dirbaio:matrix.org> 🤷♂️
<re_irc_>
<@dirbaio:matrix.org> HAL writers love their generics
<re_irc_>
<@dirbaio:matrix.org> you can make it less ugly if you paste it in a type alias
<re_irc_>
<@dirbaio:matrix.org> but the type is what it is....
<re_irc_>
<@dirbaio:matrix.org> you can't magically shorten it
<re_irc_>
<@yruama_lairba:matrix.org> type alias ? i don't rememenber the syntax,