New SPI API supporting DMA
[betaflight.git] / src / main / drivers / system.c
blobd6b340fc61f7821480c99b2a36dea44f1828fba2
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"
36 #include "system.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
45 #endif
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();
60 #else
61 RCC_ClocksTypeDef clocks;
62 RCC_GetClocksFreq(&clocks);
63 cpuClockFrequency = clocks.SYSCLK_Frequency;
64 #endif
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.
74 #define DWT_LAR
75 __O uint32_t *DWTLAR = (uint32_t *)(DWT_BASE + 0x0FB0);
76 *(DWTLAR) = DWT_LAR_UNLOCK_VALUE;
77 #endif
78 #endif
80 DWT->CYCCNT = 0;
81 DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
84 // SysTick
86 static volatile int sysTickPending = 0;
88 void SysTick_Handler(void)
90 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
91 sysTickUptime++;
92 sysTickValStamp = SysTick->VAL;
93 sysTickPending = 0;
94 (void)(SysTick->CTRL);
96 #ifdef USE_HAL_DRIVER
97 // used by the HAL for some timekeeping and timeouts, should always be 1ms
98 HAL_IncTick();
99 #endif
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) {
112 // Update pending.
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.
117 sysTickPending = 1;
119 // Read VAL again to ensure the value is read after the rollover.
121 cycle_cnt = SysTick->VAL;
124 ms = sysTickUptime;
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())) {
138 return microsISR();
141 do {
142 ms = sysTickUptime;
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)
151 return DWT->CYCCNT;
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;
165 #if 1
166 void delayMicroseconds(uint32_t us)
168 uint32_t now = micros();
169 while (micros() - now < us);
171 #else
172 void delayMicroseconds(uint32_t us)
174 uint32_t elapsed = 0;
175 uint32_t lastCount = SysTick->VAL;
177 for (;;) {
178 register uint32_t current_count = SysTick->VAL;
179 uint32_t elapsed_us;
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)
188 break;
190 // reduce the delay by the elapsed time
191 us -= elapsed_us;
193 // keep fractional microseconds for the next iteration
194 elapsed %= usTicks;
197 #endif
199 void delay(uint32_t ms)
201 while (ms--)
202 delayMicroseconds(1000);
205 static void indicate(uint8_t count, uint16_t duration)
207 if (count) {
208 LED1_ON;
209 LED0_OFF;
211 while (count--) {
212 LED1_TOGGLE;
213 LED0_TOGGLE;
214 BEEP_ON;
215 delay(duration);
217 LED1_TOGGLE;
218 LED0_TOGGLE;
219 BEEP_OFF;
220 delay(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);
234 delay(1000);
238 void failureMode(failureMode_e mode)
240 indicateFailure(mode, 10);
242 #ifdef DEBUG
243 systemReset();
244 #else
245 systemResetToBootloader(BOOTLOADER_REQUEST_ROM);
246 #endif
249 void initialiseMemorySections(void)
251 #ifdef USE_ITCM_RAM
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));
257 #endif
259 #ifdef USE_CCM_CODE
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));
265 #endif
267 #ifdef USE_FAST_DATA
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));
273 #endif
276 #ifdef STM32H7
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));
288 #endif
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);