diff --git a/README.md b/README.md index b5e7544..e79d194 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Custom firmware for Tuya [THB2](https://pvvx.github.io/THB2). * Проект в начальной стадии разработки, до появления функционального OTA. -Прошивка V0.2 (файл TestTHB2_phy6222.hexf). Всё, кроме OTA работает стабильно. +Прошивка V0.2 (файл TestTHB2.hex или TestTHB2_phy6222.hexf). Всё, кроме OTA работает стабильно. ## Основные характеристики: @@ -15,31 +15,42 @@ Custom firmware for Tuya [THB2](https://pvvx.github.io/THB2). ## Прошивка: -Прошить устройство возможно с помощью программы [PhyPlusKit](https://github.com/pvvx/PHY62x2/raw/master/PhyPlusKit/PhyPlusKit_v2.5.2c.rar), через USB-COM адаптер с выходами на 3.3В. +Прошить устройство возможно через USB-COM адаптер с выходами на 3.3В с помощью программы [PhyPlusKit](https://github.com/pvvx/PHY62x2/raw/master/PhyPlusKit/PhyPlusKit_v2.5.2c.rar): 1. Подключаются выводы GND, TX, RX, VCC (+3.3B). 2. Вывод TM соединяется с VCC. 3. В PhyPlusKit открываем COM порт, выбрав 115200 Baud. -4. Во вкладке “HEX”, позиции рядом с кнопкой “Megre” выбираем файл прошивки с расширением “.hexf”. +4. Во вкладке “HEX”, позиции рядом с кнопкой “Megre” выбираем файл прошивки с расширением “.hexf”. 5. Кратковременно замыкаем вывод RESET на GND. В логе программы появляется “cmd>>:”. Вывод TM можно отключить от VCC. 6. Нажимаем кнопку “Erase”. Ожидаем выполнения - в логе “Erase successfully!”. 7. Нажимаем кнопку “Write”. Ожидаем выполнения - в логе “ Write registers successfully!”. -8. Отключаем провода и устанавливаем батарейки. - -На этом пепрошивка устройтсва закончена. +8. Отключаем провода и устанавливаем батарейки. На этом пепрошивка устройтсва закончена. Для запуска после прошивки при быстрой отладке - отключите TM от VCC и введите команду “reset” в нижней строке PhyPlusKit. -Дополнительная информация по чипам [PHY62xx](https://github.com/pvvx/PHY62x2). +Другой вариант прошивки с помощью USB-COM адаптера с выходами на 3.3В: + +1. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). +2. Запустить: +``` +python3 rdwr_phy6222.py -p COM11 -b 1000000 -r wh TestTHB2.hex +``` +3. Прошивка зашита. Устройство работает. + +Дополнительно: + +* Для предварительного стирания всей Flash используйте опцию `-a`. + +* Для предварительного стирания рабочей области Flash используйте опцию `-e`. ## Сохранение оригинальной прошивки. 1. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). 2. Запустить: ``` -python3 rdreg_phy6222.py -p COM11 -b 1000000 0x11000000 0x80000 +python3 rdwr_phy6222.py -p COM11 -b 1000000 -r rc 0x11000000 0x80000 ff_thb2.bin ``` -3. Полученный файл r11000000-00080000.bin сохранить. +3. Полученный файл ff_thb2.bin сохранить. ## Восстановление оригинальной прошивки. @@ -47,7 +58,9 @@ python3 rdreg_phy6222.py -p COM11 -b 1000000 0x11000000 0x80000 2. Соединить GND, TX, RX, RTS–RESET, VCC (+3.3B). 3. Запустить: ``` -python3 WrFlash_phy6222.py -p COM11 -b 1000000 0 r11000000-00080000.bin +python3 rdwr_phy6222.py -p COM11 -b 1000000 -r we 0 ff_thb2.bin ``` -4. Прошивка зашита. Сбросить устройство переключением питания. +4. Прошивка зашита. Устройство работает. + +Дополнительная информация по чипам [PHY62xx](https://github.com/pvvx/PHY62x2). diff --git a/WrFlash_phy6222.py b/WrFlash_phy6222.py deleted file mode 100644 index a079e64..0000000 --- a/WrFlash_phy6222.py +++ /dev/null @@ -1,359 +0,0 @@ -#!/usr/bin/env python3 - -# wrflash_phy6202.py 07.12.2019 pvvx # - -import serial; -import time; -import argparse -import os -import struct -import sys - -START_BAUD = 9600 -DEF_RUN_BAUD = 115200 -MAX_FLASH_SIZE = 0x200000 -EXT_FLASH_ADD = 0x400000 - -PHY_FLASH_SECTOR_SIZE = 4096 -PHY_FLASH_SECTOR_MASK = 0xfffff000 -PHY_WR_BLK_SIZE = 0x2000 - -__version__ = "28.12.23" - -class phyflasher: - def __init__(self, port='COM1'): - self.port = port - self.baud = START_BAUD - try: - self._port = serial.Serial(self.port, self.baud) - self._port.timeout = 1 - except: - print ('Error: Open %s, %d baud!' % (self.port, self.baud)) - sys.exit(1) - def SetAutoErase(self, enable = True): - self.autoerase = enable - def write_cmd(self, pkt): - print(pkt); - self._port.write(pkt.encode()); - read = self._port.read(6); - return read == b'#OK>>:' - def read_regb(self, addr): - pkt = 'rdreg%08x' % addr; - sent = self._port.write(pkt.encode()); - read = self._port.read(17); - if len(read) == 17 and read[0:3] == b'=0x' and read[11:17] == b'#OK>>:': - dw = struct.pack('>:': - return int(read[1:11], 16) - return None - def write_reg(self, addr, data): - pkt = 'wrreg%08x %08x ' % (addr, data); - self._port.write(pkt.encode()); - read = self._port.read(6); - return read == b'#OK>>:' - def ExpFlashSize(self): - if not self.write_reg(0x1fff0898, EXT_FLASH_ADD): - print('Error set ext.Flash size %08x!' % EXT_FLASH_ADD) - return False - return True - def wr_flash_cmd(self, cmd, data = 0, size = 0): - if size > 0: - if not self.write_reg(0x4000c8a8, data): #Flash Command Write Data Register - print('Error write Flash Data Register!') - return False - if not self.write_reg(0x4000c890, (cmd << 24) | (size <<15) | 1): - print('Error write Flash Command Register!') - return False - return True - def FlashUnlock(self): - #Flash cmd: Write Enable, Write Status Register 0x00 - return self.wr_flash_cmd(6) and self.wr_flash_cmd(1, 0, 1) - def ReadRevision(self): - #0x001364c8 6222M005 #OK>>: - self._port.write(str.encode('rdrev+ ')); - self._port.timeout = 0.1 - read = self._port.read(26); - if len(read) == 26 and read[0:2] == b'0x' and read[20:26] == b'#OK>>:': - print('Revision:', read[2:19]) - if read[11:15] != b'6222': - print('Wrong Version!') - self.flash_id = int(read[2:11], 16) - self.flash_size = 1 << ((self.flash_id >> 16) & 0xff) - print('FlashID: %06x, size: %d kbytes' % (self.flash_id, self.flash_size >> 10)) - return True - else: - print('Error read Revision!') - return False - def SetBaud(self, baud): - if self._port.baudrate != baud: - print ('Reopen %s port %i baud...' % (self.port, baud), end = ' '), - self._port.write(str.encode("uarts%i" % baud)); - self._port.timeout = 1 - read = self._port.read(3); - if read == b'#OK': - print ('ok') - self._port.close() - self.baud = baud - self._port.baudrate = baud - self._port.open(); - else: - print ('error!') - print ('Error set %i baud on %s port!' % (baud, self.port)) - self._port.close() - sys.exit(3) - return True - def Connect(self, baud=DEF_RUN_BAUD): - self._port.setDTR(True) #TM (lo) - self._port.setRTS(True) #RSTN (lo) - self._port.flushOutput() - self._port.flushInput() - time.sleep(0.2) - self._port.setDTR(False) #TM (hi) - self._port.flushOutput() - self._port.flushInput() - time.sleep(0.1) - self._port.setRTS(False) #RSTN (hi) - self._port.timeout = 0.04 - ttcl = 50; - pkt = 'UXTDWU' # UXTL16 UDLL48 UXTDWU - while ttcl > 0: - sent = self._port.write(pkt.encode()); - read = self._port.read(6); - if read == b'cmd>>:' : - break - ttcl = ttcl - 1 - if ttcl < 1: - print('PHY62x2 - Error Reset!') - print('Check connection TX->RX, RX<-TX and Chip Power!') - self._port.close() - exit(4) - print('PHY62x2 - Reset Ok') - self._port.close() - self._port.baudrate = DEF_RUN_BAUD - self._port.open(); - self._port.timeout = 0.2 - if not self.ReadRevision(): - self._port.close() - exit(4) - if not self.FlashUnlock(): - self._port.close() - exit(4) - if not self.ExpFlashSize(): - self._port.close() - exit(4) - if not self.write_reg(0x4000f054, 0): - print('PHY62x2 - Error init1!') - self._port.close() - exit(4) - if not self.write_reg(0x4000f140, 0): - print('PHY62x2 - Error init2!') - self._port.close() - exit(4) - if not self.write_reg(0x4000f144, 0): - print('PHY62x2 - Error init3!') - self._port.close() - exit(4) - print('PHY6222 - connected Ok') - return self.SetBaud(baud) - def cmd_era4k(self, offset): - print ('Erase sector Flash at 0x%08x...' % offset, end = ' ') - self._port.write(str.encode('era4k %X' % (offset | MAX_FLASH_SIZE))), - tmp = self._port.timeout - self._port.timeout = 0.5 - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - print ('ok') - self._port.timeout = tmp - return True - def cmd_era64k(self, offset): - print ('Erase block 64k Flash at 0x%08x...' % offset, end = ' '), - self._port.write(str.encode('er64k %X' % (offset | MAX_FLASH_SIZE))) - tmp = self._port.timeout - self._port.timeout = 2 - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - print ('ok') - self._port.timeout = tmp - return True - def cmd_er512(self, offset = 0): - print ('Erase block 512k Flash at 0x%08x...' % offset, end = ' '), - self._port.write(str.encode('er512 %X' % (offset | MAX_FLASH_SIZE))) - tmp = self._port.timeout - self._port.timeout = 2 - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - print ('ok') - self._port.timeout = tmp - return True - def cmd_erase_all_chipf(self): - print ('Erase Flash work area...', end = ' '), - self._port.write(str.encode('erall ')) - tmp = self._port.timeout - self._port.timeout = 7 - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - print ('ok') - self._port.timeout = tmp - return True - def cmd_erase_all_flash(self): - print ('Erase All Chip Flash...', end = ' '), - if self.wr_flash_cmd(6) and self.wr_flash_cmd(0x60): #Write Enable, Chip Erase - print ('ok') - return True - return False - def EraseSectorsFlash(self, offset = 0, size = MAX_FLASH_SIZE): - count = int((size + PHY_FLASH_SECTOR_SIZE - 1) / PHY_FLASH_SECTOR_SIZE) - offset &= PHY_FLASH_SECTOR_MASK - if count > 0 and count < 0x10000 and offset >= 0: # 1 byte .. 16 Mbytes - while count > 0: - if (offset & 0x7FFFF) == 0 and count > 127: - if not self.cmd_er512(offset): - return False - offset += 0x80000 - count-=128 - elif (offset & 0x0FFFF) == 0 and count > 15: - if not self.cmd_era64k(offset): - return False - offset += 0x10000 - count-=16 - else: - if not self.cmd_era4k(offset): - return False - offset += PHY_FLASH_SECTOR_SIZE - count-=1 - else: - return False - return True - def send_blk(self, stream, offset, size, blkcnt, blknum): - self._port.timeout = 1 - print ('Write 0x%08x bytes to Flash at 0x%08x...' % (size, offset), end = ' '), - if blknum == 0: - self._port.write(str.encode('cpnum %d ' % blkcnt)) - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - self._port.write(str.encode('cpbin c%d %X %X %X' % (blknum, offset | MAX_FLASH_SIZE, size, 0x1FFF0000 + offset))) - read = self._port.read(12) - if read != b'by hex mode:': - print ('error!') - return False - data = stream.read(size) - self._port.write(data) - read = self._port.read(23); #'checksum is: 0x00001d1e' - #print ('%s' % read), - if read[0:15] != b'checksum is: 0x': - print ('error!') - return False - self._port.write(read[15:]) - read = self._port.read(6) - if read != b'#OK>>:': - print ('error!') - return False - print ('ok') - return True - def WriteBlockFlash(self, stream, offset = 0, size = 0x8000): - offset &= 0x00ffffff - if self.autoerase: - if not self.EraseSectorsFlash(offset, size): - return False - sblk = PHY_WR_BLK_SIZE - blkcount = (size + sblk - 1) / sblk - blknum = 0 - while(size > 0): - if size < sblk: - sblk = size - if not self.send_blk(stream, offset, sblk, blkcount, blknum): - return False - blknum+=1 - offset+=sblk - size-=sblk - return True - -class FatalError(RuntimeError): - def __init__(self, message): - RuntimeError.__init__(self, message) - - @staticmethod - def WithResult(message, result): - message += " (result was %s)" % hexify(result) - return FatalError(message) - -def arg_auto_int(x): - return int(x, 0) - -def main(): - parser = argparse.ArgumentParser(description='WrFlash-PHY6222 Utility version %s' % __version__, prog='WrFlash_phy6222') - parser.add_argument('--port', '-p', help='Serial port device', default='COM1'); - parser.add_argument('--baud', '-b', help='Set Port Baud (115200, 250000, 500000, 1000000)', type=arg_auto_int, default=DEF_RUN_BAUD); - parser.add_argument('--erase', '-e', action='store_true', help='Erase Flash work area'); - parser.add_argument('--allerase', '-a', action='store_true', help='All Chip Erase'); - parser.add_argument('address', help='Start Flash address', type=arg_auto_int) - parser.add_argument('filename', help='File name') - - args = parser.parse_args() - - print('WrFlash-PHY6222 Utility version %s' % __version__) - - phy = phyflasher(args.port) - print ('Connecting...') - offset = args.address - if offset >= MAX_FLASH_SIZE: - print ('Error Start Flash address!') - sys.exit(1) - if phy.Connect(args.baud): - stream = open(args.filename, 'rb') - size = os.path.getsize(args.filename) - if size < 1: - stream.close - print ('Error: File size = 0!') - sys.exit(1) - offset = args.address & (MAX_FLASH_SIZE-1) - if size + offset > MAX_FLASH_SIZE: - size = MAX_FLASH_SIZE - offset - if size < 1: - stream.close - print ('Error: Write File size = 0!') - sys.exit(1) - aerase = True; - if args.erase == True or args.allerase == True: - aerase = False; - if args.allerase == True: - if not phy.cmd_erase_all_flash(): # cmd_erase_all_chipf(): - stream.close - print ('Error: Erase Flash!') - sys.exit(3) - else: - if args.erase == True: - if not cmd_erase_all_chipf(): - stream.close - print ('Error: Clear Flash!') - sys.exit(3) - phy.SetAutoErase(aerase) - print ('Write Flash data 0x%08x to 0x%08x from file: %s ...' % (offset, offset + size, args.filename)) - if size > 0: - if not phy.WriteBlockFlash(stream, offset, size): - stream.close - print ('Error: Write Flash!') - sys.exit(2) - stream.close - print ('--------------------------------------------------------') - print ('Write Flash data 0x%08x to 0x%08x from file: %s - ok.' % (offset, offset + size, args.filename)) - sys.exit(0) - -if __name__ == '__main__': - main() diff --git a/rdreg_phy6222.py b/rdreg_phy6222.py deleted file mode 100644 index 7f13b4d..0000000 --- a/rdreg_phy6222.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python3 - -# rdreg_phy6202.py 30.11.2019 pvvx # - -import serial; -import time; -import argparse -import os -import struct -import sys - -__version__ = "23.11.22" - -class FatalError(RuntimeError): - def __init__(self, message): - RuntimeError.__init__(self, message) - - @staticmethod - def WithResult(message, result): - message += " (result was %s)" % hexify(result) - return FatalError(message) - -def arg_auto_int(x): - return int(x, 0) - -def main(): - parser = argparse.ArgumentParser(description='RdRegs-PHY6222 Utility version %s' % __version__, prog='rdreg_phy6222') - parser.add_argument( - '--port', '-p', - help='Serial port device', - default='COM1'); - parser.add_argument( - '--baud', '-b', - help='Set Port Baud (115200, 250000, 500000, 1000000), default: 1000000', - type=arg_auto_int, - default=1000000); - parser.add_argument('address', help='Start address', type=arg_auto_int) - parser.add_argument('size', help='Size of region to dump', type=arg_auto_int) - - args = parser.parse_args() - - baud = 9600; - print('RdRegs-PHY62x2 Utility version %s' % __version__) - try: - serialPort = serial.Serial(args.port, baud, \ - serial.EIGHTBITS,\ - serial.PARITY_NONE, \ - serial.STOPBITS_ONE); - except: - print('Error: Open %s, %d baud!' % (args.port, baud)) - sys.exit(2) - - serialPort.setDTR(False) #TM (lo) - serialPort.setRTS(True) #RSTN (lo) - serialPort.flushOutput() - serialPort.flushInput() - time.sleep(0.1) - serialPort.setDTR(True) #TM (hi) - serialPort.flushOutput() - serialPort.flushInput() - time.sleep(0.1) - serialPort.setRTS(False) #RSTN (hi) - serialPort.timeout = 0.04 - -#-------------------------------- - - byteSent = 0; - byteRead = 0; - byteSaved = 0; - - addr = args.address; - length = args.size; - - ttcl = 250; - pkt = 'UXTDWU' # UXTL16 UDLL48 UXTDWU - while ttcl > 0: - sent = serialPort.write(pkt.encode()); - byteSent += sent - read = serialPort.read(6); - byteRead += len(read); - if read == b'cmd>>:' : - break - ttcl = ttcl - 1 - if ttcl < 1: - print('PHY62x2 - Error Reset!') - print('Check connection TX->RX, RX<-TX and Chip Power!') - serialPort.close() - exit(4) - - print('PHY62x2 - Reset Ok') - serialPort.close() - serialPort.baudrate = 115200 - serialPort.open(); - serialPort.timeout = 0.2 - - pkt = 'wrreg4000f054 0 '; - sent = serialPort.write(pkt.encode()); - byteSent += sent; - read = serialPort.read(6); - byteRead += len(read); - if read != b'#OK>>:' : - print('PHY62x2 - Error init1!') - serialPort.close() - exit(4) - - pkt = 'wrreg4000f140 0 '; - sent = serialPort.write(pkt.encode()); - byteSent += sent; - read = serialPort.read(6); - byteRead += len(read); - if read != b'#OK>>:' : - print('PHY62x2 - Error init2!') - serialPort.close() - exit(4) - - pkt = 'wrreg4000f144 0 '; - sent = serialPort.write(pkt.encode()); - byteSent += sent; - read = serialPort.read(6); - byteRead += len(read); - if read != b'#OK>>:' : - print('PHY62x2 - Error init3!') - serialPort.close() - exit(4) - - if baud != args.baud: - baud = args.baud; - print('Reopen %s port %i baud' % (args.port, baud)) - pkt = "uarts%i" % baud - sent = serialPort.write(pkt.encode()); - byteSent += sent; - serialPort.timeout = 1 -# 012 -# #OK - read = serialPort.read(3); - #print(read); - serialPort.close() - serialPort.baudrate = baud - serialPort.open(); - - serialPort.write(str.encode("rdrev")); - serialPort.timeout = 0.1 - read = serialPort.read(16); - if read[0:2] == b'0x' and read[10:16] == b'#OK>>:': - print('Revision:', read[0:10]) - else: - print('Error read Revision!') - exit(2) - print('Start address: 0x%08x, length: 0x%08x' % (addr, length)) - - filename = "r%08x-%08x.bin" % (addr, length) - try: - ff = open(filename, "wb") - except: - serialPort.close() - print('Error file open ' + filename) - exit(2) - - t1 = time.time() - while length > 0: - if args.size > 128 and addr&127 == 0: - print('\rRead 0x%08x...' % addr, end='') #, flush=True - txt = "rdreg%08x" % addr; - sent = serialPort.write(txt.encode()); - byteSent += sent; -# 01234567890123456 -# =0x1fff3710#OK>>: - read = serialPort.read(17); - byteRead += len(read); - if read[0:3] == b'=0x' and read[11:17] == b'#OK>>:': - dw = struct.pack(' 1024: - print("%.3f KBytes saved to file '%s'" % (byteSaved/1024, filename)) - else: - print("%i Bytes saved to file '%s'" % (byteSaved, filename)) - ff.close() - exit(0); - -if __name__ == '__main__': - main() diff --git a/rdwr_phy6222.py b/rdwr_phy6222.py new file mode 100644 index 0000000..ce34d98 --- /dev/null +++ b/rdwr_phy6222.py @@ -0,0 +1,617 @@ +#!/usr/bin/env python3 + +# wrflash_phy6202.py 07.12.2019 pvvx # + +import serial; +import time; +import argparse +import io +import os +import struct +import sys + +START_BAUD = 9600 +DEF_RUN_BAUD = 115200 +MAX_FLASH_SIZE = 0x200000 +EXT_FLASH_ADD = 0x400000 + +PHY_FLASH_SECTOR_SIZE = 4096 +PHY_FLASH_SECTOR_MASK = 0xfffff000 +PHY_WR_BLK_SIZE = 0x2000 + +__progname__ = 'PHY6222 Utility' +__filename__ = 'rdwr_phy6222.py' +__version__ = "29.12.23" + +def ParseHexFile(hexfile): + try: + fin = open(hexfile) + except: + print('No file opened', hexfile) + return None + + table = [] + result = bytearray() + addr = 0 + addr_flg = 0 + table.append([0, result, 0x2000]) + for hexstr in fin.readlines(): + hexstr = hexstr.strip() + #size = int(hexstr[1:3],16) + if hexstr[7:9] == '04': + if(len(result)): + #print(hex(addr)) + table.append([addr, result, 0]) + addr = int(hexstr[9:13],16) << 16 + addr_flg = 0 + result = bytearray() + continue + if hexstr[7:9] == '05' or hexstr[7:9] == '01': + table.append([addr, result, 0]) + break + if addr_flg == 0: + addr_flg = 1 + addr = addr | (int(hexstr[3:7],16)) + #print(hexstr[9:-3]) + result.extend(bytearray.fromhex(hexstr[9:-2])) + fin.close() + return table + +class phyflasher: + def __init__(self, port='COM1'): + self.old_erase_start = EXT_FLASH_ADD + self.old_erase_end = EXT_FLASH_ADD + self.port = port + self.baud = START_BAUD + try: + self._port = serial.Serial(self.port, self.baud) + self._port.timeout = 1 + except: + print ('Error: Open %s, %d baud!' % (self.port, self.baud)) + sys.exit(1) + def SetAutoErase(self, enable = True): + self.autoerase = enable + def CreateHead(self): + self.hexf = [bytearray(b'\xff')*(0x100), bytearray(), bytearray(), bytearray()] + self.hexf[8:12] = int.to_bytes(0x1fff1838, 4, byteorder='little') + return self.hexf + def AddSectionToHead(self, addr, size): + #self.hexf.sec[0:4] = int.to_bytes(self.hexidx, 4, byteorder='little') + self.hexf.sec.extend(bytearray(struct.pack('>:' + def SendResetCmd(self): + return self._port.write(str.encode('reset ')); + def read_reg(self, addr): + pkt = 'rdreg%08x' % addr; + sent = self._port.write(pkt.encode()); + read = self._port.read(17); + if len(read) == 17 and read[0:3] == b'=0x' and read[11:17] == b'#OK>>:': + return int(read[1:11], 16) + return None + def write_reg(self, addr, data): + return self.write_cmd('wrreg%08x %08x ' % (addr, data)) + def ExpFlashSize(self): + if not self.write_reg(0x1fff0898, EXT_FLASH_ADD): + print('Error set ext.Flash size %08x!' % EXT_FLASH_ADD) + return False + return True + def wr_flash_cmd(self, cmd, data = 0, size = 0): + if size > 0: + if not self.write_reg(0x4000c8a8, data): #Flash Command Write Data Register + print('Error write Flash Data Register!') + return False + if not self.write_reg(0x4000c890, (cmd << 24) | (size <<15) | 1): + print('Error write Flash Command Register!') + return False + return True + def FlashUnlock(self): + #Flash cmd: Write Enable, Write Status Register 0x00 + return self.wr_flash_cmd(6) and self.wr_flash_cmd(1, 0, 1) + def ReadRevision(self): + #0x001364c8 6222M005 #OK>>: + self._port.write(str.encode('rdrev+ ')); + self._port.timeout = 0.1 + read = self._port.read(26); + if len(read) == 26 and read[0:2] == b'0x' and read[20:26] == b'#OK>>:': + print('Revision:', read[2:19]) + if read[11:15] != b'6222': + print('Wrong Version!') + self.flash_id = int(read[2:11], 16) + self.flash_size = 1 << ((self.flash_id >> 16) & 0xff) + print('FlashID: %06x, size: %d kbytes' % (self.flash_id, self.flash_size >> 10)) + return True + else: + print('Error read Revision!') + return False + def SetBaud(self, baud): + if self._port.baudrate != baud: + print ('Reopen %s port %i baud...' % (self.port, baud), end = ' '), + self._port.write(str.encode("uarts%i" % baud)); + self._port.timeout = 1 + read = self._port.read(3); + if read == b'#OK': + print ('ok') + self._port.close() + self.baud = baud + self._port.baudrate = baud + self._port.open(); + else: + print ('error!') + print ('Error set %i baud on %s port!' % (baud, self.port)) + self._port.close() + sys.exit(3) + return True + def Connect(self, baud=DEF_RUN_BAUD): + self._port.setDTR(True) #TM (lo) + self._port.setRTS(True) #RSTN (lo) + self._port.flushOutput() + self._port.flushInput() + time.sleep(0.2) + self._port.setDTR(False) #TM (hi) + self._port.flushOutput() + self._port.flushInput() + time.sleep(0.1) + self._port.setRTS(False) #RSTN (hi) + self._port.timeout = 0.04 + ttcl = 50; + pkt = 'UXTDWU' # UXTL16 UDLL48 UXTDWU + while ttcl > 0: + sent = self._port.write(pkt.encode()); + read = self._port.read(6); + if read == b'cmd>>:' : + break + ttcl = ttcl - 1 + if ttcl < 1: + print('PHY62x2 - Error Reset!') + print('Check connection TX->RX, RX<-TX and Chip Power!') + self._port.close() + exit(4) + print('PHY62x2 - Reset Ok') + self._port.close() + self._port.baudrate = DEF_RUN_BAUD + self._port.open(); + self._port.timeout = 0.2 + if not self.ReadRevision(): + self._port.close() + exit(4) + if not self.FlashUnlock(): + self._port.close() + exit(4) + if not self.write_reg(0x4000f054, 0): + print('PHY62x2 - Error init1!') + self._port.close() + exit(4) + if not self.write_reg(0x4000f140, 0): + print('PHY62x2 - Error init2!') + self._port.close() + exit(4) + if not self.write_reg(0x4000f144, 0): + print('PHY62x2 - Error init3!') + self._port.close() + exit(4) + print('PHY6222 - connected Ok') + return self.SetBaud(baud) + def cmd_era4k(self, offset): + print ('Erase sector Flash at 0x%08x...' % offset, end = ' ') + tmp = self._port.timeout + self._port.timeout = 0.5 + ret = self.write_cmd('era4k %X' % (offset | MAX_FLASH_SIZE)) + self._port.timeout = tmp + if not ret: + print ('error!') + else: + print ('ok') + return ret + def cmd_era64k(self, offset): + print ('Erase block 64k Flash at 0x%08x...' % offset, end = ' '), + tmp = self._port.timeout + self._port.timeout = 2 + ret = self.write_cmd('er64k %X' % (offset | MAX_FLASH_SIZE)) + self._port.timeout = tmp + if not ret: + print ('error!') + else: + print ('ok') + return ret + def cmd_er512(self, offset = 0): + print ('Erase block 512k Flash at 0x%08x...' % offset, end = ' '), + tmp = self._port.timeout + self._port.timeout = 2 + ret = self.write_cmd('er512 %X' % (offset | MAX_FLASH_SIZE)) + self._port.timeout = tmp + if not ret: + print ('error!') + else: + print ('ok') + return ret + def cmd_erase_all_chipf(self): + print ('Erase Flash work area...', end = ' '), + tmp = self._port.timeout + self._port.timeout = 7 + ret = self.write_cmd('erall ') + self._port.timeout = tmp + if not ret: + print ('error!') + else: + print ('ok') + return ret + def cmd_erase_all_flash(self): + print ('Erase All Chip Flash...', end = ' '), + if self.wr_flash_cmd(6) and self.wr_flash_cmd(0x60): #Write Enable, Chip Erase + time.sleep(7) + print ('ok') + return True + print ('error!') + return False + def EraseSectorsFlash(self, offset = 0, size = MAX_FLASH_SIZE): + count = int((size + PHY_FLASH_SECTOR_SIZE - 1) / PHY_FLASH_SECTOR_SIZE) + offset &= PHY_FLASH_SECTOR_MASK + if count > 0 and count < 0x10000 and offset >= 0: # 1 byte .. 16 Mbytes + while count > 0: + if offset >= self.old_erase_start and offset < self.old_erase_end: + offset += PHY_FLASH_SECTOR_SIZE + count -= 1 + continue + if (offset & 0x0FFFF) == 0 and count > 15: + if not self.cmd_era64k(offset): + return False + self.old_erase_start = offset + self.old_erase_end = offset + 0x10000 + offset += 0x10000 + count -= 16 + else: + if not self.cmd_era4k(offset): + return False + self.old_erase_start = offset + self.old_erase_end = offset + PHY_FLASH_SECTOR_SIZE + offset += PHY_FLASH_SECTOR_SIZE + count -= 1 + else: + return False + return True + def EraseSectorsFlash2(self, offset = 0, size = MAX_FLASH_SIZE): + count = int((size + PHY_FLASH_SECTOR_SIZE - 1) / PHY_FLASH_SECTOR_SIZE) + offset &= PHY_FLASH_SECTOR_MASK + if count > 0 and count < 0x10000 and offset >= 0: # 1 byte .. 16 Mbytes + while count > 0: + if (offset & 0x0FFFF) == 0 and count > 15: + if not self.cmd_era64k(offset): + return False + offset += 0x10000 + count-=16 + else: + if not self.cmd_era4k(offset): + return False + offset += PHY_FLASH_SECTOR_SIZE + count-=1 + else: + return False + return True + def send_blk(self, stream, offset, size, blkcnt, blknum): + self._port.timeout = 1 + print ('Write 0x%08x bytes to Flash at 0x%08x...' % (size, offset), end = ' '), + if blknum == 0: + if not self.write_cmd('cpnum %d ' % blkcnt): + print ('error!') + return False + self._port.write(str.encode('cpbin c%d %X %X %X' % (blknum, offset | MAX_FLASH_SIZE, size, 0x1FFF0000 + offset))) + read = self._port.read(12) + if read != b'by hex mode:': + print ('error!') + return False + data = stream.read(size) + self._port.write(data) + read = self._port.read(23); #'checksum is: 0x00001d1e' + #print ('%s' % read), + if read[0:15] != b'checksum is: 0x': + print ('error!') + return False + self._port.write(read[15:]) + read = self._port.read(6) + if read != b'#OK>>:': + print ('error!') + return False + print ('ok') + return True + def WriteBlockFlash(self, stream, offset = 0, size = 0x8000): + offset &= 0x00ffffff + if self.autoerase: + if not self.EraseSectorsFlash(offset, size): + return False + sblk = PHY_WR_BLK_SIZE + blkcount = (size + sblk - 1) / sblk + blknum = 0 + while(size > 0): + if size < sblk: + sblk = size + if not self.send_blk(stream, offset, sblk, blkcount, blknum): + return False + blknum+=1 + offset+=sblk + size-=sblk + return True + def ReadBusToFile(self, ff, addr=0x11000000, size=0x80000): + flg = size > 128 + while size > 0: + if flg and addr & 127 == 0: + print('\rRead 0x%08x...' % addr, end='') #, flush=True + rw = self.read_reg(addr) + if rw == None: + print('\rError read address 0x%08x!' % addr) + return False + dw = struct.pack(' 0): + if size < sblk: + sblk = size + if not self.send_blk(stream, offset, sblk, blkcount, blknum): + return False + blknum+=1 + offset+=sblk + size-=sblk + return True + def HexStartSend(self): + return self.write_cmd('spifs 0 1 3 0 ') and self.write_cmd('sfmod 2 2 ') and self.write_cmd('cpnum ffffffff ') + def HexfHeader(self, hp): + if len(hp) > 1: + hexf = bytearray(b'\xff')*(0x100) + hexf[0:4] = int.to_bytes(len(hp), 4, byteorder='little') + hexf[8:12] = int.to_bytes(0x1fff1838, 4, byteorder='little') + sections = 0 + faddr = 0x00020000 + raddr = 0x00005414 + print ('---- Segments Table -------------------------------------') + for ihp in hp: + if ihp[0] == 0x1fff0000: + faddr = 0x00005000 + raddr = faddr + elif ihp[0] == 0x1fff1838: + faddr = 0x00005414 + raddr = faddr + elif (ihp[0] & 0x1fff0000) == 0x1fff0000: + faddr = raddr + raddr += (len(ihp[1])+3) & 0xfffffffc + elif (ihp[0] & (~(MAX_FLASH_SIZE-1))) == 0x11000000: + faddr = ihp[0] & (MAX_FLASH_SIZE-1) + elif ihp[0] == 0: + continue + else: + print('Invalid Segment Address 0x%08x!' % ihp[0]) + return None + ihp[2] = faddr + print('Segment: %08x <- Flash addr: %08x, Size: %08x' % (ihp[0], faddr, len(ihp[1]))) + hexf.extend(bytearray(struct.pack(' 1024: + print("%.3f KBytes saved to file '%s'" % (byteSaved/1024, args.filename)) + else: + print("%i Bytes saved to file '%s'" % (byteSaved, args.filename)) + ff.close() + #--------------------------------wr flash bin + if args.operation == 'we' or args.operation == 'wf': + offset = args.address & (MAX_FLASH_SIZE-1) + if offset >= MAX_FLASH_SIZE: + print ('Error Start Flash address!') + sys.exit(1) + stream = open(args.filename, 'rb') + size = os.path.getsize(args.filename) + if size < 1: + stream.close() + print ('Error: File size = 0!') + sys.exit(1) + offset = args.address & (MAX_FLASH_SIZE-1) + if size + offset > MAX_FLASH_SIZE: + size = MAX_FLASH_SIZE - offset + if size < 1: + stream.close() + print ('Error: Write File size = 0!') + sys.exit(1) + aerase = args.operation == 'we' + if args.erase == True or args.allerase == True: + aerase = False; + if args.allerase == True: + if not phy.cmd_erase_all_flash(): + stream.close() + print ('Error: Erase All Flash!') + sys.exit(3) + else: + if args.erase == True: + if not phy.cmd_erase_all_chipf(): + stream.close + print ('Error: Erase Flash!') + sys.exit(3) + phy.SetAutoErase(aerase) + print ('Write Flash data 0x%08x to 0x%08x from file: %s ...' % (offset, offset + size, args.filename)) + if not phy.ExpFlashSize(): + exit(4) + if size > 0: + if not phy.WriteBlockFlash(stream, offset, size): + stream.close() + print ('Error: Write Flash!') + sys.exit(2) + stream.close() + print ('----------------------------------------------------------') + print ('Write Flash data 0x%08x to 0x%08x from file: %s - ok.' % (offset, offset + size, args.filename)) + #--------------------------------wr flash hex + if args.operation == 'wh': + hp = ParseHexFile(args.filename) + if hp == None: + sys.exit(2) + hexf = phy.HexfHeader(hp) + if hexf == None: + sys.exit(2) + hp[0][1] = hexf + if not phy.HexStartSend(): + sys.exit(2) + print ('----------------------------------------------------------') + aerase = True + if args.erase == True or args.allerase == True: + aerase = False; + if args.allerase == True: + if not phy.cmd_erase_all_flash(): + stream.close() + print ('Error: Erase All Flash!') + sys.exit(3) + else: + if args.erase == True: + if not phy.cmd_erase_all_chipf(): + stream.close + print ('Error: Erase Flash!') + sys.exit(3) + phy.SetAutoErase(aerase) + if not phy.ExpFlashSize(): + exit(4) + segment = 0 + for ihp in hp: + if ihp[0] == 0: + print('Segment Table[%02d] <- Flash addr: %08x, Size: %08x' % (len(hp) - 1, ihp[2], len(ihp[1]))) + else: + print('Segment: %08x <- Flash addr: %08x, Size: %08x' % (ihp[0], ihp[2], len(ihp[1]))) + stream = io.BytesIO(ihp[1]) + if not phy.WriteBlockFlash(stream, ihp[2], len(ihp[1])): + stream.close() + sys.exit(2) + stream.close() + segment += 1 + print ('----------------------------------------------------------') + print ('Write Flash from file: %s - ok.' % args.filename) + #--------------------------------erase flash region + if args.operation == 'er': + offset = args.address & (MAX_FLASH_SIZE-1) + if offset >= MAX_FLASH_SIZE: + print ('Error Flash Start address!') + sys.exit(1) + size = args.size & (MAX_FLASH_SIZE-1) + if size >= MAX_FLASH_SIZE: + print ('Error Flash Erase size!') + sys.exit(1) + if size + offset > MAX_FLASH_SIZE: + size = MAX_FLASH_SIZE - offset + if size < 1: + print ('Error Flash Erase size!') + sys.exit(1) + if not phy.ExpFlashSize(): + exit(4) + if not phy.EraseSectorsFlash(offset, size): + sys.exit(2) + #--------------------------------erase flash all + if args.operation == 'ea': + if not phy.cmd_erase_all_chipf(): + print ('Error: Erase Flash!') + sys.exit(3) + if args.reset: + phy.SendResetCmd() + print ("Send command 'reset' - ok") + sys.exit(0) + +if __name__ == '__main__': + main()