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"
38 #if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(STM32H7)
39 // See "RM CoreSight Architecture Specification"
40 // B2.3.10 "LSR and LAR, Software Lock Status Register and Software Lock Access Register"
41 // "E1.2.11 LAR, Lock Access Register"
43 #define DWT_LAR_UNLOCK_VALUE 0xC5ACCE55
47 // cycles per microsecond
48 static uint32_t usTicks
= 0;
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();
61 RCC_ClocksTypeDef clocks
;
62 RCC_GetClocksFreq(&clocks
);
63 cpuClockFrequency
= clocks
.SYSCLK_Frequency
;
65 usTicks
= cpuClockFrequency
/ 1000000;
67 CoreDebug
->DEMCR
|= CoreDebug_DEMCR_TRCENA_Msk
;
69 #if defined(DWT_LAR_UNLOCK_VALUE)
70 #if defined(STM32F7) || defined(STM32H7)
71 DWT
->LAR
= DWT_LAR_UNLOCK_VALUE
;
72 #elif defined(STM32F3) || defined(STM32F4)
73 // Note: DWT_Type does not contain LAR member.
75 __O
uint32_t *DWTLAR
= (uint32_t *)(DWT_BASE
+ 0x0FB0);
76 *(DWTLAR
) = DWT_LAR_UNLOCK_VALUE
;
81 DWT
->CTRL
|= DWT_CTRL_CYCCNTENA_Msk
;
86 static volatile int sysTickPending
= 0;
88 void SysTick_Handler(void)
90 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
92 sysTickValStamp
= SysTick
->VAL
;
94 (void)(SysTick
->CTRL
);
97 // used by the HAL for some timekeeping and timeouts, should always be 1ms
102 // Return system uptime in microseconds (rollover in 70minutes)
104 uint32_t microsISR(void)
106 register uint32_t ms
, pending
, cycle_cnt
;
108 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
109 cycle_cnt
= SysTick
->VAL
;
111 if (SysTick
->CTRL
& SysTick_CTRL_COUNTFLAG_Msk
) {
113 // Record it for multiple calls within the same rollover period
114 // (Will be cleared when serviced).
115 // Note that multiple rollovers are not considered.
119 // Read VAL again to ensure the value is read after the rollover.
121 cycle_cnt
= SysTick
->VAL
;
125 pending
= sysTickPending
;
128 return ((ms
+ pending
) * 1000) + (usTicks
* 1000 - cycle_cnt
) / usTicks
;
131 uint32_t micros(void)
133 register uint32_t ms
, cycle_cnt
;
135 // Call microsISR() in interrupt and elevated (non-zero) BASEPRI context
137 if ((SCB
->ICSR
& SCB_ICSR_VECTACTIVE_Msk
) || (__get_BASEPRI())) {
143 cycle_cnt
= SysTick
->VAL
;
144 } while (ms
!= sysTickUptime
|| cycle_cnt
> sysTickValStamp
);
146 return (ms
* 1000) + (usTicks
* 1000 - cycle_cnt
) / usTicks
;
149 inline uint32_t getCycleCounter(void)
154 uint32_t clockCyclesToMicros(uint32_t clockCycles
)
156 return clockCycles
/ usTicks
;
159 // Return system uptime in milliseconds (rollover in 49 days)
160 uint32_t millis(void)
162 return sysTickUptime
;
166 void delayMicroseconds(uint32_t us
)
168 uint32_t now
= micros();
169 while (micros() - now
< us
);
172 void delayMicroseconds(uint32_t us
)
174 uint32_t elapsed
= 0;
175 uint32_t lastCount
= SysTick
->VAL
;
178 register uint32_t current_count
= SysTick
->VAL
;
181 // measure the time elapsed since the last time we checked
182 elapsed
+= current_count
- lastCount
;
183 lastCount
= current_count
;
185 // convert to microseconds
186 elapsed_us
= elapsed
/ usTicks
;
187 if (elapsed_us
>= us
)
190 // reduce the delay by the elapsed time
193 // keep fractional microseconds for the next iteration
199 void delay(uint32_t ms
)
202 delayMicroseconds(1000);
205 static void indicate(uint8_t count
, uint16_t duration
)
225 void indicateFailure(failureMode_e mode
, int codeRepeatsRemaining
)
227 while (codeRepeatsRemaining
--) {
228 indicate(WARNING_FLASH_COUNT
, WARNING_FLASH_DURATION_MS
);
230 delay(WARNING_PAUSE_DURATION_MS
);
232 indicate(mode
+ 1, WARNING_CODE_DURATION_LONG_MS
);
238 void failureMode(failureMode_e mode
)
240 indicateFailure(mode
, 10);
245 systemResetToBootloader(BOOTLOADER_REQUEST_ROM
);
249 void initialiseMemorySections(void)
252 /* Load functions into ITCM RAM */
253 extern uint8_t tcm_code_start
;
254 extern uint8_t tcm_code_end
;
255 extern uint8_t tcm_code
;
256 memcpy(&tcm_code_start
, &tcm_code
, (size_t) (&tcm_code_end
- &tcm_code_start
));
260 /* Load functions into RAM */
261 extern uint8_t ccm_code_start
;
262 extern uint8_t ccm_code_end
;
263 extern uint8_t ccm_code
;
264 memcpy(&ccm_code_start
, &ccm_code
, (size_t) (&ccm_code_end
- &ccm_code_start
));
268 /* Load FAST_DATA variable intializers into DTCM RAM */
269 extern uint8_t _sfastram_data
;
270 extern uint8_t _efastram_data
;
271 extern uint8_t _sfastram_idata
;
272 memcpy(&_sfastram_data
, &_sfastram_idata
, (size_t) (&_efastram_data
- &_sfastram_data
));
277 void initialiseD2MemorySections(void)
279 /* Load DMA_DATA variable intializers into D2 RAM */
280 extern uint8_t _sdmaram_bss
;
281 extern uint8_t _edmaram_bss
;
282 extern uint8_t _sdmaram_data
;
283 extern uint8_t _edmaram_data
;
284 extern uint8_t _sdmaram_idata
;
285 bzero(&_sdmaram_bss
, (size_t) (&_edmaram_bss
- &_sdmaram_bss
));
286 memcpy(&_sdmaram_data
, &_sdmaram_idata
, (size_t) (&_edmaram_data
- &_sdmaram_data
));
290 static void unusedPinInit(IO_t io
)
292 if (IOGetOwner(io
) == OWNER_FREE
) {
293 IOConfigGPIO(io
, IOCFG_IPU
);
297 void unusedPinsInit(void)
299 IOTraversePins(unusedPinInit
);