-
Notifications
You must be signed in to change notification settings - Fork 118
/
platform.cpp
179 lines (156 loc) · 4.3 KB
/
platform.cpp
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
#include "pxt.h"
#include "SAMDTCTimer.h"
#include "SAMDTCCTimer.h"
#include "light.h"
namespace pxt {
struct TimerConfig {
uint8_t id;
uint8_t irq;
uint8_t dmaovf;
uint32_t addr;
};
#define DEF_TC(n) \
{ 0x10 + n, TC##n##_IRQn, TC##n##_DMAC_ID_OVF, (uint32_t)TC##n }
#ifdef SAMD21
#define DEF_TCC(n) \
{ 0x20 + n, TCC##n##_IRQn, TCC##n##_DMAC_ID_OVF, (uint32_t)TCC##n }
#else
#define DEF_TCC(n) \
{ 0x20 + n, TCC##n##_0_IRQn, TCC##n##_DMAC_ID_OVF, (uint32_t)TCC##n }
#endif
static const TimerConfig timers[] = {
#ifdef TC0
DEF_TC(0),
#endif
#ifdef TC1
DEF_TC(1),
#endif
#ifdef TC2
DEF_TC(2),
#endif
#ifdef TC3
DEF_TC(3),
#endif
#ifdef TC4
DEF_TC(4),
#endif
#ifdef TC5
DEF_TC(5),
#endif
#ifdef TCC0
DEF_TCC(0),
#endif
#ifdef TCC1
DEF_TCC(1),
#endif
#ifdef TCC2
DEF_TCC(2),
#endif
{0, 0, 0, 0}};
// Backlight:
// Kitronik: PA6 TC1 (ch 0)
// Adafruit: PA1 TC2 (ch 1)
// TC3 is used by DAC on both D21 and D51
// TCC0 and TC4 is used by IR
// TCC0, TCC1, TC4 is used by PWM on CPX
#ifdef SAMD21
#define DEF_TIMERS 0x15222021 // TC5 TCC2 TCC0 TCC1
#else
#define DEF_TIMERS 0x10111200 // TC0 TC1 TC2
#endif
static uint32_t usedTimers;
static int timerIdx(uint8_t id) {
for (unsigned i = 0; timers[i].id; i++) {
if (id == timers[i].id)
return i;
}
return -1;
}
LowLevelTimer *allocateTimer() {
uint32_t timersToUse = getConfig(CFG_TIMERS_TO_USE, DEF_TIMERS);
uint8_t blTC = 0;
// DAC hard-wired to TC3 right now
uint8_t dacTC = 0x13;
// if BL is on a known pin, don't use its PWM TC
// this is a hack for legacy boards that don't have CFG_TIMERS_TO_USE
auto blPin = PIN(DISPLAY_BL);
if (blPin == PA01)
blTC = 0x12;
for (int shift = 24; shift >= 0; shift -= 8) {
uint8_t tcId = (timersToUse >> shift) & 0xff;
if (tcId == 0 || tcId == blTC || tcId == dacTC)
continue;
int idx = timerIdx(tcId);
if (idx < 0 || (usedTimers & (1 << idx)))
continue;
LowLevelTimer *res;
if (idx < 0x20) {
Tc *tc = (Tc *)timers[idx].addr;
if (tc->COUNT16.CTRLA.bit.ENABLE)
continue;
DMESG("allocate TC%d", tcId & 0xf);
res = new SAMDTCTimer(tc, timers[idx].irq);
} else {
Tcc *tcc = (Tcc *)timers[idx].addr;
if (tcc->CTRLA.bit.ENABLE)
continue;
DMESG("allocate TCC%d", tcId & 0xf);
res = new SAMDTCCTimer(tcc, timers[idx].irq);
}
usedTimers |= 1 << idx;
return res;
}
soft_panic(PANIC_OUT_OF_TIMERS);
return NULL;
}
static void initRandomSeed() {
int seed = 0xC0DA1;
// TODO use TRNG
seedRandom(seed);
}
void platformSendSerial(const char *data, int len) {}
#ifdef SAMD21
static void remapSwdPin(int pinCfg, int fallback) {
int pinName = getConfig(pinCfg);
if (pinName == PA30 || pinName == PA31) {
if (getConfig(CFG_SWD_ENABLED, 0)) {
linkPin(pinName, fallback);
} else {
PORT->Group[pinName / 32].PINCFG[pinName % 32].reg = (uint8_t)PORT_PINCFG_INEN;
}
}
}
static void initSwdPins() {
remapSwdPin(CFG_PIN_NEOPIXEL, PIN(D0));
remapSwdPin(CFG_PIN_RXLED, PIN(D1));
remapSwdPin(CFG_PIN_SPEAKER_AMP, PIN(A2));
}
#else
static void initSwdPins() {}
#endif
void platform_init() {
initSwdPins();
initRandomSeed();
setSendToUART(platformSendSerial);
light::clear();
/*
if (*HF2_DBG_MAGIC_PTR == HF2_DBG_MAGIC_START) {
*HF2_DBG_MAGIC_PTR = 0;
// this will cause alignment fault at the first breakpoint
globals[0] = (TValue)1;
}
*/
}
int *getBootloaderConfigData() {
#ifdef SAMD51
auto config_data = *(uint32_t *)(BOOTLOADER_END - 4 * 4);
if (config_data && (config_data & 3) == 0 && config_data < BOOTLOADER_END) {
auto p = (uint32_t *)config_data;
if (p[0] == CFG_MAGIC0 && p[1] == CFG_MAGIC1)
return (int *)p + 4;
}
#endif
return NULL;
}
} // namespace pxt
void cpu_clock_init() {}