By default mark OSD element as rendered in case it's in the off blink state (#14188...
[betaflight.git] / src / platform / common / stm32 / system.c
blobd21e0ee956adc2aa1b319d61ce4d33cb02369a60
1 /*
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)
8 * any later version.
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/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
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
44 #endif
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;
64 #else
65 RCC_ClocksTypeDef clocks;
66 RCC_GetClocksFreq(&clocks);
67 cpuClockFrequency = clocks.SYSCLK_Frequency;
68 #endif
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.
81 #define DWT_LAR
82 __O uint32_t *DWTLAR = (uint32_t *)(DWT_BASE + 0x0FB0);
83 *(DWTLAR) = DWT_LAR_UNLOCK_VALUE;
84 #endif
85 #endif
87 DWT->CYCCNT = 0;
88 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
91 // SysTick
93 static volatile int sysTickPending = 0;
95 void SysTick_Handler(void)
97 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
98 sysTickUptime++;
99 sysTickValStamp = SysTick->VAL;
100 sysTickPending = 0;
101 (void)(SysTick->CTRL);
103 #ifdef USE_HAL_DRIVER
104 // used by the HAL for some timekeeping and timeouts, should always be 1ms
105 HAL_IncTick();
106 #endif
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) {
119 // Update pending.
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.
124 sysTickPending = 1;
126 // Read VAL again to ensure the value is read after the rollover.
128 cycle_cnt = SysTick->VAL;
131 ms = sysTickUptime;
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())) {
145 return microsISR();
148 do {
149 ms = sysTickUptime;
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)
158 return DWT->CYCCNT;
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;
194 #if 1
195 void delayMicroseconds(uint32_t us)
197 uint32_t now = micros();
198 while (micros() - now < us);
200 #else
201 void delayMicroseconds(uint32_t us)
203 uint32_t elapsed = 0;
204 uint32_t lastCount = SysTick->VAL;
206 for (;;) {
207 register uint32_t current_count = SysTick->VAL;
208 uint32_t elapsed_us;
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)
217 break;
219 // reduce the delay by the elapsed time
220 us -= elapsed_us;
222 // keep fractional microseconds for the next iteration
223 elapsed %= usTicks;
226 #endif
228 void delay(uint32_t ms)
230 while (ms--)
231 delayMicroseconds(1000);
234 static void indicate(uint8_t count, uint16_t duration)
236 if (count) {
237 LED1_ON;
238 LED0_OFF;
240 while (count--) {
241 LED1_TOGGLE;
242 LED0_TOGGLE;
243 BEEP_ON;
244 delay(duration);
246 LED1_TOGGLE;
247 LED0_TOGGLE;
248 BEEP_OFF;
249 delay(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);
263 delay(1000);
267 void failureMode(failureMode_e mode)
269 indicateFailure(mode, 10);
271 #ifdef DEBUG
272 systemReset();
273 #else
274 systemResetToBootloader(BOOTLOADER_REQUEST_ROM);
275 #endif
278 void initialiseMemorySections(void)
280 #ifdef USE_ITCM_RAM
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));
286 #endif
288 #ifdef USE_CCM_CODE
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));
294 #endif
296 #ifdef USE_FAST_DATA
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));
302 #endif
304 #ifdef USE_RAM_CODE
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));
310 #endif
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" },
366 #else
367 #error MCU Type info not defined for STM (or clone)
368 #endif
370 unsigned revision = 0;
371 #if defined(STM32H743xx)
372 switch (HAL_GetREVID()) {
373 case REV_ID_Y:
374 revision = 1;
375 break;
376 case REV_ID_X:
377 revision = 2;
378 break;
379 case REV_ID_V:
380 revision = 3;
381 break;
382 default:
383 revision = 0;
385 #endif
386 return info + revision;