Skip to content

Commit c0ef636

Browse files
matthijskooijmanfpistm
authored andcommitted
Use handcoded delay in USBD_reenumerate
This now runs in early startup, so the normal delay will not work (systick is not running yet). Note: Seems that on F0, inline assembler is compiled using the classic rather than unified syntax (which *is* used on F4 it seems). This explicitly selects the unified syntax in the inline assembly block, to fix building for F0. TODO: There is a variant which also overrides the enumeration.
1 parent c40cfdd commit c0ef636

File tree

1 file changed

+52
-2
lines changed

1 file changed

+52
-2
lines changed

cores/arduino/stm32/usb/usbd_if.c

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,56 @@
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

Comments
 (0)