/
system.h
308 lines (265 loc) · 8.79 KB
/
system.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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
#ifndef DSY_SYSTEM_H
#define DSY_SYSTEM_H
#ifndef UNIT_TEST // for unit tests, a dummy implementation is provided below
#include <cstdint>
#include "per/tim.h"
namespace daisy
{
/** A handle for interacting with the Core System.
** This includes the Clock tree, MPU, global DMA initialization,
** cache handling, and any other necessary global initiailzation
**
** @author shensley
** @ingroup system
*/
class System
{
public:
/** Contains settings for initializing the System */
struct Config
{
/** Specifies the system clock frequency that feeds APB/AHB clocks, etc. */
enum class SysClkFreq
{
FREQ_400MHZ,
FREQ_480MHZ,
};
/** Method to call on the struct to set to defaults
** CPU Freq set to 400MHz
** Cache Enabled
** */
void Defaults()
{
cpu_freq = SysClkFreq::FREQ_400MHZ;
use_dcache = true;
use_icache = true;
skip_clocks = false;
}
/** Method to call on the struct to set to boost mode:
** CPU Freq set to 480MHz
** Cache Enabled
** */
void Boost()
{
cpu_freq = SysClkFreq::FREQ_480MHZ;
use_dcache = true;
use_icache = true;
skip_clocks = false;
}
SysClkFreq cpu_freq;
bool use_dcache;
bool use_icache;
bool skip_clocks;
};
/** Describes the different regions of memory available to the Daisy */
enum MemoryRegion
{
INTERNAL_FLASH = 0,
ITCMRAM,
DTCMRAM,
SRAM_D1,
SRAM_D2,
SRAM_D3,
SDRAM,
QSPI,
INVALID_ADDRESS,
};
/** Bootloader struct for controlling bootloading parameters */
struct BootInfo
{
enum class Type : uint32_t
{
INVALID = 0x00000000,
JUMP = 0xDEADBEEF,
SKIP_TIMEOUT = 0x5AFEB007,
INF_TIMEOUT = 0xB0074EFA,
} status;
uint32_t data;
enum class Version : uint32_t
{
LT_v6_0 = 0, // Less than v6.0
NONE, // No bootloader present
v6_0, // v6.0
v6_1, // v6.1 or greater
LAST
} version;
};
System() {}
~System() {}
/** Default Initializer with no input will create an internal config,
** and set everything to Defaults
*/
void Init();
/** Configurable Initializer
** Initializes clock tree, DMA initializaiton and
** any necessary global inits.
*/
void Init(const Config& config);
/** Deinitializer
** Deinitializes all modules and peripherals
** set up with `Init`.
*/
void DeInit();
/** Jumps to the first address of the external flash chip (0x90000000)
** If there is no code there, the chip will likely fall through to the while() loop
** TODO: Documentation/Loader for using external flash coming soon.
*/
void JumpToQspi();
/** \return a uint32_t value of milliseconds since the SysTick started
*/
static uint32_t GetNow();
/** \return a uint32_t of microseconds within the internal timer. */
static uint32_t GetUs();
/** \return a uint32_t of ticks at (PCLk1 * 2)Hz
** Useful for measuring the number of CPU ticks
** something is taking.
** */
static uint32_t GetTick();
/** Blocking Delay that uses the SysTick (1ms callback) to wait.
** \param delay_ms Time to delay in ms
*/
static void Delay(uint32_t delay_ms);
/** Blocking Delay using internal timer to wait
** \param delay_us Time to ddelay in microseconds */
static void DelayUs(uint32_t delay_us);
/** Blocking Delay using internal timer to wait
** \param delay_ticks Time to ddelay in microseconds */
static void DelayTicks(uint32_t delay_ticks);
/** Specify how the Daisy should return to the bootloader
* \param STM return to the STM32-provided
* bootloader to program internal flash
* \param DAISY if the Daisy bootloader is used,
* this will return to it
* \param DAISY_NO_TIMEOUT if the Daisy bootloader
* is used, this will return to it and skip the
* timeout window
*/
enum BootloaderMode
{
STM = 0,
DAISY,
DAISY_SKIP_TIMEOUT,
DAISY_INFINITE_TIMEOUT
};
/** Triggers a reset of the seed and starts in bootloader
** mode to allow firmware update. */
static void ResetToBootloader(BootloaderMode mode = BootloaderMode::STM);
/** Initializes the backup SRAM */
static void InitBackupSram();
/** Checks Daisy Bootloader version, if present. */
static BootInfo::Version GetBootloaderVersion();
/** Returns the tick rate in Hz with which GetTick() is incremented. */
static uint32_t GetTickFreq();
/** Returns the Frequency of the system clock in Hz
** This is the primary system clock that is used to generate
** AXI Peripheral, APB, and AHB clocks. */
static uint32_t GetSysClkFreq();
/** Returns the frequency of the HCLK (AHB) clock. This is derived
** from the System clock, and used to clock the CPU, memory, and
** peripherals mapped on the AHB, and APB Bus.
** */
static uint32_t GetHClkFreq();
/** Returns the frequency of the PCLK1 (APB1) clock
** This is used to clock various peripherals, and timers.
**
** It's important to note that many timers run on a
** clock twice as fast as the peripheral clock for the timer.
** */
static uint32_t GetPClk1Freq();
/** Returns the frequency of the PCLK2 (APB2) clock
** This is used to clock various peripherals, and timers.
**
** It's important to note that many timers run on a
** clock twice as fast as the peripheral clock for the timer.
** */
static uint32_t GetPClk2Freq();
/**
** Returns a const reference to the Systems Configuration struct.
*/
const Config& GetConfig() const { return cfg_; }
/** Returns an enum representing the current (primary) memory space used
* for executing the program.
*/
static MemoryRegion GetProgramMemoryRegion();
/** Returns an enum representing the the memory region
* that the given address belongs to.
* \param address The address to be checked
*/
static MemoryRegion GetMemoryRegion(uint32_t address);
/** This constant indicates the Daisy bootloader's offset from
* the beginning of QSPI's address space.
* Data written within the first 256K will remain
* untouched by the Daisy bootloader.
*/
static constexpr uint32_t kQspiBootloaderOffset = 0x40000U;
private:
void ConfigureClocks();
void ConfigureMpu();
Config cfg_;
/** One TimerHandle to rule them all
** Maybe this whole class should be static.. */
static TimerHandle tim_;
};
extern volatile daisy::System::BootInfo boot_info;
} // namespace daisy
#else // ifndef UNIT_TEST
#include <cstdint>
#include "../tests/TestIsolator.h"
namespace daisy
{
/** This is a dummy implementation for use in unit tests.
* In your test, you can set the current system time to
* control the "flow of time" :-)
* Only the time-related functions are added here. If
* your tests need some of the other functions, feel
* free to add them here as well.
*
* To decouple tests that are running in parallel, each
* test can independently modify the current time.
*/
class System
{
public:
static uint32_t GetNow()
{
return testIsolator_.GetStateForCurrentTest()->currentUs_ / 1000;
}
static uint32_t GetUs()
{
return testIsolator_.GetStateForCurrentTest()->currentUs_;
}
static uint32_t GetTick()
{
return testIsolator_.GetStateForCurrentTest()->currentTick_;
}
static uint32_t GetTickFreq()
{
return testIsolator_.GetStateForCurrentTest()->tickFreqHz_;
}
/** Sets the current "tick" value for the test that's currently running. */
static void SetTickForUnitTest(uint32_t tick)
{
testIsolator_.GetStateForCurrentTest()->currentTick_ = tick;
}
/** Sets the current microsecond value for the test that's currently running. */
static void SetUsForUnitTest(uint32_t us)
{
testIsolator_.GetStateForCurrentTest()->currentUs_ = us;
}
/** Sets the tick frequency for the test that's currently running. */
static void SetTickFreqForUnitTest(uint32_t freqInHz)
{
testIsolator_.GetStateForCurrentTest()->tickFreqHz_ = freqInHz;
}
private:
struct SystemState
{
uint32_t currentTick_ = 0;
uint32_t currentUs_ = 0;
uint32_t tickFreqHz_ = 0;
};
static TestIsolator<SystemState> testIsolator_;
};
} // namespace daisy
#endif // ifndef UNIT_TEST
#endif