starblue has quit [Ping timeout: 260 seconds]
starblue has joined #rust-embedded
fabic_ has joined #rust-embedded
<re_irc> <> Hey folks, is there a good way to get a similar kind of register interface that you get with `svd2rust` or `tock-registers` where you can do bitfield ops etc, but for registers on a remote peripheral (e.g. accessed over I2C)? I tried to work out a way to implement the `tock-registers` interface for it but couldn't get anywhere..
<re_irc> <>
<re_irc> <> ah that looks interesting, thanks :)
troth has quit [Ping timeout: 264 seconds]
troth has joined #rust-embedded
<re_irc> <> Interesting concept
<re_irc> <> I think at the core of this, is that from an API perspective, this is a similar problem to that solved by SVD2Rust
<re_irc> <> But in terms of how our code works, it's a bit different. In that the MCU periphs become memory-mapped, but the device on a bus aren't. And we don't have SVDs to automate it
<re_irc> <> Ideally, coding with a high-level API is very nice. (subjective, but I think so!) You get that on the MCU level with HALs. For things like supporting an I2Cdevice, I think we have no way of getting the nice "SVD2RUST" like interface that's worth the trouble
<re_irc> <> Ie, You can write a high-level API that makes all the reg writes directly faster than you could try to make a PAC interface. And most I2C etc devices are relatively simple, at leaset compared to an MCU
<re_irc> <> So... Nice idea to have this functionality, but it's no easier it is to get it than it is to have a higher-level API. So given a choice, writing the high level API directly wins
<re_irc> <> If device makers published SVDs or something, it might be worth it
<re_irc> <> Exercise: Pick an external (I2C, SPI etc) device you use or would like to. Assume you have a high-level API for the bus, eg on HAL, and the datasheet for the device. Can you think of a faster or better way than typing up a file that does the writes directly based on the DS tables?
<re_irc> <> There's also so much weird shit, like this I2C device I'm using that has 9-bit fields, so I made a wrapper like this:
<re_irc> <> ```rust
<re_irc> <> /// This codec uses a non-standard 7-bit-address, 9-bit data setup, so we use
<re_irc> <> /// a custom function to manage this.
<re_irc> <> Or different types of memory on the device, like normal register that have one access procedures, and `EEPROM` with another
PyroPeter has quit [Ping timeout: 260 seconds]
PyroPeter has joined #rust-embedded
fabic_ has quit [Ping timeout: 260 seconds]
fabic_ has joined #rust-embedded
fabic_ has quit [Ping timeout: 260 seconds]
<re_irc> <> It deserves much more love :P
<re_irc> <> Really need to port it over to a proc macro, especially now that proc macro support in rust analyzer is starting to get somewhere
<re_irc> <> Aaahhh! I really need to work on the device driver crate again...
<re_irc> <> I was about to say, it would be much better written that way :)
<re_irc> <> Then the syntax remains very close to pure rust structs
<re_irc> <> That being said, proc macros with custom attributes on struct fields can be a lot of work to write. Just look at serde
<re_irc> <> Yeah, need to experiment with it. But I really don't have the time. Maybe I could do some work on it at my job if they allow it? Who knows
tokomak has joined #rust-embedded
fabic_ has joined #rust-embedded
tokomak has quit [Ping timeout: 268 seconds]
troth has quit [Ping timeout: 258 seconds]
troth has joined #rust-embedded
troth has quit [Ping timeout: 245 seconds]
Amanieu has joined #rust-embedded
fabic_ has quit [Ping timeout: 258 seconds]
tokomak has joined #rust-embedded
fabic_ has joined #rust-embedded
fabic_ has quit [Ping timeout: 264 seconds]
fabic_ has joined #rust-embedded
<re_irc> <> Hi everyone. I intend to write some drivers in the future and one thing I did not find out yet is how to deal with time, i.e. getting something like the well-known millis() and micros() functions for further calculations. Since I'm familiar with STM32 and have worked with the ST HAL in the past, I typically use the Cortex-M SysTick for this. So I wrote a crate that initializes the SysTick to a certain...
<re_irc> ... frequency and provide the desired functions:
<re_irc> <> But of course, the driver should not work with this crate directly but use an abstraction that gives an instant. So my question is now how to integrate this into something like embedded-hal.
<re_irc> <> embedded-hal has some timer traits
<re_irc> <> but they have some flaws
<re_irc> <> I've seen this already, but I think this is not intended to be used as monotonic time source.
<re_irc> <> so it's likely that they'll be temporarily removed to be redesigned later for embedded-hal 1.0
<re_irc> <> Basically I'm looking for something like an `Instant` type similar to what std offers.
<re_irc> <> yeah it's not for a monotonic timesource
<re_irc> <> a trait for that would be useful indeed
<re_irc> <> There is this `embedded-time` crate, but I don't fully understand it.
<re_irc> <> Also I'm asking myself if such a relatively simple thing needs another dependency.
<re_irc> <> representing instants/durations is a giant can of worms
<re_irc> <> ideally the traits would do it in a hardware-independent *and* zero-cost way
<re_irc> <> but that's still an unsolved problem
<re_irc> <> I could easily do my own thing with an Instant that is simply a u64 representing nanoseconds. But of course I would like to have something that is usable for the community.
tokomak has quit [Ping timeout: 268 seconds]
<re_irc> <> that's probably your best bet for now :'(
<re_irc> <> and feedback and proposals on how to design the traits in embedded-hal is always welcome :)
<re_irc> <> You're right on this, but my impression is, that this topic is kind of stuck and does not advance at the moment. It seems that nobody has an exact idea how it can be addressed.
<re_irc> <> yeah that's exactly why it's stuck 🤣
hifi has quit [Remote host closed the connection]
<re_irc> <> Ok, let's think a little about it...
hifi has joined #rust-embedded
<re_irc> <> Is there already a common agreement that "something" should be inside `embedded-hal` that defines a monotonic time source?
<re_irc> <> Or do the maintainers think it should be addressed separately?
<re_irc> <> not sure about Monotonic
<re_irc> <> but the main roadblock is defining a Duration trait/type (or Instant for Monotonic)
<re_irc> <> that all time-related traits would use
<re_irc> <> not sure if Monotonic has been discussed before, but I assume if the Duration/Instant stuff is resolved it wouldn't be too controversial to add it
<re_irc> <> If you don't have a monotonic time time, what else would be the alternative? Timers are not really one, because the overflow quickly and are not suitable for multi-tasking.
<re_irc> <> Imagine you use an RTOS with several tasks, there must be a way to get an instant for every task. No way to do this with a timer that is just tied to a certain function.
<re_irc> <> So FreeRTOS as example just counts ticks.
<re_irc> <> yeah totally
<re_irc> <> just got released which is an interesting new option for this stuff
<re_irc> <> basically counts ticks, but also has const parameters to indicate the frequency of the ticks, such that you can compile-time convert most things as required
<re_irc> <> (I understand the plan is for this to be used for rtic 0.6's monotonic in place of embedded-time)
<re_irc> <> yup fugit looks very interesting
<re_irc> <> I'm not sure whether e-h should use concrete Duration/Instant *types* or instead have Duration/Instant *trait*
<re_irc> <> But fugit is already an implementation, isn't it?
<re_irc> <> adamgreig: Yes the idea is to have it working with your time library of choice instead of depending on embddded-time
<re_irc> <> via another trait?
<re_irc> <> I wonder if e-h could share the trait or something
<re_irc> <> sourcebox: hm, lots of things can use timers as monotonic sources, even despite overflow since you can generally extend them to longer bit-widths in software (or often you just have to allow the monotonic count to overflow... counting ticks in u32 overflows every 30s or so for me iirc)
<re_irc> <> (depends which ticks you're counting of course but even 1ms will overflow a u32 relatively soon)
<re_irc> <> u32 at 1ms will overflow after about 50 days.
<re_irc> <> I think it's up to the app developer to decide which overflow periods are acceptable. It highly depends on the purpose.
<re_irc> <> It seems that some implementations already exist, what's missing are the traits to make it interoperable.
<re_irc> <> yea. there's a lot of interest and there have been a bunch of discussions recently too
<re_irc> <> including on potential trait designs
<re_irc> <> it's a bit tough because it might be nicer to have a concrete type (saves generic types everywhere), but what size you store and how you deal with frequencies is a bit of a pain
<re_irc> <> I just want to use something like `Instant::new().to_millis()` in my app code.
<re_irc> <> core's Instant is generally considered both too big storage-wise (2xu64) and also too annoying (ns+secs, but often this isn't a helpful unit so you end up doing loads of integer division)
<re_irc> <> The Monotonic trait was changed so you can use any time library as long as it has Instant and Duration types
<re_irc> <> ah, so the new rtic Monotonic trait is the only thing that needs to be implemented, and it no longer requires embedded-time's Clock?
<re_irc> <> Exactly!
<re_irc> <> nice
<re_irc> <> oh? link?
<re_irc> <> maybe we end up with something like that in e-h for Delay and so forth
<re_irc> <> So these traits are independent from rtic? That would be a requirement because rtic is ARM-only.
<re_irc> <> those traits are tied to what rtic requires, they're probably not going to be useful in a general-purpose sense
<re_irc> <> I think korken89 is still working on that PR, don’t know if there’s anything written about it yet!
<re_irc> <> So the embedded-hal lacks two types: Instant and Duration. But it is not clear how to define them. Am I wrong?
<re_irc> <> That's right... but maybe it will never have types, only traits
<re_irc> <> (using traits means users can bring their own types, eg a big 2xu64 type a la core, or some tiny u16 from a timer if that's what they want, but maybe this flexibility ends up being unhelpful or bad)
<re_irc> <> But what's wrong about types representing ms, µs and ns?
<re_irc> <> I've seen this approach on some crates.
<re_irc> <> Which crates? The main problem is you now have three duration types, and you need to do division to turn any of them to/from the ticks that your system actually measures or uses
<re_irc> <> Some crates want to talk about reciprocal time too for configuring clocks and communications interfaces, so if the underlying type is limited to integer ns you limit what frequencies you can talk about... but maybe this use case should be separate?
<re_irc> <> if your timer counts in 32khz ticks, you want Duration to count 32khz ticks to avoid expensive divisions every time
<re_irc> <> But probably clock frequencies are what's eventually used to determine the seconds to ticks conversion so they need to be involved somewhere
<re_irc> <> It could also work without divisions in some cases.
<re_irc> <> True, if your timer is helpfully counting ms or whatever
<re_irc> <> Yes, that's the way I usually do it.
<re_irc> <> But it seems probably better to at least support storing and manipulating ticks at the clock's native rate, and convert the human time units at compile-time
<re_irc> <> depending on the hardware that's not possible
<re_irc> <> So you write in your code and the compiler can turn it into 2678 cycles or whatever
<re_irc> <> Counting is ms should be no requirement but possible to make benefit of if possible.
<re_irc> <> I don't mean to discourage you here, just hopefully you see the various issues people have raised with every approach
<re_irc> <> For a single use case it's usually ok to find something that works really well, like maybe you have a 1MHz timer and a u32 worth of microseconds is always enough for you and you just use that
<re_irc> <> That's a question of the implementation and not the trait.
<re_irc> <> I can use an implementation that fits for me, someone else can use another one.
<re_irc> <> Yep, that's why there's this idea of using a trait for e-h instead of concrete types
<re_irc> <> Isn't this just a misunderstanding here? E.g. a type `Milliseconds` won't hurt, it just has to define a `Millis` trait to be implemented, no matter how this is done.
<re_irc> <> The implementation can then choose what it thinks is best for the use case to implement that.
<re_irc> <> Same with ns, µs, seconds...
<re_irc> <> But of course, default implementations should be provided.
<re_irc> <> But in the end, I always need time units. E.g. when I use an SPI flash chip, the datasheet specifies times in ms for page erase etc.
<re_irc> <> On the other hand, embedded-hal is already very specific - see which defines DelayUs.
<re_irc> <> There you have a trait that defines delay_ms() with a u32.
<re_irc> <> DelayUs is temporary until the final holy grail Duration/Instant is done
<re_irc> <> there's some discussion on the issue I linked
<re_irc> <> tldr is using ms/us u32 everywhere is not nice
<re_irc> <> but not having a Delay trait would be worse, so DelayUs was kept
<re_irc> <> So breaking changes are already planned ;-)
<re_irc> <> No.. plan is to add the delay using Duration as `Delay`, and leave `DelayUs`
<re_irc> <> it's somewhat suboptimal, I'd rather remove it but.. 🤷
<re_irc> <> From a pragmatic point of view, I'd like to have something that can be used in a managable time rather than a perfect solution that will never be found.
<re_irc> <> (well, this is all in the unreleased e-h 1.0, which is breaking from 0.2 that also had DelayMs and generic over ints)
<re_irc> <> I'm just saying this because of the long time the issues are outstanding.
<re_irc> <> the goal of 1.0 is to not have to break it in a long time
<re_irc> <> And we already have DelayMs and DelayUs in the currently released e-h 0.2 which can be used today
<re_irc> <> (which is why I'd remove DelayUs from 1.0 :S )
<re_irc> <> Yes, and e-h will hopefully be one of the most essential parts of the embedded ecosystem, so getting out the 1.0 is an important thing.
<re_irc> <> But the conclusion most recently was that it seems like we won't work out what to do for Delay in 1.0 yet, so keeping a basic DelayUs for now and add it later
<re_irc> <> but pelpe can keep using the 0.2 one :S
<re_irc> <> Hm, I guess...
<re_irc> <> But you cannot really mix 0.2 and 1.0 later, that could be a stopper.
<re_irc> <> you can
<re_irc> <> How to do that if traits and implementations differ?
<re_irc> <> embedded-hal-02 = { package = "embedded-hal", version = "0.2" }
<re_irc> <> embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
<re_irc> <> Are you sure that no collisions will happen in the whole dependency tree of an application?
<re_irc> <> cargo treats different major versions of the same crate independently
<re_irc> <> it's explicitly designed so you can do taht
<re_irc> <> I know, but this does not work in all cases, I think.
<re_irc> <> I'm pretty sure it does 🤷
<re_irc> <> As soon as you have different definitions for the same symbol in the linker, it will break. But that is rare.
<re_irc> <> The symbols will always be different as long as you define it like dirbaio
<re_irc> <> rust mangles all symbols so different crate versions get different symbol names
<re_irc> <> C linkage?
<re_irc> <> except for `extern "C"` and `#[no_mangle]` stuff I think, but this will probably never be in e-h
<re_irc> <> That's wanted I want to say.
<re_irc> <> It is rare, but can happen especially with embedded.
<re_irc> <> embedded-hal is all traits anyway
<re_irc> <> no symbols :D
<re_irc> <> with other crates it could indeed
<re_irc> <> if I understood it correctly `cortex-m-rt` had this problem
<re_irc> <> Yes, and this is exactly where I ran into it.
<re_irc> <> embedded-hal will never do that since the whole point of it is allowing mixing versions
<re_irc> <> Ok, that's good to know.
<re_irc> <> c-m-rt has a specialist problem because it really cannot coexist with another version of itself, since it defines vector tables and so on
<re_irc> <> Normally in Rust it's not a problem to mix versions, though still a bit annoying just for DelayUs
<re_irc> <> is it possible to use the rust stdlib on a raspberry pi pico? ive been writing a program for the pi zero, but theres too much OS to reliably get the precision i need; i *can* start over but id prefer to just port what i have
<re_irc> <> Pico is only Cortex-M0, so I doubt that.
<re_irc> <> (the Correct™ thing to do would be to get a dedicated controller but ive already got the pico)
<re_irc> <> hm alright, thanks
<re_irc> <> and the target is `thumbv6m-none-eabi`, correct?
<re_irc> <> Should be right.
<re_irc> <> So what is your advice for dealing with Instant and Duration when I need to write a driver in the near future?
<re_irc> <> Another topic: is there any concept in e-h for parallel interfaces? Typically, with a TFT, I use an 8-bit parallel port for data. I only write to the display, but it's also possible to read from port.
emerent has quit [Ping timeout: 260 seconds]
emerent has joined #rust-embedded
<re_irc> <> Hey All, I'm very new to embedded. currently working on a hobby project using a STM32f103 blue pill.
<re_irc> <> Project involves reading some sensors and sending data to my PC via usb, I've got the usb serial working and can successfully send bytes back and forth to the device.
<re_irc> <> but I'm not sure about how to design the communication protocol? are there any standards best practices.
<re_irc> <> communication basically looks like
<re_irc> <> Maybe there are some existing protocols, but what I currently do in such cases is using a request/response pattern. This may work or not in your use case.
<re_irc> <> So the PC polls the information. If this is not an option, then the device can stream it without any request from the PC.
<re_irc> <> thanks, any good bad examples of request/response pattern
<re_irc> <> Have a look at the STM32 internal bootloader as an example.
<re_irc> <> This follows such a pattern.
<re_irc> <> thanks, let me ddg it, to the other question yes pc will have to poll for info otherwise its not needed
<re_irc> <> You could use serialization library such as it also support
<re_irc> <> With STM32 bootloader protocol I refer to the serial bootloader on the UART, not the USB one in DFU mode. The latter is much more complicated to handle.
<re_irc> <> sourcebox: for display abstractions there's and e.g.
<re_irc> <> Thanks, I just had a look at the code.
<re_irc> <> Seems that it iterates over the pins, not a good solution.
<re_irc> <> yea.. I feel like I saw another parallel port abstraction at some point but I don't remember where. for parallel displays I usually use specific peripherals for it instead of gpio, either fsmc or ltdc on stm32
<re_irc> <> GPIO on STM32 is fine, but the register should be written in one operation.
<re_irc> <> But e-h does not specify anything like a slice of OutputPins, I think.
<re_irc> <> The term "bus" should be appropriate.
<re_irc> <> On STM32 DMA is also a good option - if you can afford the required RAM.
<re_irc> <> Ok, but also pending for a good while.
<re_irc> <> Another use case would be scanning a key matrix.
<re_irc> <> Why didn't they have this
<re_irc> <> before I re-did
<re_irc> <> 😣
<re_irc> <> It's not easy trivial to implement that generically, even less so without reaching into the magic box of unsafety.
<re_irc> <> However the idea here is: If you can implement that interface, any display using `display-interface` will be able to use it. the `parallel-gpio` driver is simply the easiest (and possibly only) generic implementation which can literally work anywhere where the `embedded-hal` `OutputPin` traits are implemented.
<re_irc> <> Some STM32s have a FSMC/FMC peripheral for which the `display-interface` can also be implemented (and is e.g. on the F4). If that is available the display with render in lightning speed, but of course you're giving up the possibility to choose your pins freely and have to use the ones available for the FSMC/FMC interface.
<re_irc> <> Good old trade-offs. 😅
<re_irc> <> The I2C-controlled PMU chip I'm writing a driver for has 119 registers and a high level API is going to be hundreds of functions including many that need to touch the same registers for unrelated reasons
<re_irc> <> so writing this high level API at all without some decent way to refer to bitfields inside registers etc seems like a challenge
<re_irc> <> also i'm already having to write my own documentation for the device since i'm interpreting a bad machine translation of the chinese datasheet for it, so writing that in the form of usable code isn't necessarily adding any significant work if there's sufficiently good tool/macro/etc support :)