Skip to main content
Super User
October 15, 2021
Question

[OTG USB] Delay needed between selecting PHY and softreset

  • October 15, 2021
  • 0 replies
  • 1203 views

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>
 

    This topic has been closed for replies.