**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.)