Skip to content

Commit 336c573

Browse files
author
Nathan Seidle
committed
Initial working BL with variable baud
1 parent 0534f4e commit 336c573

File tree

4 files changed

+1429
-0
lines changed

4 files changed

+1429
-0
lines changed

boards.txt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,26 @@ amap3blackboard.upload.baud=115200
6060

6161
###############################################################
6262

63+
amap3blackboardBL.name=SparkFun BlackBoard Artemis 80k Offset
64+
amap3blackboardBL.build.variant=SparkFun_BlackBoard_Artemis_BL
65+
amap3blackboardBL.build.board=AM_AP3_SFE_BB_ARTEMIS_BL
66+
amap3blackboardBL.upload.tool=artemis_bin2board
67+
amap3blackboardBL.upload.maximum_size=960000
68+
amap3blackboardBL.build.arch=APOLLO3
69+
amap3blackboardBL.build.mcu=cortex-m4
70+
amap3blackboardBL.build.f_cpu=48000000L
71+
amap3blackboardBL.build.core=arduino
72+
amap3blackboardBL.build.defs=
73+
amap3blackboardBL.build.includes=-I{build.variant.path}/config
74+
amap3blackboardBL.build.libs=
75+
amap3blackboardBL.build.extra_flags=-DPART_apollo3 -DAM_PACKAGE_BGA -DAM_PART_APOLLO3
76+
amap3blackboardBL.build.ldscript={build.variant.path}/linker_scripts/gcc/flash_with_bootloader.ld
77+
amap3blackboardBL.upload.maximum_size=960000
78+
edge.upload.use_menu_baud=0
79+
amap3blackboardBL.upload.baud=115200
80+
81+
###############################################################
82+
6383
amap3nano.name=SparkFun BlackBoard Artemis Nano
6484
amap3nano.build.variant=SparkFun_BlackBoard_Artemis_Nano
6585
amap3nano.build.board=AM_AP3_SFE_BB_ARTEMIS_NANO
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
/*
2+
Artemis Bootloader
3+
By: Nathan Seidle
4+
SparkFun Electronics
5+
Date: May 2nd, 2019
6+
License: MIT. See license file for more information but you can
7+
basically do whatever you want with this code.
8+
9+
This is a serial bootloader that receives commands from a python script and loads
10+
user's code as quickly as possible.
11+
12+
Feel like supporting open source hardware?
13+
Buy a board from SparkFun!
14+
SparkFun Edge: https://www.sparkfun.com/products/15170
15+
16+
Based on XBee Bootloader from 2009: https://www.sparkfun.com/tutorials/122
17+
18+
The Apollo3 memory looks like this:
19+
20+
0xFF000 -> -------
21+
| |
22+
| |
23+
...
24+
| |
25+
| |
26+
| |
27+
0x14000 -> | APP |
28+
| SFE |
29+
0xC000 -> | SBL |
30+
-------
31+
32+
The factory secure bootloader (SBL) lives at 0x00 to 0xC000.
33+
The SparkFun Artemis bootloader begins at 0xC000 and takes ~20k bytes
34+
We load user code starting at 0xC000 + 0x8000 (32768) = 0x14000
35+
If our bootloader times out, we jump to 0x14000 to begin running user code
36+
37+
TODO:
38+
Protect bootloader section in flash
39+
Make sure all RAM is released
40+
*/
41+
static uint32_t ui32Source[512];
42+
43+
#define MAX_WAIT_IN_MS 100 //Millisecond wait before bootload timeout and begin user code
44+
45+
enum BL_COMMANDS {
46+
BL_COMMAND_ANNOUNCE = 0x05,
47+
BL_COMMAND_AOK,
48+
BL_COMMAND_BAD_CRC,
49+
BL_COMMAND_NEXT_FRAME,
50+
BL_COMMAND_ALL_DONE,
51+
BL_COMMAND_COMPUTER_READY,
52+
};
53+
54+
bool retransmit_flag = false;
55+
uint16_t frame_size = 0;
56+
uint32_t incoming_crc32 = 0;
57+
uint32_t crc32 = 0;
58+
uint32_t frame_address = 0;
59+
60+
// Location in flash to begin storing user's code
61+
//#define USERCODE_OFFSET 0x14000
62+
#define USERCODE_OFFSET 0x80000 // Should be start of flash instance 1
63+
64+
//Comment out this line to turn off debug statements on Serial1
65+
#define DEBUG 1
66+
67+
void setup() {
68+
Serial.begin(9600); //Start comm with computer at low baud rate. We'll go faster later.
69+
70+
#ifdef DEBUG
71+
Serial1.begin(921600);
72+
Serial1.println();
73+
Serial1.println();
74+
Serial1.println("Debug");
75+
#endif
76+
77+
Serial.write(BL_COMMAND_ANNOUNCE); //Tell the world we can be bootloaded
78+
79+
//Check to see if the computer responded
80+
uint16_t count = 0;
81+
while (Serial.available() == 0)
82+
{
83+
if (count++ > MAX_WAIT_IN_MS)
84+
{
85+
app_start();
86+
}
87+
delay(1);
88+
}
89+
if (Serial.read() != BL_COMMAND_AOK) app_start(); //If the computer did not respond correctly with a AOK, we jump to user's program
90+
91+
//Now get upload baud rate from caller
92+
uint32_t uploadRate = get4Bytes();
93+
94+
Serial.flush();
95+
Serial.begin(uploadRate); //Go to new baud rate
96+
97+
//We need to give the computer some time to switch baud rates
98+
//Let's erase the flash while we wait
99+
100+
#ifdef DEBUG
101+
Serial1.printf("Erasing all of flash instance %d.\n\r", AM_HAL_FLASH_ADDR2INST(USERCODE_OFFSET));
102+
#endif
103+
104+
int32_t i32ReturnCode = am_hal_flash_mass_erase(AM_HAL_FLASH_PROGRAM_KEY, AM_HAL_FLASH_ADDR2INST(USERCODE_OFFSET));
105+
106+
#ifdef DEBUG
107+
if (i32ReturnCode)
108+
{
109+
Serial1.printf("FLASH_MASS_ERASE i32ReturnCode = 0x%x.\n\r", i32ReturnCode);
110+
}
111+
#endif
112+
113+
delay(10); //Give the computer some time to switch baud rates
114+
115+
#ifdef DEBUG
116+
Serial1.print("Bootloading @ ");
117+
Serial1.println(uploadRate);
118+
#endif
119+
}
120+
121+
//This is the main bootloader
122+
//We'll loop until the whole file is received
123+
void loop() {
124+
//Determine if the last received data was good or bad
125+
if (crc32 != incoming_crc32)
126+
{
127+
RESTART:
128+
Serial.write(BL_COMMAND_BAD_CRC); //Tell client to resend last frame
129+
#ifdef DEBUG
130+
Serial1.println("RESTART!");
131+
#endif
132+
}
133+
else
134+
{
135+
Serial.write(BL_COMMAND_NEXT_FRAME); //Get next frame
136+
#ifdef DEBUG
137+
Serial1.println();
138+
Serial1.println("Getting next frame");
139+
#endif
140+
}
141+
142+
while (1) //Wait for the computer to tell us its ready to chat
143+
{
144+
if (getch() == BL_COMMAND_COMPUTER_READY) break; //This is the "gimme the next chunk" command
145+
if (retransmit_flag == true) goto RESTART;
146+
}
147+
148+
frame_size = ((uint16_t)getch() << 8) | getch(); //Get the size of this frame
149+
if (retransmit_flag == true)goto RESTART;
150+
151+
if (frame_size == BL_COMMAND_ALL_DONE) //Check to see if we are done
152+
{
153+
am_hal_reset_control(AM_HAL_RESET_CONTROL_SWPOI, 0); //Cause a system Power On Init to release as much of the stack as possible
154+
}
155+
156+
#ifdef DEBUG
157+
Serial1.print("frame_size: ");
158+
Serial1.println(frame_size);
159+
#endif
160+
161+
//Get the memory address at which to store this block of data
162+
frame_address = get4Bytes();
163+
if (retransmit_flag == true) goto RESTART;
164+
165+
//Serial1.print("frame_address: ");
166+
//Serial1.println(frame_address);
167+
168+
//Get CRC from client
169+
incoming_crc32 = get4Bytes();
170+
if (retransmit_flag == true) goto RESTART;
171+
172+
//Serial1.print("incoming_crc32: ");
173+
//Serial1.println(incoming_crc32);
174+
175+
//Receive this frame
176+
crc32 = 0;
177+
for (uint16_t i = 0 ; i < frame_size / 4 ; i++)
178+
{
179+
ui32Source[i] = get4BytesReversed();
180+
crc32 += ui32Source[i]; //Calculate CRC as we go
181+
}
182+
183+
if (incoming_crc32 == crc32)
184+
{
185+
#ifdef DEBUG
186+
Serial1.println("CRC good. Record array");
187+
#endif
188+
int32_t i32ReturnCode = program_array(frame_address + USERCODE_OFFSET);
189+
190+
#ifdef DEBUG
191+
if (i32ReturnCode)
192+
Serial1.printf("FLASH_WRITE error = 0x%x.\n", i32ReturnCode);
193+
#endif
194+
}
195+
else
196+
{
197+
#ifdef DEBUG
198+
Serial1.println("Bad CRC:");
199+
Serial1.printf("incoming_crc32: 0x%04X\n\r", incoming_crc32);
200+
Serial1.printf("CRC: 0x%04X\n\r", crc32);
201+
#endif
202+
}
203+
}
204+
205+
//Gets a character from Serial
206+
uint8_t getch()
207+
{
208+
retransmit_flag = false;
209+
210+
uint16_t counter = 0;
211+
while (Serial.available() == 0)
212+
{
213+
delayMicroseconds(10);
214+
if (counter++ > 10000)
215+
{
216+
retransmit_flag = true;
217+
return (0); //Timeout
218+
}
219+
}
220+
return (Serial.read());
221+
}
222+
223+
uint32_t get4Bytes(void)
224+
{
225+
uint32_t incoming = 0;
226+
for (byte x = 0 ; x < 4 ; x++)
227+
{
228+
incoming <<= 8;
229+
incoming |= getch();
230+
}
231+
return (incoming);
232+
}
233+
234+
uint32_t get4BytesReversed(void)
235+
{
236+
uint32_t incoming = 0;
237+
for (byte x = 0 ; x < 4 ; x++)
238+
{
239+
incoming >>= 8;
240+
incoming |= (getch() << 8 * 3);
241+
}
242+
return (incoming);
243+
}
244+
245+
void app_start()
246+
{
247+
// Print a section of flash
248+
// uint32_t start_address = USERCODE_OFFSET;
249+
// Serial1.printf("Printing page starting at offset 0x%04X", start_address);
250+
// for (uint16_t x = 0; x < 512; x++)
251+
// {
252+
// if (x % 8 == 0)
253+
// {
254+
// Serial1.println();
255+
// Serial1.printf("Adr: 0x%04X", start_address + (x * 4));
256+
// }
257+
// Serial1.printf(" 0x%08X", *(uint32_t *)(start_address + (x * 4)));
258+
// }
259+
// Serial1.println();
260+
261+
uint32_t entryPoint = *(uint32_t *)(USERCODE_OFFSET + 4);
262+
263+
#ifdef DEBUG
264+
Serial1.printf("Jump to 0x%08X", entryPoint);
265+
#endif
266+
delay(10); //Wait for prints to complete
267+
268+
goto *entryPoint; //Jump to start of user code
269+
270+
#ifdef DEBUG
271+
Serial1.println("Not here");
272+
#endif
273+
while (1);
274+
}
275+
276+
//Commits whatever is in the ui32Source to the given location
277+
int32_t program_array(uint32_t ui32PrgmAddr)
278+
{
279+
uint32_t *pui32Dst;
280+
int32_t i32ReturnCode;
281+
//
282+
// Program a few words in a page in the main block of instance 1.
283+
//
284+
pui32Dst = (uint32_t *) ui32PrgmAddr;
285+
i32ReturnCode = am_hal_flash_program_main(AM_HAL_FLASH_PROGRAM_KEY,
286+
ui32Source,
287+
pui32Dst,
288+
512);
289+
290+
return (i32ReturnCode);
291+
}

0 commit comments

Comments
 (0)