├── LarduinoISP.ino ├── README.md ├── larduinoISP.png ├── swd_drv.c └── swd_drv.h /LarduinoISP.ino: -------------------------------------------------------------------------------- 1 | // LarduinoISP for LGT8FX8D series 2 | // Project fork from 3 | // - ArduinoISP version 04m3 4 | // Copyright (c) 2008-2011 Randall Bohn 5 | // If you require a license, see 6 | // http://www.opensource.org/licenses/bsd-license.php 7 | // 8 | // This sketch turns the Arduino into a AVRISP 9 | // using the following arduino pins: 10 | // 11 | // pin name: Arduino: LGT8FX8D/P: 12 | // slave reset: 10: PC6/RESET 13 | // SWD: 12: PE2/SWD 14 | // SWC: 13: PE0/SWC 15 | // 16 | // Put an LED (with resistor) on the following pins: 17 | // 9: Heartbeat - shows the programmer is running 18 | // 8: Error - Lights up if something goes wrong (use red if that makes sense) 19 | // 7: Programming - In communication with the slave 20 | // 21 | // 23 July 2011 Randall Bohn 22 | // -Address Arduino issue 509 :: Portability of ArduinoISP 23 | // http://code.google.com/p/arduino/issues/detail?id=509 24 | // 25 | // October 2010 by Randall Bohn 26 | // - Write to EEPROM > 256 bytes 27 | // - Better use of LEDs: 28 | // -- Flash LED_PMODE on each flash commit 29 | // -- Flash LED_PMODE while writing EEPROM (both give visual feedback of writing progress) 30 | // - Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync. 31 | // - Use pins_arduino.h (should also work on Arduino Mega) 32 | // 33 | // October 2009 by David A. Mellis 34 | // - Added support for the read signature command 35 | // 36 | // February 2009 by Randall Bohn 37 | // - Added support for writing to EEPROM (what took so long?) 38 | // Windows users should consider WinAVR's avrdude instead of the 39 | // avrdude included with Arduino software. 40 | // 41 | // January 2008 by Randall Bohn 42 | // - Thanks to Amplificar for helping me with the STK500 protocol 43 | // - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader 44 | // - The SPI functions herein were developed for the AVR910_ARD programmer 45 | // - More information at http://code.google.com/p/mega-isp 46 | 47 | // LarduinoISP for LGTF8FX8D/P Series 48 | #include "swd_drv.h" 49 | #include "pins_arduino.h" 50 | 51 | #define RESET SS 52 | #define LED_HB 9 53 | #define LED_ERR 8 54 | #define LED_PMODE 7 55 | #define PROG_FLICKER true 56 | 57 | #define HWVER 2 58 | #define SWMAJ 1 59 | #define SWMIN 18 60 | 61 | // STK Definitions 62 | #define STK_OK 0x10 63 | #define STK_FAILED 0x11 64 | #define STK_UNKNOWN 0x12 65 | #define STK_INSYNC 0x14 66 | #define STK_NOSYNC 0x15 67 | #define CRC_EOP 0x20 //ok it is a space... 68 | 69 | void pulse(int pin, int times); 70 | 71 | void setup() 72 | { 73 | SWD_init(); 74 | Serial.begin(19200); 75 | 76 | //pinMode(LED_PMODE, OUTPUT); 77 | //pulse(LED_PMODE, 2); 78 | //pinMode(LED_ERR, OUTPUT); 79 | //pulse(LED_ERR, 2); 80 | //pinMode(LED_HB, OUTPUT); 81 | //pulse(LED_HB, 2); 82 | } 83 | 84 | uint8_t error=0; 85 | uint8_t pmode=0; 86 | 87 | // address for reading and writing, set by 'U' command 88 | uint16_t address; 89 | uint8_t buff[256]; // global block storage 90 | 91 | #define beget16(addr) (*addr * 256 + *(addr+1) ) 92 | typedef struct param { 93 | uint8_t devicecode; 94 | uint8_t revision; 95 | uint8_t progtype; 96 | uint8_t parmode; 97 | uint8_t polling; 98 | uint8_t selftimed; 99 | uint8_t lockbytes; 100 | uint8_t fusebytes; 101 | uint8_t flashpoll; 102 | uint16_t eeprompoll; 103 | uint16_t pagesize; 104 | uint16_t eepromsize; 105 | uint32_t flashsize; 106 | } parameter_t; 107 | parameter_t param; 108 | 109 | // this provides a heartbeat on pin 9, so you can tell the software is running. 110 | uint8_t hbval=128; 111 | uint8_t hbdelta=8; 112 | void heartbeat() 113 | { 114 | if (hbval > 192) hbdelta = -hbdelta; 115 | if (hbval < 32) hbdelta = -hbdelta; 116 | hbval += hbdelta; 117 | analogWrite(LED_HB, hbval); 118 | delay(40); 119 | } 120 | 121 | void loop(void) 122 | { 123 | // is pmode active? 124 | /* 125 | if (pmode) digitalWrite(LED_PMODE, HIGH); 126 | else digitalWrite(LED_PMODE, LOW); 127 | // is taddress an error? 128 | if (error) digitalWrite(LED_ERR, HIGH); 129 | else digitalWrite(LED_ERR, LOW); 130 | */ 131 | // light the heartbeat LED 132 | //heartbeat(); 133 | if (Serial.available()) 134 | avrisp(); 135 | } 136 | 137 | uint8_t getch() { 138 | while(!Serial.available()); 139 | return Serial.read(); 140 | } 141 | 142 | void fill(int n) 143 | { 144 | for (int x = 0; x < n; x++) { 145 | buff[x] = getch(); 146 | } 147 | } 148 | 149 | #define PTIME 30 150 | void pulse(int pin, int times) 151 | { 152 | do { 153 | digitalWrite(pin, HIGH); 154 | delay(PTIME); 155 | digitalWrite(pin, LOW); 156 | delay(PTIME); 157 | } 158 | while (times--); 159 | } 160 | 161 | void prog_lamp(int state) 162 | { 163 | if (PROG_FLICKER) 164 | digitalWrite(LED_PMODE, state); 165 | } 166 | 167 | void empty_reply() 168 | { 169 | if (CRC_EOP == getch()) { 170 | Serial.print((char)STK_INSYNC); 171 | Serial.print((char)STK_OK); 172 | } 173 | else { 174 | error++; 175 | Serial.print((char)STK_NOSYNC); 176 | } 177 | } 178 | 179 | void breply(uint8_t b) 180 | { 181 | if (CRC_EOP == getch()) { 182 | Serial.print((char)STK_INSYNC); 183 | Serial.print((char)b); 184 | Serial.print((char)STK_OK); 185 | } 186 | else { 187 | error++; 188 | Serial.print((char)STK_NOSYNC); 189 | } 190 | } 191 | 192 | void get_version(uint8_t c) 193 | { 194 | switch(c) { 195 | case 0x80: 196 | breply(HWVER); 197 | break; 198 | case 0x81: 199 | breply(SWMAJ); 200 | break; 201 | case 0x82: 202 | breply(SWMIN); 203 | break; 204 | case 0x93: 205 | breply('S'); // serial programmer 206 | break; 207 | default: 208 | breply(0); 209 | } 210 | } 211 | 212 | void set_parameters() 213 | { 214 | // call this after reading paramter packet into buff[] 215 | param.devicecode = buff[0]; 216 | param.revision = buff[1]; 217 | param.progtype = buff[2]; 218 | param.parmode = buff[3]; 219 | param.polling = buff[4]; 220 | param.selftimed = buff[5]; 221 | param.lockbytes = buff[6]; 222 | param.fusebytes = buff[7]; 223 | param.flashpoll = buff[8]; 224 | // ignore buff[9] (= buff[8]) 225 | // following are 16 bits (big endian) 226 | param.eeprompoll = beget16(&buff[10]); 227 | param.pagesize = beget16(&buff[12]); 228 | param.eepromsize = beget16(&buff[14]); 229 | 230 | // 32 bits flashsize (big endian) 231 | param.flashsize = buff[16] * 0x01000000 232 | + buff[17] * 0x00010000 233 | + buff[18] * 0x00000100 234 | + buff[19]; 235 | 236 | } 237 | 238 | void start_pmode() 239 | { 240 | digitalWrite(RESET, HIGH); 241 | pinMode(RESET, OUTPUT); 242 | delay(10); 243 | digitalWrite(RESET, LOW); 244 | delay(10); 245 | 246 | SWD_Idle(80); 247 | SWD_init(); 248 | 249 | do { 250 | pmode = SWD_UnLock(); 251 | } while (pmode == 0); 252 | 253 | // device type 254 | pmode &= 0x7f; 255 | SWD_Idle(10); 256 | } 257 | 258 | void end_pmode() 259 | { 260 | SWD_SWDEN(); 261 | SWD_exit(); 262 | pmode = LGTMCU_UNKNOWN; 263 | 264 | digitalWrite(RESET, HIGH); 265 | pinMode(RESET, INPUT); 266 | } 267 | 268 | void universal() 269 | { 270 | fill(4); 271 | 272 | if(buff[0] == 0x30 && buff[1] == 0x00) { 273 | switch(buff[2]) { 274 | case 0x00: 275 | breply(0x1e); 276 | break; 277 | case 0x01: 278 | breply(0x95); 279 | break; 280 | case 0x02: 281 | breply(0x0f); 282 | break; 283 | default: 284 | breply(0xff); 285 | break; 286 | } 287 | } else if(buff[0] == 0xf0) { 288 | breply(0x00); 289 | } else { 290 | breply(0xff); 291 | } 292 | } 293 | 294 | void write_flash(int length) 295 | { 296 | fill(length); 297 | if (CRC_EOP == getch()) { 298 | Serial.print((char) STK_INSYNC); 299 | Serial.print((char) write_flash_pages(length)); 300 | } 301 | else { 302 | error++; 303 | Serial.print((char) STK_NOSYNC); 304 | } 305 | } 306 | 307 | uint8_t write_flash_pages(int length) 308 | { 309 | int cnt = 0; 310 | uint32_t word; 311 | 312 | // in case address is not 32bit aligned 313 | // we just care of header-unaligned !!! 314 | // cuz its seems no problem if the tail is not 32bit aligned 315 | uint8_t _start = 0; 316 | 317 | if(address & 0x1) 318 | _start = 1; 319 | 320 | if(pmode == LGTMCU_8F328P) 321 | address >>= 1; 322 | 323 | while (cnt < length) { 324 | if(pmode == LGTMCU_8F328P) { 325 | if(_start == 1) { 326 | word = 0xffff; 327 | _start = 0; 328 | } else { 329 | word = buff[cnt++]; 330 | word += (uint32_t)buff[cnt++] << 8; 331 | } 332 | 333 | word += (uint32_t)buff[cnt++] << 16; 334 | word += (uint32_t)buff[cnt++] << 24; 335 | SWD_EEP_Write(word, address); 336 | } 337 | else 338 | { 339 | word = buff[cnt++]; 340 | word += (uint16_t)buff[cnt++] << 8; 341 | SWD_EEE_Write((uint16_t)word, address); 342 | } 343 | 344 | address++; 345 | } 346 | 347 | return STK_OK; 348 | } 349 | 350 | #define EECHUNK (32) 351 | uint8_t write_eeprom(int length) 352 | { 353 | // address is a word address, get the byte address 354 | int start = address * 2; 355 | int remaining = length; 356 | if (length > param.eepromsize) { 357 | error++; 358 | return STK_FAILED; 359 | } 360 | while (remaining > EECHUNK) { 361 | write_eeprom_chunk(start, EECHUNK); 362 | start += EECHUNK; 363 | remaining -= EECHUNK; 364 | } 365 | write_eeprom_chunk(start, remaining); 366 | return STK_OK; 367 | } 368 | 369 | // write (length) bytes, (start) is a byte address 370 | uint8_t write_eeprom_chunk(int start, int length) 371 | { 372 | // this writes byte-by-byte, 373 | // page writing may be faster (4 bytes at a time) 374 | fill(length); 375 | prog_lamp(LOW); 376 | for (int x = 0; x < length; x++) { 377 | int addr = start+x; 378 | // do e2prom program here 379 | // donothing for lgt8fx8d/p series 380 | delay(45); 381 | } 382 | prog_lamp(HIGH); 383 | return STK_OK; 384 | } 385 | 386 | void program_page() 387 | { 388 | char result = (char) STK_FAILED; 389 | 390 | // get length 391 | uint16_t length = getch() << 8; 392 | length += getch(); 393 | 394 | char memtype = getch(); 395 | // flash memory @address, (length) bytes 396 | if (memtype == 'F') { 397 | write_flash(length); 398 | return; 399 | } 400 | 401 | if (memtype == 'E') { 402 | result = (char)write_eeprom(length); 403 | if (CRC_EOP == getch()) { 404 | Serial.print((char) STK_INSYNC); 405 | Serial.print(result); 406 | } 407 | else { 408 | error++; 409 | Serial.print((char) STK_NOSYNC); 410 | } 411 | return; 412 | } 413 | Serial.print((char)STK_FAILED); 414 | return; 415 | } 416 | 417 | char flash_read_page(uint16_t length) 418 | { 419 | uint8_t _start = 0; 420 | 421 | if(pmode == LGTMCU_8F328P) { 422 | // case of address not 32bit aligned 423 | if(address & 1) 424 | _start = 1; 425 | 426 | // re-aligned to 32bits 427 | address >>= 1; 428 | 429 | for (uint16_t x = 0; x < length; x+=2) { 430 | uint32_t word = SWD_EEP_Read(address); 431 | 432 | if(_start == 0) { 433 | Serial.print((char) (word & 0xff)); 434 | Serial.print((char) ((word >> 8) & 0xff)); 435 | x += 2; 436 | } 437 | 438 | _start = 0; 439 | 440 | // if length is not 4bytes aligned 441 | if(x < length) { 442 | Serial.print((char) ((word >> 16) & 0xff)); 443 | Serial.print((char) ((word >> 24) & 0xff)); 444 | } 445 | address++; 446 | } 447 | } else { 448 | for (uint16_t x = 0; x < length; x+=2) { 449 | uint16_t word = SWD_EEE_Read(address); 450 | Serial.print((char) (word & 0xff)); 451 | Serial.print((char) ((word >> 8) & 0xff)); 452 | address++; 453 | } 454 | } 455 | 456 | return STK_OK; 457 | } 458 | 459 | char eeprom_read_page(uint16_t length) 460 | { 461 | // address again we have a word address 462 | uint16_t start = address * 2; 463 | for (int x = 0; x < length; x++) { 464 | uint16_t addr = start + x; 465 | // do ep2rom read here 466 | // but donothing for lgt8fx8d series (by now...) 467 | Serial.print((char) 0xff); 468 | } 469 | return STK_OK; 470 | } 471 | 472 | void read_page() 473 | { 474 | char result = (char)STK_FAILED; 475 | 476 | uint16_t length = getch() << 8; 477 | length += getch(); 478 | char memtype = getch(); 479 | if (CRC_EOP != getch()) { 480 | error++; 481 | Serial.print((char) STK_NOSYNC); 482 | return; 483 | } 484 | Serial.print((char) STK_INSYNC); 485 | 486 | if (memtype == 'F') result = flash_read_page(length); 487 | if (memtype == 'E') result = eeprom_read_page(length); 488 | Serial.print(result); 489 | return; 490 | } 491 | 492 | void read_signature() 493 | { 494 | if (CRC_EOP != getch()) { 495 | error++; 496 | Serial.print((char) STK_NOSYNC); 497 | return; 498 | } 499 | 500 | Serial.print((char) STK_INSYNC); 501 | Serial.print((char) 0x1e); 502 | Serial.print((char) 0x95); 503 | Serial.print((char) 0x0f); 504 | Serial.print((char) STK_OK); 505 | } 506 | 507 | ////////////////////////////////////////// 508 | ////////////////////////////////////////// 509 | 510 | 511 | //////////////////////////////////// 512 | //////////////////////////////////// 513 | int avrisp() 514 | { 515 | uint8_t data, low, high; 516 | uint8_t ch = getch(); 517 | switch (ch) { 518 | case '0': // signon 519 | error = 0; 520 | empty_reply(); 521 | break; 522 | case '1': 523 | if (getch() == CRC_EOP) { 524 | Serial.print((char) STK_INSYNC); 525 | Serial.print("AVR ISP"); 526 | Serial.print((char) STK_OK); 527 | } else { 528 | error++; 529 | Serial.print((char) STK_NOSYNC); 530 | } 531 | break; 532 | case 'A': 533 | get_version(getch()); 534 | break; 535 | case 'B': // optional for lgt8fx8d series 536 | fill(20); 537 | set_parameters(); 538 | empty_reply(); 539 | break; 540 | case 'E': // extended parameters - ignore for now 541 | fill(5); 542 | empty_reply(); 543 | break; 544 | 545 | case 'P': // 0x50 546 | if (pmode) { 547 | pulse(LED_ERR, 3); 548 | } else { 549 | start_pmode(); 550 | } 551 | empty_reply(); 552 | break; 553 | case 'U': // 0x55, set address (word) 554 | address = getch(); 555 | address += ((uint16_t)getch() << 8); 556 | empty_reply(); 557 | break; 558 | case 0x60: //STK_PROG_FLASH 559 | low = getch(); 560 | high = getch(); 561 | empty_reply(); 562 | break; 563 | case 0x61: //STK_PROG_DATA 564 | data = getch(); 565 | empty_reply(); 566 | break; 567 | case 0x64: //STK_PROG_PAGE 568 | program_page(); 569 | break; 570 | case 0x74: //STK_READ_PAGE 't' 571 | read_page(); 572 | break; 573 | case 'V': //0x56 574 | universal(); 575 | break; 576 | case 'Q': //0x51 577 | error=0; 578 | end_pmode(); 579 | empty_reply(); 580 | break; 581 | case 0x75: //STK_READ_SIGN 'u' 582 | read_signature(); 583 | break; 584 | // expecting a command, not CRC_EOP 585 | // this is how we can get back in sync 586 | case CRC_EOP: 587 | error++; 588 | Serial.print((char) STK_NOSYNC); 589 | break; 590 | 591 | // anything else we will return STK_UNKNOWN 592 | default: 593 | error++; 594 | if (CRC_EOP == getch()) 595 | Serial.print((char)STK_UNKNOWN); 596 | else 597 | Serial.print((char)STK_NOSYNC); 598 | } 599 | 600 | return 0; 601 | } 602 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LarduinoISP 2 | make arduino board to be an ISP of LGT8FX8D/P series MCU 3 | 4 | ![](https://image.geek-workshop.com/forum/201604/03/110353eiiwydix7fx7aw7t.png) 5 | -------------------------------------------------------------------------------- /larduinoISP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LGTMCU/LarduinoISP/2e79da969dac8d103750fb835e68eb7990743f08/larduinoISP.png -------------------------------------------------------------------------------- /swd_drv.c: -------------------------------------------------------------------------------- 1 | // implement of swd interface 2 | 3 | #include "swd_drv.h" 4 | 5 | void SWD_init() 6 | { 7 | // set to output 8 | SWDIF_DIR |= (SWDIF_CLK | SWDIF_DAT); 9 | // clear output 10 | SWD_CLR(); 11 | SWC_CLR(); 12 | } 13 | 14 | void SWD_exit() 15 | { 16 | SWDIF_DIR &= ~(SWDIF_CLK | SWDIF_DAT); 17 | } 18 | 19 | void SWD_WriteByte(uint8_t start, uint8_t data, uint8_t stop) 20 | { 21 | volatile uint8_t cnt; 22 | 23 | if(start) { 24 | SWC_CLR(); 25 | SWD_Delay(); 26 | SWD_CLR(); 27 | SWD_Delay(); 28 | SWC_SET(); 29 | SWD_Delay(); 30 | } 31 | 32 | // send data 33 | for(cnt = 0; cnt < 8; cnt++) 34 | { 35 | SWC_CLR(); 36 | if(data & 0x1) SWD_SET(); 37 | else SWD_CLR(); 38 | SWD_Delay(); 39 | data >>= 1; 40 | SWC_SET(); 41 | SWD_Delay(); 42 | } 43 | 44 | SWC_CLR(); 45 | if(stop) SWD_SET(); 46 | else SWD_CLR(); 47 | 48 | SWD_Delay(); 49 | SWC_SET(); 50 | SWD_Delay(); 51 | } 52 | 53 | uint8_t SWD_ReadByte(uint8_t start, uint8_t stop) 54 | { 55 | volatile uint8_t cnt; 56 | volatile uint8_t bRes = 0; 57 | 58 | if(start) 59 | { 60 | SWC_CLR(); 61 | SWD_CLR(); 62 | SWD_Delay(); 63 | SWC_SET(); 64 | SWD_Delay(); 65 | } 66 | 67 | SWD_IND(); 68 | //SWD_Delay(); 69 | for(cnt = 0; cnt < 8; cnt++) 70 | { 71 | bRes >>= 1; 72 | SWC_CLR(); 73 | SWD_Delay(); 74 | if(SWDIF_PIN & SWDIF_DAT) 75 | bRes |= 0x80; 76 | 77 | SWC_SET(); 78 | SWD_Delay(); 79 | } 80 | 81 | SWD_OUD(); 82 | 83 | SWC_CLR(); 84 | if(stop) SWD_SET(); 85 | else SWD_CLR(); 86 | 87 | SWD_Delay(); 88 | SWC_SET(); 89 | SWD_Delay(); 90 | 91 | return bRes; 92 | } 93 | 94 | void SWD_Idle(uint8_t cnt) 95 | { 96 | volatile uint8_t i; 97 | 98 | SWD_SET(); 99 | 100 | for(i = 0; i < cnt; i++) 101 | { 102 | SWC_CLR(); 103 | SWD_Delay(); 104 | SWC_SET(); 105 | SWD_Delay(); 106 | } 107 | } 108 | 109 | void SWD_ReadSWDID(char *pdata) 110 | { 111 | SWD_WriteByte(1, 0xae, 1); 112 | SWD_Idle(8); 113 | pdata[0] = SWD_ReadByte(1, 0); 114 | pdata[1] = SWD_ReadByte(0, 0); 115 | pdata[2] = SWD_ReadByte(0, 0); 116 | pdata[3] = SWD_ReadByte(0, 1); 117 | SWD_Idle(8); 118 | } 119 | 120 | void SWD_SWDEN() 121 | { 122 | SWD_WriteByte(1, 0xd0, 0); 123 | SWD_WriteByte(0, 0xaa, 0); 124 | SWD_WriteByte(0, 0x55, 0); 125 | SWD_WriteByte(0, 0xaa, 0); 126 | SWD_WriteByte(0, 0x55, 1); 127 | SWD_Idle(8); 128 | } 129 | 130 | void SWD_UnLock0() 131 | { 132 | SWD_WriteByte(1, 0xf0, 0); 133 | SWD_WriteByte(0, 0x54, 0); 134 | SWD_WriteByte(0, 0x51, 0); 135 | SWD_WriteByte(0, 0x4a, 0); 136 | SWD_WriteByte(0, 0x4c, 1); 137 | SWD_Idle(8); 138 | } 139 | 140 | void SWD_UnLock1() 141 | { 142 | SWD_WriteByte(1, 0xf0, 0); 143 | SWD_WriteByte(0, 0x23, 0); 144 | SWD_WriteByte(0, 0x50, 0); 145 | SWD_WriteByte(0, 0x49, 0); 146 | SWD_WriteByte(0, 0x2d, 1); 147 | SWD_Idle(8); 148 | } 149 | 150 | void SWD_EEE_CSEQ(uint8_t ctrl, uint16_t addr) 151 | { 152 | SWD_WriteByte(1, 0xb2, 0); 153 | SWD_WriteByte(0, (addr & 0xff), 0); 154 | SWD_WriteByte(0, ((ctrl & 0x3) << 6) | ((addr >> 8) & 0x3f), 0); 155 | SWD_WriteByte(0, (0xC0 | (ctrl >> 2)), 1); 156 | SWD_Idle(8); 157 | } 158 | 159 | void SWD_EEE_DSEQ(uint16_t data) 160 | { 161 | SWD_WriteByte(1, 0xb2, 0); 162 | SWD_WriteByte(0, (data & 0xff), 0); 163 | SWD_WriteByte(0, ((data >> 8) & 0xff), 1); 164 | SWD_Idle(8); 165 | } 166 | 167 | void SWD_EEP_DSEQ(uint32_t data) 168 | { 169 | SWD_WriteByte(1, 0xb2, 0); 170 | SWD_WriteByte(0, (data & 0xff), 0); 171 | SWD_WriteByte(0, ((data >> 8) & 0xff), 0); 172 | SWD_WriteByte(0, ((data >> 16) & 0xff), 0); 173 | SWD_WriteByte(0, ((data >> 24) & 0xff), 1); 174 | SWD_Idle(8); 175 | } 176 | 177 | uint8_t SWD_EEE_GetBusy() 178 | { 179 | uint8_t res = 0; 180 | 181 | SWD_WriteByte(1, 0xaa, 1); 182 | SWD_Idle(8); 183 | SWD_ReadByte(1, 0); 184 | SWD_ReadByte(0, 0); 185 | res = SWD_ReadByte(0, 1); 186 | SWD_Idle(8); 187 | 188 | return res & 0x1; 189 | } 190 | 191 | void SWD_EEE_UnlockTiming() 192 | { 193 | volatile uint8_t ib; 194 | volatile uint8_t timout = 0x1f; 195 | 196 | SWD_EEE_CSEQ(0x00, 0x00); 197 | delay(5); 198 | SWD_EEE_CSEQ(0x08, 0x00); 199 | SWD_EEE_CSEQ(0x88, 0x00); 200 | SWD_EEE_CSEQ(0x02, 0x00); 201 | 202 | do { 203 | delayus(50); 204 | ib = SWD_EEE_GetBusy(); 205 | --timout; 206 | } while(ib == 1 && timout > 0); 207 | } 208 | 209 | void SWD_EEP_UnlockTiming() 210 | { 211 | SWD_EEE_CSEQ(0x00, 0x00); 212 | delayus(100); 213 | SWD_EEE_CSEQ(0x98, 0x00); 214 | delayus(50); 215 | SWD_EEE_CSEQ(0x9a, 0x00); 216 | delay(30); 217 | SWD_EEE_CSEQ(0x8a, 0x00); 218 | delayus(300); 219 | SWD_EEE_CSEQ(0x88, 0x00); 220 | delayus(100); 221 | SWD_EEE_CSEQ(0x00, 0x00); 222 | delayus(100); 223 | 224 | } 225 | 226 | uint16_t SWD_EEE_Read(uint16_t addr) 227 | { 228 | uint8_t hbyte, lbyte; 229 | 230 | SWD_EEE_CSEQ(0x00, addr); 231 | SWD_EEE_CSEQ(0xa0, addr); 232 | 233 | SWD_WriteByte(1, 0xaa, 1); 234 | lbyte = SWD_ReadByte(1, 0); 235 | hbyte = SWD_ReadByte(0, 1); 236 | SWD_Idle(10); 237 | SWD_EEE_CSEQ(0x00, addr); 238 | 239 | return ((uint16_t)hbyte << 8) | lbyte; 240 | } 241 | 242 | uint32_t SWD_EEP_Read(uint16_t addr) 243 | { 244 | uint32_t dw; 245 | 246 | SWD_EEE_CSEQ(0xc0, addr); 247 | SWD_EEE_CSEQ(0xe0, addr); 248 | 249 | SWD_WriteByte(1, 0xaa, 1); 250 | dw = SWD_ReadByte(1, 0); 251 | dw |= (uint32_t)SWD_ReadByte(0, 0) << 8; 252 | dw |= (uint32_t)SWD_ReadByte(0, 0) << 16; 253 | dw |= (uint32_t)SWD_ReadByte(0, 1) << 24; 254 | SWD_Idle(10); 255 | SWD_EEE_CSEQ(0x00, addr); 256 | SWD_Idle(10); 257 | 258 | return dw; 259 | } 260 | 261 | void SWD_EEE_Write(uint16_t data, uint16_t addr) 262 | { 263 | volatile uint8_t ib; 264 | volatile uint8_t timout = 0x1f; 265 | 266 | SWD_EEE_CSEQ(0x00, addr); 267 | SWD_EEE_DSEQ(data); 268 | SWD_EEE_CSEQ(0x04, addr); 269 | SWD_EEE_CSEQ(0x84, addr); 270 | SWD_EEE_CSEQ(0x02, addr); 271 | 272 | do { 273 | delayus(50); 274 | ib = SWD_EEE_GetBusy(); 275 | --timout; 276 | } while(ib == 1 && timout > 0); 277 | 278 | SWD_EEE_CSEQ(0x00, addr); 279 | } 280 | 281 | void SWD_EEP_Write(uint32_t data, uint16_t addr) 282 | { 283 | SWD_EEE_CSEQ(0x84, addr); 284 | SWD_EEP_DSEQ(data); 285 | SWD_EEE_CSEQ(0x86, addr); 286 | delayus(2); 287 | SWD_EEE_CSEQ(0xc6, addr); 288 | delayus(12); 289 | SWD_EEE_CSEQ(0x86, addr); 290 | SWD_EEE_CSEQ(0x82, addr); 291 | SWD_EEE_CSEQ(0x80, addr); 292 | SWD_EEE_CSEQ(0x00, addr); 293 | delayus(1); 294 | } 295 | 296 | uint8_t SWD_UnLock() 297 | { 298 | char swdid[4]; 299 | 300 | uint8_t mtype = LGTMCU_UNKNOWN; 301 | 302 | SWD_Idle(80); 303 | SWD_SWDEN(); 304 | SWD_ReadSWDID(swdid); 305 | 306 | if((uint8_t)swdid[1] == 0xA2) { 307 | mtype = LGTMCU_8F328P; // 328P 308 | } else if((uint8_t)swdid[1] == 0xA1) { 309 | mtype = LGTMCU_8F328D; // 328D 310 | } else { 311 | return LGTMCU_UNKNOWN; // unknown 312 | } 313 | 314 | if(((uint8_t)swdid[0] & 0x3f) == 0x3f) 315 | return (mtype | 0x80); 316 | 317 | SWD_UnLock0(); 318 | 319 | if(mtype == LGTMCU_8F328P) 320 | { 321 | SWD_EEP_UnlockTiming(); 322 | } 323 | else 324 | { 325 | SWD_EEE_UnlockTiming(); 326 | } 327 | 328 | SWD_UnLock1(); 329 | delayus(100); 330 | SWD_UnLock0(); 331 | delayus(100); 332 | SWD_UnLock1(); 333 | 334 | SWD_ReadSWDID(swdid); 335 | 336 | if(((uint8_t)swdid[0] & 0x3f) == 0x3f) 337 | return (mtype | 0x80); 338 | 339 | return 0; 340 | } 341 | 342 | -------------------------------------------------------------------------------- /swd_drv.h: -------------------------------------------------------------------------------- 1 | // swd interface definition 2 | #ifndef __LGT_SWDIF__ 3 | #define __LGT_SWDIF__ 4 | 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C"{ 9 | #endif 10 | 11 | #define LGTMCU_8F328D 0x1 12 | #define LGTMCU_8F328P 0x2 13 | #define LGTMCU_UNKNOWN 0x0 14 | 15 | #define SWDIF_PIN PINB 16 | #define SWDIF_DIR DDRB 17 | #define SWDIF_PORT PORTB 18 | #define SWDIF_CLK (1 << 5) // PB5 19 | #define SWDIF_DAT (1 << 4) // PB4 20 | #define SWDIF_RSTN (1 << 2) // PB2 21 | 22 | #define SWC_CLR() (SWDIF_PORT &= ~SWDIF_CLK) 23 | #define SWC_SET() (SWDIF_PORT |= SWDIF_CLK) 24 | #define SWD_CLR() (SWDIF_PORT &= ~SWDIF_DAT) 25 | #define SWD_SET() (SWDIF_PORT |= SWDIF_DAT) 26 | #define SWD_IND() (SWDIF_DIR &= ~SWDIF_DAT) 27 | #define SWD_OUD() (SWDIF_DIR |= SWDIF_DAT) 28 | 29 | #define RSTN_CLR() (SWDIF_PORT &= ~SWDIF_RSTN) 30 | #define RSTN_SET() (SWDIF_PORT |= SWDIF_RSTN) 31 | #define RSTN_IND() (SWDIF_DIR &= ~SWDIF_RSTN) 32 | #define RSTN_OUD() (SWDIF_DIR |= SWDIF_RSTN) 33 | 34 | // for 16MHz system clock 35 | // delay used for swc generator 36 | #ifndef NOP 37 | #define NOP() asm volatile("nop") 38 | #endif 39 | 40 | #define SWD_Delay() do {\ 41 | NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ 42 | NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ 43 | } while(0); 44 | 45 | // reuse delay from Arduino 46 | #ifndef delayus 47 | #define delayus(n) delayMicroseconds(n) 48 | #endif 49 | 50 | void SWD_init(); 51 | void SWD_exit(); 52 | void SWD_Idle(uint8_t); 53 | void SWD_WriteByte(uint8_t, uint8_t, uint8_t); 54 | uint8_t SWD_ReadByte(uint8_t, uint8_t); 55 | 56 | void SWD_SWDEN(); 57 | uint8_t SWD_UnLock(); 58 | void SWD_EEE_Write(uint16_t, uint16_t); 59 | uint16_t SWD_EEE_Read(uint16_t); 60 | 61 | void SWD_EEP_Write(uint32_t, uint16_t); 62 | uint32_t SWD_EEP_Read(uint16_t); 63 | 64 | #ifdef __cplusplus 65 | } 66 | #endif 67 | 68 | #endif 69 | --------------------------------------------------------------------------------