2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
27 #include "build/atomic.h"
29 #include "drivers/io.h"
30 #include "drivers/light_led.h"
31 #include "drivers/nvic.h"
32 #include "drivers/resource.h"
33 #include "drivers/sound_beeper.h"
35 #include "drivers/system.h"
37 #if defined(STM32F4) || defined(STM32F7) || defined(STM32H7) || defined(AT32F4) || defined(APM32F4)
38 // See "RM CoreSight Architecture Specification"
39 // B2.3.10 "LSR and LAR, Software Lock Status Register and Software Lock Access Register"
40 // "E1.2.11 LAR, Lock Access Register"
42 #define DWT_LAR_UNLOCK_VALUE 0xC5ACCE55
46 // cycles per microsecond
47 static uint32_t usTicks
= 0;
48 static float usTicksInv
= 0.0f
;
49 // current uptime for 1kHz systick timer. will rollover after 49 days. hopefully we won't care.
50 static volatile uint32_t sysTickUptime
= 0;
51 static volatile uint32_t sysTickValStamp
= 0;
52 // cached value of RCC->CSR
53 uint32_t cachedRccCsrValue
;
54 static uint32_t cpuClockFrequency
= 0;
56 void cycleCounterInit(void)
58 #if defined(USE_HAL_DRIVER)
59 cpuClockFrequency
= HAL_RCC_GetSysClockFreq();
60 #elif defined(USE_ATBSP_DRIVER)
61 crm_clocks_freq_type clocks
;
62 crm_clocks_freq_get(&clocks
);
63 cpuClockFrequency
= clocks
.sclk_freq
;
65 RCC_ClocksTypeDef clocks
;
66 RCC_GetClocksFreq(&clocks
);
67 cpuClockFrequency
= clocks
.SYSCLK_Frequency
;
69 usTicks
= cpuClockFrequency
/ 1000000;
70 usTicksInv
= 1e6f
/ cpuClockFrequency
;
72 CoreDebug
->DEMCR
|= CoreDebug_DEMCR_TRCENA_Msk
;
74 #if defined(DWT_LAR_UNLOCK_VALUE)
75 #if defined(STM32H7) || defined(AT32F4)
76 ITM
->LAR
= DWT_LAR_UNLOCK_VALUE
;
77 #elif defined(STM32F7)
78 DWT
->LAR
= DWT_LAR_UNLOCK_VALUE
;
79 #elif defined(STM32F4) || defined(APM32F4)
80 // Note: DWT_Type does not contain LAR member.
82 __O
uint32_t *DWTLAR
= (uint32_t *)(DWT_BASE
+ 0x0FB0);
83 *(DWTLAR
) = DWT_LAR_UNLOCK_VALUE
;
88 DWT
->CTRL
|= DWT_CTRL_CYCCNTENA_Msk
;
93 static volatile int sysTickPending
= 0;
95 void SysTick_Handler(void)
97 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
99 sysTickValStamp
= SysTick
->VAL
;
101 (void)(SysTick
->CTRL
);
103 #ifdef USE_HAL_DRIVER
104 // used by the HAL for some timekeeping and timeouts, should always be 1ms
109 // Return system uptime in microseconds (rollover in 70minutes)
111 MMFLASH_CODE_NOINLINE
uint32_t microsISR(void)
113 register uint32_t ms
, pending
, cycle_cnt
;
115 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
116 cycle_cnt
= SysTick
->VAL
;
118 if (SysTick
->CTRL
& SysTick_CTRL_COUNTFLAG_Msk
) {
120 // Record it for multiple calls within the same rollover period
121 // (Will be cleared when serviced).
122 // Note that multiple rollovers are not considered.
126 // Read VAL again to ensure the value is read after the rollover.
128 cycle_cnt
= SysTick
->VAL
;
132 pending
= sysTickPending
;
135 return ((ms
+ pending
) * 1000) + (usTicks
* 1000 - cycle_cnt
) / usTicks
;
138 uint32_t micros(void)
140 register uint32_t ms
, cycle_cnt
;
142 // Call microsISR() in interrupt and elevated (non-zero) BASEPRI context
144 if ((SCB
->ICSR
& SCB_ICSR_VECTACTIVE_Msk
) || (__get_BASEPRI())) {
150 cycle_cnt
= SysTick
->VAL
;
151 } while (ms
!= sysTickUptime
|| cycle_cnt
> sysTickValStamp
);
153 return (ms
* 1000) + (usTicks
* 1000 - cycle_cnt
) / usTicks
;
156 uint32_t getCycleCounter(void)
161 int32_t clockCyclesToMicros(int32_t clockCycles
)
163 return clockCycles
/ usTicks
;
166 float clockCyclesToMicrosf(int32_t clockCycles
)
168 return clockCycles
* usTicksInv
;
171 // Note that this conversion is signed as this is used for periods rather than absolute timestamps
172 int32_t clockCyclesTo10thMicros(int32_t clockCycles
)
174 return 10 * clockCycles
/ (int32_t)usTicks
;
177 // Note that this conversion is signed as this is used for periods rather than absolute timestamps
178 int32_t clockCyclesTo100thMicros(int32_t clockCycles
)
180 return 100 * clockCycles
/ (int32_t)usTicks
;
183 uint32_t clockMicrosToCycles(uint32_t micros
)
185 return micros
* usTicks
;
188 // Return system uptime in milliseconds (rollover in 49 days)
189 uint32_t millis(void)
191 return sysTickUptime
;
195 void delayMicroseconds(uint32_t us
)
197 uint32_t now
= micros();
198 while (micros() - now
< us
);
201 void delayMicroseconds(uint32_t us
)
203 uint32_t elapsed
= 0;
204 uint32_t lastCount
= SysTick
->VAL
;
207 register uint32_t current_count
= SysTick
->VAL
;
210 // measure the time elapsed since the last time we checked
211 elapsed
+= current_count
- lastCount
;
212 lastCount
= current_count
;
214 // convert to microseconds
215 elapsed_us
= elapsed
/ usTicks
;
216 if (elapsed_us
>= us
)
219 // reduce the delay by the elapsed time
222 // keep fractional microseconds for the next iteration
228 void delay(uint32_t ms
)
231 delayMicroseconds(1000);
234 static void indicate(uint8_t count
, uint16_t duration
)
254 void indicateFailure(failureMode_e mode
, int codeRepeatsRemaining
)
256 while (codeRepeatsRemaining
--) {
257 indicate(WARNING_FLASH_COUNT
, WARNING_FLASH_DURATION_MS
);
259 delay(WARNING_PAUSE_DURATION_MS
);
261 indicate(mode
+ 1, WARNING_CODE_DURATION_LONG_MS
);
267 void failureMode(failureMode_e mode
)
269 indicateFailure(mode
, 10);
274 systemResetToBootloader(BOOTLOADER_REQUEST_ROM
);
278 void initialiseMemorySections(void)
281 /* Load fast-functions into ITCM RAM */
282 extern uint8_t tcm_code_start
;
283 extern uint8_t tcm_code_end
;
284 extern uint8_t tcm_code
;
285 memcpy(&tcm_code_start
, &tcm_code
, (size_t) (&tcm_code_end
- &tcm_code_start
));
289 /* Load functions into RAM */
290 extern uint8_t ccm_code_start
;
291 extern uint8_t ccm_code_end
;
292 extern uint8_t ccm_code
;
293 memcpy(&ccm_code_start
, &ccm_code
, (size_t) (&ccm_code_end
- &ccm_code_start
));
297 /* Load FAST_DATA variable initializers into DTCM RAM */
298 extern uint8_t _sfastram_data
;
299 extern uint8_t _efastram_data
;
300 extern uint8_t _sfastram_idata
;
301 memcpy(&_sfastram_data
, &_sfastram_idata
, (size_t) (&_efastram_data
- &_sfastram_data
));
305 /* Load slow-functions into ITCM RAM */
306 extern uint8_t ram_code_start
;
307 extern uint8_t ram_code_end
;
308 extern uint8_t ram_code
;
309 memcpy(&ram_code_start
, &ram_code
, (size_t) (&ram_code_end
- &ram_code_start
));
314 static void unusedPinInit(IO_t io
)
316 if (IOGetOwner(io
) == OWNER_FREE
) {
317 IOConfigGPIO(io
, IOCFG_IPU
);
321 void unusedPinsInit(void)
323 IOTraversePins(unusedPinInit
);
326 const mcuTypeInfo_t
*getMcuTypeInfo(void)
328 static const mcuTypeInfo_t info
[] = {
329 #if defined(STM32H743xx)
330 { .id
= MCU_TYPE_H743_REV_UNKNOWN
, .name
= "STM32H743 (Rev Unknown)" },
331 { .id
= MCU_TYPE_H743_REV_Y
, .name
= "STM32H743 (Rev.Y)" },
332 { .id
= MCU_TYPE_H743_REV_X
, .name
= "STM32H743 (Rev.X)" },
333 { .id
= MCU_TYPE_H743_REV_V
, .name
= "STM32H743 (Rev.V)" },
334 #elif defined(STM32F40_41xxx)
335 { .id
= MCU_TYPE_F40X
, .name
= "STM32F40X" },
336 #elif defined(STM32F411xE)
337 { .id
= MCU_TYPE_F411
, .name
= "STM32F411" },
338 #elif defined(STM32F446xx)
339 { .id
= MCU_TYPE_F446
, .name
= "STM32F446" },
340 #elif defined(STM32F722xx)
341 { .id
= MCU_TYPE_F722
, .name
= "STM32F722" },
342 #elif defined(STM32F745xx)
343 { .id
= MCU_TYPE_F745
, .name
= "STM32F745" },
344 #elif defined(STM32F746xx)
345 { .id
= MCU_TYPE_F746
, .name
= "STM32F746" },
346 #elif defined(STM32F765xx)
347 { .id
= MCU_TYPE_F765
, .name
= "STM32F765" },
348 #elif defined(STM32H750xx)
349 { .id
= MCU_TYPE_H750
, .name
= "STM32H750" },
350 #elif defined(STM32H730xx)
351 { .id
= MCU_TYPE_H730
, .name
= "STM32H730" },
352 #elif defined(STM32H7A3xx) || defined(STM32H7A3xxQ)
353 { .id
= MCU_TYPE_H7A3
, .name
= "STM32H7A3" },
354 #elif defined(STM32H723xx) || defined(STM32H725xx)
355 { .id
= MCU_TYPE_H723_725
, .name
= "STM32H723/H725" },
356 #elif defined(STM32G474xx)
357 { .id
= MCU_TYPE_G474
, .name
= "STM32G474" },
358 #elif defined(AT32F435G)
359 { .id
= MCU_TYPE_AT32F435G
, .name
= "AT32F435G" },
360 #elif defined(AT32F435M)
361 { .id
= MCU_TYPE_AT32F435M
, .name
= "AT32F435M" },
362 #elif defined(APM32F405)
363 { .id
= MCU_TYPE_APM32F405
, .name
= "APM32F405" },
364 #elif defined(APM32F407)
365 { .id
= MCU_TYPE_APM32F407
, .name
= "APM32F407" },
367 #error MCU Type info not defined for STM (or clone)
370 unsigned revision
= 0;
371 #if defined(STM32H743xx)
372 switch (HAL_GetREVID()) {
386 return info
+ revision
;