2024-09-02 03:42 PM - edited 2024-09-02 07:20 PM
[Not a bug report, explanation below, first post kept for context]
I'm writing a USB host library for the STM32H743 rev V. Bits PENA and PENCHNG of register OTG_HPRT represent Port enable and Port enable/disable change. Port enable is supposed to be a status bit - can't be set, can be reset which disables the port, or is reset when the port is disabled because of a disconnect.
PENCHNG is supposed to be change detection bit about PENA, gets set to 1 whenever PENA change, optionally triggers an interrupt via a chain of interrupt-aggregating register. PENCHNG is supposed to be reset when it causes an interrupt. This reset is supposed to be accomplished by writing 1 to this bit, as per the datasheet. PENA is also described as rc_w1 (clearable by writing 1) but that's probably a mistake.
Except, writing 1 to PENCHNG doesn't clear PENCHNG, it clears PENA, and disables the port. Writing 1 to PENCHNG a second time (when PENA is 0) sets PENCHNG to 0 as expected. This makes it impossible to clear the bit so that it triggers an interrupt when the port is disconnected, without disconnecting the port yourself.
A USB reset starts between log1 and log2. It ends between log2 and log3. Log3 reports the port is now enabled. PENCHNG is set between log3 and log4. PENCHNG is still 1, PENA is 0 (the port is now disabled). PENCHNG is set again between log4 and log5. PENCHNG is now 0.
For the record, here's the relevant excerpts from the reference:
Also, HPRT isn't built into CubeMX, as far as I can tell, this is how I defined USB2_OTG_FS__HPRT:
__IO uint32_t& USB2_OTG_FS__HPRT = (__IO uint32_t&)*(((uint8_t*)USB2_OTG_FS_PERIPH_BASE)+0x440);
2024-09-02 07:17 PM - edited 2024-09-02 07:21 PM
The lightbulb went on as I read this again and realized that |= writes 1 to all the bits that are set to 1.
That means the first write writes to PENCHNG and PENA, clears both of them, then PENCHNG goes back to 1 because PENA just went to 0.
So the correct way to go about a shared normal bits / rc_w1 register is to make a mask with all the rc_w1 register so you can keep the normal bits untouched but write 0 to all the rc_w1 bits except the one you want to write to. In this case that would be:
USB2_OTG_FS__HPRT = (USB2_OTG_FS__HPRT & ~(USB_OTG_HPRT_PENCHNG | USB_OTG_HPRT_PENA | USB_OTG_HPRT_PCDET | USB_OTG_HPRT_POCCHNG)) | USB_OTG_HPRT_PENCHNG;
I'd have deleted this 'bug report' but apparently I can't, so instead let's hope my struggles help someone else out !