2 * This file is part of Cleanflight.
4 * Cleanflight is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Cleanflight is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Cleanflight. If not, see <http://www.gnu.org/licenses/>.
17 * for info about Hagens AVRootloader:
18 * http://www.mikrocontroller.net/topic/avr-bootloader-mit-verschluesselung
27 #ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
29 #include "common/utils.h"
30 #include "drivers/system.h"
31 #include "drivers/serial.h"
32 #include "drivers/buf_writer.h"
33 #include "drivers/pwm_mapping.h"
34 #include "drivers/gpio.h"
35 #include "io/serial.h"
36 #include "io/serial_msp.h"
37 #include "io/serial_4way.h"
38 #include "io/serial_4way_impl.h"
39 #include "io/serial_4way_avrootloader.h"
41 // Bootloader commands
43 #define RestartBootloader 0
44 #define ExitBootloader 1
47 #define CMD_PROG_FLASH 0x01
48 #define CMD_ERASE_FLASH 0x02
49 #define CMD_READ_FLASH_SIL 0x03
50 #define CMD_VERIFY_FLASH 0x03
51 #define CMD_READ_EEPROM 0x04
52 #define CMD_PROG_EEPROM 0x05
53 #define CMD_READ_SRAM 0x06
54 #define CMD_READ_FLASH_ATM 0x07
55 #define CMD_KEEP_ALIVE 0xFD
56 #define CMD_SET_ADDRESS 0xFF
57 #define CMD_SET_BUFFER 0xFE
59 #define CMD_BOOTINIT 0x07
60 #define CMD_BOOTSIGN 0x08
62 // Bootloader result codes
64 #define BR_SUCCESS 0x30
65 #define BR_ERRORCOMMAND 0xC1
66 #define BR_ERRORCRC 0xC2
69 #define START_BIT_TIMEOUT 2000 // 2ms
71 #define BIT_TIME 52 // 52uS
72 #define BIT_TIME_HALVE (BIT_TIME >> 1) // 26uS
73 #define START_BIT_TIME (BIT_TIME_HALVE + 1)
75 static int suart_getc(void)
80 uint32_t wait_time
= micros() + START_BIT_TIMEOUT
;
82 // check for startbit begin
83 if (micros() >= wait_time
) {
88 start_time
= micros();
89 btime
= start_time
+ START_BIT_TIME
;
91 for(int bit
= 0; bit
< 10; bit
++) {
92 while (cmp32(micros(), btime
) < 0);
94 bitmask
|= (1 << bit
);
95 btime
= btime
+ BIT_TIME
;
97 // check start bit and stop bit
98 if ((bitmask
& (1 << 0)) || (!(bitmask
& (1 << 9)))) {
104 static void suart_putc(uint8_t byte
)
106 // send one idle bit first (stopbit from previous byte)
107 uint16_t bitmask
= (byte
<< 2) | (1 << 0) | (1 << 10);
108 uint32_t btime
= micros();
114 btime
= btime
+ BIT_TIME
;
117 break; // stopbit shifted out - but don't wait
118 while (cmp32(micros(), btime
) < 0);
122 static uint16_t crc16Byte(uint16_t from
, uint8_t byte
)
124 uint16_t crc16
= from
;
125 for (int i
= 0; i
< 8; i
++) {
126 if (((byte
& 0x01) ^ (crc16
& 0x0001)) != 0) {
137 static uint8_t BL_ReadBuf(uint8_t *pstring
, int len
, bool checkCrc
)
142 uint8_t lastACK
= BR_NONE
;
143 for(int i
= 0; i
< len
; i
++) {
145 if ((c
= suart_getc()) < 0) goto timeout
;
146 crc
= crc16Byte(crc
, c
);
151 // With CRC read 3 more
152 for(int i
= 0; i
< 2; i
++) { // checksum 2 CRC bytes
153 if ((c
= suart_getc()) < 0) goto timeout
;
154 crc
= crc16Byte(crc
, c
);
156 if((c
= suart_getc()) < 0) goto timeout
;
158 if (crc
!= 0) // CRC of correct message is 0
159 lastACK
= BR_ERRORCRC
;
161 if((c
= suart_getc()) < 0) goto timeout
;
165 return (lastACK
== BR_SUCCESS
);
168 static void BL_SendBuf(uint8_t *pstring
, int len
, bool appendCrc
)
172 for(int i
= 0; i
< len
; i
++) {
173 suart_putc(pstring
[i
]);
174 crc
= crc16Byte(crc
, pstring
[i
]);
177 suart_putc(crc
& 0xff);
178 suart_putc(crc
>> 8);
183 uint8_t BL_ConnectEx(escDeviceInfo_t
*pDeviceInfo
)
185 #define BOOT_MSG_LEN 4
186 #define DevSignHi (BOOT_MSG_LEN)
187 #define DevSignLo (BOOT_MSG_LEN + 1)
189 memset(pDeviceInfo
, 0, sizeof(*pDeviceInfo
));
190 uint8_t bootInfo
[BOOT_MSG_LEN
+ 4];
191 static const uint8_t bootMsgCheck
[BOOT_MSG_LEN
- 1] = "471";
193 #if defined(USE_SERIAL_4WAY_SK_BOOTLOADER)
194 // SK message was sent during autodetection, use longer preamble
195 uint8_t bootInit
[] = {0,0,0,0,0,0,0,0,0,0,0,0,0x0D,'B','L','H','e','l','i',0xF4,0x7D};
197 uint8_t bootInit
[] = { 0,0,0,0,0,0,0,0,0x0D,'B','L','H','e','l','i',0xF4,0x7D};
199 BL_SendBuf(bootInit
, sizeof(bootInit
), false);
200 if (!BL_ReadBuf(bootInfo
, sizeof(bootInfo
), false))
202 // BootInfo has no CRC (ACK byte already analyzed... )
203 // Format = BootMsg("471c") SIGNATURE_001, SIGNATURE_002, BootVersion (always 6), BootPages (,ACK)
204 if(memcmp(bootInfo
, bootMsgCheck
, sizeof(bootMsgCheck
)) != 0) // Check only the first 3 letters -> 471x OK
207 pDeviceInfo
->signature2
= bootInfo
[BOOT_MSG_LEN
- 1]; // taken from bootloaderMsg part, ascii 'c' now
208 pDeviceInfo
->signature
= (bootInfo
[DevSignHi
] << 8) | bootInfo
[DevSignLo
]; // SIGNATURE_001, SIGNATURE_002
212 static uint8_t BL_GetACK(int timeout
)
215 while ((c
= suart_getc()) < 0)
216 if(--timeout
< 0) // timeout=1 -> 1 retry
221 uint8_t BL_SendCMDKeepAlive(void)
223 uint8_t sCMD
[] = {CMD_KEEP_ALIVE
, 0};
224 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
225 if (BL_GetACK(1) != BR_ERRORCOMMAND
)
230 void BL_SendCMDRunRestartBootloader(void)
232 uint8_t sCMD
[] = {RestartBootloader
, 0};
233 BL_SendBuf(sCMD
, sizeof(sCMD
), true); // sends simply 4 x 0x00 (CRC = 00)
237 static uint8_t BL_SendCMDSetAddress(ioMem_t
*pMem
) //supports only 16 bit Adr
239 // skip if adr == 0xFFFF
240 if((pMem
->addr
== 0xffff))
242 uint8_t sCMD
[] = {CMD_SET_ADDRESS
, 0, pMem
->addr
>> 8, pMem
->addr
& 0xff };
243 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
244 return BL_GetACK(2) == BR_SUCCESS
;
247 static uint8_t BL_SendCMDSetBuffer(ioMem_t
*pMem
)
249 uint16_t len
= pMem
->len
;
250 uint8_t sCMD
[] = {CMD_SET_BUFFER
, 0, len
>> 8, len
& 0xff};
251 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
252 if (BL_GetACK(2) != BR_NONE
)
254 BL_SendBuf(pMem
->data
, len
, true);
255 return BL_GetACK(40) == BR_SUCCESS
;
258 static uint8_t BL_ReadA(uint8_t cmd
, ioMem_t
*pMem
)
260 if(!BL_SendCMDSetAddress(pMem
))
262 unsigned len
= pMem
->len
;
263 uint8_t sCMD
[] = {cmd
, len
& 0xff}; // 0x100 is sent a 0x00 here
264 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
265 return BL_ReadBuf(pMem
->data
, len
, true);
268 static uint8_t BL_WriteA(uint8_t cmd
, ioMem_t
*pMem
, uint32_t timeout
)
270 if(!BL_SendCMDSetAddress(pMem
))
272 if (!BL_SendCMDSetBuffer(pMem
))
274 uint8_t sCMD
[] = {cmd
, 0x01};
275 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
276 return BL_GetACK(timeout
) == BR_SUCCESS
;
280 uint8_t BL_ReadFlashATM(ioMem_t
*pMem
)
282 return BL_ReadA(CMD_READ_FLASH_ATM
, pMem
);
285 uint8_t BL_ReadFlashSIL(ioMem_t
*pMem
)
287 return BL_ReadA(CMD_READ_FLASH_SIL
, pMem
);
291 uint8_t BL_ReadEEprom(ioMem_t
*pMem
)
293 return BL_ReadA(CMD_READ_EEPROM
, pMem
);
296 uint8_t BL_PageErase(ioMem_t
*pMem
)
298 if(!BL_SendCMDSetAddress(pMem
))
301 uint8_t sCMD
[] = {CMD_ERASE_FLASH
, 0x01};
302 BL_SendBuf(sCMD
, sizeof(sCMD
), true);
303 return BL_GetACK(40 * 1000 / START_BIT_TIMEOUT
) == BR_SUCCESS
;
306 uint8_t BL_WriteEEprom(ioMem_t
*pMem
)
308 return BL_WriteA(CMD_PROG_EEPROM
, pMem
, 3000 * 1000 / START_BIT_TIMEOUT
);
311 uint8_t BL_WriteFlash(ioMem_t
*pMem
)
313 return BL_WriteA(CMD_PROG_FLASH
, pMem
, 40 * 1000 / START_BIT_TIMEOUT
);