TangNano-9K-example project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

211 lines
5.3 KiB

# coding: utf-8
# compile and linking
# to be optimized
# $ riscv32-unknown-elf-gcc -march=RV32IMC -Wl,-Bstatic,-T,sections.lds,--strip-debug -ffreestanding -nostdlib -o firmware.elf start.s isp_flasher.s firmware.c
#
# $ riscv32-unknown-elf-objcopy.exe -O verilog firmware.elf firmware.out
import serial, sys
import time
def isp_wait_byte(ser, exbyte):
resp = bytes([])
while len(resp) == 0:
resp = ser.read()
return resp[0] == exbyte, resp[0]
def isp_exec_esec(ser, addr):
# ISP Flasher ESEC (Erase Sector)
# Host: 0x30 addr2-0
# Reply: 0x31 [erase] 0x32
saddr = bytes([(addr // 65535) & 0xFF, (addr // 256) & 0xF0, 0x00])
ser.write(bytes([0x30]))
isp_wait_byte(ser, 0x31)
ser.write(saddr)
isp_wait_byte(ser, 0x32)
def isp_exec_wbuf(ser, data):
# ISP Flasher WBUF (Write Pagebuf)
# Host: 0x10 len dat0-datn
# Reply: 0x11 chk
wrbyte = bytes([len(data) - 1] + data)
chksum = sum(data) & 0xFF
ser.write(bytes([0x10]))
isp_wait_byte(ser, 0x11)
ser.write(wrbyte)
chksumPass, rxval = isp_wait_byte(ser, chksum)
if not chksumPass:
print(" Bad chksum", rxval)
return False
else:
return True
def isp_exec_wpag(ser, addr):
# ISP Flasher WPAG (Write Page)
# page length saved from last WBUF
# Host: 0x40 addr2-0
# Reply: 0x41 [program] 0x42
pgbuf = bytes([(addr // 65535) & 0xFF, (addr // 256) & 0xFF, addr & 0xFF])
ser.write(bytes([0x40]))
isp_wait_byte(ser, 0x41)
ser.write(pgbuf)
isp_wait_byte(ser, 0x42)
def isp_exec_rst(ser):
# ISP Flasher RST
# Host: 0xF0
# Reply: 0xF1
ser.write(bytes([0xF0]))
ser.read()
if __name__ == '__main__':
if len(sys.argv) != 3 or '-h' in sys.argv:
print("Usage: python pico-programmer.py <firmware.out file path> <serial port>")
sys.exit()
# read file
filepath = sys.argv[1]
file = open(filepath, 'r', buffering=8192)
lprog = []
plinecount = 0
lbegin = False
for line in file:
# skipping ram space
if lbegin:
lprog.append(line)
plinecount += 1
if line.startswith('@00000000'):
lbegin = True
lprog.append(line)
file.close()
nproglen = 16 * (plinecount-1) + len(lprog[plinecount-1].split(' ')) - 1
print("Read program with", nproglen, "bytes")
prog = [0] * nproglen
wp = 0
flash_base = 0x00000000
for i, lstr in enumerate(lprog):
if lstr.startswith('@'):
wp = int(lstr[1:], 16) - flash_base
for j, bprog in enumerate(lstr.split(' ')[0:-1]):
prog[wp] = int(bprog, 16)
wp += 1
# open serial and check status
ser = serial.Serial(sys.argv[2], 115200, timeout=0.01)
print(" - Waiting for reset -", flush=True)
print(' ', end='', flush=True)
for i in range(100):
ser.reset_input_buffer()
ser.write(bytes([0x55, 0x55]))
ser.flush()
time.sleep(0.1)
res = ser.read()
if i % 10 == 0:
print('.', end='', flush=True)
if len(res) > 0 and res[0] == 0x56:
break
print("")
if len(res) == 0 or res[0] != 0x56:
print("Picorv32-isp not detected or not in isp mode")
print("Check serial port or check reset button")
ser.close()
sys.exit()
time.sleep(0.1)
ser.read()
# begin programming
sectind = 0
pageind = 0
wrtbyte = 0
rembyte = len(prog)
curraddr = 0
pagestep = 256
sectreq = ((rembyte - 1) // 4096) + 1
pagereq = ((rembyte - 1) // pagestep) + 1
print("Total sectors", sectreq, flush=True)
print("Total pages", pagereq, flush=True)
wbufFailed = False
wbufRetryLimit = 3
for i in range(sectreq):
print(f"Flashing {i+1} / {sectreq}", flush=True)
# Erase the sector to be programmed
# print("Erasing sector", i, "at 0x{:06x}".format(curraddr & 0xFFF000))
isp_exec_esec(ser, curraddr)
for j in range( min(16, pagereq - i*16) ):
wlen = min(pagestep, rembyte - curraddr)
wrdat = prog[curraddr:curraddr+wlen]
# Send data to page buffer
# print(f" Writing from 0x{curraddr:06X} to 0x{curraddr+wlen-1:06X}")
wbufRetryCnt = 0
while True:
if isp_exec_wbuf(ser, wrdat):
break
else:
wbufRetryCnt += 1
if wbufRetryCnt > wbufRetryLimit:
wbufFailed = True
break
if wbufFailed:
break
# Write from page buffer to flash
# print(f" Programming {j+i*16} at 0x{curraddr:06X}")
isp_exec_wpag(ser, curraddr)
curraddr += pagestep
if wbufFailed:
# time.sleep(1)
# print(ser.read())
print(" Too many retires on sending data to page buffer")
break
# reset system
if wbufFailed:
print("Flashing failed")
else:
isp_exec_rst(ser)
print("")
print("Flashing completed")
ser.close()