crabbedhaloablut has quit [Ping timeout: 276 seconds]
crabbedhaloablut has joined #rust-embedded
SomeWeirdAnon has quit []
tokomak has joined #rust-embedded
fabic has joined #rust-embedded
PyroPeter has quit [Ping timeout: 264 seconds]
PyroPeter has joined #rust-embedded
flatwhatson has quit [Read error: Connection reset by peer]
flatwhatson has joined #rust-embedded
emerent has joined #rust-embedded
cr1901 has quit [Quit: Leaving.]
npm_bored is now known as edm
<re_irc> <> Hi, I am working on a HAL for ambiq apollo chips. I was wondering if there is any way to write tests that try to compile (but not run) for the correct target?
<re_irc> <> Simply make a binary and compile it should do the trick
<re_irc> <> cargo test --no-run
<re_irc> <> Hmm, brain misfiring today, I don't think that will work.
<re_irc> <> I think I can use compiletest_rs
<re_irc> <> maybe. or just make them examples and use cargo build/check.
<re_irc> <> Yes- maybe that is easier, need to specify target anyway. In which case my std-dependent tests won't work. so need to run cargo test twice anyway
<re_irc> <> 9names: that works, have to specify target when compiling but otherwise ok
<re_irc> <> you shouldn't need to specify a target when compiling examples if you put the target in your .cargo/config file:
<re_irc> <> target =thumbv6m-none-eabi # insert your target here
<re_irc> <> [build]
<re_irc> <> 9names: Yeah, but that breaks std tests
<re_irc> <> (unit tests in the lib)
<re_irc> <> true. have to choose to either specify target for tests, or target for examples.
<re_irc> <> It seems like const-generics, especially for enums, can replace some of the typelevel meta programming for e.g. defining a pin and its state. Are there any examples on that.. or maybe reasons for why not?
<re_irc> <> We're doing that in stm32f4xx-hal now:
<re_irc> <> wow! great, just what I am looking for.
tokomak has quit [Ping timeout: 245 seconds]
<re_irc> <> are you using the port name 'A'/'B' to resolve which submodule to use?
<re_irc> <> Well, which GPIO port to use. Those chips have multiple ports of up to 32 pins per port. The port determines the base address of the registers to use.
<re_irc> <> ok
<re_irc> <> the ambiq-apollo3 has something similar, split across 4 pads (i think..)
<re_irc> <> The catchall at line 879 is not ideal but not easy (or even impossible, not sure) to workaround without const panics.
<re_irc> <> Ideally one should not be able to instantiate non-existing pins.
<re_irc> <> ok. so it works because the registerblock of each GPIO has the same layout + base address?
<re_irc> <> Yes.
<re_irc> <> Well, not the same base address, they're offset. 😉
<re_irc> <> right; the base address changes :)
emerent has quit [Remote host closed the connection]
emerent has joined #rust-embedded
<re_irc> <> might be avoidable by combining typenum with a port enum. then typenum ranges can be used to only allow valid port nums
<re_irc> <> (pin nums)
<Lumpio-> typenum instead of const generics?
<re_irc> <> Indeed, but then life might become harder elsewhere (at least for stm32f4). Certainly something to explore.
<re_irc> <> you'd still need const generics for Mode and others
fabic has quit [Ping timeout: 245 seconds]
<re_irc> <> "Currently Rust on embedded only works well with ARM Cortex-M-based MCUs."
<re_irc> <> As read on a TWIR article
<re_irc> <> Question re that GPIO code. The [reg block access code]( returns `*const crate::pac::gpioa::RegisterBlock`. This is really nice. How is it done, since [not all the ports deref to GPIOA]( in PAC?
<re_irc> <> And how does that differ from `D: Deref<Target = GPIOA::RegisterBlock>,`. Is it a const generic thing? Note that the latter syntax won't work here due to the ports dereffing to different things (A, B, I in this example)
<re_irc> <> all the match arms cast the returned ptr to a *const gpioa::RegisterBlock
<re_irc> <> the `ptr()` methods in each arm return a *const gpioaX::RegisterBlock, and you can freely cast pointers
<re_irc> <> Is that considered "safe"? I haven't looked if the different things they deref to are actually the same minus the name
<re_irc> <> it's safe to cast pointers because it's unsafe to deref them
<re_irc> <> in this case it's assumed that using a gpioa::RegisterBlock _type_ with the right address will work for all GPIO ports
<re_irc> <> which is presumably true on the F4? they differ in reset values but that doesn't matter for this
<re_irc> <> I mean, the PAC GPIOA, C, and I blocks are the same enough so you can do this?
<re_irc> <> Thank you. This is much nicer than the match/macros I've been doing to get aroudn this
<re_irc> <> in some stm32s they differ more, because only some ports have lock bits for example, so it wouldn't be ok on e.g. f3
<re_irc> <> but this sort of assumption is what underlies the embassy stuff too
<re_irc> <> it's mostly right most of the time, if you don't need some specialist features
<re_irc> <> I've been doing it for other modules btw
<re_irc> <> Where they all deref to the same
<re_irc> <> But not in cases like this where they don't. I'll probably make the change
dreamcat4 has joined #rust-embedded
<re_irc> <> for example on the F37x, GPIOx_LCKR only exists for x=A, B, D, while the other registers are for A..F
<re_irc> <> so if you used gpioa::RegisterBlock there, you'd incorrectly allow users to write to LCKR on GPIOC, which doesn't exist... probably not the end of the world, and arguably worth it for the type cleanliness
<re_irc> <> Oh no. Is this a *third* STM32 HAL?
<re_irc> <> what do you mean? even in stm32-rs there's something like ten stm32 HALs
<re_irc> <> that article you linked is firefrommoonlight's btw thejpster
<re_irc> <> Oh!
<re_irc> <> it was posted here yesterday iirc?
<re_irc> <> maybe day before..
<re_irc> <> My bad. I'm late to the party as usual.
<re_irc> <> That HAL is uses is
<re_irc> <> yea, it's firefrommoonlight's HAL
<re_irc> <> riiight
<re_irc> <> Names are confusing
<re_irc> <> I haven't noticed any port-to-port differences in STM32 RMs. Eg the reg tables look like this: `PIO port mode register (GPIOx_MODER) (x =A to K)` And with the f4xx and embassy votes of confidence, I'm going to adopt this technique and deref all ports to GPIOA
<re_irc> <> This has been a thorn in my side for a while actually, and that example and Adam's explanation showed it's possible
<re_irc> <> It's a good article!
<re_irc> <> firefrommoonlight: except for the port-to-port difference I just mentioned :P
<re_irc> <> and I'm sure there's more
<re_irc> <> just a question of whether you care
<re_irc> <> Thanks
<re_irc> <> I'll take a look and see if it seems worth it
<re_irc> <> there's some debate about whether using const generic chars like that is best, because it allows invalid types like GPIO<'Z'> which would silently alias to GPIOA
<re_irc> <> (Right now my GPIO code for STM32 is a disaster of macros and match arms)
<re_irc> <> though I'm sure it would be cleaner than a million macros and match arms, yep
<re_irc> <> Re your lock code. I have this gem in there:
<re_irc> <> ```rust
<re_irc> <> #[cfg(not(feature = "f373"))]
<re_irc> <> // It appears f373 doesn't have lckr on ports C or E. (PAC error?)
<re_irc> <> the RM says LCKR only exists on A, B, D, it's not meant to exist on C, E, or F
<re_irc> <> I don't know why ST did that, but I don't think it's an error in the RM, they're very explicit only A, B, and D can be locked
<re_irc> <> Isn't locking normally to stop you disabling JTAG or NMI or something?
<re_irc> <> Perfect
<re_irc> <> Might be worth looking at the AF table for those ports
<re_irc> <> Tiva-C locks Port F because F1 is NMI I think. Which is annoying as they connect PF1 to a button on the devkit.
<re_irc> <> Good point
<re_irc> <> For nRF, I'm using this (similar FN sig for GPIO ports):
<re_irc> <> ```rust
<re_irc> <> Where the ports all deref to p0.
<re_irc> <> fn regs(&self) -> &pac::p0::RegisterBlock {
<re_irc> <> firefrommoonlight: what are you doing with the input pin here? 0 shifted by any number is still zero. or'ing 0 with any number does not have any effect.
<re_irc> <> ptr::write_volatile(
<re_irc> <> GPIOA_MODER as *mut u32,
<re_irc> <> moder_val | 0b01 << (output_pin_num * 2) | 0b00 << (input_pin_num * 2)
<re_irc> <> );
<re_irc> <> You're right. Error
<re_irc> <> Good catch
<re_irc> <> I think there are also parenthesis issues in that section
<re_irc> <> yea, << binds weakly, so you're doing (moder_val | 1) << (output_pin_num * 2) etc
<re_irc> <> stick brackets around each term being OR'd
cr1901 has joined #rust-embedded
<re_irc> <> Fixed article. Thank you
fabic has joined #rust-embedded
fabic_ has joined #rust-embedded
mrkajetanp_ has joined #rust-embedded
xnor_ has joined #rust-embedded
fabic has quit [*.net *.split]
cr1901 has quit [*.net *.split]
dreamcat4 has quit [*.net *.split]
GenTooMan has quit [*.net *.split]
ni has quit [*.net *.split]
mrkajetanp has quit [*.net *.split]
xnor has quit [*.net *.split]
sauce has quit [*.net *.split]
Shell has quit [*.net *.split]
Shell has joined #rust-embedded
GenTooMan has joined #rust-embedded
sauce has joined #rust-embedded
ni has joined #rust-embedded
dreamcat4 has joined #rust-embedded
cr1901 has joined #rust-embedded
troth has quit [Ping timeout: 265 seconds]
troth has joined #rust-embedded
Foxyloxy_ has joined #rust-embedded
richarde1 has joined #rust-embedded
richardeoin has quit [Ping timeout: 265 seconds]
Foxyloxy has quit [Ping timeout: 265 seconds]
xnor_ has quit [Changing host]
xnor_ has joined #rust-embedded
xnor_ is now known as xnor
fabic_ has quit [Ping timeout: 252 seconds]
GenTooMan has quit [Quit: Leaving]
GenTooMan has joined #rust-embedded
richarde1 is now known as richardeoin
wose has quit [Ping timeout: 252 seconds]
crabbedhaloablut has quit [Write error: Connection reset by peer]
crabbedhaloablut has joined #rust-embedded
wose has joined #rust-embedded
<re_irc> <> It seems like a lot of hal implementations do not make use of the register fields directly, but rather use pointer offsets + bit manipulation (once it has taken ownership of that memory). Presumably this is so that you can generalize pin operations over port sets. But it would be nice to use the information and safety in the PAC, are there any examples on that?
<re_irc> <> it's because STM32 chips have very slight differences between different gpio ports/pins
<re_irc> <> such as a particular pin having a different reset value because it has some special function such as SWD/JTAG
<re_irc> <> to not "lose" that information, the stm32 pacs don't "unify" all GPIO ports into the same struct, and don't "arrayify" all pins into an array of the registers
<re_irc> <> the downside is then you can't write code that deals with any pin, because each gpio port/pin is a different ty
<re_irc> <> so HALs workaround that by doing direct pointer/bit manipulation
<re_irc> <> you can totally do it if you do the PAC differently
<re_irc> <> so it can do the GPIO HAL without macros or raw pointer/bit manipulation
<re_irc> <> gauteh: For BSRR (atomic register writes), the reg is set up in a way where high is a write to one half of the register, and low is the other
<re_irc> <> So that's one reason
<re_irc> <> For the others, I assume it's as you said, to bind a number to write
<re_irc> <> the nRF regs and PACs are set up in a way so you don't have to. It's quite nice. I use STM32 code that makes use of the fields, but it does this using a macro loop, which also kind of sucks
<re_irc> <> you can have the PAC do that for you too, using "field arrays":
<re_irc> <> ```rust
<re_irc> <> So, let's look at what you can do using the nRF PAC:
<re_irc> <> self.regs()
<re_irc> <> pub fn set_high(&mut self) {
<re_irc> <> Where pin is the pin number. Isn't that clean?
<re_irc> <> While on STM32, some of the fields are 2 bits wide etc so you can't always do that
<re_irc> <> I guess you could for some fields
<re_irc> <> I can post the macro if you'd like since it technically answers your question of an example using the PAC fields, but I'm not proud of it
<re_irc> <> Please do, I haven't figure out how to solve this yet.
<re_irc> <> That sounds very elegant. how do you modify the PAC? manually? or by configuring svd2rust?
<re_irc> <> ```rust
<re_irc> <> // These macros are used to interate over pin number, for use with PAC fields.
<re_irc> <> macro_rules! set_field {
<re_irc> <> ($regs: expr, $pin:expr, $reg:ident, $field:ident, $bit:ident, $val:expr, [$($num:expr),+]) => {
<re_irc> <> Told you
<re_irc> <> embassy uses a [different PAC](, taking register/chip data from [here](
<re_irc> <> I'd actually prefer the bit shifting, except the fields all have slight differences. Ie AF has 2 regs, each field having 4 bits. Mode and PUPDR has 2 bits per field. BSRR uses atomic writes with the mentioned offset. For things like LCKR and OTYPER that have 1 bit field, I actually like the bit arith approach more
<re_irc> <> the reason for writing a new PAC was to unify all these inconsistencies (within a chip, and across chip families) to make writing a single HAL for all chips viable
<re_irc> <> dirbaio: are the field arrays included in the `stm32-rs` PACs, or something only in embassy?
<re_irc> <> Obviously that's a better approach
<re_irc> <> Re inconsistencies btween chips: The alt-fn code and configuring EXTI/SYSCFG for GPIO interrupts is a pain. The other GPIO functions are identical, other than what ports are avail
<re_irc> <> svd2rust [0.18]( added support for field arrays
<re_irc> <> Nice. Presuambly not avail on released PACs though, other than yorus?
<re_irc> <> I think the issue in the stm32 ones is that the SVDs don't have the field arrays defined
<re_irc> <> firefrommoonlight: in the nRF hal, do you pass around the pins/ports/gpio struct or do you get to the fields through pointers? I would have to pass the GPIO struct (from Peripherals) to all methods like Pin<...>::into_output(&self, gpio: GPIO). Wheras, with pointers that becomes a bit simpler.
<re_irc> <> svdtools does now support field arrays when patching svd, but yea it's not yet implemented across the pacs
<re_irc> <> Folks is anyone a test guru? I have a method decorated with `#[cfg(test)]` and I try to use it in a file `tests/`. Sadly it then wont compile because it cannot find the method. If I make the method unconditional it compiles and runs the test fine. I am very confused. Does anyone have a hint here?
<re_irc> <> ah it is compiled like an external crate in /tests :(
<re_irc> <> gauteh: I get to the fields through pointers (For GPIO)
<re_irc> <> For most peripherals on STM and nRF, the periph structs own PAC reg blocks
emerent has quit [Ping timeout: 252 seconds]
emerent has joined #rust-embedded