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