dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
serial_4way_stk500v2.c
Go to the documentation of this file.
1 /*
2  * This file is part of Cleanflight.
3  *
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.
8  *
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.
13  *
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/>.
16  * Author: 4712
17  * have a look at https://github.com/sim-/tgy/blob/master/boot.inc
18  * for info about the stk500v2 implementation
19  */
20 
21 #include <stdbool.h>
22 #include <stdint.h>
23 
24 #include "platform.h"
25 
26 #ifdef USE_SERIAL_4WAY_BLHELI_INTERFACE
27 
28 #ifndef DRONIN_TARGET
29 #include "drivers/io.h"
30 #include "drivers/serial.h"
31 #include "drivers/system.h"
32 
33 #include "io/serial.h"
34 #endif
35 
36 #include "io/serial_4way.h"
37 #include "io/serial_4way_impl.h"
39 
40 #ifdef USE_SERIAL_4WAY_SK_BOOTLOADER
41 
42 #define BIT_LO_US (32) //32uS
43 #define BIT_HI_US (2*BIT_LO_US)
44 
45 static uint8_t StkInBuf[16];
46 
47 #define STK_BIT_TIMEOUT 250 // micro seconds
48 #define STK_WAIT_TICKS (1000 / STK_BIT_TIMEOUT) // per ms
49 #define STK_WAITCYLCES (STK_WAIT_TICKS * 35) // 35ms
50 #define STK_WAITCYLCES_START (STK_WAIT_TICKS / 2) // 0.5 ms
51 #define STK_WAITCYLCES_EXT (STK_WAIT_TICKS * 5000) //5 s
52 
53 #define WaitPinLo while (ESC_IS_HI) {if (micros() > timeout_timer) goto timeout;}
54 #define WaitPinHi while (ESC_IS_LO) {if (micros() > timeout_timer) goto timeout;}
55 
56 static uint32_t LastBitTime;
57 static uint32_t HiLoTsh;
58 
59 static uint8_t SeqNumber;
60 static uint8_t StkCmd;
61 static uint8_t ckSumIn;
62 static uint8_t ckSumOut;
63 
64 // used STK message constants from ATMEL AVR - Application note
65 #define MESSAGE_START 0x1B
66 #define TOKEN 0x0E
67 
68 #define CMD_SIGN_ON 0x01
69 #define CMD_LOAD_ADDRESS 0x06
70 #define CMD_CHIP_ERASE_ISP 0x12
71 #define CMD_PROGRAM_FLASH_ISP 0x13
72 #define CMD_READ_FLASH_ISP 0x14
73 #define CMD_PROGRAM_EEPROM_ISP 0x15
74 #define CMD_READ_EEPROM_ISP 0x16
75 #define CMD_READ_SIGNATURE_ISP 0x1B
76 #define CMD_SPI_MULTI 0x1D
77 
78 #define STATUS_CMD_OK 0x00
79 
80 #define CmdFlashEepromRead 0xA0
81 #define EnterIspCmd1 0xAC
82 #define EnterIspCmd2 0x53
83 #define signature_r 0x30
84 
85 #define delay_us(x) delayMicroseconds(x)
86 #define IRQ_OFF // dummy
87 #define IRQ_ON // dummy
88 
89 static void StkSendByte(uint8_t dat)
90 {
91  ckSumOut ^= dat;
92  for (uint8_t i = 0; i < 8; i++) {
93  if (dat & 0x01) {
94  // 1-bits are encoded as 64.0us high, 72.8us low (135.8us total).
95  ESC_SET_HI;
96  delay_us(BIT_HI_US);
97  ESC_SET_LO;
98  delay_us(BIT_HI_US);
99  } else {
100  // 0-bits are encoded as 27.8us high, 34.5us low, 34.4us high, 37.9 low (134.6us total)
101  ESC_SET_HI;
102  delay_us(BIT_LO_US);
103  ESC_SET_LO;
104  delay_us(BIT_LO_US);
105  ESC_SET_HI;
106  delay_us(BIT_LO_US);
107  ESC_SET_LO;
108  delay_us(BIT_LO_US);
109  }
110  dat >>= 1;
111  }
112 }
113 
114 static void StkSendPacketHeader(void)
115 {
116  IRQ_OFF;
117  ESC_OUTPUT;
118  StkSendByte(0xFF);
119  StkSendByte(0xFF);
120  StkSendByte(0x7F);
121  ckSumOut = 0;
122  StkSendByte(MESSAGE_START);
123  StkSendByte(++SeqNumber);
124 }
125 
126 static void StkSendPacketFooter(void)
127 {
128  StkSendByte(ckSumOut);
129  ESC_SET_HI;
130  delay_us(BIT_LO_US);
131  ESC_INPUT;
132  IRQ_ON;
133 }
134 
135 
136 
137 static int8_t ReadBit(void)
138 {
139  uint32_t btimer = micros();
140  uint32_t timeout_timer = btimer + STK_BIT_TIMEOUT;
141  WaitPinLo;
142  WaitPinHi;
143  LastBitTime = micros() - btimer;
144  if (LastBitTime <= HiLoTsh) {
145  timeout_timer = timeout_timer + STK_BIT_TIMEOUT;
146  WaitPinLo;
147  WaitPinHi;
148  //lo-bit
149  return 0;
150  } else {
151  return 1;
152  }
153 timeout:
154  return -1;
155 }
156 
157 static uint8_t ReadByte(uint8_t *bt)
158 {
159  *bt = 0;
160  for (uint8_t i = 0; i < 8; i++) {
161  int8_t bit = ReadBit();
162  if (bit == -1) goto timeout;
163  if (bit == 1) {
164  *bt |= (1 << i);
165  }
166  }
167  ckSumIn ^=*bt;
168  return 1;
169 timeout:
170  return 0;
171 }
172 
173 static uint8_t StkReadLeader(void)
174 {
175 
176  // Reset learned timing
177  HiLoTsh = BIT_HI_US + BIT_LO_US;
178 
179  // Wait for the first bit
180  uint32_t waitcycl; //250uS each
181 
182  if((StkCmd == CMD_PROGRAM_EEPROM_ISP) || (StkCmd == CMD_CHIP_ERASE_ISP)) {
183  waitcycl = STK_WAITCYLCES_EXT;
184  } else if(StkCmd == CMD_SIGN_ON) {
185  waitcycl = STK_WAITCYLCES_START;
186  } else {
187  waitcycl= STK_WAITCYLCES;
188  }
189  for ( ; waitcycl >0 ; waitcycl--) {
190  //check is not timeout
191  if (ReadBit() >- 1) break;
192  }
193 
194  //Skip the first bits
195  if (waitcycl == 0){
196  goto timeout;
197  }
198 
199  for (uint8_t i = 0; i < 10; i++) {
200  if (ReadBit() == -1) goto timeout;
201  }
202 
203  // learn timing
204  HiLoTsh = (LastBitTime >> 1) + (LastBitTime >> 2);
205 
206  // Read until we get a 0 bit
207  int8_t bit;
208  do {
209  bit = ReadBit();
210  if (bit == -1) goto timeout;
211  } while (bit > 0);
212  return 1;
213 timeout:
214  return 0;
215 }
216 
217 static uint8_t StkRcvPacket(uint8_t *pstring)
218 {
219  uint8_t bt = 0;
220  uint8_16_u Len;
221 
222  IRQ_OFF;
223  if (!StkReadLeader()) goto Err;
224  ckSumIn=0;
225  if (!ReadByte(&bt) || (bt != MESSAGE_START)) goto Err;
226  if (!ReadByte(&bt) || (bt != SeqNumber)) goto Err;
227  ReadByte(&Len.bytes[1]);
228  if (Len.bytes[1] > 1) goto Err;
229  ReadByte(&Len.bytes[0]);
230  if (Len.bytes[0] < 1) goto Err;
231  if (!ReadByte(&bt) || (bt != TOKEN)) goto Err;
232  if (!ReadByte(&bt) || (bt != StkCmd)) goto Err;
233  if (!ReadByte(&bt) || (bt != STATUS_CMD_OK)) goto Err;
234  for (uint16_t i = 0; i < (Len.word - 2); i++)
235  {
236  if (!ReadByte(pstring)) goto Err;
237  pstring++;
238  }
239  ReadByte(&bt);
240  if (ckSumIn != 0) goto Err;
241  IRQ_ON;
242  return 1;
243 Err:
244  IRQ_ON;
245  return 0;
246 }
247 
248 static uint8_t _CMD_SPI_MULTI_EX(volatile uint8_t * ResByte,uint8_t Cmd,uint8_t AdrHi,uint8_t AdrLo)
249 {
250  StkCmd= CMD_SPI_MULTI;
251  StkSendPacketHeader();
252  StkSendByte(0); // hi byte Msg len
253  StkSendByte(8); // lo byte Msg len
254  StkSendByte(TOKEN);
255  StkSendByte(CMD_SPI_MULTI);
256  StkSendByte(4); // NumTX
257  StkSendByte(4); // NumRX
258  StkSendByte(0); // RxStartAdr
259  StkSendByte(Cmd); // {TxData} Cmd
260  StkSendByte(AdrHi); // {TxData} AdrHi
261  StkSendByte(AdrLo); // {TxData} AdrLoch
262  StkSendByte(0); // {TxData} 0
263  StkSendPacketFooter();
264  if (StkRcvPacket((void *)StkInBuf)) { // NumRX + 3
265  if ((StkInBuf[0] == 0x00) && ((StkInBuf[1] == Cmd)||(StkInBuf[1] == 0x00)/* ignore zero returns */) &&(StkInBuf[2] == 0x00)) {
266  *ResByte = StkInBuf[3];
267  }
268  return 1;
269  }
270  return 0;
271 }
272 
273 static uint8_t _CMD_LOAD_ADDRESS(ioMem_t *pMem)
274 {
275  // ignore 0xFFFF
276  // assume address is set before and we read or write the immediately following package
277  if((pMem->D_FLASH_ADDR_H == 0xFF) && (pMem->D_FLASH_ADDR_L == 0xFF)) return 1;
278  StkCmd = CMD_LOAD_ADDRESS;
279  StkSendPacketHeader();
280  StkSendByte(0); // hi byte Msg len
281  StkSendByte(5); // lo byte Msg len
282  StkSendByte(TOKEN);
283  StkSendByte(CMD_LOAD_ADDRESS);
284  StkSendByte(0);
285  StkSendByte(0);
286  StkSendByte(pMem->D_FLASH_ADDR_H);
287  StkSendByte(pMem->D_FLASH_ADDR_L);
288  StkSendPacketFooter();
289  return (StkRcvPacket((void *)StkInBuf));
290 }
291 
292 static uint8_t _CMD_READ_MEM_ISP(ioMem_t *pMem)
293 {
294  uint8_t LenHi;
295  if (pMem->D_NUM_BYTES>0) {
296  LenHi=0;
297  } else {
298  LenHi=1;
299  }
300  StkSendPacketHeader();
301  StkSendByte(0); // hi byte Msg len
302  StkSendByte(4); // lo byte Msg len
303  StkSendByte(TOKEN);
304  StkSendByte(StkCmd);
305  StkSendByte(LenHi);
306  StkSendByte(pMem->D_NUM_BYTES);
307  StkSendByte(CmdFlashEepromRead);
308  StkSendPacketFooter();
309  return (StkRcvPacket(pMem->D_PTR_I));
310 }
311 
312 static uint8_t _CMD_PROGRAM_MEM_ISP(ioMem_t *pMem)
313 {
314  uint8_16_u Len;
315  uint8_t LenLo = pMem->D_NUM_BYTES;
316  uint8_t LenHi;
317  if (LenLo) {
318  LenHi = 0;
319  Len.word = LenLo + 10;
320  } else {
321  LenHi = 1;
322  Len.word = 256 + 10;
323  }
324  StkSendPacketHeader();
325  StkSendByte(Len.bytes[1]); // high byte Msg len
326  StkSendByte(Len.bytes[0]); // low byte Msg len
327  StkSendByte(TOKEN);
328  StkSendByte(StkCmd);
329  StkSendByte(LenHi);
330  StkSendByte(LenLo);
331  StkSendByte(0); // mode
332  StkSendByte(0); // delay
333  StkSendByte(0); // cmd1
334  StkSendByte(0); // cmd2
335  StkSendByte(0); // cmd3
336  StkSendByte(0); // poll1
337  StkSendByte(0); // poll2
338  do {
339  StkSendByte(*pMem->D_PTR_I);
340  pMem->D_PTR_I++;
341  LenLo--;
342  } while (LenLo);
343  StkSendPacketFooter();
344  return StkRcvPacket((void *)StkInBuf);
345 }
346 
347 uint8_t Stk_SignOn(void)
348 {
349  StkCmd=CMD_SIGN_ON;
350  StkSendPacketHeader();
351  StkSendByte(0); // hi byte Msg len
352  StkSendByte(1); // lo byte Msg len
353  StkSendByte(TOKEN);
354  StkSendByte(CMD_SIGN_ON);
355  StkSendPacketFooter();
356  return (StkRcvPacket((void *) StkInBuf));
357 }
358 
359 uint8_t Stk_ConnectEx(uint8_32_u *pDeviceInfo)
360 {
361  if (Stk_SignOn()) {
362  if (_CMD_SPI_MULTI_EX(&pDeviceInfo->bytes[1], signature_r,0,1)) {
363  if (_CMD_SPI_MULTI_EX(&pDeviceInfo->bytes[0], signature_r,0,2)) {
364  return 1;
365  }
366  }
367  }
368  return 0;
369 }
370 
371 uint8_t Stk_Chip_Erase(void)
372 {
373  StkCmd = CMD_CHIP_ERASE_ISP;
374  StkSendPacketHeader();
375  StkSendByte(0); // high byte Msg len
376  StkSendByte(7); // low byte Msg len
377  StkSendByte(TOKEN);
378  StkSendByte(CMD_CHIP_ERASE_ISP);
379  StkSendByte(20); // ChipErase_eraseDelay atmega8
380  StkSendByte(0); // ChipErase_pollMethod atmega8
381  StkSendByte(0xAC);
382  StkSendByte(0x88);
383  StkSendByte(0x13);
384  StkSendByte(0x76);
385  StkSendPacketFooter();
386  return (StkRcvPacket(StkInBuf));
387 }
388 
389 uint8_t Stk_ReadFlash(ioMem_t *pMem)
390 {
391  if (_CMD_LOAD_ADDRESS(pMem)) {
392  StkCmd = CMD_READ_FLASH_ISP;
393  return (_CMD_READ_MEM_ISP(pMem));
394  }
395  return 0;
396 }
397 
398 
399 uint8_t Stk_ReadEEprom(ioMem_t *pMem)
400 {
401  if (_CMD_LOAD_ADDRESS(pMem)) {
402  StkCmd = CMD_READ_EEPROM_ISP;
403  return (_CMD_READ_MEM_ISP(pMem));
404  }
405  return 0;
406 }
407 
408 uint8_t Stk_WriteFlash(ioMem_t *pMem)
409 {
410  if (_CMD_LOAD_ADDRESS(pMem)) {
411  StkCmd = CMD_PROGRAM_FLASH_ISP;
412  return (_CMD_PROGRAM_MEM_ISP(pMem));
413  }
414  return 0;
415 }
416 
417 uint8_t Stk_WriteEEprom(ioMem_t *pMem)
418 {
419  if (_CMD_LOAD_ADDRESS(pMem)) {
420  StkCmd = CMD_PROGRAM_EEPROM_ISP;
421  return (_CMD_PROGRAM_MEM_ISP(pMem));
422  }
423  return 0;
424 }
425 #endif
426 #endif
uint8_32_u
Definition: serial_4way.h:47
uint8_t Stk_WriteEEprom(ioMem_t *pMem)
#define ESC_SET_LO
uint8_t Stk_WriteFlash(ioMem_t *pMem)
#define ESC_OUTPUT
uint8_t D_NUM_BYTES
uint8_16_u
Definition: serial_4way.h:41
uint8_t Stk_ConnectEx(uint8_32_u *pDeviceInfo)
#define ESC_SET_HI
uint8_t D_FLASH_ADDR_L
uint8_t i
Definition: msp_messages.h:97
uint8_t Stk_Chip_Erase(void)
uint8_t Stk_ReadFlash(ioMem_t *pMem)
uint8_t D_FLASH_ADDR_H
uint8_t Stk_SignOn(void)
uint8_t * D_PTR_I
uint8_t Stk_ReadEEprom(ioMem_t *pMem)
#define ESC_INPUT