**Issue**
While using `usb_device` and `usbd_serial` crates with `rp2040_hal`, the first frame from the host device is always getting lost. Consecutive frames work just fine.
**Root Cause**
The `LENGTH_0` region of the `EP_BUFFER_CONTROL` register is always reset (0) while waiting for the first frame. After the first frame failure, the poll operation implicitly sets it to the necessary value (`max_packet_size`) and this clears the problem for the rest of the app execution life time.
The main problem is while resetting and readjustment of the bits needs a step by step operation to avoid potential issues. While doing that and setting `AVAILABLE` bit, the wrong method had been chosen and was invalidating previous changes. Hence the `LENGTH_0` param is reset, too.
**Proposed Solution**
Instead of direct register `write` operation I've used `modify` to keep current bits in the register.
Co-authored-by: Murat Ursavas <mursavas@nebra.com>
If the latency is too high, there is a risk that the status reverts to a
previous state while keeping the interrupt flag up.
This fixes that by relying on ints instead of sie_status to process the
events.
The documentation of CLKDIV_RESTART contains the following sentence:
"Note also that CLKDIV_RESTART can be written to whilst the state
machine is running, and this is useful to resynchronise clock dividers
after the divisors (SMx_CLKDIV) have been changed on-the-fly."
This implies that it's allowed to change the value of CLKDIV on a
running state machine.
Add derive(Debug) and derive(defmt::Format) to error types.
pll and xosc Error types didn't implement Debug, which made them annoying to work with.
And only a few of our Error types implemented derive(defmt::Format).
I added both to all the errors I could find to make things a little more consistent.
The wrap source and target cannot change after installing the program
into the PIO at present, even though this is possible with the C/C++
HAL. This is useful when using the same program across multiple state
machines that have different wrap sources and targets.
`LOCK_OWNER` is only accessed using the atomic APIs, which take `&self`, so it does not need to be `static mut`, `static` is fine.
(I haven't seen any miscompilations of this, but I'm unsure if Rust is allowed to assume `static mut`s are not aliased and apply optimizations based on that. If so, this would prevent that.)
Limit the discarded data reference to the data that has actually been
read so far, instead of the whole input buffer. Also fix a spelling
error in the field name.