Skip to content

Commit 3b9958d

Browse files
committed
Add new Firmware Updater Tool sketch (which talks to ESP32 boot ROM)
1 parent ca62f67 commit 3b9958d

File tree

4 files changed

+543
-0
lines changed

4 files changed

+543
-0
lines changed
Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
/*
2+
ESP32BootROM - part of the Firmware Updater for the
3+
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
4+
5+
Copyright (c) 2018 Arduino SA. All rights reserved.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#include "ESP32BootROM.h"
23+
24+
ESP32BootROMClass::ESP32BootROMClass(HardwareSerial& serial, int gpio0Pin, int resetnPin) :
25+
_serial(&serial),
26+
_gpio0Pin(gpio0Pin),
27+
_resetnPin(resetnPin)
28+
{
29+
30+
}
31+
32+
int ESP32BootROMClass::begin(unsigned long baudrate)
33+
{ pinMode(_gpio0Pin, OUTPUT);
34+
pinMode(_resetnPin, OUTPUT);
35+
36+
digitalWrite(_gpio0Pin, LOW);
37+
38+
digitalWrite(_resetnPin, HIGH);
39+
delay(10);
40+
digitalWrite(_resetnPin, LOW);
41+
delay(100);
42+
43+
_serial->begin(115200);
44+
45+
int synced = 0;
46+
47+
for (int retries = 0; !synced && (retries < 5); retries++) {
48+
synced = sync();
49+
}
50+
51+
if (!synced) {
52+
return 0;
53+
}
54+
55+
if (baudrate != 115200) {
56+
if (!changeBaudrate(baudrate)) {
57+
return 0;
58+
}
59+
60+
delay(100);
61+
62+
_serial->end();
63+
_serial->begin(baudrate);
64+
}
65+
66+
if (!spiAttach()) {
67+
return 0;
68+
}
69+
70+
return 1;
71+
}
72+
73+
void ESP32BootROMClass::end() {
74+
_serial->end();
75+
}
76+
77+
int ESP32BootROMClass::sync()
78+
{
79+
const uint8_t data[] = {
80+
0x07, 0x07, 0x12, 0x20,
81+
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
82+
};
83+
84+
command(0x08, data, sizeof(data));
85+
86+
int results[8];
87+
88+
for (int i = 0; i < 8; i++) {
89+
results[i] = response(0x08, 100);
90+
}
91+
92+
return (results[0] == 0);
93+
}
94+
95+
int ESP32BootROMClass::changeBaudrate(unsigned long baudrate)
96+
{
97+
const uint32_t data[2] = {
98+
baudrate,
99+
0
100+
};
101+
102+
command(0x0f, data, sizeof(data));
103+
104+
return (response(0x0f, 3000) == 0);
105+
}
106+
107+
int ESP32BootROMClass::spiAttach()
108+
{
109+
const uint8_t data[] = {
110+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
111+
};
112+
113+
command(0x0d, data, sizeof(data));
114+
115+
return (response(0x0d, 3000) == 0);
116+
}
117+
118+
int ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize) {
119+
const uint32_t data[4] = {
120+
size,
121+
size / chunkSize,
122+
chunkSize,
123+
offset
124+
};
125+
126+
command(0x02, data, sizeof(data));
127+
128+
_flashSequenceNumber = 0;
129+
_chunkSize = chunkSize;
130+
131+
return (response(0x02, 120000) == 0);
132+
}
133+
134+
int ESP32BootROMClass::dataFlash(const void* data, uint32_t length)
135+
{
136+
uint32_t cmdData[4 + (_chunkSize / 4)];
137+
138+
cmdData[0] = length;
139+
cmdData[1] = _flashSequenceNumber++;
140+
cmdData[2] = 0;
141+
cmdData[3] = 0;
142+
143+
memcpy(&cmdData[4], data, length);
144+
145+
if (length < _chunkSize) {
146+
memset(&cmdData[4 + (length / 4)], 0xff, _chunkSize - length);
147+
}
148+
149+
command(0x03, cmdData, sizeof(cmdData));
150+
151+
return (response(0x03, 3000) == 0);
152+
}
153+
154+
int ESP32BootROMClass::endFlash(uint32_t reboot) {
155+
const uint32_t data[1] = {
156+
reboot
157+
};
158+
159+
command(0x04, data, sizeof(data));
160+
161+
return (response(0x04, 3000) == 0);
162+
}
163+
164+
int ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size, uint8_t* result)
165+
{
166+
const uint32_t data[4] = {
167+
offset,
168+
size,
169+
0,
170+
0
171+
};
172+
173+
command(0x13, data, sizeof(data));
174+
175+
uint8_t asciiResult[32];
176+
177+
if (response(0x13, 3000, asciiResult) != 0) {
178+
return 0;
179+
}
180+
181+
char temp[3] = { 0, 0, 0 };
182+
183+
for (int i = 0; i < 16; i++) {
184+
temp[0] = asciiResult[i * 2];
185+
temp[1] = asciiResult[i * 2 + 1];
186+
187+
result[i] = strtoul(temp, NULL, 16);
188+
}
189+
190+
return 1;
191+
}
192+
193+
void ESP32BootROMClass::command(int opcode, const void* data, uint16_t length)
194+
{
195+
uint32_t checksum = 0;
196+
197+
if (opcode == 0x03) {
198+
checksum = 0xef; // seed
199+
200+
for (uint16_t i = 16; i < length; i++) {
201+
checksum ^= ((const uint8_t*)data)[i];
202+
}
203+
}
204+
205+
_serial->write(0xc0);
206+
_serial->write((uint8_t)0x00); // direction
207+
_serial->write(opcode);
208+
_serial->write((uint8_t*)&length, sizeof(length));
209+
writeEscapedBytes((uint8_t*)&checksum, sizeof(checksum));
210+
writeEscapedBytes((uint8_t*)data, length);
211+
_serial->write(0xc0);
212+
_serial->flush();
213+
}
214+
215+
int ESP32BootROMClass::response(int opcode, unsigned int timeout, void* body)
216+
{
217+
uint8_t data[10 + 256];
218+
uint16_t index = 0;
219+
220+
uint8_t responseLength = 4;
221+
222+
for (unsigned long start = millis(); (index < (10 + responseLength)) && (millis() - start) < timeout;) {
223+
if (_serial->available()) {
224+
data[index] = _serial->read();
225+
226+
if (index == 3) {
227+
responseLength = data[index];
228+
}
229+
230+
index++;
231+
}
232+
}
233+
234+
#ifdef DEBUG
235+
if (index) {
236+
for (int i = 0; i < index; i++) {
237+
byte b = data[i];
238+
239+
if (b < 0x10) {
240+
Serial.print('0');
241+
}
242+
243+
Serial.print(b, HEX);
244+
Serial.print(' ');
245+
}
246+
Serial.println();
247+
}
248+
#endif
249+
250+
if (index != (10 + responseLength)) {
251+
return -1;
252+
}
253+
254+
if (data[0] != 0xc0 || data[1] != 0x01 || data[2] != opcode || data[responseLength + 5] != 0x00 || data[responseLength + 6] != 0x00 || data[responseLength + 9] != 0xc0) {
255+
return -1;
256+
}
257+
258+
if (body) {
259+
memcpy(body, &data[9], responseLength - 4);
260+
}
261+
262+
return data[responseLength + 5];
263+
}
264+
265+
void ESP32BootROMClass::writeEscapedBytes(const uint8_t* data, uint16_t length)
266+
{
267+
uint16_t written = 0;
268+
269+
while (written < length) {
270+
uint8_t b = data[written++];
271+
272+
if (b == 0xdb) {
273+
_serial->write(0xdb);
274+
_serial->write(0xdd);
275+
} else if (b == 0xc0) {
276+
_serial->write(0xdb);
277+
_serial->write(0xdc);
278+
} else {
279+
_serial->write(b);
280+
}
281+
}
282+
}
283+
284+
ESP32BootROMClass ESP32BootROM(SerialNina, NINA_GPIO0, NINA_RESETN);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
ESP32BootROM - part of the Firmware Updater for the
3+
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
4+
5+
Copyright (c) 2018 Arduino SA. All rights reserved.
6+
7+
This library is free software; you can redistribute it and/or
8+
modify it under the terms of the GNU Lesser General Public
9+
License as published by the Free Software Foundation; either
10+
version 2.1 of the License, or (at your option) any later version.
11+
12+
This library is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15+
Lesser General Public License for more details.
16+
17+
You should have received a copy of the GNU Lesser General Public
18+
License along with this library; if not, write to the Free Software
19+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20+
*/
21+
22+
#include <Arduino.h>
23+
24+
class ESP32BootROMClass {
25+
public:
26+
ESP32BootROMClass(HardwareSerial& hwSerial, int gpio0Pin, int resetnPin);
27+
28+
int begin(unsigned long baudrate);
29+
void end();
30+
31+
int beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize);
32+
int dataFlash(const void* data, uint32_t length);
33+
int endFlash(uint32_t reboot);
34+
35+
int md5Flash(uint32_t offset, uint32_t size, uint8_t* result);
36+
37+
private:
38+
int sync();
39+
int changeBaudrate(unsigned long baudrate);
40+
int spiAttach();
41+
42+
void command(int opcode, const void* data, uint16_t length);
43+
int response(int opcode, unsigned int timeout, void* body = NULL);
44+
45+
void writeEscapedBytes(const uint8_t* data, uint16_t length);
46+
47+
private:
48+
HardwareSerial* _serial;
49+
int _gpio0Pin;
50+
int _resetnPin;
51+
52+
uint32_t _flashSequenceNumber;
53+
uint32_t _chunkSize;
54+
};
55+
56+
extern ESP32BootROMClass ESP32BootROM;

0 commit comments

Comments
 (0)