115
115
#define USBD_DP_TRICK
116
116
#endif
117
117
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
+
118
168
/**
119
169
* @brief Force to re-enumerate USB.
120
170
*
@@ -134,7 +184,7 @@ WEAK void USBD_reenumerate(void)
134
184
digitalWriteFast (USBD_PULLUP_CONTROL_PINNAME , USBD_DETACH_LEVEL );
135
185
136
186
/* Wait */
137
- delay (USBD_ENUM_DELAY );
187
+ USBD_early_startup_delay_us (USBD_ENUM_DELAY * 1000 );
138
188
139
189
/* Attach */
140
190
#if defined(USBD_DP_TRICK )
@@ -145,7 +195,7 @@ WEAK void USBD_reenumerate(void)
145
195
#endif /* defined(USBD_PULLUP_CONTROL_FLOATING) */
146
196
#elif defined(USBD_HAVE_INTERNAL_PULLUPS )
147
197
USB_DevDisconnect (USBD_USB_INSTANCE );
148
- delay (USBD_ENUM_DELAY );
198
+ USBD_early_startup_delay_us (USBD_ENUM_DELAY * 1000 );
149
199
USB_DevConnect (USBD_USB_INSTANCE );
150
200
#else
151
201
#warning "No USB attach/detach method, USB might not be reliable through system resets"
0 commit comments