ChanServ changed the topic of #rust-embedded to: Welcome to the Rust Embedded IRC channel! Bridged to #rust-embedded:matrix.org and logged at https://libera.irclog.whitequark.org/rust-embedded, code of conduct at https://www.rust-lang.org/conduct.html
exark_ has joined #rust-embedded
exark has quit [Ping timeout: 245 seconds]
BentoMon has quit [Ping timeout: 276 seconds]
BentoMon has joined #rust-embedded
haobogu[m] has joined #rust-embedded
<haobogu[m]> Hi everyone, is it possible to define a "weak" constant/variable in Rust?
<haobogu[m]> like GCC's __attribute__((weak))
takkaryx[m] has joined #rust-embedded
<takkaryx[m]> isn't there a `#[linkage = "weak"]` attribute you can use? I think you need a `#[no_mangle]` as well so it doesn't get compiled away.
<takkaryx[m]> might be nightly only right now?
<haobogu[m]> <takkaryx[m]> "isn't there a `#[linkage = "weak..." <- Yeah it works only on nightly.
<takkaryx[m]> sorry, I don't actually know how to use it fully, I've just read about it.
<JamesMunns[m]> weak linkage is probably not likely to work (ever?) for const fns
<JamesMunns[m]> const fns are execcuted at compile time (by rustc) when used in const position, and weak linkage can take place much later, at linking time (by ldd, gcc-ld)
<JamesMunns[m]> haobogu might be worth sharing what you're trying to do, and there might be another way to do it? From your example, maybe you're trying to set a "config" parameter in a crate, sort of like a `#define` in C?
<diondokter[m]> (oh, btw haobogu I'll take another look at your PR this afternoon)
<JamesMunns[m]> in which case, the typical way to do that is using something like the env! macro to grab an env var at compile time. defmt uses that pattern
crespum[m] has joined #rust-embedded
<JamesMunns[m]> You might find better answers elsewhere, but my general answer is: Rust doesn't have inheritance, and you won't be able to generally port patterns from other languages 1:1.
<JamesMunns[m]> I can share some ways to sort of get closer, but you might hit other bumps along the way if you keep trying to implement inheritance-like patterns
<JamesMunns[m]> Rust doesn't really have "base classes", and usually focuses more on composition than inheritance. if you maybe have a more specific example of what you're trying to do we might be able to suggest things, but you might also get more non-embedded support in the official discord or zulip, or the rust channel on matrix `#rust:matrix.org` I think?
<JamesMunns[m]> * I can share some ways to sort of get closer, but you might hit other bumps along the way (that aren't easy or possible to do in Rust) if you keep trying to implement inheritance-like patterns
<JamesMunns[m]> specifically in Rust, traits only cover methods, not fields. there's no way to require certain fields in traits. you can have get() and set() trait methods, but usually you wouldn't generally do this in idiomatic Rust code.
emerent_ has joined #rust-embedded
emerent is now known as Guest8560
Guest8560 has quit [Killed (osmium.libera.chat (Nickname regained by services))]
emerent_ is now known as emerent
<crespum[m]> <JamesMunns[m]> "specifically in Rust, traits..." <- Thanks James, this was exactly what I initially tried, but it didn't feel _right_
<JamesMunns[m]> yeah, it's very possible to get yourself in an "uncanny valley" when trying to do python (or other lang) things in Rust. It's an unsatisfying answer, but sometimes you need to unlearn patterns or learn patterns that are more "natural" in Rust, otherwise you will end up running into some pretty hard to solve challenges.
<crespum[m]> Have you checked [this](https://matrix.to/#/!BHcierreUuwCMxVqOf:matrix.org/$3WQDmmJ4-wJ-IxudTE0x9uko4HXoy6-_hYBQC8VzG74?via=matrix.org&via=catircservices.org&via=tchncs.de)? To me (not a Rust guru at all) it also doesn't feel idiomatic...
<JamesMunns[m]> I mean, it's hard to tell what you're trying to do. If you have a concrete example of what you're trying to abstract over, I can comment on that. But there's not a general "how to do inheritance" pattern I can suggest.
<JamesMunns[m]> normally traits would have methods for the kind of thing you are doing. Like the embedded-hal traits: there are ones for sending data on a UART for example. the idea with traits is to encapsulate the implementation, with a common interface.
<JamesMunns[m]> * normally traits would have methods for the kind of thing you are doing. Like the embedded-hal traits: there are ones for sending data on a UART for example. the idea with traits is to encapsulate (or abstract over) the implementation, with a common interface.
<crespum[m]> I understand. I will give it another chance. Thanks again!
dkm has quit [Ping timeout: 245 seconds]
dkm has joined #rust-embedded
cinemaSundays has joined #rust-embedded
JulianDickert[m] has joined #rust-embedded
<JulianDickert[m]> <haobogu[m]> "And it doesn't work for `const..." <- > <@haobogu:matrix.org> And it doesn't work for `const fn`? The following code doesn't work:... (full message at <https://catircservices.org/_irc/v1/media/download/AUG9Pt9eIxU5h6TrZ-M4cYppKQxiAKZ9fcSTXw21Xc03TC_2-Ggnqst16_QY4Q34FYlwy1PtvQImR3_29k7IDRm_8AAAAAAAAGNhdGlyY3NlcnZpY2VzLm9yZy9ER2N2bWVoS0JxbERHQmV2eXlpaGpEdmo>)
<JulianDickert[m]> Oh sorry, matrix hasn't loaded the new messages :D
<JulianDickert[m]> Is the current version of Element broken in general w.rt. messages not loading – or is it on my machine?
Mattia[m] has quit [Quit: Idle timeout reached: 172800s]
cinemaSundays has quit [Quit: Connection closed for inactivity]
<thejpster[m]> Anyone tried these? Renesas RISC-V microcontroller. Runs at up to 5V. 48 MHz.
<diondokter[m]> thejpster[m]: I've got one of them! (or a close family of it)
<diondokter[m]> I tried running Rust on it, but gave up when the SVD didn't generate a nice PAC
<thejpster[m]> Oh no. Shame.
<thejpster[m]> What was wrong with the PAC?
<diondokter[m]> Probably possible though, I just went on with other more interesting things
<diondokter[m]> It's been a while, so I don't quite remember. Something weird about the interrupts I think and duplicate names of registers
kenny has quit [Quit: WeeChat 4.4.2]
kenny has joined #rust-embedded
cr1901_ has joined #rust-embedded
cr1901 has quit [Ping timeout: 260 seconds]
JamesSizeland[m] has joined #rust-embedded
<JamesSizeland[m]> Does anyone know why docstrings don't show up properly when parsed and constructed through a proc_macro quote? They seem to appear correctly in the cargo expand but not as hover text on the output struct fields...
<diondokter[m]> JamesSizeland[m]: Got an example? I've not seen this go wrong tbh
<danielb[m]> do you emit docstrings as #[doc = ""] or /// foo?
<diondokter[m]> That too yeah. In device-driver I emit them in the attribute form
<danielb[m]> I think that's pretty much required when generating docs
<diondokter[m]> You don't have to split the lines
<diondokter[m]> Just put the full string in there
dirbaio[m] has joined #rust-embedded
<dirbaio[m]> you can make it a giant #[doc = "..."] with \n
<dirbaio[m]> ninja'd :D
<diondokter[m]> :P
<diondokter[m]> I mean, splitting it should work too I would think, but maybe it makes something be weird
<JamesSizeland[m]> Maybe the span is wrong, it renders exactly the same in the expanded file both ways, with ///
<JamesSizeland[m]> Do you know any examples I could follow? The macro book talks about consuming but not re-outputting docstrings
<diondokter[m]> What does the output look like?
<diondokter[m]> Should be fine!
<JamesSizeland[m]> ikr!
<diondokter[m]> Might just be an RA issue?
<diondokter[m]> Though with device-driver it usually does pretty well
<diondokter[m]> Maybe let RA rebuild the build dependencies?
<JamesSizeland[m]> I think it is an RA issue, at least I don't think I'm doing something wrong here. I've tried opening it on another machine in another editor and still not showing up. I'll see if there's a relevant issue for it.
<JamesSizeland[m]> thanks!
davidmpye[m] has joined #rust-embedded
<davidmpye[m]> Does anybody know if you can send things wrapped in an Option over Postcard-rpc? I am thinking of an endpoint to query the embedded device about whether a peripheral is present
<davidmpye[m]> and it makes sense that you'd return Some(ThePeripheralStruct) or None if it wasnt present
<davidmpye[m]> Likewise, for an endpoint do do something, can you return a Result
<davidmpye[m]> *to do
barafael[m] has quit [Quit: Idle timeout reached: 172800s]
cgc17[m] has quit [Quit: Idle timeout reached: 172800s]
<dirbaio[m]> does anyone know how to get "link to binary" working in godbolt? https://godbolt.org/z/YsWTo78xx
<dirbaio[m]> (I want to see the full asm of core::str::from_utf8, to check my suspicions that it's mega bloated)
bitts[m] has joined #rust-embedded
<bitts[m]> <davidmpye[m]> "Does anybody know if you can..." <- You can with postcard, so I would think so
<thejpster[m]> Ferrous Systems needs another Advanced/Rust trainer because we’re very busy. If you like the idea of sharing your love of Embedded Rust with complete strangers, you should apply.
<thejpster[m]> Especially if you speak German, as I don’t, and that’s a big market for us as you can imagine.
<danielb[m]> <dirbaio[m]> "(I want to see the full asm of..." <- I don't have an answer for you, you'll sooner get an answer from rustc and --emit-asm, but anything that involves UTF8 validation should be terrible
<JamesMunns[m]> <davidmpye[m]> "Does anybody know if you can..." <- are you running into https://github.com/jamesmunns/postcard-rpc/issues/56 ?
<danielb[m]> FWIW on Xtensa, the function is 2005 bytes long
<danielb[m]> * bytes long,, * only counting instructions
<danielb[m]> * bytes long,, * only counting instructions, not including functions that it calls
<dirbaio[m]> so bloated yep :D
<dirbaio[m]> hmm i've removed all uses I could find but size barely went down
<dirbaio[m]> I must have more... but tehy don't show up in objdump :(
<davidmpye[m]> JamesMunns[m]: No, but I would have when I try to implement it! So I can do what I want as long as I alias the Result?
<JamesMunns[m]> Yep!
<davidmpye[m]> That works for me, thank you!
<davidmpye[m]> It's an implementation of a vending machine controller on a Pico, with a Pi talking to it. The vmc has a series of optional peripherals and I wanted a sensible way to pass information about them to the Pi
<dirbaio[m]> ugh core::ffi::c_str::CStr::to_str
<JamesMunns[m]> davidmpye[m]: is it optional per binary? or detected at runtime?
<danielb[m]> dirbaio[m]: do you actually need utf8, or can you get away with ascii?
<dirbaio[m]> yeah I don't need it. it's just places that convert from `&[u8]` to `&str` that do it the safe way because reasons
<dirbaio[m]> I should just avoid `&str` even for things that are strings in theory
<danielb[m]> would it work if you loop through string, verify that it's all u8::is_ascii and transmute?
<JamesMunns[m]> danielb[m]: or `from_utf8_unchecked` :D
<danielb[m]> JamesMunns[m]: but transmute is so much more arcane
<danielb[m]> I expected unsafe precondition checks in there
<dirbaio[m]> welp got rid of the utf8 validation, it went down only 800 bytes
<dirbaio[m]> but it's really gone now
<dirbaio[m]> so it wasn't that big
<danielb[m]> or you're really not done getting rid of it 😅
<davidmpye[m]> <JamesMunns[m]> "is it optional per binary? or..." <- Detected at runtime over a 9bit serial bus. They are devices like a contactless card reader or a coin acceptor. They might or might not be connected
<davidmpye[m]> You poll the bus and if they're present they will reply, and then there's an opaque dance to initialise them and find out about them
<davidmpye[m]> Most of the nuts and bolts at that level is done, it's just tying it together with the pi controlling it that needs to be done
jmogens[m] has joined #rust-embedded
<jmogens[m]> Hello, using serde_json_core, how can I deserialize the JSON response from https://api-v3.mbta.com/predictions?filter[route]=87&filter[stop]=2576&page[limit]=1 to access the arrival_time value? This JSON response has a list, but the list is guaranteed to only have one element (controlled by the "[limit]=1" URL parameter.
<jmogens[m]> s/pub//, s/no_std/no\_std/
<jmogens[m]> * Hello, using serde\_json\_core, how can I deserialize the JSON response from https://api-v3.mbta.com/predictions?filter\[route\]=87&filter\[stop\]=2576&page\[limit\]=1 to access the arrival\_time value? This JSON response has a list, but the list is guaranteed to only have one element (controlled by the "page\[limit\]=1" URL parameter.
<JamesMunns[m]> jmogens[m]: You could use heapless::Vec
<jmogens[m]> I can give that a try. If I know that there will only be one Data in the Response, is it possible to tell serde_json_core to stop deserializing after the first Data element in the list or to drop other Data items that don't fit in the Response struct (similar to how serde_json_core will drop other values not defined in the Response struct)?
<JamesMunns[m]> <jmogens[m]> "I can give that a try. If I know..." <- You can use a heapless Vec with capacity 1, deser will fail if you get more.
Der_Moom has joined #rust-embedded
Der_Moom has left #rust-embedded [#rust-embedded]
<danielb[m]> do you have the serde feature enabled?
<jmogens[m]> Doh! Didn't see anything about serde in docs.rs, but it's mentioned right in the github README for heapless...
hjeldin__[m] has joined #rust-embedded
<hjeldin__[m]> so, i find myself in a bit of a pickle: i wrote an spi driver for a display (ili9341), then i implemented the DrawTarget trait from embedded-graphics. it kinda works, but it's slow as hell. i guess the issue is that the trait is sync and using write_blocking, while i'd like to use DMA by using spi.transfer, which is async. i guess my only course of action is to implement a command queue, right? then in the task i can pop the
<hjeldin__[m]> draw call from the queue and transfer it asynchronously. would this be the right approach or am i missing something?
<dirbaio[m]> Are you building with --release?
<hjeldin__[m]> cargo run --release, yep
<dirbaio[m]> Try setting opt-level to s or z, smaller code is often faster. Try enabling lto as well
<dirbaio[m]> What microcontroller is it, are you running it at the max freq?
<dirbaio[m]> And have you tried increasing the spi freq?
<hjeldin__[m]> it's a stm32l476rg, currently running @ 80Mhz, spi is actually set at 2MHz so i might try increasing it. let me check
<hjeldin__[m]> huh that made no difference
<danielb[m]> how much did you increase it to?
<hjeldin__[m]> set it to 32MHz, it should be noticeable i guess
<danielb[m]> yeah although still not zippy I think
<danielb[m]> usually you can try rendering into a framebuffer and DMAing that out separately, but I suspect you don't have the RAM for it
<hjeldin__[m]> not nearly enough, yeah :D
<dirbaio[m]> Are you using SpiDevice or SpiBus? The former does a CS toggle for every tramsfer which can make it slower
<dirbaio[m]> which Hal?
<hjeldin__[m]> i'm using embassy-stm32, do not know what happens under the hood. i only know that i need to handle the CS myself (in this configuration it's permanently set to low)
<dirbaio[m]> SpiBus then
<dirbaio[m]> *
<dirbaio[m]> Hmm
<danielb[m]> you can try and implement your own display interface, and buffer more than 64 bytes, but I'm not sure how much that would help
<danielb[m]> DMA only helps if you buffer more and can swap two buffers, that way you can output data while e-g draws
<danielb[m]> if you have to still wait for the transfer to complete, it's not a big win
<hjeldin__[m]> but it might be able to squeeze the transfer between tasks?
<dirbaio[m]> the "obvious" way to add async (changing spi.blocking_write() to spi.write().await won't help perf
<hjeldin__[m]> and also embedded-graphics forces me to stay sync'd, so without a decoupled command queue i'm out of luck
<dirbaio[m]> because when the spi write runs, it starts DMA then suspends, this lets other tasks run in the meantime, but it won't make your display task faster because it still won't parallelize cpu work and dma writes.
<dirbaio[m]> so you'd need two tasks at least, and coordinating between them
<dirbaio[m]> also an async context switch is ~100 cycles, and you'd need 2 (one out of your task and one back in) for each transfer. In that time you can send 100*2/80*32/8
<dirbaio[m]> s//`/, s//` = 10 bytes/
<hjeldin__[m]> jeez
<dirbaio[m]> if your transfers are about that size or smaller, it's likely async will be a net perf loss 🥲
<dirbaio[m]> and I think e-g does make transfers small like that (?)
<danielb[m]> it depends what you draw, and how the display driver is implemented
<hjeldin__[m]> yep
<dirbaio[m]> the magic ideal solution would be like BufferedUart but for SPI 🥲
<dirbaio[m]> there's a ringbuffer, cpu enqueues bytes, dma sends them
<danielb[m]> also if the draw call ends up passing an iterator to display-interface, it's getting chopped up into 64-byte transfers
<danielb[m]> display-interface doesn't provide very sophisticated implementations :)
<dirbaio[m]> it's a hard problem yeah 🥲
<dirbaio[m]> embassy-stm32 could be a bit smarter here, it's flushing for every transfer https://github.com/embassy-rs/embassy/blob/main/embassy-stm32/src/spi/mod.rs#L368-L372
<dirbaio[m]> not flushing would allow overlapping some spi and cpu work
<hjeldin__[m]> let me try
<hjeldin__[m]> mmm it's still taking ~150ms to transfer 512 bytes
<danielb[m]> wow that is terrible
<hjeldin__[m]> i must be doing something wrong
<diondokter[m]> Lol, are you sure you haven't left an old sleep(10) around :P
<danielb[m]> sleep(10) // one future miracle perf improvement
<diondokter[m]> Probably start logging. If you're using defmt you can also see the time of the log. See how long each single transaction takes. Are they all long? Is only one long?
<danielb[m]> this would be very educational to check with a logic analyzer I think
<dirbaio[m]> can you share your code?
<hjeldin__[m]> yep, it's extremely shit, hold on
<hjeldin__[m]> https://github.com/hjeldin/dive-computer-fw/blob/master/src/ili9341.rs#L183 this is actually where the data gets handled from embedded-graphics, and it gets written in https://github.com/hjeldin/dive-computer-fw/blob/master/src/spidriver.rs#L66
<diondokter[m]> The mutex in the spi driver probably doesn't help
<diondokter[m]> But unlikely to be the cause
<hjeldin__[m]> i'd disable it if i could 🥲 the display is the only spi peripheral connected to the bus
<danielb[m]> actually [this](https://github.com/hjeldin/dive-computer-fw/blob/master/src/ili9341.rs#L401) handles what's coming from embedded-graphics
<danielb[m]> that is two SPI transfers per pixel I believe
<dirbaio[m]> hjeldin__[m]: why can't you remove it?
<danielb[m]> * that is <del>two, * two</del>, * no at least 4 SPI transfers
<dirbaio[m]> if you don't need to share the spi bus, you totally can remove it
<hjeldin__[m]> static variables should be wrapped with a mutex right?
<danielb[m]> * that is <del>two, * two</del>, * no at least 6 SPI transfers
<diondokter[m]> danielb[m]: set_window alone is 5 calls
<danielb[m]> diondokter[m]: yeah let's accept that I can't count at 10:30
<diondokter[m]> Haha
<dirbaio[m]> also remove these prints if you haven't tried already. printing is very slow. https://github.com/hjeldin/dive-computer-fw/blob/master/src/spidriver.rs#L62
<hjeldin__[m]> danielb[m]: you are right, i believe that's how embedded graphics handles fonts
<hjeldin__[m]> s/fonts/font rendering/
<danielb[m]> my friend, embedded-graphics tries to use draw_iter as much as possible
<danielb[m]> if you break it down to single pixel draws, you're doing the worst thing possible to drawing perf
<hjeldin__[m]> well, disabling single pixel draw calls and the prints we're down to 40ms, which is close to the 33ms target
<dirbaio[m]> s/<'a>//
<danielb[m]> if write_command sets DC to high, enable_write_data is also just wasted time
<danielb[m]> that is, fill_rect and draw_raw_iter don't need enable_write_data - won't save you much, but for you, every bit helps I think :D
<danielb[m]> you should see if you can implement set_window without 5 separate SPI transfers
<danielb[m]> * you should see if you can implement set_window without 5 separate SPI transfers - i.e., does the display really need DC=data to transfer the data of the commands?
<hjeldin__[m]> let me check the datasheet
<hjeldin__[m]> and unfortunately DC needs to be interleaved high/low for command/data
<hjeldin__[m]> would you look at that
<hjeldin__[m]> apparently it was the mutex after all?