<re_irc>
<thejpster> 7pm UTC+0100 on Friday. Iโm chatting with the legends that are Bil Herd and Ben Jordan.
<re_irc>
<K900> Ooooh
<re_irc>
<K900> That is one hell of a cast
<re_irc>
<thejpster> Desperately thinking of a way Bil can sign my C128D remotelyโฆ
<re_irc>
<James Munns> Got a pen plotter?
b00bl1k has joined #rust-embedded
b00bl1k has quit [Remote host closed the connection]
<cr1901>
Pen plotter... Holy crap, that's an amazing idea
<re_irc>
<firefrommoonlight> Let's say we're reading from a few ADC channels. So, not a lot of data. We don't need it that often. Are there significant pros/cons to:
<re_irc>
- A Make blocking reads of the channels when we need it
<re_irc>
- Start a circular DMA transfer, with the ADC configured with a sequence, in continuous mode
<re_irc>
<firefrommoonlight> My intuition says it probably doesn't matter, and the latter has the advantages of never troubling the CPU after init. Although the CPU will probably be in use on the order of ns or w/e
<re_irc>
<firefrommoonlight> Of note, I've tried both, and both approaches _work_ for my use case
<re_irc>
<firefrommoonlight> My intuition says it probably doesn't matter, and the latter has the advantages of never troubling the CPU after init. You just read the static buffer when you need data, without asking the ADC for anything. Although the CPU will probably be in use on the order of ns or w/e
<re_irc>
<adamgreig> yea, I'd have the ADC continually convert into a buffer with one reading per channel and just grab the most recent reading whenever i wanted it
<re_irc>
<adamgreig> less wasted time, and you can leave the adc sample time nice and long
<re_irc>
<adamgreig> but whatever, it's a bit more code work setting up the dma, so for a super simple example or something just doing a blocking sample is fine
<re_irc>
<firefrommoonlight> *Of note, there's also an intermediate approach of command reading, and storing the value somewhere in its conversion-complete interrupt
<re_irc>
<firefrommoonlight> * reading when needed,
<re_irc>
<firefrommoonlight> I guess, DMA seems like the least-blocking approach, but seems overkill for reading a few channels at low rate
<re_irc>
<firefrommoonlight> I appreciate the insight
<re_irc>
<adamgreig> probably just doing the blocking conversions is lower power, when that's a concern
<re_irc>
<firefrommoonlight> Oh yea!
<re_irc>
<firefrommoonlight> Great point. Definitely
<re_irc>
<firefrommoonlight> In the current use case, power isn't a concern
<re_irc>
<firefrommoonlight> With the continuous DMA xfer, the ADC is powered on and working uh... continuously
<re_irc>
<firefrommoonlight> and the large majority of readings are discarded, which is I guess why it feels weird
<re_irc>
<James Munns> firefrommoonlight most MCUs have some way of triggering a sample conversion from a timer or something
<re_irc>
<James Munns> so you can start the DMA, but not in a freerunning conversion, only one that gets triggered on a timer, and then you can check it every N samples (the DMA length) or whatever
<re_irc>
<James Munns> Or:
<re_irc>
- Sleep all the time
<re_irc>
- Have a periodic timer interrupt fire to start a conversion
<re_irc>
<James Munns> Conversions don't usually take THAT long (10s-100s of uS), but I guess it can matter on a battery, so you don't want to spin while it's working
<re_irc>
<dirbaio> or use async: "adc.read().await", CPU sleeps automatically while waiting for the adc read ๐
<re_irc>
<James Munns> I'm gunna stop answering questions when dirbaio is online ๐
<re_irc>
<dirbaio> ๐
<re_irc>
<James Munns> I'll have to wake up at like 6am CEST to avoid "just do it async" retorts
<re_irc>
<James Munns> but yes, using an existing driver/async configuration like embassy would achieve my suggestion.
<re_irc>
<dirbaio> (not joking now) am I unhelpful or annoying? if so I'll stop!
<re_irc>
<James Munns> I mean
<re_irc>
<James Munns> you're never wrong
<re_irc>
<James Munns> but yeah, it's... a common refrain lol
<re_irc>
<James Munns> I'm sold on async!
<re_irc>
<James Munns> but as I was writing it up, I KNEW you were gunna respond with that
<re_irc>
<dirbaio> ๐
<re_irc>
<firefrommoonlight> James Munns: That's a good pt. Basic timers on STM32 are perf for this
<re_irc>
<firefrommoonlight> To settle my irrational nerves about "waste"
<re_irc>
<firefrommoonlight> *In this particular use, there is no sleeping
<re_irc>
<James Munns> if you're not on a battery: it literally doesn't matter
<re_irc>
<James Munns> oh
<re_irc>
<James Munns> then yeah, just sample whenever lol
<re_irc>
<firefrommoonlight> Although for other use cases that may come up in the future, it would be wise to only convert when needed!
<re_irc>
<firefrommoonlight> So, it is on battery, but there are power draws from motors that dwarf the MCU
<re_irc>
<James Munns> lol
<re_irc>
<James Munns> I had a customer like that once that was REALLY worried about MCU power draw
<re_irc>
<James Munns> and they had big old multi-amp motors on the same thing lol
<re_irc>
<James Munns> I convinced them the MCU was the least of their power budget problems.
<re_irc>
<James Munns> (I think like 24 hours of MCU power at max speed/all on was something like 1 second of operating power from the motor or something)
<re_irc>
<James Munns> but yeah
<re_irc>
<James Munns> I'd probably say:
<re_irc>
- use async, OR
<re_irc>
- use a timer to do the conversion, break it into two steps if the blocking for a few micros really bothers you
<re_irc>
<firefrommoonlight> lol!
<re_irc>
<James Munns> the former is really easy in embassy, the latter is really easy in RTIC
<re_irc>
<firefrommoonlight> I _am_ using rtic
<re_irc>
<firefrommoonlight> I have it currently set up with the continuous xfer; may throw the timer on instead
<re_irc>
<firefrommoonlight> I've done taht with DAC before; was p easy
<re_irc>
<James Munns> yeah, you might not even need a(n extra) timer. Set a task to trigger every whatever N ms, then a hardware task that catches the "conversion done" interrupt.
<re_irc>
<James Munns> whats your sample rate?
<re_irc>
<firefrommoonlight> I'm looking for the data ~1.6kHz
<re_irc>
<firefrommoonlight> Could probably go slower
<re_irc>
<firefrommoonlight> *Of note, I did set the ADC sample time to max as AGG suggested
<re_irc>
<James Munns> yeah, check out what your conversion time is for that precision or whatever
<re_irc>
<firefrommoonlight> haven't run the numbers on what its' actually sampling at with that set
<re_irc>
<firefrommoonlight> *Ah yea, that loop actually has some %-based subdivisions already
<re_irc>
<James Munns> 1.6khz means a sample every 625 uS
<re_irc>
<James Munns> so if your sample and conversion rate (that you would block on) is like... 500uS
<re_irc>
<James Munns> that's bad
<re_irc>
<firefrommoonlight> Of note, these readings are "FYI" readings only; not critical to operation
<re_irc>
<firefrommoonlight> And not timing critical
<re_irc>
<firefrommoonlight> Good pt; I may be sampling faster than I think rel to conv time
<re_irc>
<James Munns> yeah, take a look at your datasheet and figure out what times you're working with :)
<re_irc>
<James Munns> you'll be able to calculate sample + conversion times, and what steps you can get interrupts for.
<re_irc>
<firefrommoonlight> Yea; of note, I have this set up for 2 MCUs (G4 and H7). STM32 ADC sample time reg is same for most/all STM32s (well, most of the ADC periph is actually), but what the sample time bits correspond to is quite diff!
<re_irc>
<James Munns> or: yeah, start a DMA for 1600 samples or whatever, trigger a conversion every 625us with the timer, and process all the data (for FFT or smoothing or whatever) once a second.
<re_irc>
<James Munns> (or some subdivision thereof)
<re_irc>
<James Munns> that way your CPU isn't getting involved with the sample-to-sample timing, leaving you free to sleep or whatever the whole time.
<re_irc>
<firefrommoonlight> *Actually I think the sample time is the same for G4 and H7 in terms of # of clock cycles, but the clock cycles obv mean diff things
<re_irc>
<firefrommoonlight> +setting
<re_irc>
<James Munns> yeah, you'll probably have to do the math for that :D
<re_irc>
<James Munns> but do the math!
<re_irc>
<James Munns> then you can figure out what the rest of your timing budget is
<re_irc>
<firefrommoonlight> Yea great point. Timing budget is critical overall for this program
<re_irc>
<firefrommoonlight> since there are several competing processes that need low latency
<re_irc>
<James Munns> yaaaay I get to share my "oft repeated advice" too!
<re_irc>
<James Munns> Know how long (roughly) all the important things you do take, then figure how much of that is idle (e.g. wait for conversion) vs active (e.g. doing math), then work backwards from there
<re_irc>
<James Munns> it's an architecture planning thing, and necessary regardless of main loop/rtic/embassy.
<re_irc>
<James Munns> (how you juggle all the things is the next architecture step, and is guided by timing and requirements)
<re_irc>
<firefrommoonlight> Solid. Taking it big picture like that... I probably shouldn't stress over this particular part too much!
<re_irc>
<James Munns> Yeah!
<re_irc>
<James Munns> writing all the bits down, you'll know EXACTLY where the albatross is
<re_irc>
<James Munns> and where 1/2 the resolution will be a game changer, and where 10x the resolution is peanuts.
<re_irc>
<James Munns> like, for serious timing projects, I usually have a spreadsheet for all that stuff:
<re_irc>
<firefrommoonlight> That'll probably come up soon
<re_irc>
<James Munns> how long ADC conversion takes, how long typical SPI/I2C messages take, what frequency do they each occur, etc.
<re_irc>
<James Munns> that'll give you a sixth sense, especially if you have to negotiate/tweak requirements with a customer.
<re_irc>
<James Munns> like, you can turn the dial from 1.6khz to 3.2kHz and know (ballpark) whether thats easy, possible, risky, or impossible.
<re_irc>
<firefrommoonlight> I'm a bit worried (esp on G4 vice H7) that once I activate teh onboard radio circuit, it will fight with the main sensor-reading/control loop
<re_irc>
<firefrommoonlight> (Currently using an offboard radio circuit over UART)
<re_irc>
<James Munns> honestly, you should know exactly how long all that stuff takes.
<re_irc>
<James Munns> if you have (in the worst case) 1200ms of stuff to do per second, you'll be in trouble.
<re_irc>
<James Munns> don't necessarily worry about getting all the times exact
<re_irc>
<James Munns> give yourself a healthy fudge factor/overhead. If it still clears the "stuff/second" mark, you're good!
<re_irc>
<James Munns> You know when you start getting over 40-50% though: you need to either firm up your estimates and cutting some of the fudge factor, or cutting functionality.
<re_irc>
<James Munns> watching that number (and maybe remembering the peak) during dev/testing, will also tell you when you start getting close to the danger zone
<re_irc>
<firefrommoonlight> Great points!
<re_irc>
<firefrommoonlight> I don't have any calculation metrics yet :(
<re_irc>
<firefrommoonlight> This is an IO-heavy program (drone firmware)
<re_irc>
<firefrommoonlight> But there aren't many CPU-intensive parts
<re_irc>
<firefrommoonlight> Obv the H7 will have WAY MORE cpu power than G4 variant
<re_irc>
<firefrommoonlight> But I think it will work out fine on both
<re_irc>
<James Munns> sure! But you know how much data you're sending, and how fast it is, right?
<re_irc>
<firefrommoonlight> Yep
<re_irc>
<James Munns> then you know the time spent sending/receiving
<re_irc>
<James Munns> then the only answer is "how much of that is idle vs active"
<re_irc>
<firefrommoonlight> Just don't know how long the CPU stuff takes to compute
<re_irc>
<James Munns> where ser/de is active, but DMA is idle.
<re_irc>
<James Munns> Measure!
<re_irc>
<firefrommoonlight> I'm using DMA whenever possible
<re_irc>
<firefrommoonlight> Circular transfers in a lot of cases, so I don't have to mess with the IO periphs
<re_irc>
<firefrommoonlight> yea need to
<re_irc>
<James Munns> find a bunch of representative messages, spam them from your PC, and figure out how long you spend processing like 1M messages
<re_irc>
<James Munns> then divide by 1M, multiply by three, and call that your current per-message estimate.
<re_irc>
<firefrommoonlight> Good call; need to add that to my toolbox
<re_irc>
<James Munns> Or some times you don't even need a PC
<re_irc>
<James Munns> like, when I'm measuring ser/de performance, I'll usually just make one of the biggest/most complicated messages
<re_irc>
<James Munns> time how long it takes to serialize 1M times, then time how long it takes to deser 1M times
<re_irc>
<James Munns> then those become my "worst case" estimates
<re_irc>
<James Munns> (just make sure you "black_box" the data or whatever so it doesn't get optimized out)
<re_irc>
<James Munns> doing this with stuff like control loops is possible too
<re_irc>
<James Munns> esp if you have HF and have more deterministic math timing. You'll basically just be counting how many MAdds you are doing per cycle.
<re_irc>
<firefrommoonlight> Also, my control loops don't work too good lol
<re_irc>
<firefrommoonlight> That's top pri
<re_irc>
<firefrommoonlight> Ie aircraft crashes on launch
<re_irc>
<James Munns> You've got the first part of "throw yourself at the ground and miss" going, that's progress :D
<re_irc>
<firefrommoonlight> lol
<re_irc>
<James Munns> but yeah, "measure how long stuff takes currently", multiply it by 2x-4x, and update that number whenever you change some algo is a pretty quick and easy way to keep your spreadsheet up to date
<re_irc>
<James Munns> it doesn't have to be super precise formal. You're just keeping yourself honest with a bit of napkin math.
<re_irc>
<James Munns> +and/or
<re_irc>
<firefrommoonlight> My fav type of math
<re_irc>
<James Munns> Get nervous when it goes over 50% of your budget, and get scared when it goes over 80%. Then figure out how to calm yourself down with better measurements or changing how you do things (or converting some of that "active time" into "idle time")
<re_irc>
<James Munns> but it's also good for moving quick:
<re_irc>
<James Munns> if you do the math, and everything (even all the "idle time") fits in your budget: Hooray!
<re_irc>
<James Munns> It means you don't need DMA or interrupts at all!
<re_irc>
<James Munns> And your life is 10x easier!
<re_irc>
<firefrommoonlight> Gotta run for now, but apprecaite all the advice!
<re_irc>
<firefrommoonlight> Have some refactoring and measurement to do
<re_irc>
<James Munns> like if you are doing 2k "control loops" per second, and your worst case "control loop" time is << 500us, then just write a "loop { }"!
<re_irc>
<James Munns> Good luck!
<re_irc>
<James Munns> I should make a dummy spreadsheet showing how I do timing analysis at some point. It seems like it would be helpful for folks.
<re_irc>
<firefrommoonlight> Thanks!
<re_irc>
<firefrommoonlight> Yea, that would be great