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
ello_ has quit [Ping timeout: 252 seconds]
ello has quit [Ping timeout: 252 seconds]
ello has joined #rust-embedded
ello_ has joined #rust-embedded
<KevinPFleming[m]> funny that they call out "True 5V IOs" when the part runs on 5V
feldrinh[m] has joined #rust-embedded
<feldrinh[m]> Hey!
<feldrinh[m]> I've been reading up on embedded Rust, and I found this old discussion which is very relevant to my current struggles: https://github.com/rust-embedded/not-yet-awesome-embedded-rust?tab=readme-ov-file#sharing-data-with-interrupts.
<feldrinh[m]> But that repo is archived and the disclaimer at the top of the readme states that these topics have been "pretty much resolved". So my question is, what is now the recommended way to share data with interrupts? What was the ultimate outcome of that discussion?
Kert[m] has joined #rust-embedded
<Kert[m]> <feldrinh[m]> "Hey!..." <- Here's my cheatsheet for myself, because i get confused : https://gist.github.com/kaidokert/08bbc4903366028177d57761a55e792f
<Kert[m]> Outside of leaning into frameworks like RTIC and Embassy i don't know that those have been "solved" at language level
<i509vcb[m]> <Kert[m]> "Here's my cheatsheet for myself,..." <- How much data you are trying to share to an interrupt is also a question worth asking
<i509vcb[m]> i509vcb[m]: Something like "this happened" is probably doable via some variant of Waker/semaphore
<i509vcb[m]> i509vcb[m]: Channels for something more structured probably
<i509vcb[m]> i509vcb[m]: Something I use in embassy-mspm0 is using the hardware registers for transporting some flags via side channel
<i509vcb[m]> i509vcb[m]: For the GPIO driver I have the interrupt handler unmask the interrupt for the pin which caused an interrupt so that the future when polled again can just ask the hardware if a specific pin's interrupt is enabled to determine if the waker is actually being polled
<i509vcb[m]> * structured probably, assuming you can meet backpressure as needed
Ralph[m]1 has quit [Quit: Idle timeout reached: 172800s]
rainingmessages has quit [Quit: bye]
rainingmessages has joined #rust-embedded
thejpster[m] has joined #rust-embedded
<thejpster[m]> I made a thread for tomorrow's meeting - https://github.com/rust-embedded/wg/discussions/848
<thejpster[m]> also added a question about doing a cortex-m release, and the curious case of https://github.com/rust-embedded/cortex-m/issues/602
sourcebox[m] has joined #rust-embedded
<sourcebox[m]> I'm currently doing a little bit of work on the HAL I've started 2 years ago. Are you still interested in this?
d34db33f has quit [Remote host closed the connection]
RobinMueller[m] has joined #rust-embedded
<RobinMueller[m]> If you want to start something, keep in mind that maintenance for https://github.com/rust-embedded/cortex-ar/ is active again, and we added various modules which might be useful for you
<sourcebox[m]> <RobinMueller[m]> "If you want to start something..." <- Yes, I've already seen that. There are things offered by `cortex-ar` that I've done manually, so it might be a good idea to take that from the crate.
<sourcebox[m]> My intention is to get the HAL to a MVP, but it's a long way to go and the overall setup is quite complex.
<thejpster[m]> > and the overall setup is quite complex
<thejpster[m]> We, or at least I, forgot how much easier Cortex-M made embedded systems. Standardised start-up routines, Interrupt Controller and vectoring mechanism, memory map, timer peripheral and debug interface! There are some standards for those things with the other Arm profiles, but chips are always a bit different and a bit special.
<sourcebox[m]> Yep, for Cortex-M, there's common startup code, but I think that is not possible for the Cortex-A, so the HAL has to provide it.
<sourcebox[m]> I already had fun on getting that running and it's still not really in good shape.
<sourcebox[m]> One thing I still have to solve is to provide the __libc_init_array function that is required when some C/C++ code is linked with the project. I've already tried it as weak function with just a bx lr in the startup, so it can be redefined later, but that results in always having the default in the binary.
<RobinMueller[m]> <sourcebox[m]> "I already had fun on getting..." <- I had the same process for the zynq7000. cortex-a-rt is a useful template though at the very least. i guess most cortex-a chips need a custom runtime init anyway for various reasons.
<RobinMueller[m]> * I had the same process for the zynq7000 which also has a custom run-time init, but strongly based on cortex-a-rt. cortex-a-rt can be a useful template at the very least. i guess most cortex-a chips need a custom runtime init anyway for various reasons.
<sourcebox[m]> Thanks for the hint. This crate did not even exist when I started the HAL.
<RobinMueller[m]> <sourcebox[m]> "One thing I still have to..." <- oh, thats special. you can not call it in regular rust code right at the start of the main method, before calling into the C lib(s)?
<sourcebox[m]> Maybe. But that's of course easy to forget and doing that is not always obvious.
<sourcebox[m]> Question is, if this function can be written in Rust.
<sourcebox[m]> In the startup code, I have a `bl __libc_init_arry' just before branching to main.
<sourcebox[m]> s/`/\`/, s/__libc_init_arry'/\_\_libc\_init\_array`/
<sourcebox[m]> s/__libc_init_arry'/__libc_init_array`/
<RobinMueller[m]> <sourcebox[m]> "One thing I still have to..." <- why do you need to override this method?
<RobinMueller[m]> * to override/redefine this
<sourcebox[m]> This method is only needed when using C/C++ code.
<RobinMueller[m]> ah okay. I think cortex-a-rt and cortex-r-rt had weakly defined assembler functions, using the PROVIDE syntax inside the link.x file
<RobinMueller[m]> * link.x file IIRC. maybe this helps?
<sourcebox[m]> In can always be present, but atm I just define it in C.
<sourcebox[m]> And my question is, if this just can be ported to Rust somehow.
<sourcebox[m]> Because it's even annoying that it must be included in the C sources.
<RobinMueller[m]> sourcebox[m]: phew, maybe someone who is well versed in FFI can answer this. I would guess yes, and possibly not that complicated, because this is just a void function without any call arguments? have you tried defining functions at the top as extern C functions, and then writing the libc init routine yourself in Rust?
<sourcebox[m]> Not yet.
<RobinMueller[m]> * phew, maybe someone who is well versed in FFI can answer this. I would guess yes, and possibly not that complicated, because this is just a void function without any call arguments? have you tried defining the symbols at the top as extern C symbols, and then writing the libc init routine yourself in Rust?
<sourcebox[m]> Surely not that complicated, but in the whole mess of things to do, I've postponed it.
<RobinMueller[m]> I just saw that thos are not functions, but just a magic array of function pointers
<RobinMueller[m]> * are not just functions, but
<RobinMueller[m]> well, the best solution is to avoid C/C++ altogether, but I know that this might not always be possible :D
therealprof[m] has joined #rust-embedded
<therealprof[m]> <sourcebox[m]> "And my question is, if this just..." <- Doesn't seem complicated but is a potentially deep rabbit hole... you know, "no life before main", etc.
<sourcebox[m]> The function could be also written in asm directly.
<sourcebox[m]> When I google for that function, the result give me only C functions.
<sourcebox[m]> Should I dare to take the output of the compiler explorer? https://godbolt.org/z/bv7ojEnW4
diondokter[m] has joined #rust-embedded
<diondokter[m]> <sourcebox[m]> "Should I dare to take the output..." <- Just a note that naked functions are a thing now, so copying this is easier than ever
<sourcebox[m]> Yep. For now I've just copied it into the assembly file that already contains the other parts.
<sourcebox[m]> At first glance, it seems to work.
<diondokter[m]> Is there any embedded-hal like qspi trait? I can only find implementations of qspi
<diondokter[m]> MS has something like what I want (but I think it's the wrong abstraction): https://github.com/OpenDevicePartnership/embedded-services/tree/main/storage-bus
<dirbaio[m]> if it's for qspi flashes i'd use NorFlash
<diondokter[m]> Well, I want to build a norflash driver that can take a QSPI
<diondokter[m]> * a QSPI as a bus
<dirbaio[m]> I don't think a trait for the QSPI bus itself would work well because the QSPI peripherals out there are very designed for QSPI flashes
<diondokter[m]> * a QSPI as a bus, generically
<dirbaio[m]> they're not "like SPI but with 4 wires"
<dirbaio[m]> see nrf's for example. you program it with info about your qspi flash (instructions, number of lanes, delays, etc) and then you fire "read, write, erase" tasks to it
<diondokter[m]> Yeah I know, but is there really no way to build a driver generically? I want it to work everywhere, not just on e.g. embassy-stm32
<dirbaio[m]> you never write the instructions themselves as data
<dirbaio[m]> stm32 is also kind of like that
<dirbaio[m]> so if you make a qspi trait that's "like spi but with 4 wires" you couldn't impl it on nrf
<dirbaio[m]> * on nrf at all
<diondokter[m]> But... I'm not asking for that
<dirbaio[m]> you probably could for stm32, it offers a bit more low-level control
<dirbaio[m]> but at reduced performance because you'd be doing all the instruction stuff in software
<dirbaio[m]> then what are you asking for? :D
wassasin[m] has joined #rust-embedded
<wassasin[m]> diondokter: you want a trait to send commands and data; such that you can implement a NorFlash driver for most HALs probably?
<diondokter[m]> wassasin[m]: Yes
<dirbaio[m]> you either make a trait for "below" the qspi flash protocol (so, spi with 4 wires)
<dirbaio[m]> or youmake a trait for "above" the qspi flash protocol (so, NorFlash)
<dirbaio[m]> if you make something in the middle like "send arbitrary qspi command with arbitrary data" you can't impl it for nrf
<dirbaio[m]> the api nrf's qspi gives you is higher-level than that
<diondokter[m]> Then how do I write a flash driver, using qspi, that works for both embassy-nrf and embassy-stm32?
<dirbaio[m]> yay matrix is not sending my messages now
<diondokter[m]> <dirbaio[m]> "see nrf's for example. you..." <- Ah ok
<dirbaio[m]> it also wouldn't work for rp2040, you need to do a ton more state handling there to disengage/reengage XIP
<diondokter[m]> That's not a great qspi interface
<dirbaio[m]> it's hard to do if you let the caller do arbitrary qspi instructions which could do arbitrary changes to the qspi chip state
<diondokter[m]> Ugh, my messages are being sent so slowly
<dirbaio[m]> diondokter[m]: that's the NorFlash trait :P
<diondokter[m]> dirbaio[m]: Surely the NorFlash trait is the output of the driver :P
<diondokter[m]> diondokter[m]: Take in qspi, present NorFlash interface to the user
<dirbaio[m]> no
<dirbaio[m]> nrf's qspi is not really a "qspi" peripheral, it's a "qspi flash" peripheral that implements all the protocol in hardware
<dirbaio[m]> so the register api it gives you is basically the NorFlash api
<diondokter[m]> But yeah, if so many chips have such bad qspi impls, then maybe it doesn't make sense yeah
<dirbaio[m]> qspi hardware does funny things like this because it's designed to allow for XIP
<dirbaio[m]> so it has to implement (at least part of) the qspi flash protocol in hardware
<dirbaio[m]> yeah
Koen[m] has joined #rust-embedded
<Koen[m]> Like, we're talking peripherals that already implement some form of XIP memory mapping, so they already implement the read commands in hw.
<diondokter[m]> Well, STM32 does XIP but also has a proper interface
<wassasin[m]> Zephyr also does not have a generic flash configuration method for all chipsets; the perspective is more from the MCU/qspi peripheral, which you configure such that your memory is mapped
<dirbaio[m]> some decided to *additionally* give you more level control (stm32)
<dirbaio[m]> some just don't (nrf)
<diondokter[m]> Ugh
<diondokter[m]> Fire all chipdesigners
<dirbaio[m]> lol
<wassasin[m]> :''')
<dirbaio[m]> I think it kinda makes sense
<wassasin[m]> If JEDEC memory standardization were better you would not have to write a driver for your flash
<diondokter[m]> wassasin[m]: Kinda yeah. For the basic stuff.
<diondokter[m]> But so... on the nrf you can't set up e.g. memory protection configs?
<wassasin[m]> You can write custom instructions, but not invoke specific instructions for memory read/write used by XIP
<diondokter[m]> Hmmm, I see a super simplistic 'custom_instruction' function on the nrf qspi in embassy
<dirbaio[m]> it does cpu copy, so it's slowwwwwww
<dirbaio[m]> no DMA
<dirbaio[m]> I really wouldn't use it
<diondokter[m]> Yeah, I've heard people complain about nrf XIP before
<diondokter[m]> Hmmm, so RP2350 does have a direct-mode QSPI (though not as elaborate as STM has)
<dirbaio[m]> <dirbaio[m]> "it also wouldn't work for rp2040..." <- yeah but you can't use it directly due to ^
<diondokter[m]> Sure, obviously you can't do XIP when you're doing something else
<dirbaio[m]> but in rp2040/rp2350 the only flash you have is the QSPI XIP :D
<dirbaio[m]> so you're using it 100% for sure
<dirbaio[m]> embassy-rp does some evil hacks to stop all cores, jump both to RAM, disable XIP, do the QSPI operation, reenable XIP, then resume both cores
<diondokter[m]> Yeah that's true. There it makes sense
<diondokter[m]> On nrf52 it doesn't make sense (to me)
<dirbaio[m]> so it can provide a NorFlash impl
<dirbaio[m]> that doesn't make the chip suicide if you're running your firmware from flash
<diondokter[m]> (Btw, the W25N, the nand-variant, is pretty crazy. Elaborate ECC, and block address remapping to do bad block management with)
<diondokter[m]> * management with. But only 10 remappings are supported)
<wassasin[m]> Limited amount of remappings are normal
<wassasin[m]> Honestly sounds pretty normal for NAND
<diondokter[m]> Ah, it seems to be 10 per half gig
<diondokter[m]> The 1 gig version has 20 remappings
<wassasin[m]> I found the NRF52840 QSPI XIP errata to be pretty wild "Reading QSPI registers after XIP might halt CPU" "Race condition occurs in XIP" and "External flash and QSPI returns erroneous data when the SoftDevice is running"
<dirbaio[m]> yeah it's cursed
<dirbaio[m]> thankfully these erratas are only about the actual XIP, they don't affect you if you just use qspi for read/write/erase from a firmware running in internal flash
<dirbaio[m]> ah well maybe the 3rd one?
<diondokter[m]> Did they at least fix things for the nrf54?
<diondokter[m]> I don't see qspi errata for the 54L15
<diondokter[m]> Oh, because it doesn't have qspi I think
<JamesMunns[m]> <dirbaio[m]> "but in rp2040/rp2350 the only..." <- but the 2350 has two QSPI periphs
<JamesMunns[m]> <dirbaio[m]> "but in rp2040/rp2350 the only..." <- for 2040 I agree it's only useful if you boot from ram then disengage the external flash or whatever.
<JamesMunns[m]> but the 2350 you can have your main qspi flash then use the second for PSRAM or a second flash.
<dirbaio[m]> can't fix the errata? just remove the thing. easy peasy
<dirbaio[m]> JamesMunns[m]: ooooooooh interesting
<diondokter[m]> JamesMunns[m]: Sweet! Didn't notice that
<JamesMunns[m]> I do agree with dirbaio tho: we could have a "normal qspi" trait and do a blanket impl of norflash for qspi, BUT practically most chips can't and would need their own direct Hal-specific impl that bypasses the qspi trait because they can't fulfill the "normal qspi" interface contract.
<JamesMunns[m]> So, until we find enough "normal qspi" chips to make a reasonable trait for it, we should just ask people to impl the norflash trait directly for now (and for cursed qspi like nrf, for forever)
<M9names[m]> RP2350 doesn't have 2 qspi peripherals, it has 1 peripheral that can address 2 chips (via chip select)
<M9names[m]> Would be nice though...
<JamesMunns[m]> Ah, TIL
Ralph[m] has joined #rust-embedded
<Ralph[m]> i also like the preview of the link shown by element:
<Ralph[m]> > Description will go into a meta tag in <head />
<Ralph[m]> 🙈
<Ralph[m]> * i also like the preview of the link shown by element:
<Ralph[m]> > Description will go into a meta tag in \<head />
<Ralph[m]> 🙈
<diondokter[m]> Ralph[m]: I think this is still sort of being set up
<diondokter[m]> Ah yes, my colleague Marc is part of it. I thought it sounded familiar haha
<JamesMunns[m]> btw, released v0.2 of `bbq2`, the experimental next-gen version of `bbqueue`. The plan is to iterate on it, then likely merge it into `bbqueue` as v1.0.... (full message at <https://catircservices.org/_irc/v1/media/download/AbyeV5JI7ERR35wioC-7sWj9rnGUONKopS20Rf--ZFwQa_ZC6jFt2xJwFGDB_i0Le3Bpf_60S2-vM3K3VWRmBf6_8AAAAAAAAGNhdGlyY3NlcnZpY2VzLm9yZy9MQ2NBc3dGcmp0TnBBRWRZbFhvQ3JzT3M>)
<JamesMunns[m]> s/2/3/
<JamesMunns[m]> (oh, and "what is bbqueue"):
<JamesMunns[m]> bbqueue/bbq2 is an SPSC byte queue, that allows you to gain access for "chunks" of data at a time, instead of popping single items. This makes it *awesome* for things like DMA: you can push things in one end, and on the other end, "get all the available bytes", and then start a dma transaction for transmitting, OR, get a slab of data, DMA directly into it, and then commit the grant.
<JamesMunns[m]> This means if you do things like DMA on one side and deserialize in-place on the other side, you can literally do *zero* CPU copies for processing incoming data.
<JamesMunns[m]> I'd call it "lock free" if you have CAS atomics, but you can also use it with non-CAS targets, only taking a short CS to take/release grants.
<JamesMunns[m]> The core algorithm (described here: https://ferrous-systems.com/blog/lock-free-ring-buffer/) is the same between bbqueue/bbq2, the latter just has generics that let me be flexible in all of those ways without copy-and-pasting everything 16 times.
<KevinPFleming[m]> Interesting... I built a buffer-manager in my project for handling incoming UART data, because the protocol is framed and so the receiving code has to be able to read specific numbers of bytes from the stream at various times. I wonder if this would be useful there.
<JamesMunns[m]> It has a "framed" mode and "stream" mode :)
<JamesMunns[m]> so you can receive into the grant, then specify how many bytes you used, and you get the exact same chunk out the other side.
<JamesMunns[m]> It's also safe to share with interrupts, which means you can do non-blocking actions in an interrupt handler on one side, and get async notifications on the other when data becomes available.
<diondokter[m]> JamesMunns[m]: Oh, is that new in BBQ2? I might have a good place where I could use the framed mode
<KevinPFleming[m]> In my case framing is not optimal as the 'frame sync' byte can appear in the regular data stream, so the frame receiver has to be able to 'back up' and start over when it turns out that what appeared to be a frame wasn't a frame :-)
<JamesMunns[m]> JamesMunns[m]: it's not!
<diondokter[m]> Oh, whoops :P
<JamesMunns[m]> tho in bbq2 I make you pick u16 or usize for framing len, instead of using a varint.
<JamesMunns[m]> (it makes a lot of stuff much easier to use fixed lengths)
<KevinPFleming[m]> yes, my protocol uses protobuf, but a u16 for 'frame size'
<JamesMunns[m]> interesting, no way to recover if you get out of sync?
<JamesMunns[m]> (or do you also use magic words/line silence/etc. to recover frame boundaries?)
<JamesMunns[m]> I Have Opinions about frame synchronization, and why I use cobs as a default for everything :p
dne has quit [Remote host closed the connection]
dne has joined #rust-embedded
danielb[m] has quit [Quit: Idle timeout reached: 172800s]
<KevinPFleming[m]> (sorry for the delay, $dayjob) The way my frame receiver works is that it look for a sync byte, then a u16 message length, reads that many bytes if possible, then a CRC-16. If the CRC check fails, or the attempt to read that many bytes fails (line goes idle), then it assumes that byte which appeared to be a sync byte was not a sync byte, and it looks forward from that point in the buffer for another sync byte, and starts
<KevinPFleming[m]> over. It will get back in sync this way, even if the sender is sending long frames.
<KevinPFleming[m]> * that point (after the 'fake' sync byte) in the
TiagoManczak[m] has joined #rust-embedded
sroemer has quit [Quit: WeeChat 4.5.2]
<GrantM11235[m]> <GrantM11235[m]> "Can anyone help me figure out..." <- I'm glad the git version of probe-rs fixed the panic message issue, but is there anything I can do to fix the backtrace? I tried `force-frame-pointers=yes` in my rustflags, but that didn't help
kkrolczyk[m] has quit [Quit: Idle timeout reached: 172800s]
sirhcel[m] has quit [Quit: Idle timeout reached: 172800s]
<M9names[m]> panic-immediate-abort is the only option I'm aware of, unless you're offering to work on probe-rs
<M9names[m]> But then you lose your panic message :'(
<dirbaio[m]> i'm not even sure if it's a probe-rs bug or rustc bug, even
<M9names[m]> Either am I
vollbrecht[m] has quit [Quit: Idle timeout reached: 172800s]
RockBoynton[m] has joined #rust-embedded
<RockBoynton[m]> is there any way to change the defmt log level without needing to recompile every crate in the dependency graph that depends on it? I understand the benefit of compiling it out at compile time, but I just want to quickly rerun my app with different log filters without having to wait for for the recomplilation
<M9names[m]> no
ana_briated has left #rust-embedded [#rust-embedded]
dngrs[m] has joined #rust-embedded
<dngrs[m]> you could compile for the highest log level desired and filter things out on the receiving end