tokomak has quit [Read error: Connection reset by peer]
ymwm has joined #rust-embedded
ymwm has quit [Client Quit]
<re_irc>
<firefrommoonlight> Don't know if it's in EH yet, but you could set up a buffer of "[u8; 6]", start a DMA transfer, then fire an interrupt on Transfer Complete
Guest2 has joined #rust-embedded
skunkjoe has joined #rust-embedded
<re_irc>
<romen> This might be a dumb question, but I cannot manage to find an answer online: when using "embedded_hal::digital::v2" is there any guarantee on blocking behavior? e.g. I have a loop like this to scan a keypad matrix:
<re_irc>
<romen> This might be a dumb question, but I cannot manage to find an answer online: when using "embedded_hal::digital::v2" is there any guarantee on blocking behavior? e.g. I have a loop like this to scan a keypad matrix:
<re_irc>
<chrysn (@chrysn:matrix.org)> If you're reading electrical states, that's nothing the HAL alone can help you with: Even if the MCU has completed its setting of the pin to "high", there may be any number of capacities that need to be filled until a connected input will read the "high" signal.
<re_irc>
<chrysn (@chrysn:matrix.org)> I think it is the expectation that the operation would "block" until the pin is set, but that alone is not enough, and you'll need to determine the electrical properties of your "data" lines (or just find an estimate that is good enough, as 1ms you just used).
<re_irc>
<K900> That's the only thing you can do really
<re_irc>
<K900> Even reading the "electrical state" of the pin will give you a point measurement at the pin itself, which does not necessarily represent the rest of the circuit
<re_irc>
<romen> but aren't delays going to change depending on the MCU, dev_board, and wiring?
<re_irc>
<K900> You can't really treat things as being digital at that level
<re_irc>
<chrysn (@chrysn:matrix.org)> Yeah, but the point is "wiring".
<re_irc>
<K900> You're knee deep in non-deterministic analogue fuckery
<re_irc>
<K900> You just have to accept it, really
<re_irc>
<romen> K900: It's so hard to let go of my fully digital abstractions :)
<re_irc>
<chrysn (@chrysn:matrix.org)> The HAL can at most make statements up to the MCU's chip boundary; if you're depending on thinsgs like wires outside that boundary, you'll need to feed your application with the information to deal with it.
<re_irc>
<K900> It is, yes
<re_irc>
<K900> But when you're wiring things by hand, you don't really have other options
<re_irc>
<burrbull> In most cases just into_alternate
<re_irc>
<xiretza> right, it should be able to infer it if you actually pass the pin to something that needs a specific alternate mode.
<re_irc>
<yruama_lairba> sorry, i was unclear, i don't understand to what correspond the "3".
<re_irc>
<xiretza> yruama_lairba: it's the alternate mode that you want the pin to be in, as specified in the RM
<re_irc>
<xiretza> but you probably don't need to specify it at all
<re_irc>
<ryan-summers> monacoprinsen: As previously mentioned, this is based almost entirely around application requirements. Different vendors are known for different things and lend themselves better to different projects. Nordic is well-established in terms of bluetooth + wireless device stacks, as well as low power devices, while ST is well suited towards mass-market products and general purpose devices. MSP430 has been around...
<re_irc>
... forever, so lends itself well to high reliability, etc. but primarily, you're looking at what the MCU offers you and what your product needs. The vendor's reputation is a small part in the overall selection process
<re_irc>
<ryan-summers> Also, what tooling and support are available for various platforms is important as well
<re_irc>
<dirbaio> because by then UB has already happened
<re_irc>
<GrantM11235> What is the best way to fix that? Replace the buffer reference with a special type that only does volatile reads?
<re_irc>
<firefrommoonlight> GrantM11235: If you do something with that reference, yes
<re_irc>
<firefrommoonlight> (This is called a double buffer btw, and is very useful in some cases)
<re_irc>
<dirbaio> GrantM11235: that would kill performance by preventing the compiler to optimize stuff
<re_irc>
<firefrommoonlight> Make sure your code is sequence properly, and that whatever you're doing with the CPU doesn't take longer than it takes the buffer to flip etc
<re_irc>
<dirbaio> and I'm still not sure if that'd fix the UB... is it UB for a volatile read/write to race with DMA?
<re_irc>
<GrantM11235> firefrommoonlight: I think it is UB even if you never do anything with the reference
<re_irc>
<firefrommoonlight> ASs long as it doesn't win the race
<re_irc>
<firefrommoonlight> *I mean it's fine as long as it loses the race lol
<re_irc>
<dirbaio> yeah, just the reference _existing_ means nothing else can modify that memory, otherwise it's UB
<re_irc>
<dirbaio> GrantM11235: one fix is to have code explicitly start DMA into the other half when the closure is done with it, so if the closure takes too long it simply stops
<re_irc>
<firefrommoonlight> General idea to do this safely:
<re_irc>
- Set up the buffer as a static mut, of twice your block size
<re_irc>
- Start the transfer with a circular buffer
<re_irc>
- Set up DMA interrupts on half transfer, and transfer complete
<re_irc>
<firefrommoonlight> If the code that's doing the reading or writing takes long than it takes the buffer to flip, UB happens
<re_irc>
<firefrommoonlight> For example, with audio, your audio might turn into garbage noise
<re_irc>
<dirbaio> firefrommoonlight: that's exactly what we're trying to avoid
<re_irc>
<GrantM11235> dirbaio: I don't think you can do that with the stm32f1 circular dma
<re_irc>
<firefrommoonlight> (Or if you try to do something with the "static mut" not part of what I listed, you'll obviously get UB)
<re_irc>
<dirbaio> and "UB" doesn't mean "that particular data gets corrupted"
<re_irc>
<dirbaio> it means "the whole program execution gets corrupted and is completely invalid"
<re_irc>
<firefrommoonlight> +while the transfer is happening,
<re_irc>
<firefrommoonlight> Oh nvm, I'm using it here to mean the data gets corrupted
<re_irc>
<dirbaio> DMA modifying data while a rust reference exists to it is _by definition_ UB
<re_irc>
<firefrommoonlight> I think UB in the way dirbaio suggested couldn't happen if the buffer is static
<re_irc>
<dirbaio> and UB _by definition_ means anything can happen
<re_irc>
<dirbaio> the compiler is allowed to assume nothing else touches that memory
<re_irc>
<dirbaio> and do any optimization based on that
<re_irc>
<dirbaio> * assuming that holds
<re_irc>
<dirbaio> with zero regards to the consequences if it doesn't hold
<re_irc>
<dirbaio> for example
<re_irc>
<dirbaio> the compiler would be allowed to emit code like this
<re_irc>
<dirbaio> let a = buf[0];
<re_irc>
let b = buf[0];
<re_irc>
if a != b { loop {} }
<re_irc>
<dirbaio> so
<re_irc>
<dirbaio> * because it knows buf[0] can't change while it has a &mut or & to it
<re_irc>
<dirbaio> that compilation is 100% correct
<re_irc>
<dirbaio> of course the compiler won't emit that code, it'd be stupid
<re_irc>
<firefrommoonlight> Good explanation
<re_irc>
<dirbaio> but you can have similar effects with optimizations around loops and maths and stuff
<re_irc>
<GrantM11235> or "if a != b { unsafe { flip_random_bit_in_ram() } }"
<re_irc>
<firefrommoonlight> Does "compiler_fence" happen in that case
<re_irc>
<firefrommoonlight> * prevent that?
<re_irc>
<dirbaio> so here "UB" doesn't just mean "data might be garbage", it means "anything", literally anything
<re_irc>
<dirbaio> the program might hang, might panic, might corrupt other memory, might rewrite itself to become a minesweeper AI...
<re_irc>
<dirbaio> :D
<re_irc>
<dirbaio> compiler_fence doesn't avoid this
<re_irc>
<dirbaio> GrantM11235: yeah, I think it's impossible to wrap the circular DMA into a safe Rust API
<re_irc>
<GrantM11235> For the record, I want to read the adc at a constant rate of about 1 mhz without jitter or missed samples
<re_irc>
<firefrommoonlight> Circular DMA + continuous mode sounds like the way to go
<re_irc>
<GrantM11235> dirbaio: What about with volatile reads? That would prevent some optimizations but the performance might still be ok
<re_irc>
<dirbaio> oof
<re_irc>
<GrantM11235> Is there a crate for working with volatile arrays?
<re_irc>
<dirbaio> volatile is _rough_, it means the compiler can't reorder, can't merge 4 u8 reads into a u32 read, can't use memcpy..
<re_irc>
<dirbaio> I mean, sure, try it
<re_irc>
<dirbaio> but it's a quite hardcore solution to have it as a general solution for the HAL imo :D
<re_irc>
<thalesfragoso> I don't think volatile makes a difference, the problem is stopping the user from touching the half of the thing
<re_irc>
<thalesfragoso> +before the DMA goes around
<re_irc>
<dirbaio> is DMA racing with volatile reads still UB?
<re_irc>
<dirbaio> I have no idea
<re_irc>
<dirbaio> I would guess it isn't, but it's just a guess
<re_irc>
<thalesfragoso> Probably not UB at the compiler, but you will probably read garbage
<re_irc>
<dirbaio> yeah it's still a bad API because you can get garbage and not notice it...
<re_irc>
<thalesfragoso> On STM we got a trick to write an invalid value to the DMA ptr that isn't being used and then call an user closure
<re_irc>
<thalesfragoso> After the closure we write the correct one back
<re_irc>
<thalesfragoso> If the closure takes too long you get a hardfault
<re_irc>
<GrantM11235> dirbaio: You can still check for an overrun after you process half the buffer. You may have lost some samples, but at least you can know it happened after the fact
<re_irc>
<thalesfragoso> And about re-ordering, you solve that with fences/compiler_fences
<re_irc>
<thalesfragoso> GrantM11235: But that's race by default and could cause some false positives
<re_irc>
<dirbaio> fences won't prevent UB if racing normal reads with DMA
<re_irc>
<dirbaio> can't you "emulate" double buffer with the M0AR/M1AR regs?
<re_irc>
<thalesfragoso> dirbaio: I think it would be the same case as the volatile, probably not very UB at the compiler level, but still, garbage
<re_irc>
<dirbaio> it's definitely UB
<re_irc>
<thalesfragoso> But like I said, you want to write an invalid addr to the DMA before
<re_irc>
<thalesfragoso> dirbaio: It's the same as with volatile, which is still UB in theory
<re_irc>
<thalesfragoso> A data race is UB, with volatile or not
<re_irc>
<dirbaio> yeah..
<re_irc>
<dirbaio> oof, F1 doesn't have M0AR/M1AR ??
<re_irc>
<thalesfragoso> Oh, F1 doesn't have double buffer mode
<re_irc>
<thalesfragoso> So, nope, forget about it, no safe way
<re_irc>
<thalesfragoso> You can check later and panic/report to the user, but two problems with that
<re_irc>
<dirbaio> you could swap the buffers from the irq
<re_irc>
<thalesfragoso> The check is race, and you will only know have the data race occurred
<re_irc>
<thalesfragoso> dirbaio: I don't think you can touch the pointer with the DMA running on the F1
<re_irc>
<dirbaio> no, when it has finished
<re_irc>
<thalesfragoso> On F4 and others, you have double buffer mode with two pointers
<re_irc>
<dirbaio> restart it against the other buffer as fast as possible
<re_irc>
<thalesfragoso> dirbaio: It doesn't finish with circular
<re_irc>
<dirbaio> no ciruclar
<re_irc>
<thalesfragoso> Yeah, not really circular
<re_irc>
<thalesfragoso> Ok, I thought the use case needed circular
<re_irc>
<dirbaio> start normal DMA against buffer1, wait for it to finish
<re_irc>
start normal DMA against buffer2, give buffer1 to the closure, when closure returns set a flag "OK to swap to buffer1"
<re_irc>
etcetc
<re_irc>
on irq, check flag, restart normal DMA against buffer1
<re_irc>
<thalesfragoso> I think the F1 HAL does that, panics if a data raced occured, but it's the best
<re_irc>
<dirbaio> as long as the irq is fast enough you shouldn't lose data..?
<re_irc>
<thalesfragoso> dirbaio: It depends on the application
<re_irc>
<thalesfragoso> Check after the data race (UB) occured
<re_irc>
<dirbaio> that's unsound
<re_irc>
<thalesfragoso> Of course
<re_irc>
<GrantM11235> Can the half-transfer / transfer-complete interrupts be used to stop access to half of the buffer before it starts getting rewritten?
<re_irc>
<thalesfragoso> Tbh, I would just go with a chip with a double buffered DMA if I needed circular/countinuous
<re_irc>
<thalesfragoso> * circular/continuous
<re_irc>
<thalesfragoso> If you control the interrupt, like in embassy, you might be able to do in some cases, but again, it depends of the DMA rate
<re_irc>
<thalesfragoso> * on
<re_irc>
<GrantM11235> thalesfragoso: I am writing some new firmware for the dso-138 mini-oscilloscope, so I am stuck with the stm32f103
<re_irc>
<thalesfragoso> GrantM11235: I mean, you wouldn't be able to stop the user from touching the buffer, best you can do is panic
<re_irc>
<dirbaio> wow out of all BDMA chips, only H7 and L5 can doublebuffer
<re_irc>
<thalesfragoso> GrantM11235: I would probably go the unsound route and check after the fact, but don't quote me on that
<re_irc>
<thalesfragoso> If you're doing a firmware to yourself, not a library
<re_irc>
<dirbaio> this'd be a nice addition to embassy
<re_irc>
<dirbaio> shouldn't be too hard because it owns the irqs
<re_irc>
<dirbaio> and we'll need it for DMA-based BufferedUart too..
<re_irc>
<dirbaio> so, it seems only F2, F4, F7, H7, L5 can do native double-buffered mode??
<re_irc>
<dirbaio> WTF ST
<re_irc>
<dirbaio> and all other chips can do the crap "circular" mode that's impossible to wrap safely, yay
<re_irc>
<GrantM11235> dirbaio: You mean doing a linear dma and switching the buffer in the transfer-complete irq?
<re_irc>
<dirbaio> yeah
<re_irc>
<GrantM11235> dirbaio: There must be _some_ way to safely wrap it, even if the performance is not very good
<re_irc>
<dirbaio> well if you know one I'm all ears 😂
<re_irc>
<dirbaio> you want to sample ADC at 1Mhz?
<re_irc>
<GrantM11235> Yeah, but I might need to settle for 0.857mhz
<re_irc>
<thalesfragoso> Can you even write to the display before the things wraps ?
<re_irc>
<thalesfragoso> If you're just doing N samples, stopping and then displaying, you don't really need circular
<re_irc>
<GrantM11235> I am using a small buffer for dma, then I scale and downsample the samples and put them in a big buffer
<re_irc>
<thalesfragoso> GrantM11235: But don't you have to stop the DMA eventually ? It's always racing with the display
<re_irc>
<thalesfragoso> And if the display is slower than the DMA, eventually you will lose to it
<re_irc>
<GrantM11235> After the signal crosses the trigger threshold, I continue sampling for half the large buffer size, then I stop the dma and display the data in the big buffer
<re_irc>
<GrantM11235> I need to downsample before putting the data in the big buffer because the adc always needs to run at 1mhz to prevent aliasing
<re_irc>
<monacoprinsen> ryan-summers: Thanks!
<re_irc>
<GrantM11235> Currently I am not updating the display at all until I finish sampling, but in the future I might start updating the display as soon as the trigger is detected
<re_irc>
<thalesfragoso> GrantM11235: Can't you use just the big buffer and do the operations in-place checking if the DMA already passed the place you're operating in ?
<re_irc>
<firefrommoonlight> I didn't know some STMs had hardware double-buffering. That's cool!
<re_irc>
<firefrommoonlight> I've been doing "software", as described above
<re_irc>
<firefrommoonlight> (Without concern for a general purpose wrapper)
<re_irc>
<GrantM11235> thalesfragoso: The big buffer also needs to be a circular buffer because it needs to keep collecting samples until it detects the trigger
skunkjoe has joined #rust-embedded
<re_irc>
<adamgreig> For an application I'd totally just use the circular buffer and make sure your application timing avoids accessing the half the DMA is using
<re_irc>
<adamgreig> It's just another safety contract
<re_irc>
<adamgreig> (assuming the double buffer isn't available; when it is that's nicer)
<re_irc>
<dirbaio> maybe the HAL could hook HTIE and TCIE and panic in the interrupt handler if the user code runs late?
<re_irc>
<dirbaio> that'd avoid UB before it happens
<re_irc>
<firefrommoonlight> if dma.transfer_is_complete(DmaChannel::C4) {
<re_irc>
// Transfer complete: SAI will now play from the left half of the buffer,
<re_irc>
// Because SAI is on the same clock, it's syced to this for output.
<re_irc>
<adamgreig> Is it? Just check if the other completion flag got set before you finished processing your half
<re_irc>
<adamgreig> Or indeed check in the interrupt handler but it can't preempt itself so troublesome if your processing is inside the ist
<re_irc>
<adamgreig> * isr
<re_irc>
<firefrommoonlight> -// toto temp?
<re_irc>
<GrantM11235> adamgreig: But by the time that happens, I will already have hit UB, so I can't be sure that the check will work correctly. I guess that is mostly a theoretical concern, but still
<re_irc>
<firefrommoonlight> Note that the code I just posted will write garbage to the buffer if the user code takes too long
<re_irc>
<adamgreig> Especially if you're not doing anything conditional on the data values, only copying them or running through a filter or whatever, I wouldn't expect to run into trouble, but
<re_irc>
<adamgreig> You could also check the NDTR register every so often and panic if it gets too close to the edge, if you like
<re_irc>
<adamgreig> It shows how many words are left this transfer so you can tell if the DMA is close to hitting the next interrupt before it does so
<re_irc>
<adamgreig> But I'd probably instead try and ensure the firmware will always complete processing the new half-buffer in time
<re_irc>
<thalesfragoso> Yep, if you control the firmware I would also just go with that, especially if you can't do the processing outside the IRQ
<re_irc>
<thalesfragoso> Which is almost always the best thing to do
<re_irc>
<thalesfragoso> Just set an AtomicBool before start the processing and unset after you're done
<re_irc>
<thalesfragoso> And check in the IRQ and panic if it's set
<re_irc>
<thalesfragoso> You might still cause a data race depending on the DMA rate and Irq latency, but tbh, not much you can do
<re_irc>
<thalesfragoso> And it won't cause nasal demons
<re_irc>
<thalesfragoso> (probably)
<re_irc>
<dirbaio> nasal ghosts maybe 👻
<re_irc>
<thalesfragoso> It's way harder when you are writing a library that will call an user closure
<re_irc>
<thalesfragoso> Yep, if you control the firmware I would also just go with that, especially if you can do the processing outside the IRQ
<re_irc>
<thalesfragoso> Edited, should read if you *can*
<re_irc>
<thalesfragoso> And like Adam said, if there aren't conditionals, if you didn't hit once then you won't hit it
<re_irc>
<adamgreig> Especially in rtic I often end up doing everything inside irqs but for something like this you could have a very high prio DMA interrupt pend a lower prio software task to do the processing, then you'll still get the later interrupt on completion
<re_irc>
<GrantM11235> thalesfragoso: I would like to be able to add this to embassy, so there needs to be some sort of sound api
<re_irc>
<thalesfragoso> GrantM11235: Must mark it as unsafe, heh
<re_irc>
<adamgreig> Ah, adding a generic circular DMA api to embassy is probably quite a different task
<re_irc>
on DMA: use the hardware double-buffering support
<re_irc>
on BDMA: flip the buffer on TCIE irq handler
<re_irc>
<adamgreig> Since it's already doing processing in thread mode maybe dirbaio suggestion of just having single shot DMA and restarting asap after tcie is best
<re_irc>
<adamgreig> Make sure that interrupt is decently high prio and hope you don't miss any samples :p
<re_irc>
<thalesfragoso> Probably the best for general use case, but for a oscilloscope at 1MHz...
<re_irc>
<firefrommoonlight> I was wondering why I hadn't heard of hardware double buffering
<re_irc>
<firefrommoonlight> Is "DMA" called "MDMA" on H7?
<re_irc>
<thalesfragoso> Still might be good enough
<re_irc>
<firefrommoonlight> This is confusing!
<re_irc>
<adamgreig> Yea at 1M on an f103 doing 72MHz I'd worry about flipping buffers inside 72 cycles
<re_irc>
<GrantM11235> Is there any way to ensure that the software-double-buffering doesn't introduce any jitter?
<re_irc>
<dirbaio> nope! MDMA is yet another thing 😂
<re_irc>
H7 has DMA _and_ BDMA _and_ DMAMUX _and_ MDMA
<re_irc>
<thalesfragoso> adamgreig: Don't even think of using the fpu, heh
<re_irc>
<firefrommoonlight> I'm so confused
<re_irc>
<GrantM11235> BTW, to actually hit 1mhz on the adc, I think I need to reduce the system clock to 56mhz
<re_irc>
<firefrommoonlight> (I haven't looked into BDMA or MDMA, but "DMA" on H7 seems to work the same way as on other platforms)
<re_irc>
<firefrommoonlight> (Maybe with more features I haven't tried?)
<re_irc>
<GrantM11235> thalesfragoso: Does the f103 have an fpu?
<re_irc>
<thalesfragoso> Don't they have also a 2D DMA or something, or is it the MDMA ?
<re_irc>
<thalesfragoso> GrantM11235: Nope, you're right, no need to worry bout the fpu interrupt latency then :)
<re_irc>
<dirbaio> firefrommoonlight: "DMA" on F1, L1, F0, F3, L0, L4, L4+, G0, L5, G4, WB, WL is the same as "BDMA" on H7
<re_irc>
"DMA" on F2, F4, F7 is the same as "DMA" on H7
<re_irc>
<thalesfragoso> * about
<re_irc>
<dirbaio> so I'm calling the first thing "BDMA" for all chips, the second thing "DMA"
<re_irc>
<GrantM11235> Is it short for Bulls**t Direct Memory Access 🤬
<re_irc>
<adamgreig> And... The u5? :X
<re_irc>
<dirbaio> "BDMA" doesn't have hardware-double-buffer (except on H7, L5)
<re_irc>
"DMA" does have it
<re_irc>
<dirbaio> u5 is "GPDMA" which is again completely different 😵
<re_irc>
<adamgreig> got bored of their existing dma, invented gpdma
<re_irc>
<dirbaio> not enough DMAs
<re_irc>
<firefrommoonlight> gotcha
skunkjoe has quit [Ping timeout: 256 seconds]
<re_irc>
<GrantM11235> How does embassy avoid UB when doing a regular dma read into a "&mut [u8]"? (ignoring the future-forgetting problem)
<re_irc>
<dirbaio> it stops DMA if the future is dropped
<re_irc>
<dirbaio> and the future borrows the buffer, so while the future is running the user can't access the buffer
<re_irc>
<GrantM11235> Isn't it UB for the data in a "&mut [u8]" to be modified by something else while the mut ref exists?
<re_irc>
<dirbaio> not if you get the "*mut u8" from it then give that to DMA
<re_irc>
<dirbaio> you'll have to read on "stacked borrows" for the why
<re_irc>
<dirbaio> I'm afraid I'm not an expert
<re_irc>
<dirbaio> but
<re_irc>
<dirbaio> as I understand it, if you get a "*mut u8" from the "&mut [u8]", for example with ".as_ptr()", you're allowed to use that to read/write to it
<re_irc>
<dirbaio> usually by cpu read/writes, but also through DMA
<re_irc>
<dirbaio> it's "like a borrow" but not enforced by the borrow checker
<re_irc>
<dirbaio> but as soon as you touch the original "&mut [u8]" (by reading or writing) the "borrow" for that "*mut u8" is invalidated
<re_irc>
<GrantM11235> So the compiler knows that the "exclusive" reference isn't exclusive between when you get the ptr and when you touch it again?
<re_irc>
<dirbaio> it's the same as regular "reborrows"
<re_irc>
<dirbaio> say you got a "&mut [u8]"
<re_irc>
<dirbaio> * "buf: &mut
<re_irc>
<dirbaio> and a fn "write_to_buf(buf: &mut [u8])"
<re_irc>
<dirbaio> you call "write_to_buf(buf)"
<re_irc>
<dirbaio> while "write_to_buf" is running, two "&mut [u8]"s exist: one in your local variable, and one in "write_to_buf"'s param
<re_irc>
<dirbaio> so you might say "I have a "&mut [u8]" to the buffer, why is "write_to_buf" allowed to modify that? isn't that UB?`
<re_irc>
<dirbaio> * UB?"
<re_irc>
<dirbaio> it's not because your "&mut [u8]" is borrowed, by doing that you've allowed someone else to write to that buf even though your "&mut [u8]" sti'll "exists"
<re_irc>
<dirbaio> * still
<re_irc>
<dirbaio> * not,
<re_irc>
<dirbaio> * borrowed. By
<re_irc>
<dirbaio> raw pointers like "*mut u8" behave kinda like that, they're like a "temporal right to write to that buffer", the only difference is they're not checked by rust's borrow checkr
<re_irc>
<dirbaio> * checker
<re_irc>
<dirbaio> so it's OK to take a "*mut u8" out of the "&mut [u8]" and give that to DMA to write
<re_irc>
<dirbaio> what's not OK is reborrowing the "&mut [u8]" again and giving it to a user closure, by doing that you're invalidating the "*mut u8" borrow, so it's UB if DMA keeps using it to write to that buffer