<re_irc>
<James Munns> Thanks again for knocking this out! It definitely fixes a long term paper cut :D
<re_irc>
<Lachlan Sneff> Something I'd be interested in taking a look in later on would be built-in booleans to bitfield serialization
fabic has joined #rust-embedded
<re_irc>
<Lachlan Sneff> Whatโs a decent way to share the i2c peripheral when using rtic? The shared-bus hands out proxies with a reference, but Iโm not sure how I could make that static
<re_irc>
<Lachlan Sneff> Oh, I found a good example, nvm
tokomak has joined #rust-embedded
emerent has quit [Ping timeout: 250 seconds]
emerent has joined #rust-embedded
emerent has quit [Remote host closed the connection]
emerent has joined #rust-embedded
fabic has quit [Ping timeout: 256 seconds]
fabic has joined #rust-embedded
Guest2 has joined #rust-embedded
dne has quit [Ping timeout: 268 seconds]
dne has joined #rust-embedded
VShell has joined #rust-embedded
edm has quit [Ping timeout: 268 seconds]
Rondom_ has quit [Ping timeout: 268 seconds]
Shell has quit [Ping timeout: 268 seconds]
darknighte has quit [Ping timeout: 268 seconds]
VShell is now known as Shell
Rondom has joined #rust-embedded
darknighte has joined #rust-embedded
edm has joined #rust-embedded
fabic has quit [Ping timeout: 256 seconds]
edm has quit [Ping timeout: 260 seconds]
edm has joined #rust-embedded
<re_irc>
pub trait Timer<const TIMER_HZ: u32> {
<re_irc>
<MathiasKoch> What is the "most" correct way to implement a trait like
<re_irc>
/// An error that might happen during waiting
<re_irc>
<ryan-summers> Why wouldn't you just truncate the u32 instead of modulo-ing it? E.g. bitwise and with u32::MAX and cast as u32? Alternatively, can't you just to "Self::now() as u32" to truncate to 32-bits?
<re_irc>
<ryan-summers> * do
<re_irc>
<ryan-summers> And libraries like "fugit" and "embedded-time" _should_ handle detection of overflow conditions as long as the duration is less than half of the full full-scale resolution
<re_irc>
<MathiasKoch> but.. would that work? "Self::now() as u32"?
<re_irc>
i would assume that once my actual timer goes above u32::max, every call to now would result in "u32::max"?
<re_irc>
<ryan-summers> Ah good point
<re_irc>
<ryan-summers> Well no,
<re_irc>
<ryan-summers> Hmmm
<re_irc>
<ryan-summers> I would mask with u32::MAX and then cast to avoid that
<re_irc>
<ryan-summers> Essentially just discard the upper 32-bits of the timer
<re_irc>
<ryan-summers> They're essentially just a counter on the amount of times the 32-bit portion has overflown anyways
<re_irc>
<MathiasKoch> Ahh, that would probably work yeah
<re_irc>
<MathiasKoch> Good point ๐๏ธ
<re_irc>
<MathiasKoch> Ahh, seems like that is actually the bahaviour of "as 32" on a u64
<re_irc>
<MathiasKoch> i wasn't sure if it truncated
<re_irc>
<MathiasKoch> Cool, thanks. (It does truncate.. But ofc. it truncates the bits, not the decimal value)
<re_irc>
<danielzfranklin> If I'm writing an embedded library that needs to index into an array based on a "u32" read from a binary protocol, is "as usize" the best way to do it? Maybe ideally I'd compile-error on platforms where "usize" is less than 4 bytes, but in practice does that even exist?
<re_irc>
<ryan-summers> there's plenty of 16-bit platforms out there still widely in use, see msp430 for example
<re_irc>
<ryan-summers> usize is only guaranteed to be pointable to internal device memory, not necessarily the memory space of some external chip (e.g. EEPROM). If you have known sizes and address space on the device, use a well-defined, compiler-platform-independent type for it
<re_irc>
<ryan-summers> If you intend your driver to be usable for 16-bit platforms that is
<re_irc>
<danielzfranklin> This array is known to be exactly "2^12", so I think "as usize" will also work on 16 bits (i.e. truncating won't give me the wrong element`)
<re_irc>
<ryan-summers> I deal with the same issue in C using an external EEPROM with an MSP430, and we intentionally don't use size_t to index into the EEPROM
<re_irc>
<danielzfranklin> ryan-summers: I use platform-independent types whenever possible but you can't index with them
<re_irc>
<ryan-summers> Ah that's an interesting point
<re_irc>
<ryan-summers> But if you had an 8-bit processor and an array of 2^12 size, it could never fit it in memory anyways
<re_irc>
<ryan-summers> So the compile would never work
<re_irc>
<danielzfranklin> My parser would need a major architectural refactor to be able to support not having all 2^12 bytes at once, which I don't think is worth it anyway
<re_irc>
<danielzfranklin> So maybe this is a case where I just need a comment reminding future me the as is valid only because of the size
starblue1 has quit [Ping timeout: 256 seconds]
fabic has joined #rust-embedded
starblue1 has joined #rust-embedded
<re_irc>
<MathiasKoch> I am looking for some minor guidance on STM32L4 DMA Serial :)
<re_irc>
<chrysn (@chrysn:matrix.org)> Can't answer that for UARTs; in network buffers there is often some concept of "high water marks", where at a queued write the level of the queue is measured, and if it exceeds some configured high water mark, some indication is sent back to reduce the data rate -- but there is still some headspace between high-water and queue-full to receive data in flight.
<re_irc>
<chrysn (@chrysn:matrix.org)> (Then, when data is processed and a low water mark is reached, signal is sent to resume transmission).
<re_irc>
<MathiasKoch> That sounds like exactly what i need here.. In my case i don't have control over the other end of the uart (SOC), but i do have the flow control available.. Would it be possible for me to somehow tell the uart/ the DMA to pause the peripheral RX?
<re_irc>
<chrysn (@chrysn:matrix.org)> I think you wouldn't pause RX, but set the flow control pin to indicate the peer to stop transmitting. RX would stay on (and hope that the peer pauses fast enough)
<re_irc>
<dirbaio> if you enable rts/cts the uart peri automatically deasserts RTS when its fifo gets full
<re_irc>
<dirbaio> you shouldn't have to do anything special even if using dma
<re_irc>
<ryan-summers> Yeah, I do something similar with SPI DMA, The peripheral actually negotiates with the DMA impl to flow control automatically
<re_irc>
<ryan-summers> Or at least it should, but you'd have to read about the DMA impl specifically
<re_irc>
<chrysn (@chrysn:matrix.org)> Good to know, sorry for spreading not-so-helpful references.
<re_irc>
<dirbaio> assuming "buf.read()" is the data read from uart, and "self.ingress.write()" is pushing that data to somewhere else in the system: maybe the issue is if "self.ingress.write()" returns "buffer full" you're throwing away the buffer with data in it, then immediately resupplying a new buffer to dma?
<re_irc>
<dirbaio> so uart never runs out of buffers so it never deasserts RTS, but you're throwing away data in software...?
<re_irc>
<dirbaio> hard to know without more context on the code
<re_irc>
<MathiasKoch> dirbaio: This is exactly my issue..
<re_irc>
<MathiasKoch> I can easily implement a "high water mark" check on self.ingress, but would it be enough to just not read the dma ("buf.read") in this case?
<re_irc>
<dirbaio> if you stop supplying buffers to DMA the uart fifo will fill up which should cause RTS to go high yep
<re_irc>
<dirbaio> and go low when you supply a buffer again later
<re_irc>
<MathiasKoch> Awesome.. Will give it a shot!
<re_irc>
<dirbaio> uart+dma never lose data with rts/cts enabled
<re_irc>
<dirbaio> * the uart+dma hardware never loses
<re_irc>
<dirbaio> maybe it's easier to have "ingress" itself pull the data from uart though
<re_irc>
<dirbaio> so if it goes slow it'll naturally cause dma/uart to stall without you having to do anything special
<re_irc>
<dirbaio> here you're "puliing" data from uart then "pushing" it to the ingress
<re_irc>
<dirbaio> mixing "push" and "pull" IO always ends up being messy in my exprience ๐
<re_irc>
<thejpster> I struggle with UART DMA for RX because I normally don't know how much data I want
<re_irc>
<thejpster> So I either DMA only one byte, or just pulling from the FIFO under interrupt into a ring buffer
<re_irc>
<adamgreig> I've often used the idle detection for this
<re_irc>
<adamgreig> DMA into a large buffer, on IDLE interrupt and disable DMA and read out the data
<re_irc>
<adamgreig> or, better, keep DMA going into a circular buffer and on IDLE interrupt read out the new data
<re_irc>
<thejpster> Oh, that's quite neat
<re_irc>
<adamgreig> IDLE will go after a single byte of space or whatever so for anything packetised (GPS packets in my case) it works nicely
<cr1901>
>But if you had an 8-bit processor and an array of 2^12 size, it could never fit it in memory anyways
<cr1901>
Are there 8-bits in practice that don't go up to 64kB of addr space?
* re_irc
chrysn (@chrysn:matrix.org) thinks once again that the classification into 8, 16 and 32 bit MCUs is a bit pointless, and the more relevant criterion is the memory bus size
Lumpio- has quit [Ping timeout: 252 seconds]
Lumpio- has joined #rust-embedded
<re_irc>
<ryan-summers> I mean it's a bit more nuanced, especially when you look at architectures like the MSP430, where it's actually a 20-bit address space, 16-bit PC, and special instructions to say if you're working over the 64KB boundary of a 16-bit device
<re_irc>
<ryan-summers> So memory bus size is _not_ necessarily everything from a computer engineering perspective
<re_irc>
<chrysn (@chrysn:matrix.org)> The precise questions to ask might be "what is the maximum number of items I can address in an array" (I think that's size_t -- and I'd guess still 16bit on that system?), and "how much memory does it take to store a pointer" (24 bit? 32 bit?)
<re_irc>
<chrysn (@chrysn:matrix.org)> (Of course, whether you can map some 4k stuff on external memory into a contiguous address space is yet another question.)
<re_irc>
<ryan-summers> Mapping memory still has to be done on the same memory bus, so you still have to be able to address it natively
<re_irc>
<ryan-summers> That's why ARM architectures tend to have big stretches of unused memory, as you can map external flash and such there
<re_irc>
<ryan-summers> But yeah, that's actually quite interesting. How would an MSP430 handle having 2^17 elements in an array?
<re_irc>
<ryan-summers> Technically, a usize should be 16-bit, but data can be larger than 16-bit...
<re_irc>
<ryan-summers> I imagine there's a soft requirement that an array cannot cross the 16-bit address space boundary?
<re_irc>
<chrysn (@chrysn:matrix.org)> Probably; the concept of "within an allocation unit" may become much more relevant there. (I always thought of this as "something malloc returned", but here it does bear meaning)
<re_irc>
<ryan-summers> I think current rust support for MSP430 only allows usage of the first 64KB anyways
<re_irc>
<ryan-summers> And in C you have to explicitly tell the compiler if something goes in the DATA20 memory space
<re_irc>
<ryan-summers> So it doesn't treat it as a contiguous link section, so I suspect your comment on "within an allocation unit" is correct
<re_irc>
<chrysn (@chrysn:matrix.org)> Hehe, so maybe the size of &T can stay 16bit even, as long as the T resides in a known data section :-D
<re_irc>
<chrysn (@chrysn:matrix.org)> (I doubt it works precisely in that way, but hey it might)
<re_irc>
<danielzfranklin> adamgreig: This sounds like exactly what I need. Do you mind if I ask you some architecture questions?
<re_irc>
Right now I'm writing a separate library for my gps that uses embedded-hal, and then using it. Should I just give up on embedded-hal? It seems to not support anything like this that's even vaguely clever.
<re_irc>
I had an alternative design idea where the library user gives the library the producer end of a tx bipbuffer and the consumer end of an rx bipbuffer, provides some callbacks for when data is received, and then is responsible for servicing the buffers and also calling a "do work" function in idle that gives the gps a chance to process the buffers and call callbacks.
<re_irc>
<dirbaio> yeah there's no embedded-hal trait for that
<re_irc>
<dirbaio> well you could impl the nb read one, but it's byte-by-byte which kinda defeats the point
<re_irc>
<adamgreig> I wasn't writing a portable driver so didn't have these concerns, but yea, embedded-hal doesn't cover more sophisticated uart than "transmit some data" or "receive some data"
<re_irc>
<adamgreig> I think implementing your portable driver as "here's struct that holds state, it has a function you should give data to whenever you have data, and a function to poll occasionally which might give you some data to transmit"
<re_irc>
<adamgreig> and leave the rest up to the user, would be my approach
<re_irc>
<danielzfranklin> Would you recommend against writing a portable driver?
<re_irc>
<adamgreig> (maybe require polling after giving data, too, or maybe the function to give it data may also return data to transmit)
<re_irc>
<adamgreig> let the user pass in individual bytes or large buffers or nicely segmented packets or whatever
<re_irc>
<dirbaio> with "buffered uart" like this, it makes lots of sense to impl the good old io traits (Read, Write)
<re_irc>
Except they're not no-std because they require io::Error
<re_irc>
<dirbaio> embassy has a copy of the io traits with a custom error due to that
<re_irc>
<dirbaio> and it has BufferedUart impls like that for nrf, stm32
<re_irc>
<dirbaio> (stm32 not using DMA though, probably coming soon)
<re_irc>
<danielzfranklin> adamgreig: So would the poll function return some struct containing either/both gps positions and statuses and bytes to transmit?
<re_irc>
<dirbaio> so you can write device-independent code using io::Read
<re_irc>
<dirbaio> that will work on embedded uart, or on std uart, or on a tcp connection or whatever
<re_irc>
<danielzfranklin> dirbaio: Interesting. I was planning on avoiding embassy because I didn't want to pull in all the async stuff at first so I could understand what was going on better
<re_irc>
<dirbaio> uart reading is inherently async though ๐
<re_irc>
<adamgreig> sure, yea, the poll can return both things
<re_irc>
<danielzfranklin> dirbaio: Yeah a better way of putting it was I wanted to do the work myself the first few times so I'd understand the abstractions better
<re_irc>
<adamgreig> I don't think your driver needs to specifically implement embassy or e-h traits, though async would probably simplify the implementation
<re_irc>
<adamgreig> I wish it was easier to have an internal async abstraction boundary, maybe it is?
<re_irc>
<adamgreig> like, for this, I'd write the driver with a completely sync interface ("fn poll()" and "fn new_data()"), but the internal state machine that processes new data would be very convenient to write with async and just tick
<re_irc>
<adamgreig> basically just having rust write the state machine handling for you
<re_irc>
<danielzfranklin> that makes a lot of sense. Currently reading is async and writing is sync, but I'm going to have to rip it all out anyway because the architecture didn't actually work that way
<re_irc>
<chrysn (@chrysn:matrix.org)> but what benefit does a local executor that only operates on a single task have over the task blocking internally?
<re_irc>
<adamgreig> it's more convenient to write the code, is all
<re_irc>
<chrysn (@chrysn:matrix.org)> (the state machine would just be trading dynamic stack for something big allocated on the stack)
<re_irc>
<dirbaio> adamgreig: that's totally possible, you can wrap a "polling" nonasync api into an async api easily
<re_irc>
you need the nonasync api to provide some "callback" so you can wake the async waker though
<re_irc>
<chrysn (@chrysn:matrix.org)> adamgreig: if one wants to do it on an external async later, yes
<re_irc>
<adamgreig> dirbaio: why? I just want the user to occasionally call a function that feeds in new data, then it processes it all
<re_irc>
<dirbaio> ah, for writing
<re_irc>
<dirbaio> still, you'll somehow have to handle "can't write now, buffer full"
<re_irc>
<adamgreig> I don't follow
<re_irc>
<adamgreig> I'm talking about, say, a parser
<re_irc>
<adamgreig> where you feed in &[u8] whenever you have new data available, synchronously
<re_irc>
<adamgreig> and it might be 1 byte or 1000 bytes or whatever, and I want to process it essentially byte-by-byte as I decode a packet or whatever
<re_irc>
<adamgreig> a normal C option is you write a little state machine that moves through states as it parses each byte
<re_irc>
<dirbaio> ahhhh so the opposite
<re_irc>
<dirbaio> use async internally but have an external sync api
<re_irc>
<adamgreig> yea, exactly
<re_irc>
<adamgreig> I think you can do this if you just have your external api be basically loop { poll.is_ready } or whatever
<re_irc>
<dirbaio> yeah that's what generators are supposed to be used for
<re_irc>
<adamgreig> but it doesn't seem super convenient?
<re_irc>
<dirbaio> rust async is a layer "on top of" generators
<re_irc>
<adamgreig> right, I guess that's what I'm waiting for :P
<re_irc>
<danielzfranklin> adamgreig: What if I want the driver to work at a level of abstraction where I can say something like "gps.read_logged_points()". To do that it needs to send the device a request, then read responses, so if the write buffer is full it has to block/error
<re_irc>
<dirbaio> you can kinda abuse async to simulate generators in rust stable yeah
<re_irc>
<dirbaio> it's kinda gross because when you feed in "new data", there's no way to make it "magically appear" in the async code in an .await point
<re_irc>
<dirbaio> so you need to "share" it from the outside with a refcell or similar
<re_irc>
<danielzfranklin> Instead read_logged_points returning a generator I was thinking I'd just have it call a driver-global callback you provide when initializing it. Not ideal but good enough
<re_irc>
<dirbaio> plus you need to pin the parser (this'll still be the case with generators though)
<re_irc>
<marmrt> I am having issues with setting the defmt logging level on WSL. No matter what I seem to do I only get error logging. Using Powershell it works fine.
<re_irc>
<dirbaio> what command(s) are you running?
<re_irc>
<marmrt> export DEFMT_LOG=debug
<re_irc>
cargo run
<re_irc>
with probe-run as my runner
<re_irc>
<marmrt> I've also tried
<re_irc>
DEFMT_LOG=debug cargo run
<re_irc>
<dirbaio> both should work yep
<re_irc>
<dirbaio> are you using defmt 0.3?
<re_irc>
<dirbaio> if you change the envvar can you see it rebuilding?
<re_irc>
<marmrt> It does not rebuild
<re_irc>
<dirbaio> ie if you run "DEFMT_LOG=debug cargo run" it builds+flashes
<re_irc>
then you run "DEFMT_LOG=debug cargo run" again, it instantly goes to flashing because it's already built
<re_irc>
but if you run "DEFMT_LOG=info cargo run" then it still instantly goes to flashing?
<re_irc>
I think the issue is in the way WSL-windows interacts. My cargo installation is on Windows, so it apparently isn't aware of WSL environment variables, yet when running it from the WSL terminal it isn't aware of Windows env variables either
<re_irc>
<luojia65> happy Chinese New year :)
<re_irc>
<dirbaio> ah oof you're running windows cargo from inside wsl?
<re_irc>
<dirbaio> maybe you can install linux cargo inside wsl and use that
<re_irc>
<marmrt> yep
<re_irc>
<danielzfranklin> If you just want to change it semi-permanently marmrt you could try making a file ".cargo/config.toml" in your project directory with
<re_irc>
[env]
<re_irc>
DEFMT_LOG = "info"
<re_irc>
<Lachlan Sneff> danielzfranklin: Iโve been trying to figure out how to do this! Thank you!
<re_irc>
<dirbaio> be careful though, that's buggy, it doesn't always rebuild if you change it :D
fabic has quit [Ping timeout: 268 seconds]
Guest2 has quit [Ping timeout: 256 seconds]
xnor has quit [Quit: WeeChat 3.4]
xnor has joined #rust-embedded
<cr1901>
> I think current rust support for MSP430 only allows usage of the first 64KB anyways
<cr1901>
I have no idea even in C how to use the upper 64kB
<Lumpio->
Maybe there's a long pointer type or something in C
<Lumpio->
Or "far"
<Darius>
it uses 20 bit pointers for >64kb parts
<re_irc>
<thejpster> Nothing in C says function pointers have to be the same size as data pointers.
<re_irc>
<chrysn (@chrysn:matrix.org)> On Atmel chips, a pointer to a string in flash could even have a different size than a pointer to a string in RAM. (Not sure if there are actual differences, but the buses are split enough that there could be).
tokomak has joined #rust-embedded
<re_irc>
<dalepsmith> thejpster: Or even in the same address-space
<re_irc>
<chrysn (@chrysn:matrix.org)> Gets cast to the same int? Doesn't mean it's the same thing.
<cr1901>
I think Rust has to handle addr spaces invisibly in order for AVR to work