-
Notifications
You must be signed in to change notification settings - Fork 2k
/
cpu.h
235 lines (206 loc) · 6.21 KB
/
cpu.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
/*
* Copyright (C) 2014-2015 Freie Universität Berlin
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_cortexm_common ARM Cortex-M common
* @ingroup cpu
* @brief Common implementations and headers for Cortex-M family based
* micro-controllers
* @{
*
* @file
* @brief Basic definitions for the Cortex-M common module
*
* When ever you want to do something hardware related, that is accessing MCUs
* registers, just include this file. It will then make sure that the MCU
* specific headers are included.
*
* @author Stefan Pfeiffer <[email protected]>
* @author Hauke Petersen <[email protected]>
* @author Joakim Nohlgård <[email protected]>
*
* @todo remove include irq.h once core was adjusted
*/
#ifndef CPU_H
#define CPU_H
#include <stdio.h>
#include "irq.h"
#include "sched.h"
#include "thread.h"
#include "cpu_conf.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Interrupt stack canary value
*
* @note 0xe7fe is the ARM Thumb machine code equivalent of asm("bl #-2\n") or
* 'while (1);', i.e. an infinite loop.
* @internal
*/
#define STACK_CANARY_WORD (0xE7FEE7FEu)
/**
* @brief All Cortex-m-based CPUs provide pm_set_lowest
*
* The pm_set_lowest is provided either by the pm_layered module if used, or
* alternatively as fallback by the cortexm's own implementation.
*/
#define PROVIDES_PM_SET_LOWEST
/**
* @brief Pattern to write into the co-processor Access Control Register to
* allow full FPU access
*
* Used in the @ref cortexm_init_fpu inline function below.
*/
#define CORTEXM_SCB_CPACR_FPU_ACCESS_FULL (0x00f00000)
/**
* @brief Initialization of the CPU
*/
void cpu_init(void);
/**
* @brief Initialize Cortex-M specific core parts of the CPU
*
* @ref cortexm_init calls, in a default order, @ref cortexm_init_fpu,
* @ref cortexm_init_isr_priorities, and @ref cortexm_init_misc. Also
* performs other default initialisations, including ones which you
* may or may not want.
*
* Unless you have special requirements (like nRF52 with SD has), it
* is sufficient to call just @ref cortexm_init and the `cortexm_init_*`
* functions do not need to (and should not) be called separately.
* If you have conflicting requirements, you may want to have a look
* `cpu/nrft/cpu.c` for an example of a non-default approach.
*/
void cortexm_init(void);
/**
* @brief Initialize Cortex-M FPU
*
* Called from `cpu/nrf52/cpu.c`, since it cannot use the
* whole @ref cortexm_init due to conflicting requirements.
*
* Defined here as a static inline function to allow all
* callers to optimise this away if the FPU is not used.
*/
static inline void cortexm_init_fpu(void)
{
/* initialize the FPU on Cortex-M4F CPUs */
#if defined(CPU_ARCH_CORTEX_M4F) || defined(CPU_ARCH_CORTEX_M7)
/* give full access to the FPU */
SCB->CPACR |= (uint32_t)CORTEXM_SCB_CPACR_FPU_ACCESS_FULL;
#endif
}
#if defined(CPU_CORTEXM_INIT_SUBFUNCTIONS) || defined(DOXYGEN)
/**
* @brief Initialize Cortex-M interrupt priorities
*
* Called from `cpu/nrf52/cpu.c`, since it cannot use the
* whole @ref cortexm_init due to conflicting requirements.
*
* Define `CPU_CORTEXM_INIT_SUBFUNCTIONS` to make this function
* publicly available.
*/
void cortexm_init_isr_priorities(void);
/**
* @brief Initialize Cortex-M misc functions
*
* Called from `cpu/nrf52/cpu.c`, since it cannot use the
* whole @ref cortexm_init due to conflicting requirements.
*
* Define `CPU_CORTEXM_INIT_SUBFUNCTIONS` to make this function
* publicly available.
*/
void cortexm_init_misc(void);
#endif /* defined(CPU_CORTEXM_INIT_SUBFUNCTIONS) || defined(DOXYGEN) */
/**
* @brief Prints the current content of the link register (lr)
*/
static inline void cpu_print_last_instruction(void)
{
uint32_t *lr_ptr;
__asm__ __volatile__("mov %0, lr" : "=r"(lr_ptr));
printf("%p\n", (void*) lr_ptr);
}
/**
* @brief Put the CPU into the 'wait for event' sleep mode
*
* This function is meant to be used for short periods of time, where it is not
* feasible to switch to the idle thread and back.
*/
static inline void cortexm_sleep_until_event(void)
{
__WFE();
}
/**
* @brief Put the CPU into (deep) sleep mode, using the `WFI` instruction
*
* @param[in] deep !=0 for deep sleep, 0 for light sleep
*/
static inline void cortexm_sleep(int deep)
{
if (deep) {
SCB->SCR |= (SCB_SCR_SLEEPDEEP_Msk);
}
else {
SCB->SCR &= ~(SCB_SCR_SLEEPDEEP_Msk);
}
/* ensure that all memory accesses have completed and trigger sleeping */
unsigned state = irq_disable();
__DSB();
__WFI();
#if defined(CPU_MODEL_STM32L152RE)
/* STM32L152RE crashes without this __NOP(). See #8518. */
__NOP();
#endif
irq_restore(state);
}
/**
* @brief Trigger a conditional context scheduler run / context switch
*
* This function is supposed to be called in the end of each ISR.
*/
static inline void cortexm_isr_end(void)
{
if (sched_context_switch_request) {
thread_yield_higher();
}
}
/**
* @brief Jumps to another image in flash
*
* This function is supposed to be called by a bootloader application.
*
* @param[in] image_address address in flash of other image
*/
static inline void cpu_jump_to_image(uint32_t image_address)
{
/* Disable IRQ */
__disable_irq();
/* set MSP */
__set_MSP(*(uint32_t*)image_address);
/* skip stack pointer */
image_address += 4;
/* load the images reset_vector address */
uint32_t destination_address = *(uint32_t*)image_address;
/* Make sure the Thumb State bit is set. */
destination_address |= 0x1;
/* Branch execution */
__asm("BX %0" :: "r" (destination_address));
}
/* The following register is only present for Cortex-M0+, -M3, -M4 and -M7 CPUs */
#if defined(CPU_ARCH_CORTEX_M0PLUS) || defined(CPU_ARCH_CORTEX_M3) || \
defined(CPU_ARCH_CORTEX_M4) || defined(CPU_ARCH_CORTEX_M4F) || \
defined(CPU_ARCH_CORTEX_M7)
static inline uint32_t cpu_get_image_baseaddr(void)
{
return SCB->VTOR;
}
#endif
#ifdef __cplusplus
}
#endif
#endif /* CPU_H */
/** @} */