2021-10-15 03:08 AM
In STM32F427 OTG_HS used with its internal FS PHY, the following sequence is used to initialize the OTG module (with all settings in RCC, i.e. setting up the 48MHz clock from PLL's Q tap, and enabling the clock in respective RCC_AHBxENR, performed far before this sequence):
usb->c->u->global.GAHBCFG &= ~USB_OTG_GAHBCFG_GINT; // disable interrupts
usb->c->u->global.GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // select (built-in) FS PHY
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_AHBIDL) == 0); // Wait for AHB master IDLE state
usb->c->u->global.GRSTCTL |= USB_OTG_GRSTCTL_CSRST; // core soft reset
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_CSRST) != 0);
where usb->c->u points to OTG_HS. This worked well, until I tried to use a newer version of gcc, with presumably more aggressive optimization. This resulted in the following binary (I don't have the older version's disasm at hand):
0803d46c <USBD_Init>:
usb->c->u->global.GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
803d46c: 6803 ldr r3, [r0, #0]
803d46e: 681b ldr r3, [r3, #0]
803d470: 689a ldr r2, [r3, #8]
803d472: f022 0201 bic.w r2, r2, #1
void USBD_Init(TUsbDeviceStruct * usb) {
803d476: b570 push {r4, r5, r6, lr}
usb->c->u->global.GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
803d478: 609a str r2, [r3, #8]
usb->c->u->global.GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // select (built-in) FS PHY
803d47a: 68da ldr r2, [r3, #12]
803d47c: f042 0240 orr.w r2, r2, #64 ; 0x40
void USBD_Init(TUsbDeviceStruct * usb) {
803d480: 4604 mov r4, r0
usb->c->u->global.GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // select (built-in) FS PHY
803d482: 60da str r2, [r3, #12]
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_AHBIDL) == 0); // Wait for AHB master IDLE state
803d484: 691a ldr r2, [r3, #16]
803d486: 2a00 cmp r2, #0
803d488: dafc bge.n 803d484 <USBD_Init+0x18>
usb->c->u->global.GRSTCTL |= USB_OTG_GRSTCTL_CSRST; // core soft reset
803d48a: 691a ldr r2, [r3, #16]
803d48c: f042 0201 orr.w r2, r2, #1
803d490: 611a str r2, [r3, #16]
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_CSRST) != 0);
803d492: 691a ldr r2, [r3, #16]
803d494: 07d1 lsls r1, r2, #31
803d496: d4fc bmi.n 803d492 <USBD_Init+0x26>
This hung with cca 50% probability on the last while, where GRSTCTL.CSRST bit did not autoclear as it is supposed to.
It appears that adding delay (a single NOP) between setting GUSBCFG.PHYSEL and GRSTCTL.CSRST results in 100% working code. Adding delay anywhere else did not help. As there is no documentation for this and I am tired of digging deep into the Synopsys's mess, I just added
while ((usb->c->u->global.GUSBCFG & USB_OTG_GUSBCFG_PHYSEL) == 0);
after setting GUSBCFG.PHYSEL and threw in some hope.
JW
[EDIT] It appears that objdump which came with the newer gcc choked on the .elf generated by older gcc... it took more than 10 minutes until it produced the disasm, but here it is, at the left-hand side in comparison with the new one
803cd54: b5f8 push {r3, r4, r5, r6, r7, lr}
803cd56: 6803 ldr r3, [r0, #0] 803d46c: 6803 ldr r3, [r0, #0]
803cd58: 681a ldr r2, [r3, #0] 803d46e: 681b ldr r3, [r3, #0]
803cd5a: 6893 ldr r3, [r2, #8] 803d470: 689a ldr r2, [r3, #8]
803cd5c: f023 0301 bic.w r3, r3, #1 803d472: f022 0201 bic.w r2, r2, #1
803d476: b570 push {r4, r5, r6, lr}
usb->c->u->global.GAHBCFG &= ~USB_OTG_GAHBCFG_GINT;
803cd60: 6093 str r3, [r2, #8] 803d478: 609a str r2, [r3, #8]
803cd62: 6803 ldr r3, [r0, #0]
803cd64: 681a ldr r2, [r3, #0]
803cd66: 68d3 ldr r3, [r2, #12] 803d47a: 68da ldr r2, [r3, #12]
803cd68: f043 0340 orr.w r3, r3, #64 ; 0x40 803d47c: f042 0240 orr.w r2, r2, #64 ; 0x40
803d480: 4604 mov r4, r0
usb->c->u->global.GUSBCFG |= USB_OTG_GUSBCFG_PHYSEL; // select (built-in) FS PHY
803cd6c: 60d3 str r3, [r2, #12] 803d482: 60da str r2, [r3, #12]
803cd6e: 6803 ldr r3, [r0, #0]
803cd70: 681a ldr r2, [r3, #0]
803cd72: 4604 mov r4, r0
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_AHBIDL) == 0); // Wait for AHB master IDLE state
803cd74: 6913 ldr r3, [r2, #16] 803d484: 691a ldr r2, [r3, #16]
803cd76: 2b00 cmp r3, #0 803d486: 2a00 cmp r2, #0
803cd78: dafc bge.n 803cd74 <USBD_Init+0x20> 803d488: dafc bge.n 803d484 <USBD_Init+0x18>
usb->c->u->global.GRSTCTL |= USB_OTG_GRSTCTL_CSRST; // core soft reset
803cd7a: 6913 ldr r3, [r2, #16] 803d48a: 691a ldr r2, [r3, #16]
803cd7c: f043 0301 orr.w r3, r3, #1 803d48c: f042 0201 orr.w r2, r2, #1
803cd80: 6113 str r3, [r2, #16] 803d490: 611a str r2, [r3, #16]
while ((usb->c->u->global.GRSTCTL AND USB_OTG_GRSTCTL_CSRST) != 0);
803cd82: 6823 ldr r3, [r4, #0]
803cd84: 681a ldr r2, [r3, #0]
803cd86: 6913 ldr r3, [r2, #16] 803d492: 691a ldr r2, [r3, #16]
803cd88: 07d9 lsls r1, r3, #31 803d494: 07d1 lsls r1, r2, #31
803cd8a: d4fc bmi.n 803cd86 <USBD_Init+0x32> 803d496: d4fc bmi.n 803d492 <USBD_Init+0x26>