Numworks Epsilon  1.4.1
Graphing Calculator Operating System
device.cpp
Go to the documentation of this file.
1 #include "device.h"
2 #include "regs/regs.h"
3 extern "C" {
4 #include <assert.h>
5 }
6 #include <ion.h>
7 #include "led.h"
8 #include "display.h"
9 #include "keyboard.h"
10 #include "battery.h"
11 #include "sd_card.h"
12 #include "backlight.h"
13 #include "console.h"
14 #include "swd.h"
15 #include "usb.h"
16 #include "bench/bench.h"
17 
18 #define USE_SD_CARD 0
19 
20 // Public Ion methods
21 
22 /* TODO: The delay methods 'msleep' and 'usleep' are currently dependent on the
23  * optimizations chosen by the compiler. To prevent that and to gain in
24  * precision, we could use the controller cycle counter (Systick). */
25 
26 void Ion::msleep(long ms) {
27  for (volatile long i=0; i<8852*ms; i++) {
28  __asm volatile("nop");
29  }
30 }
31 void Ion::usleep(long us) {
32  for (volatile long i=0; i<9*us; i++) {
33  __asm volatile("nop");
34  }
35 }
36 
37 uint32_t Ion::crc32(const uint32_t * data, size_t length) {
38  bool initialCRCEngineState = RCC.AHB1ENR()->getCRCEN();
39  RCC.AHB1ENR()->setCRCEN(true);
40  CRC.CR()->setRESET(true);
41 
42  const uint32_t * end = data + length;
43  while (data < end) {
44  CRC.DR()->set(*data++);
45  }
46 
47  uint32_t result = CRC.DR()->get();
48  RCC.AHB1ENR()->setCRCEN(initialCRCEngineState);
49  return result;
50 }
51 
53  bool initialRNGEngineState = RCC.AHB2ENR()->getRNGEN();
54  RCC.AHB2ENR()->setRNGEN(true);
55 
56  RNG.CR()->setRNGEN(true);
57 
58  while (RNG.SR()->getDRDY() == 0) {
59  }
60  uint32_t result = RNG.DR()->get();
61 
62  RNG.CR()->setRNGEN(false);
63  RCC.AHB2ENR()->setRNGEN(initialRNGEngineState);
64 
65  return result;
66 }
67 
68 
69 
70 static inline char hex(uint8_t d) {
71  if (d > 9) {
72  return 'A'+d-10;
73  }
74  return '0'+d;
75 }
76 
77 void Ion::getSerialNumber(char * buffer) {
78  uint8_t * rawUniqueID = (uint8_t *)0x1FFF7A10;
79  for (int i=0; i<SerialNumberLength/2; i++) {
80  uint8_t d = *rawUniqueID++;
81  buffer[2*i] = hex(d >> 4);
82  buffer[2*i+1] = hex(d & 0xF);
83  }
84  buffer[SerialNumberLength] = 0;
85 }
86 
87 // Private Ion::Device methods
88 
89 namespace Ion {
90 namespace Device {
91 
92 void initFPU() {
93  // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0553a/BABDBFBJ.html
96  // FIXME: The pipeline should be flushed at this point
97 }
98 
99 void coreReset() {
100  // Perform a full core reset
101  CM4.AIRCR()->requestReset();
102 }
103 
104 void jumpReset() {
105  uint32_t * stackPointerAddress = reinterpret_cast<uint32_t *>(0x08000000);
106  uint32_t * resetHandlerAddress = reinterpret_cast<uint32_t *>(0x08000004);
107 
108  /* Jump to the reset service routine after having reset the stack pointer.
109  * Both addresses are fetched from the base of the Flash memory, just like a
110  * real reset would. These operations should be made at once, otherwise the C
111  * compiler might emit some instructions that modify the stack inbetween. */
112 
113  asm volatile (
114  "msr MSP, %[stackPointer] ; bx %[resetHandler]"
115  : :
116  [stackPointer] "r" (*stackPointerAddress),
117  [resetHandler] "r" (*resetHandlerAddress)
118  );
119 }
120 
121 void init() {
122  initClocks();
123 
124  // Ensure right location of interrupt vectors
125  // The bootloader leaves its own after flashing
127  CM4.VTOR()->setVTOR((void*) 0);
128 
129  // Put all inputs as Analog Input, No pull-up nor pull-down
130  // Except for the SWD port (PB3, PA13, PA14)
131  GPIOA.MODER()->set(0xEBFFFFFF);
132  GPIOA.PUPDR()->set(0x24000000);
133  GPIOB.MODER()->set(0xFFFFFFBF);
134  GPIOB.PUPDR()->set(0x00000000);
135  for (int g=2; g<5; g++) {
136  GPIO(g).MODER()->set(0xFFFFFFFF); // All to "Analog"
137  GPIO(g).PUPDR()->set(0x00000000); // All to "None"
138  }
139 
140 #if EPSILON_DEVICE_BENCH
141  bool consolePeerConnectedOnBoot = Ion::Console::Device::peerConnected();
142 #endif
143 
144  initPeripherals();
145 
146 #if EPSILON_DEVICE_BENCH
147  if (consolePeerConnectedOnBoot) {
149  }
150 #endif
151 }
152 
153 void shutdown() {
155  shutdownClocks();
156 }
157 
165 #if USE_SD_CARD
167 #endif
170 }
171 
175 #if USE_SD_CARD
177 #endif
184 }
185 
186 void initClocks() {
187  /* System clock
188  * Configure the CPU at 96 MHz, APB2 and USB at 48 MHz. */
189 
190  /* After reset the Flash runs as fast as the CPU. When we clock the CPU faster
191  * the flash memory cannot follow and therefore flash memory accesses need to
192  * wait a little bit.
193  * The spec tells us that at 2.8V and over 90MHz the flash expects 3 WS. */
194  FLASH.ACR()->setLATENCY(3);
195 
196  /* Enable prefetching flash instructions */
197  /* Fetching instructions increases slightly the power consumption but the
198  * increase is negligible compared to the screen consumption. */
199  FLASH.ACR()->setPRFTEN(true);
200 
201  /* Set flash instruction and data cache */
202  FLASH.ACR()->setDCEN(true);
203  FLASH.ACR()->setICEN(true);
204 
205  /* After reset, the device is using the high-speed internal oscillator (HSI)
206  * as a clock source, which runs at a fixed 16 MHz frequency. The HSI is not
207  * accurate enough for reliable USB operation, so we need to use the external
208  * high-speed oscillator (HSE). */
209 
210  // Enable the HSE and wait for it to be ready
211  RCC.CR()->setHSEON(true);
212  while(!RCC.CR()->getHSERDY()) {
213  }
214 
215  /* Given the crystal used on our device, the HSE will oscillate at 25 MHz. By
216  * piping it through a phase-locked loop (PLL) we can derive other frequencies
217  * for use in different parts of the system. Combining the default PLL values
218  * with a PLLM of 25 and a PLLQ of 4 yields both a 96 MHz frequency for SYSCLK
219  * and the required 48 MHz USB clock. */
220 
221  // Configure the PLL ratios and use HSE as a PLL input
222  RCC.PLLCFGR()->setPLLM(25);
223  RCC.PLLCFGR()->setPLLQ(4);
225  // 96 MHz is too fast for APB1. Divide it by two to reach 48 MHz
227 
228  // Enable the PLL and wait for it to be ready
229  RCC.CR()->setPLLON(true);
230  while(!RCC.CR()->getPLLRDY()) {
231  }
232 
233  // Use the PLL output as a SYSCLK source
235  while (RCC.CFGR()->getSWS() != RCC::CFGR::SW::PLL) {
236  }
237 
238  // Now that we don't need use it anymore, turn the HSI off
239  RCC.CR()->setHSION(false);
240 
241  // Peripheral clocks
242 
243  // AHB1 bus
244  // Our peripherals are using GPIO A, B, C, D and E.
245  // We're not using the CRC nor DMA engines.
246  class RCC::AHB1ENR ahb1enr(0); // Reset value
247  ahb1enr.setGPIOAEN(true);
248  ahb1enr.setGPIOBEN(true);
249  ahb1enr.setGPIOCEN(true);
250  ahb1enr.setGPIODEN(true);
251  ahb1enr.setGPIOEEN(true);
252  ahb1enr.setDMA2EN(true);
253  RCC.AHB1ENR()->set(ahb1enr);
254 
255  // AHB2 bus
256  RCC.AHB2ENR()->setOTGFSEN(true);
257 
258  // AHB3 bus
259  RCC.AHB3ENR()->setFSMCEN(true);
260 
261  // APB1 bus
262  // We're using TIM3
263  RCC.APB1ENR()->setTIM3EN(true);
264  RCC.APB1ENR()->setPWREN(true);
265 
266  // APB2 bus
267  class RCC::APB2ENR apb2enr(0x00008000); // Reset value
268  apb2enr.setADC1EN(true);
269  apb2enr.setSYSCFGEN(true);
270 #if USE_SD_CARD
271  apb2enr.setSDIOEN(true);
272 #endif
273  RCC.APB2ENR()->set(apb2enr);
274 }
275 
277  // APB2 bus
278  RCC.APB2ENR()->set(0x00008000); // Reset value
279 
280  // AHB1
281  RCC.APB1ENR()->set(0x00000400);
282 
283  // AHB1 bus
284  RCC.AHB1ENR()->set(0); // Reset value
285 
286  RCC.AHB3ENR()->setFSMCEN(false);
287 }
288 
289 }
290 }
void shutdownClocks()
Definition: device.cpp:276
void shutdown()
Definition: led.cpp:25
void init()
Definition: led.cpp:20
Definition: rcc.h:31
Definition: gpio.h:6
def data
Definition: i18n.py:176
Definition: rng.h:6
void shutdown()
Definition: device.cpp:153
void msleep(long ms)
Definition: ion.cpp:4
void setPLLSRC(PLLSRC s) volatile
Definition: rcc.h:26
Definition: syscfg.h:8
void init()
Definition: usb.cpp:44
uint32_t random()
Definition: device.cpp:52
unsigned char uint8_t
Definition: stdint.h:4
Definition: cm4.h:6
Definition: rcc.h:6
void set(Register< T > value) volatile
Definition: register.h:12
T get() volatile
Definition: register.h:18
void jumpReset()
Definition: device.cpp:104
void initClocks()
Definition: device.cpp:186
constexpr GPIO GPIOB(1)
Definition: crc.h:6
void init()
Definition: device.cpp:121
unsigned int uint32_t
Definition: stdint.h:6
void shutdownPeripherals()
Definition: device.cpp:172
void getSerialNumber(char *buffer)
Definition: device.cpp:77
void shutdown()
Definition: swd.cpp:15
void requestReset() volatile
Definition: cm4.h:32
void coreReset()
Definition: device.cpp:99
void setAccess(int index, Access a) volatile
Definition: cm4.h:24
void shutdown()
Definition: usb.cpp:49
uint32_t crc32(const uint32_t *data, size_t length)
Definition: device.cpp:37
void initPeripherals()
Definition: device.cpp:158
Definition: cm4.h:30
void usleep(long us)
Definition: device.cpp:31
Definition: crc.h:11
void initFPU()
Definition: device.cpp:92
Definition: cm4.h:10
Definition: crc.h:8
Definition: cm4.h:17
Definition: rcc.h:8
constexpr GPIO GPIOA(0)
Definition: rng.h:8
Definition: backlight.h:6
Definition: rng.h:18
void setPPRE1(AHBRatio r) volatile
Definition: rcc.h:47
SW getSWS() volatile
Definition: rcc.h:39
void setSW(SW s) volatile
Definition: rcc.h:38
Definition: flash.h:6
void init()
Definition: swd.cpp:8
Definition: rng.h:13
void setVTOR(void *address) volatile
Definition: cm4.h:12