From c2faf302f65417f98380f05fa633c1c8c3f98b7a Mon Sep 17 00:00:00 2001 From: qitas Date: Fri, 2 Jul 2021 20:36:20 +0800 Subject: [PATCH] add --- .github/FUNDING.yml | 12 + index.json | 21 +- src/LGTISP/LGTISP.ino | 557 ++++++++++++++++++++++++++++++++++++ src/LGTISP/readme.md | 35 +++ src/LGTISP/swd_lgt8fx8p.cpp | 471 ++++++++++++++++++++++++++++++ src/LGTISP/swd_lgt8fx8p.h | 82 ++++++ 6 files changed, 1176 insertions(+), 2 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 src/LGTISP/LGTISP.ino create mode 100644 src/LGTISP/readme.md create mode 100644 src/LGTISP/swd_lgt8fx8p.cpp create mode 100644 src/LGTISP/swd_lgt8fx8p.h diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..b67d20e --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: qitas +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/index.json b/index.json index bce6102..f254b89 100644 --- a/index.json +++ b/index.json @@ -1,7 +1,9 @@ { "type":"MCU", - "name":"LGT8F", + "name":"LGT8F328P", + "title": "LogicGreen MCU LGT8F328P", "description":"LogicGreen Flash RISC 8bit MCU", + "version":"1.0.0", "Core": { "num": 1, "type":"AVR", @@ -17,10 +19,25 @@ "type": "git", "url": "https://github.com/SoCXin/LGT8F328P" }, - "version":"1.0.0", "series":["LGT8F328P","LGT8F328D"], "package":["QFP48","QFP32","SSOP20"], "peripheral": ["TIM","ADC","DAC","UART","SPI","LDO","PWM"], + "PWR": { + "VDD": [2800,5000], + "Ivdd": 3.5, + "LDO": [5000,3300], + "rate": 1024 + }, + "EMC": { + "EFT": 2000, + "ESD": 4000 + }, + "upload": { + "ISP": true, + "IAP": true, + "SWD": true, + "speed": 115200 + }, "keywords": [ "dev-platform", "AVR", diff --git a/src/LGTISP/LGTISP.ino b/src/LGTISP/LGTISP.ino new file mode 100644 index 0000000..f7e2379 --- /dev/null +++ b/src/LGTISP/LGTISP.ino @@ -0,0 +1,557 @@ +// author : brother_yan +// +// LarduinoISP for LGT8FX8P series +// Project fork from +// - ArduinoISP version 04m3 +// Copyright (c) 2008-2011 Randall Bohn +// If you require a license, see +// http://www.opensource.org/licenses/bsd-license.php +// +// This sketch turns the Arduino into a AVRISP +// using the following arduino pins: +// +// pin name: Arduino: LGT8FX8P: +// slave reset: 10: PC6/RESET +// SWD: 12: PE2/SWD +// SWC: 13: PE0/SCK +// +// Put an LED (with resistor) on the following pins: +// 9: Heartbeat - shows the programmer is running +// 8: Error - Lights up if something goes wrong (use red if that makes sense) +// 7: Programming - In communication with the slave +// +// 23 July 2011 Randall Bohn +// -Address Arduino issue 509 :: Portability of ArduinoISP +// http://code.google.com/p/arduino/issues/detail?id=509 +// +// October 2010 by Randall Bohn +// - Write to EEPROM > 256 bytes +// - Better use of LEDs: +// -- Flash LED_PMODE on each flash commit +// -- Flash LED_PMODE while writing EEPROM (both give visual feedback of writing progress) +// - Light LED_ERR whenever we hit a STK_NOSYNC. Turn it off when back in sync. +// - Use pins_arduino.h (should also work on Arduino Mega) +// +// October 2009 by David A. Mellis +// - Added support for the read signature command +// +// February 2009 by Randall Bohn +// - Added support for writing to EEPROM (what took so long?) +// Windows users should consider WinAVR's avrdude instead of the +// avrdude included with Arduino software. +// +// January 2008 by Randall Bohn +// - Thanks to Amplificar for helping me with the STK500 protocol +// - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader +// - The SPI functions herein were developed for the AVR910_ARD programmer +// - More information at http://code.google.com/p/mega-isp + +// LarduinoISP for LGTF8FX8P Series +#include "swd_lgt8fx8p.h" + +#if SERIAL_RX_BUFFER_SIZE < 250 // 64 bytes的RX缓冲不够大 +#error : Please change the macro SERIAL_RX_BUFFER_SIZE to 250 +#endif + +#define LED_HB 9 +#define LED_ERR 8 +#define LED_PMODE 7 +#define PROG_FLICKER true + +#define HWVER 3 +#define SWMAJ 6 +#define SWMIN 4 + +// STK Definitions +#define STK_OK 0x10 +#define STK_FAILED 0x11 +#define STK_UNKNOWN 0x12 +#define STK_INSYNC 0x14 +#define STK_NOSYNC 0x15 +#define CRC_EOP 0x20 //ok it is a space... + +void pulse(int pin, int times); + +void setup() +{ + Serial.begin(115200); + + pinMode(LED_PMODE, OUTPUT); + //pulse(LED_PMODE, 2); + pinMode(LED_ERR, OUTPUT); + //pulse(LED_ERR, 2); + //pinMode(LED_HB, OUTPUT); + //pulse(LED_HB, 2); +} + +uint8_t error=0; + +// address for reading and writing, set by 'U' command +int address; +uint8_t buff[256]; // global block storage + +#define beget16(addr) (*addr * 256 + *(addr+1) ) +typedef struct param { + uint8_t devicecode; + uint8_t revision; + uint8_t progtype; + uint8_t parmode; + uint8_t polling; + uint8_t selftimed; + uint8_t lockbytes; + uint8_t fusebytes; + uint8_t flashpoll; + uint16_t eeprompoll; + uint16_t pagesize; + uint16_t eepromsize; + uint32_t flashsize; +} parameter_t; +parameter_t param; + +// this provides a heartbeat on pin 9, so you can tell the software is running. +uint8_t hbval=128; +uint8_t hbdelta=8; +void heartbeat() +{ + if (hbval > 192) hbdelta = -hbdelta; + if (hbval < 32) hbdelta = -hbdelta; + hbval += hbdelta; + analogWrite(LED_HB, hbval); + delay(40); +} + +void loop(void) +{ + // is pmode active? + if (LGTISP.isPmode()) digitalWrite(LED_PMODE, HIGH); + else digitalWrite(LED_PMODE, LOW); + // is taddress an error? + if (error) digitalWrite(LED_ERR, HIGH); + else digitalWrite(LED_ERR, LOW); + + // light the heartbeat LED + //heartbeat(); + if (Serial.available()) + avrisp(); +} + +uint8_t getch() { + while(!Serial.available()); + return Serial.read(); +} + +void fill(int n) +{ + for (int x = 0; x < n; x++) { + buff[x] = getch(); + } +} + +#define PTIME 30 +void pulse(int pin, int times) +{ + do { + digitalWrite(pin, HIGH); + delay(PTIME); + digitalWrite(pin, LOW); + delay(PTIME); + } + while (times--); +} + +void prog_lamp(int state) +{ + if (PROG_FLICKER) + digitalWrite(LED_PMODE, state); +} + +void empty_reply() +{ + if (CRC_EOP == getch()) { + Serial.print((char)STK_INSYNC); + Serial.print((char)STK_OK); + } + else { + error++; + Serial.print((char)STK_NOSYNC); + } +} + +void breply(uint8_t b) +{ + if (CRC_EOP == getch()) { + Serial.print((char)STK_INSYNC); + Serial.print((char)b); + Serial.print((char)STK_OK); + } + else { + error++; + Serial.print((char)STK_NOSYNC); + } +} + +void get_version(uint8_t c) +{ + switch(c) { + case 0x80: + breply(HWVER); + break; + case 0x81: + breply(SWMAJ); + break; + case 0x82: + breply(SWMIN); + break; + case 0x93: + breply('S'); // serial programmer + break; + default: + breply(0); + } +} + +void set_parameters() +{ + // call this after reading paramter packet into buff[] + param.devicecode = buff[0]; + param.revision = buff[1]; + param.progtype = buff[2]; + param.parmode = buff[3]; + param.polling = buff[4]; + param.selftimed = buff[5]; + param.lockbytes = buff[6]; + param.fusebytes = buff[7]; + param.flashpoll = buff[8]; + // ignore buff[9] (= buff[8]) + // following are 16 bits (big endian) + param.eeprompoll = beget16(&buff[10]); + param.pagesize = beget16(&buff[12]); + param.eepromsize = beget16(&buff[14]); + + // 32 bits flashsize (big endian) + param.flashsize = buff[16] * 0x01000000 + + buff[17] * 0x00010000 + + buff[18] * 0x00000100 + + buff[19]; + +} + +void universal() +{ + fill(4); + + if(buff[0] == 0x30 && buff[1] == 0x00) { + switch(buff[2]) { + case 0x00: + breply(0x1e); + break; + case 0x01: + breply(0x95); + break; + case 0x02: + breply(0x0f); + break; + default: + breply(0xff); + break; + } + } else if(buff[0] == 0xf0) { + breply(0x00); + } else { + breply(0xff); + } +} + +void write_flash(int length) +{ + int addr = address * 2; // 字节地址 + /* + lgt8fx8p的flash是按4字节编址的,而avr是按2字节编址的,avrdude传过来的是按2字节编址的address + avrisp()函数中也有证实: + case 'U': // set address (word) + */ + + fill(length); + if (CRC_EOP == getch()) { + Serial.print((char) STK_INSYNC); + LGTISP.write(addr, buff, length); + Serial.print((char) STK_OK); + } + else { + error++; + Serial.print((char) STK_NOSYNC); + } +} + +#define EECHUNK (32) +uint8_t write_eeprom(int length) +{ + // address is a word address, get the byte address + int start = address * 2; + int remaining = length; + if (length > param.eepromsize) { + error++; + return STK_FAILED; + } + while (remaining > EECHUNK) { + write_eeprom_chunk(start, EECHUNK); + start += EECHUNK; + remaining -= EECHUNK; + } + write_eeprom_chunk(start, remaining); + return STK_OK; +} + +// write (length) bytes, (start) is a byte address +uint8_t write_eeprom_chunk(int start, int length) +{ + // this writes byte-by-byte, + // page writing may be faster (4 bytes at a time) + fill(length); + prog_lamp(LOW); + for (int x = 0; x < length; x++) { + int addr = start+x; + // do e2prom program here + // donothing for lgt8fx8d series + delay(45); + } + prog_lamp(HIGH); + return STK_OK; +} + +void program_page() +{ + char result = (char) STK_FAILED; + + // get length + uint16_t length = getch() << 8; + length += getch(); + + char memtype = getch(); + // flash memory @address, (length) bytes + if (memtype == 'F') { + write_flash(length); + return; + } + if (memtype == 'E') { + result = (char)write_eeprom(length); + if (CRC_EOP == getch()) { + Serial.print((char) STK_INSYNC); + Serial.print(result); + } + else { + error++; + Serial.print((char) STK_NOSYNC); + } + return; + } + Serial.print((char)STK_FAILED); + return; +} + +char eeprom_read_page(uint16_t length) +{ + // address again we have a word address + uint16_t start = address * 2; + for (int x = 0; x < length; x++) { + uint16_t addr = start + x; + // do ep2rom read here + // but donothing for lgt8fx8d series (by now...) + Serial.print((char) 0xff); + } + return STK_OK; +} + +void read_page() +{ + char result = (char)STK_FAILED; + int addr = address * 2; // 字节地址 + /* + lgt8fx8p的flash是按4字节编址的,而avr是按2字节编址的,avrdude传过来的是按2字节编址的address + avrisp()函数中也有证实: + case 'U': // set address (word) + */ + + uint16_t length = getch() << 8; + length += getch(); + char memtype = getch(); + if (CRC_EOP != getch()) { + error++; + Serial.print((char) STK_NOSYNC); + return; + } + Serial.print((char) STK_INSYNC); + + if (memtype == 'F') + { + LGTISP.read(addr, buff, length); + for (int i = 0; i < length; ++i) + Serial.print((char)buff[i]); + result = STK_OK; + } + if (memtype == 'E') result = eeprom_read_page(length); + Serial.print(result); + return; +} + +void read_signature() +{ + if (CRC_EOP != getch()) { + error++; + Serial.print((char) STK_NOSYNC); + return; + } + + Serial.print((char) STK_INSYNC); + Serial.print((char) 0x1e); + Serial.print((char) 0x95); + Serial.print((char) 0x0a); + Serial.print((char) STK_OK); +} + +////////////////////////////////////////// +////////////////////////////////////////// + + +//////////////////////////////////// +//////////////////////////////////// +int avrisp() +{ + const char copyright[] = "{\"author\" : \"brother_yan\"}"; + uint16_t sum = 0; + for (uint16_t i = 0; copyright[i] != 0; ++i) + sum ^= (uint8_t)(copyright[i]) * i; + if (sum != 0x0bdc) + return 0; + + uint8_t data, low, high; + uint8_t ch = getch(); + switch (ch) { + case '0': // signon + error = 0; + empty_reply(); + break; + case '1': + if (getch() == CRC_EOP) { + Serial.print((char) STK_INSYNC); + Serial.print("AVR ISP"); + Serial.print((char) STK_OK); + } else { + error++; + Serial.print((char) STK_NOSYNC); + } + break; + case 'y': // 0x79, not used in stk500 protocol. I use this command to read copyright information + if (getch() == CRC_EOP) + { + Serial.print((char) STK_INSYNC); + Serial.println(copyright); + Serial.print((char) STK_OK); + } + else + { + error++; + Serial.print((char) STK_NOSYNC); + } + break; + case 'z': // 0x7a, not used in stk500 protocol. I use this command to read GUID + if (getch() == CRC_EOP) + { + char guid[4]; + + *((uint32_t *)guid) = LGTISP.getGUID(); + Serial.print((char) STK_INSYNC); + Serial.print(guid[0]); + Serial.print(guid[1]); + Serial.print(guid[2]); + Serial.print(guid[3]); + Serial.print((char) STK_OK); + } + else + { + error++; + Serial.print((char) STK_NOSYNC); + } + break; + case 'A': + get_version(getch()); + break; + case 'B': // optional for lgt8fx8d series + fill(20); + set_parameters(); + empty_reply(); + break; + case 'E': // extended parameters - ignore for now + fill(5); + empty_reply(); + break; + + case 'P': + if (LGTISP.isPmode()) { + pulse(LED_ERR, 3); + } else { + LGTISP.begin(); + } + if (LGTISP.isPmode()) + empty_reply(); + else + { + if (CRC_EOP == getch()) { + Serial.print((char)STK_INSYNC); + Serial.print((char)STK_FAILED); + } + else { + error++; + Serial.print((char)STK_NOSYNC); + } + } + break; + case 'U': // set address (word) + address = getch(); + address += (getch() << 8); + empty_reply(); + break; + case 0x60: //STK_PROG_FLASH + low = getch(); + high = getch(); + empty_reply(); + break; + case 0x61: //STK_PROG_DATA + data = getch(); + empty_reply(); + break; + case 0x64: //STK_PROG_PAGE + program_page(); + break; + case 0x74: //STK_READ_PAGE 't' + read_page(); + break; + case 'V': //0x56 + universal(); + break; + case 'Q': //0x51 + error=0; + LGTISP.end(); + empty_reply(); + break; + case 0x75: //STK_READ_SIGN 'u' + read_signature(); + break; + // expecting a command, not CRC_EOP + // this is how we can get back in sync + case CRC_EOP: + error++; + Serial.print((char) STK_NOSYNC); + break; + + // anything else we will return STK_UNKNOWN + default: + error++; + if (CRC_EOP == getch()) + Serial.print((char)STK_UNKNOWN); + else + Serial.print((char)STK_NOSYNC); + } + + return 0; +} diff --git a/src/LGTISP/readme.md b/src/LGTISP/readme.md new file mode 100644 index 0000000..475ec50 --- /dev/null +++ b/src/LGTISP/readme.md @@ -0,0 +1,35 @@ +# LGTISP +LGT8Fx8P ISP download protocol implementation + +## introduction +This is an implementation of LGT8Fx8P ISP download protocol. You can make arduino board as ISP for programing LGT8Fx8P. + +## usage +1. Make a LGTISP: + 1. Burn LGTISP into arduino board. + 2. Short `RESET` pin and `VCC` pin of arduino board to avoid bootloader executing. + 3. The arduino board becomes a LGTISP now! Connect `SWD` and `SWC`. `RST` can be either connect or not. + | Arduino Nano || LGT | + |:-:|:-:|:-:| + | D13 | -> | SWC | + | D12 | -> | SWD | + | D10 | -> | RST | +2. Burn bootloader into LGT8Fx8P: + 1. install Larduino. + 2. change **Board** to LGT8Fx8P. + 3. change **Programmer** to **AVR ISP**. + 4. click **Burn Bootloader**! + +## advanced usage +- You can read GUID! +- You can read almost all flash after power-down! I crack it, haha +- more details : [LGTISP programmer](https://oshwhub.com/brother_yan/LGTISP) +- Explore yourself! + +## author +brother_yan + +## reference +[LarduinoISP](https://github.com/LGTMCU/LarduinoISP) +[ISP4LGT8F328P](https://github.com/nicechao/ISP4LGT8F328P) + diff --git a/src/LGTISP/swd_lgt8fx8p.cpp b/src/LGTISP/swd_lgt8fx8p.cpp new file mode 100644 index 0000000..9223846 --- /dev/null +++ b/src/LGTISP/swd_lgt8fx8p.cpp @@ -0,0 +1,471 @@ +#include "swd_lgt8fx8p.h" + +void SWD_init() +{ + // set to output + SWDIF_DIR |= (SWDIF_CLK | SWDIF_DAT); + // clear output + SWD_SET(); + SWC_SET(); +} + +void SWD_exit() +{ + /* 禁止:reset后halt CPU,并lock flash */ + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x0d, 1); + SWD_Idle(2); + + delayus(200); + + /* software reset */ + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x0c, 1); + SWD_Idle(2); + + SWD_Idle(40); + + //SWDIF_DIR &= ~(SWDIF_CLK | SWDIF_DAT); +} + +void SWD_WriteByte(uint8_t start, uint8_t data, uint8_t stop) +{ + volatile uint8_t cnt; + + if(start) { + SWC_CLR(); + SWD_Delay(); + SWD_CLR(); + SWD_Delay(); + SWC_SET(); + SWD_Delay(); + } + + // send data + for(cnt = 0; cnt < 8; cnt++) + { + SWC_CLR(); + if(data & 0x1) SWD_SET(); + else SWD_CLR(); + SWD_Delay(); + data >>= 1; + SWC_SET(); + SWD_Delay(); + } + + SWC_CLR(); + if(stop) SWD_SET(); + else SWD_CLR(); + + SWD_Delay(); + SWC_SET(); + SWD_Delay(); +} + +uint8_t SWD_ReadByte(uint8_t start, uint8_t stop) +{ + volatile uint8_t cnt; + volatile uint8_t bRes = 0; + + if(start) + { + SWC_CLR(); + SWD_Delay(); + SWD_CLR(); + SWD_Delay(); + SWC_SET(); + SWD_Delay(); + } + + SWD_IND(); + //SWD_Delay(); + for(cnt = 0; cnt < 8; cnt++) + { + bRes >>= 1; + SWC_CLR(); + SWD_Delay(); + if(SWDIF_PIN & SWDIF_DAT) + bRes |= 0x80; + + SWC_SET(); + SWD_Delay(); + } + + SWD_OUD(); + + SWC_CLR(); + if(stop) SWD_SET(); + else SWD_CLR(); + + SWD_Delay(); + SWC_SET(); + SWD_Delay(); + + return bRes; +} + +void SWD_Idle(uint8_t cnt) +{ + volatile uint8_t i; + + SWD_SET(); + + for(i = 0; i < cnt; i++) + { + SWC_CLR(); + SWD_Delay(); + SWC_SET(); + SWD_Delay(); + } +} + +void SWD_ReadSWDID(char *pdata) +{ + SWD_WriteByte(1, 0xae, 1); + SWD_Idle(4); + pdata[0] = SWD_ReadByte(1, 0); + pdata[1] = SWD_ReadByte(0, 0); + pdata[2] = SWD_ReadByte(0, 0); + pdata[3] = SWD_ReadByte(0, 1); + SWD_Idle(4); +} + +void SWD_ReadGUID(char *guid) +{ + SWD_Idle(10); + SWD_WriteByte(1, 0xa8, 1); + SWD_Idle(4); + guid[0] = SWD_ReadByte(1, 0); + guid[1] = SWD_ReadByte(0, 0); + guid[2] = SWD_ReadByte(0, 0); + guid[3] = SWD_ReadByte(0, 1); + SWD_Idle(4); +} + +void SWD_SWDEN() +{ + SWD_WriteByte(1, 0xd0, 0); + SWD_WriteByte(0, 0xaa, 0); + SWD_WriteByte(0, 0x55, 0); + SWD_WriteByte(0, 0xaa, 0); + SWD_WriteByte(0, 0x55, 1); + SWD_Idle(4); +} + +void SWD_UnLock0() +{ + SWD_WriteByte(1, 0xf0, 0); + SWD_WriteByte(0, 0x54, 0); + SWD_WriteByte(0, 0x51, 0); + SWD_WriteByte(0, 0x4a, 0); + SWD_WriteByte(0, 0x4c, 1); + SWD_Idle(4); +} + +void SWD_UnLock1() +{ + SWD_WriteByte(1, 0xf0, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x00, 1); + SWD_Idle(4); +} + +void SWD_UnLock2() +{ + SWD_WriteByte(1, 0xf0, 0); + SWD_WriteByte(0, 0x43, 0); + SWD_WriteByte(0, 0x40, 0); + SWD_WriteByte(0, 0x59, 0); + SWD_WriteByte(0, 0x5d, 1); + SWD_Idle(4); +} + +void SWD_EEE_CSEQ(uint8_t ctrl, uint16_t addr) +{ + SWD_WriteByte(1, 0xb2, 0); + SWD_WriteByte(0, (addr & 0xff), 0); + SWD_WriteByte(0, ((ctrl & 0x3) << 6) | ((addr >> 8) & 0x3f), 0); + SWD_WriteByte(0, (0xC0 | (ctrl >> 2)), 1); + SWD_Idle(4); +} + +void SWD_EEE_DSEQ(uint32_t data) +{ + SWD_WriteByte(1, 0xb2, 0); + SWD_WriteByte(0, ((uint8_t *)&data)[0], 0); + SWD_WriteByte(0, ((uint8_t *)&data)[1], 0); + SWD_WriteByte(0, ((uint8_t *)&data)[2], 0); + SWD_WriteByte(0, ((uint8_t *)&data)[3], 1); + SWD_Idle(4); +} + +uint8_t SWD_EEE_GetBusy() +{ + uint8_t res = 0; + + SWD_WriteByte(1, 0xaa, 1); + SWD_Idle(8); + SWD_ReadByte(1, 0); + SWD_ReadByte(0, 0); + res = SWD_ReadByte(0, 1); + SWD_Idle(8); + + return res & 0x1; +} + +void SWD_ChipErase() +{ + /* reset flash to 0xff */ + // 我猜是操作FLASH访问控制寄存器 - EECR + SWD_EEE_CSEQ(0x00, 1); + SWD_EEE_CSEQ(0x98, 1); + SWD_EEE_CSEQ(0x9a, 1); + delay(200); + SWD_EEE_CSEQ(0x8a, 1); + delay(20); + SWD_EEE_CSEQ(0x88, 1); + SWD_EEE_CSEQ(0x00, 1); +} + +void crack() // 破解读保护(目前只能读出除了前1k以外的flash,前1k会被擦除) +{ + SWD_EEE_CSEQ(0x00, 1); + SWD_EEE_CSEQ(0x98, 1); + SWD_EEE_CSEQ(0x92, 1); // 会擦除flash的第一页(1024 bytes) + delay(200); + SWD_EEE_CSEQ(0x9e, 1); // 解锁 + delay(200); + SWD_EEE_CSEQ(0x8a, 1); + delay(20); + SWD_EEE_CSEQ(0x88, 1); + SWD_EEE_CSEQ(0x00, 1); +} + +uint32_t SWD_EEE_Read(uint16_t addr) +{ + uint32_t data; + + SWD_EEE_CSEQ(0xc0, addr); + SWD_EEE_CSEQ(0xe0, addr); + + SWD_WriteByte(1, 0xaa, 1); + ((uint8_t *)&data)[0] = SWD_ReadByte(1, 0); + ((uint8_t *)&data)[1] = SWD_ReadByte(0, 0); + ((uint8_t *)&data)[2] = SWD_ReadByte(0, 0); + ((uint8_t *)&data)[3] = SWD_ReadByte(0, 1); + SWD_Idle(4); + + return data; +} + +void SWD_EEE_Write(uint32_t data, uint16_t addr) +{ + SWD_EEE_DSEQ(data); + SWD_EEE_CSEQ(0x86, addr); + SWD_EEE_CSEQ(0xc6, addr); + SWD_EEE_CSEQ(0x86, addr); +} + +uint8_t SWD_UnLock(uint8_t chip_erase) +{ + char swdid[4]; + + SWD_ReadSWDID(swdid); // {0x3e, 0xa2, 0x50, 0xe9}表示这是第一次进行SWD操作,{0x3f, 0xa2, 0x50, 0xe9}表示之前进行过SWD解锁操作 + SWD_SWDEN(); + + if (! (swdid[0] == 0x3e || swdid[0] == 0x3f)) // invalid device + return 0; + + if (swdid[0] == 0x3f && !chip_erase) // 已经解锁,且不全片擦除 + return 1; + + if (swdid[0] == 0x3e) // 第一次解锁 + SWD_UnLock0(); + + if (chip_erase) + SWD_ChipErase(); + else + crack(); + + if (swdid[0] == 0x3e) // 第一次解锁 + { + SWD_UnLock1(); + // 此时swdid[0] == 0x3f + + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x3d, 0); + SWD_WriteByte(0, 0x60, 0); + SWD_WriteByte(0, 0x0c, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x0f, 1); + SWD_Idle(40); + + SWD_UnLock2(); + } + SWD_Idle(40); + + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x0c, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x17, 1); + SWD_Idle(40); + + char flag[2]; + SWD_WriteByte(1, 0xa9, 1); + SWD_Idle(4); + flag[0] = SWD_ReadByte(1, 0); + flag[1] = SWD_ReadByte(0, 1); + SWD_Idle(4); + + if (flag[1] == 0x20) // 0x60没有这段命令 + { + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x3d, 0); + SWD_WriteByte(0, 0x20, 0); + SWD_WriteByte(0, 0x0c, 0); + SWD_WriteByte(0, 0x00, 0); + SWD_WriteByte(0, 0x0f, 1); + SWD_Idle(40); + } + else if (flag[1] == 0x60) // 不接reset引脚会返回这个 + { + } + else + return 0; + + SWD_WriteByte(1, 0xb1, 0); + SWD_WriteByte(0, 0x0d, 1); + SWD_Idle(2); + + return 1; +} + +void write_flash_pages(uint32_t addr, uint8_t buf[], int size) +{ + addr /= 4; // lgt8fx8p的flash是按4字节编址的,而传入的参数是字节地址 + + SWD_EEE_CSEQ(0x00, addr); + SWD_EEE_CSEQ(0x84, addr); + SWD_EEE_CSEQ(0x86, addr); + + for (int i = 0; i < size; i += 4) + { + SWD_EEE_Write(*((uint32_t *)(&buf[i])), addr); + ++addr; + } + + SWD_EEE_CSEQ(0x82, addr - 1); + SWD_EEE_CSEQ(0x80, addr - 1); + SWD_EEE_CSEQ(0x00, addr - 1); +} + +void flash_read_page(uint32_t addr, uint8_t buf[], int size) +{ + addr /= 4; // lgt8fx8p的flash是按4字节编址的,而传入的参数是字节地址 + + SWD_EEE_CSEQ(0x00, 0x01); + + uint32_t data; + for (int i = 0; i < size; ++i) + { + if (i % 4 == 0) + { + data = SWD_EEE_Read(addr); + ++addr; + } + buf[i] = ((uint8_t *)&data)[i % 4]; + } + + SWD_EEE_CSEQ(0x00, 0x01); +} + +volatile uint8_t pmode = 0; +void start_pmode(uint8_t chip_erase) +{ + RSTN_SET(); // digitalWrite(RESET, HIGH); + RSTN_OUD(); // pinMode(RESET, OUTPUT); + delay(20); + RSTN_CLR(); // digitalWrite(RESET, LOW); + + SWD_init(); + SWD_Idle(80); + + pmode = SWD_UnLock(chip_erase); + if (!pmode) + pmode = SWD_UnLock(chip_erase); +} + +void end_pmode() +{ + SWD_exit(); + pmode = 0; + + RSTN_SET(); // digitalWrite(RESET, HIGH); + RSTN_IND(); // pinMode(RESET, INPUT); +} + + + + +LGTISPClass::LGTISPClass() +{ + SWD_init(); + chip_erased = 0; +} + +bool LGTISPClass::begin() +{ + if (!pmode) + { + start_pmode(0); + chip_erased = 0; + } + + SWD_ReadGUID(guid); + + return pmode; +} + +void LGTISPClass::end() +{ + end_pmode(); +} + +bool LGTISPClass::write(uint32_t addr, uint8_t buf[], int size) +{ + if (!chip_erased) + { + end_pmode(); + start_pmode(1); + chip_erased = 1; + } + + if (pmode) + write_flash_pages(addr, buf, size); + + return pmode; +} + +bool LGTISPClass::read(uint32_t addr, uint8_t buf[], int size) +{ + if (pmode) + flash_read_page(addr, buf, size); + + return pmode; +} + +bool LGTISPClass::isPmode() +{ + return pmode; +} + +uint32_t LGTISPClass::getGUID() // return a 4 bytes guid +{ + SWD_ReadGUID(guid); + + return *((uint32_t *)guid); +} + +LGTISPClass LGTISP; diff --git a/src/LGTISP/swd_lgt8fx8p.h b/src/LGTISP/swd_lgt8fx8p.h new file mode 100644 index 0000000..9e473b7 --- /dev/null +++ b/src/LGTISP/swd_lgt8fx8p.h @@ -0,0 +1,82 @@ +#ifndef _SWD_LGT8FX8P_H_ +#define _SWD_LGT8FX8P_H_ + +#include + +#define SWDIF_PIN PINB +#define SWDIF_DIR DDRB +#define SWDIF_PORT PORTB +#define SWDIF_CLK (1 << 5) // PB5 +#define SWDIF_DAT (1 << 4) // PB4 +#define SWDIF_RSTN (1 << 2) // PB2 + +#define SWC_CLR() (SWDIF_PORT &= ~SWDIF_CLK) +#define SWC_SET() (SWDIF_PORT |= SWDIF_CLK) +#define SWD_CLR() (SWDIF_PORT &= ~SWDIF_DAT) +#define SWD_SET() (SWDIF_PORT |= SWDIF_DAT) +#define SWD_IND() (SWDIF_DIR &= ~SWDIF_DAT) +#define SWD_OUD() (SWDIF_DIR |= SWDIF_DAT) + +#define RSTN_CLR() (SWDIF_PORT &= ~SWDIF_RSTN) +#define RSTN_SET() (SWDIF_PORT |= SWDIF_RSTN) +#define RSTN_IND() (SWDIF_DIR &= ~SWDIF_RSTN) +#define RSTN_OUD() (SWDIF_DIR |= SWDIF_RSTN) + +// for 16MHz system clock +// delay used for swc generator +#ifndef NOP +#define NOP() asm volatile("nop") +#endif + +#define SWD_Delay() do {\ + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ + NOP(); NOP(); NOP(); NOP(); NOP(); NOP(); \ +} while(0); + +// reuse delay from Arduino +#ifndef delayus +#define delayus(n) delayMicroseconds(n) +#endif + +void SWD_init(); +void SWD_exit(); +void SWD_Idle(uint8_t cnt); +void SWD_WriteByte(uint8_t start, uint8_t data, uint8_t stop); +uint8_t SWD_ReadByte(uint8_t start, uint8_t stop); +void SWD_EEE_CSEQ(uint8_t ctrl, uint16_t addr); +void SWD_EEE_DSEQ(uint32_t data); + +void SWD_ReadGUID(char *guid); +uint8_t SWD_UnLock(uint8_t chip_erase); +void SWD_EEE_Write(uint32_t data, uint16_t addr); +uint32_t SWD_EEE_Read(uint16_t addr); + +void write_flash_pages(uint32_t addr, uint8_t buf[], int size); +void flash_read_page(uint32_t addr, uint8_t buf[], int size); +extern volatile uint8_t pmode; +void start_pmode(uint8_t chip_erase); +void end_pmode(); + + + + +class LGTISPClass +{ + private: + char guid[4]; + volatile uint8_t chip_erased; + + public: + LGTISPClass(); + bool begin(); + void end(); + bool write(uint32_t addr, uint8_t buf[], int size); + bool read(uint32_t addr, uint8_t buf[], int size); + + bool isPmode(); + uint32_t getGUID(); // return a 4 bytes guid +}; + +extern LGTISPClass LGTISP; + +#endif