-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbootloader.c
163 lines (134 loc) · 3.81 KB
/
bootloader.c
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
#include <stdint.h>
#include "kl17.h"
#include "core_cm0plus.h"
#include "palawan.h"
#include "palawan_bl.h"
#include "radio.h"
enum bootloader_reason bootloader_reason;
int updateRx(void);
int updateTx(void);
static __attribute__((section(".appvectors"))) uint32_t appVectors[64];
static int test_boot_token(void)
{
/*
* If we find a valid boot token in RAM, the application is asking us explicitly
* to enter DFU mode. This is used to implement the DFU_DETACH command when the app
* is running.
*/
return boot_token.magic == 0x74624346;
}
static int button_held_down(void)
{
int before;
int after;
/* Set PTB12 as a GPIO input, slow slew rate */
PORTB->PCR[12] = (1 << 8) | (1 << 2);
/* Set it as an input */
FGPIOB->PDDR &= ~(1 << 12);
/* If the pin isn't held down, don't enter the bootloader */
before = !(FGPIOB->PDIR & (1 << 12));
if (!before)
return 0;
/* Sample the pin before, then wait about 500ms and sample again */
{
int i;
for (i = 0; i < 500000; i++)
{
int j;
for (j = 0; j < 77; j++)
{
asm("");
}
}
}
after = !(FGPIOB->PDIR & (1 << 12));
if (!after)
return 0;
return 1;
}
static int should_enter_bootloader(void)
{
extern uint32_t __ram_start__;
extern uint32_t __ram_end__;
extern uint32_t __app_start__;
extern uint32_t __app_end__;
/* Reset the boot token if we've just been powered up for the first time */
if (RCM->SRS0 & RCM_SRS0_POR)
{
boot_token.magic = 0;
boot_token.boot_count = 0;
}
/* If the special magic number is present, enter the bootloader */
if (test_boot_token())
{
bootloader_reason = BOOT_TOKEN_PRESENT;
return 1;
}
/* If the user is holding the button down */
if (button_held_down())
{
bootloader_reason = BUTTON_HELD_DOWN;
return 1;
}
/* If we've failed to boot many times, enter the bootloader */
if (boot_token.boot_count > 3)
{
bootloader_reason = BOOT_FAILED_TOO_MANY_TIMES;
return 1;
}
/* Otherwise, if the application appears valid (i.e. stack is in a sane
* place, and the program counter is in flash,) boot to it */
if (((appVectors[0] >= (uint32_t)&__ram_start__) && (appVectors[0] <= (uint32_t)&__ram_end__)) && ((appVectors[1] >= (uint32_t)&__app_start__) && (appVectors[1] <= (uint32_t)&__app_end__)))
{
bootloader_reason = NOT_ENTERING_BOOTLOADER;
return 0;
}
/* If there is no valid program, enter the bootloader */
bootloader_reason = NO_PROGRAM_PRESENT;
return 1;
}
__attribute__((noreturn)) static void boot_app(void)
{
// Relocate IVT to application flash
__disable_irq();
SCB->VTOR = (uint32_t)&appVectors[0];
// Switch the clock mode from FEE back to FEI
if (palawanModel() == palawan_rx) {
MCG->C1 = /* Clear the IREFS bit to switch to the external reference. */
MCG_C1_CLKS_FLLPLL | /* Use FLL for system clock, MCGCLKOUT. */
MCG_C1_IRCLKEN | /* Enable the internal reference clock. */
MCG_C1_IREFS; /* Use the internal reference clock. */
MCG->C6 = 0; /* PLLS=0: Select FLL as MCG source, not PLL */
}
// Refresh watchdog right before launching app
watchdog_refresh();
// Clear the boot token, so we don't repeatedly enter DFU mode.
boot_token.magic = 0;
boot_token.boot_count++;
asm volatile(
"mov lr, %0 \n\t"
"mov sp, %1 \n\t"
"bx %2 \n\t"
:
: "r"(0xFFFFFFFF),
"r"(appVectors[0]),
"r"(appVectors[1]));
while (1)
;
}
__attribute__((noreturn)) void bootloader_main(void)
{
if (should_enter_bootloader())
{
boot_token.magic = 0;
boot_token.boot_count = 0;
spiInit();
radioInit();
if (palawanModel() == palawan_rx)
/* Start USB */
updateRx();
else if (palawanModel() == palawan_tx)
updateTx();
}
boot_app();
}