115115 #define USBD_DP_TRICK
116116#endif
117117
118+ /**
119+ * @brief USBD_early_startup_delay
120+ * @param us - number of us to delay
121+ * @retval None
122+ *
123+ * This is a minimal delay which is usable in very early startup, when
124+ * nothing has been initialized yet (no clocks, no memory, no systick
125+ * timer). It works by counting CPU cycles, and assumes the system is
126+ * still running from the HSI.
127+ *
128+ * If the systick timer is already enabled, this assumes everything is
129+ * intialized and instead used the normal delayMicroseconds function.
130+ *
131+ * Max delay depends on HSI, but is around 268 sec with 16Mhz HSI.
132+ */
133+ void USBD_early_startup_delay_us (uint32_t us )
134+ {
135+ if (SysTick -> CTRL & SysTick_CTRL_ENABLE_Msk ) {
136+ delayMicroseconds (us );
137+ return ;
138+ }
139+
140+ #if !HSI_VALUE
141+ #error "Missing HSI_VALUE"
142+ #endif
143+
144+ #if HSI_VALUE % 4000000 != 0
145+ #warning "HSI not multiple of 4MHz, early startup delay will be inaccurate!"
146+ #endif
147+
148+ // To simplify this calculation, this assumes the HSI runs at a
149+ // multiple of 4Mhz (1Mhz to scale to us, times 4 to account for 4
150+ // cycles per loop).
151+ const uint32_t loops_per_us = (HSI_VALUE / 1000000 ) / 4 ;
152+ const uint32_t loop_count = us * loops_per_us ;
153+
154+ // Assembly loop, designed to run at exactly 4 cycles per loop.
155+ asm volatile (
156+ // Use the unified ARM/Thumb syntax, which seems to be more
157+ // universally used and corresponds to what avr-objdump outputs
158+ // See https://sourceware.org/binutils/docs/as/ARM_002dInstruction_002dSet.html
159+ ".syntax unified\n\t"
160+ "1:\n\t"
161+ "nop /* 1 cycle */\n\t"
162+ "subs %[loop], %[loop], #1 /* 1 cycle */\n\t"
163+ "bne 1b /* 2 if taken, 1 otherwise */\n\t"
164+ : : [loop ] "l" (loop_count )
165+ );
166+ }
167+
118168/**
119169 * @brief Force to re-enumerate USB.
120170 *
@@ -134,7 +184,7 @@ WEAK void USBD_reenumerate(void)
134184 digitalWriteFast (USBD_PULLUP_CONTROL_PINNAME , USBD_DETACH_LEVEL );
135185
136186 /* Wait */
137- delay (USBD_ENUM_DELAY );
187+ USBD_early_startup_delay_us (USBD_ENUM_DELAY * 1000 );
138188
139189 /* Attach */
140190#if defined(USBD_DP_TRICK )
@@ -145,7 +195,7 @@ WEAK void USBD_reenumerate(void)
145195#endif /* defined(USBD_PULLUP_CONTROL_FLOATING) */
146196#elif defined(USBD_HAVE_INTERNAL_PULLUPS )
147197 USB_DevDisconnect (USBD_USB_INSTANCE );
148- delay (USBD_ENUM_DELAY );
198+ USBD_early_startup_delay_us (USBD_ENUM_DELAY * 1000 );
149199 USB_DevConnect (USBD_USB_INSTANCE );
150200#else
151201#warning "No USB attach/detach method, USB might not be reliable through system resets"
0 commit comments