従来に公開していたSHマイコンのフラッシュライターでは、Windows7以降の環境やUbuntu18以降の環境では動作しないケースがありました。
このような環境でも動作するように新規にPython3でフラッシュライターを開発しました。
対象となるマイコンは、SH3/SH4/SH4A、SH7084、SH7216、SH7124となっており、Ubuntu21とWIndows10で動作確認をしました。
import serial
import sys
import os
import struct
from sys import exit
BIT_RATE_SET_MAX = 256
BIT_SET_RES = 0xaa
BIT_RATE_SET_MAX_INTER = 30
BIT_SET_RES_INTER = 0xe6
BIT_SET_RES_NG = 0xff
BIT_SET_CODE = 0x00
BIT_SET_CHECK = 0x55
BIT_SET_FIN = 0x00
QUERY_DEV_CMD = 0x20
QUERY_DEV_RES = 0x30
QUERY_DEV_SIZE = 4
SELECT_DEV_CMD = 0x10
SELECT_DEV_RES = 0x06
SELECT_DEV_ERROR_RES = 0x90
SELECT_DEV_ERROR_SUM = 0x11
SELECT_DEV_ERROR_CODE = 0x21
QUERY_CLOCK_CMD = 0x21
QUERY_CLOCK_RES = 0x31
SELECT_CLOCK_CMD = 0x11
SELECT_CLOCK_RES = 0x06
SELECT_CLOCK_ERROR_RES = 0x91
SELECT_CLOCK_ERROR_SUM = 0x11
SELECT_CLOCK_ERROR_MODE = 0x22
SELECT_CLOCK_SIZE = 1
SELECT_CLOCK_MODE0 = 0
SELECT_CLOCK_MODE1 = 1
QUERY_SCALE_CMD = 0x22
QUERY_SCALE_RES = 0x32
QUERY_FREQ_CMD = 0x23
QUERY_FREQ_RES = 0x33
QUERY_PAGE_SIZE_CMD = 0x27
QUERY_PAGE_SIZE_RES = 0x37
SET_RATE_CMD = 0x3f
SET_RATE_RES = 0x06
SET_RATE_ERROR_RES = 0xbf
SET_RATE_ERROR_SUM = 0x11
SET_RATE_ERROR_RATE = 0x24
SET_RATE_ERROR_NEW_FREQ = 0x25
SET_RATE_ERROR_PLL = 0x26
SET_RATE_ERROR_FREQ = 0x27
SET_RATE_CHECK_CMD = 0x06
SET_RATE_SIZE = 7
QUERY_AREA_CMD = 0x25
QUERY_AREA_RES = 0x35
SWITCH_TO_ERASE_CMD = 0x40
SELECT_WRITE_FORMAT = 0x43
QUERY_ERROR_RES = 0x80
NON_ERROR_RES = 0x06
WRITE_CMD = 0x50
WRITE_ERROR_ADDRESS = 0x2a
WRITE_ERROR_WRITE = 0x53
argc = len(sys.argv)
if argc >= 3:
if sys.argv[1] != '-p':
argc = 1
if argc < 4:
print('Usage: flush -p port file')
exit()
filename = sys.argv[argc - 1]
port = sys.argv[2]
osc = 0
baud = 19200
if not os.path.isfile(filename):
print('File not found.\n')
try:
ser = serial.Serial(port, baud, timeout=0.05)
except:
print('Serial port not found\n')
exit()
for i in range(10):
for j in range(BIT_RATE_SET_MAX_INTER):
ser.write(b'\x00')
c = ser.read()
if c != b'':
break
if c != b'\x00':
ser.close()
ser = serial.Serial(port, 115200, timeout=0.2)
for i in range(8):
ser.write(b'\x5a')
c = ser.read()
if c != b'':
break
if i == 7:
print('Serial port not found')
exit()
for i in range(255):
c1 = struct.pack('B', i)
if c1 != B'E':
ser.write(c1)
c2 = ser.read()
if c1 != c2:
print('Serial port not found')
exit()
cpu = 'SH3/4/4A'
flushsize = 0x80000
pagesize = 256
ser.timeout = 5
ser.write(b'E')
c = ser.read()
print('CPU is', cpu)
print('Flush erase', end='', flush=True)
while c != b'S':
c = ser.read()
if c == b'.':
print('.', end='', flush=True)
if c != b'S' and c != b'.':
print('Flush earse fail')
exit()
print('.', flush=True)
else:
ser.write(struct.pack('B', BIT_SET_CHECK))
while True:
stat = int.from_bytes(ser.read(),'big')
if stat == BIT_SET_RES_NG:
print('Bit set check error')
exit()
if stat == BIT_SET_RES_INTER:
break
ser.write(struct.pack('B', QUERY_DEV_CMD))
stat = int.from_bytes(ser.read(),'big')
sum1 = stat
if stat != QUERY_DEV_RES:
print('Query device error')
exit()
size = int.from_bytes(ser.read(),'big')
sum1 = sum1 + size
devnum = int.from_bytes(ser.read(),'big')
sum1 = sum1 + devnum
status = bytearray(size - 1)
for i in range(size - 1):
status[i] = int.from_bytes(ser.read(),'big')
sum1 = sum1 + status[i]
sum1 = sum1 + int.from_bytes(ser.read(),'big')
sum1 = sum1 % 0x100
if sum1 != 0:
print('Query device error')
exit()
devcode = bytearray(QUERY_DEV_SIZE)
for i in range(QUERY_DEV_SIZE):
devcode[i] = status[i + 1]
length = status[0] - QUERY_DEV_SIZE;
devname = bytearray(length)
for i in range(length):
devname[i] = status[i + QUERY_DEV_SIZE + 1]
cpu = devname.decode()
if cpu == 'R5F7084':
if osc == 0:
osc = 1000
elif cpu == 'R5F7216':
if osc == 0:
osc = 1200
elif cpu == 'R5F7124':
if osc == 0:
osc = 1250
else:
print('This is a unknown cpu')
exit()
print('CPU is', cpu)
c = SELECT_DEV_CMD
sum1 = c
ser.write(struct.pack('B', c))
c = QUERY_DEV_SIZE
sum1 = sum1 + c
ser.write(struct.pack('B', c))
for i in range(QUERY_DEV_SIZE):
c = devcode[i]
ser.write(struct.pack('B', c))
sum1 = sum1 + c
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
ser.write(struct.pack('B', sum1))
c = int.from_bytes(ser.read(),'big')
if c != SELECT_DEV_RES:
print('Select device error')
exit()
ser.write(struct.pack('B', QUERY_CLOCK_CMD))
c = int.from_bytes(ser.read(),'big')
sum1 = c;
if c != QUERY_CLOCK_RES:
print('Query clock error')
exit()
size = int.from_bytes(ser.read(),'big')
sum1 = sum1 + size
status = bytearray(size)
for i in range(size):
status[i] = int.from_bytes(ser.read(),'big')
sum1 = sum1 + status[i];
sum1 = sum1 + int.from_bytes(ser.read(),'big')
sum1 = sum1 % 0x100
if sum1 != 0:
print('Query clock error')
exit()
c = SELECT_CLOCK_CMD
sum1 = c;
ser.write(struct.pack('B', c))
c = SELECT_CLOCK_SIZE
sum1 = sum1 + c
ser.write(struct.pack('B', c))
if cpu == 'R5F7216':
c = SELECT_CLOCK_MODE1
else:
c = SELECT_CLOCK_MODE0
sum1 = sum1 + c;
ser.write(struct.pack('B', c))
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
ser.write(struct.pack('B', sum1))
c = int.from_bytes(ser.read(),'big')
if c != SELECT_CLOCK_RES:
print('Select clock error')
exit()
gain = 6
speed = baud * gain
bitrate = speed // 100
c = SET_RATE_CMD
sum1 = c
ser.write(struct.pack('B', c))
c = SET_RATE_SIZE
sum1 = sum1 + c
ser.write(struct.pack('B', c))
c = bitrate // 0x100
sum1 = sum1 + c
ser.write(struct.pack('B', c))
c = bitrate % 0x100
sum1 = sum1 + c
ser.write(struct.pack('B', c))
c = osc // 0x100
sum1 = sum1 + c
ser.write(struct.pack('B', c))
c = osc % 0x100
sum1 = sum1 + c;
ser.write(struct.pack('B', c))
pll = bytearray(3)
if cpu == 'R5F7084':
pll[0] = 2
pll[1] = 4
pll[2] = 4
elif cpu == 'R5F7216':
pll[0] = 2
pll[1] = 8
pll[2] = 4
elif cpu == 'R5F7124':
pll[0] = 2
pll[1] = 4
pll[2] = 2
for i in range(3):
c = pll[i]
sum1 = sum1 + c
ser.write(struct.pack('B', c))
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
ser.write(struct.pack('B', sum1))
c = int.from_bytes(ser.read(),'big')
if c != SET_RATE_RES:
c = int.from_bytes(ser.read(),'big')
if c == SET_RATE_ERROR_SUM:
print('Set rate checksum error')
elif c == SET_RATE_ERROR_RATE:
print('Set rate speed error')
elif c == SET_RATE_ERROR_NEW_FREQ:
print('Set rate new freq error')
elif c == SET_RATE_ERROR_PLL:
print('Set rate pll error')
elif c == SET_RATE_ERROR_FREQ:
print('Set rate new freq error')
else:
print('Set rate unknown error')
exit()
ser.close()
ser = serial.Serial(port, speed, timeout=0.05)
ser.write(struct.pack('B', SET_RATE_CHECK_CMD))
c = int.from_bytes(ser.read(),'big')
if c != NON_ERROR_RES:
print('Set rate clock error')
exit()
ser.write(struct.pack('B', QUERY_AREA_CMD))
c = int.from_bytes(ser.read(),'big')
sum1 = c;
if c != QUERY_AREA_RES:
print('Query area error')
exit()
size = int.from_bytes(ser.read(),'big')
sum1 = sum1 + size
num = int.from_bytes(ser.read(),'big')
sum1 = sum1 + num
saddr = list(range(num))
taddr = list(range(num))
for i in range(num):
saddr[i] = 0
for j in range(4):
c = int.from_bytes(ser.read(),'big')
sum1 = sum1 + c
saddr[i] = saddr[i] * 0x100
saddr[i] = saddr[i] + c
taddr[i] = 0
for j in range(4):
c = int.from_bytes(ser.read(),'big')
sum1 = sum1 + c;
taddr[i] = taddr[i] * 0x100
taddr[i] = taddr[i] + c
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
c = int.from_bytes(ser.read(),'big')
if sum1 != c:
print('Query area error')
exit()
flushsize = taddr[0] + 1;
ser.write(struct.pack('B', QUERY_PAGE_SIZE_CMD))
c = int.from_bytes(ser.read(),'big')
sum1 = c
if c != QUERY_PAGE_SIZE_RES:
print('Query page size error')
exit()
size = int.from_bytes(ser.read(),'big')
sum1 = sum1 + size;
pagesize = 0;
for i in range(size):
c = int.from_bytes(ser.read(),'big')
sum1 = sum1 + c;
pagesize = pagesize * 0x100;
pagesize = pagesize + c;
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
c = int.from_bytes(ser.read(),'big')
if sum1 != c:
print('Query page size error')
exit()
print('Flush erase', flush=True)
ser.timeout = 5
ser.write(struct.pack('B', SWITCH_TO_ERASE_CMD))
c = int.from_bytes(ser.read(),'big')
if c != NON_ERROR_RES:
print('Switch to erase error')
exit()
ser.timeout = 0.05
ser.write(struct.pack('B', SELECT_WRITE_FORMAT))
c = int.from_bytes(ser.read(),'big')
if c != NON_ERROR_RES:
print('Select write format error')
exit()
print('Flush write ready')
buff = bytearray(flushsize)
for i in range(flushsize):
buff[i] = 255
verify = bytearray(pagesize)
nopgm = bytearray(pagesize)
for i in range(pagesize):
nopgm[i] = 255
with open(filename) as f:
while True:
s_line = f.readline()
if not s_line:
break
s_line = s_line.replace('\n','')
if s_line[0] != 'S':
print('File format error')
f.close()
exit()
linesize = int(s_line[2:4],16)
length2 = linesize * 2 + 4
length1 = len(s_line)
if length1 != length2:
print('File format error')
f.close()
exit()
addrsize = (int(s_line[1:2],16) + 1) * 2
if addrsize >= 4 and addrsize <= 8:
address = int(s_line[4:addrsize + 4], 16)
datasize = linesize - (addrsize // 2) - 1
data = s_line[addrsize + 4:addrsize + 4 + datasize * 2]
if (address + datasize) > flushsize:
print('Flush address is overflow')
f.close()
exit()
for i in range(datasize):
buff[address + i] = int(data[i * 2:i * 2 + 2], 16)
f.close()
count = 0;
for address in range(0, flushsize, pagesize):
for i in range(pagesize):
if buff[address + i] != 255:
break
if i < (pagesize - 1):
if cpu == 'SH3/4/4A':
ser.writetimeout = 0.24
c2 = struct.pack('B',(address // 0x10000) % 0x100)
ser.write(c2)
c1 = struct.pack('B',(address // 0x100) % 0x100)
ser.write(c1)
ser.write(buff[address:address+pagesize])
verify = ser.read(pagesize)
c = ser.read()
if c != b'S':
print(c, 'Flush write error')
exit()
if buff[address:address+pagesize] != verify:
print(address, 'Verify error')
exit()
else:
c = WRITE_CMD;
ser.write(struct.pack('B', c))
sum1 = c
ser.write(b'\x00')
c = (address // 0x10000) % 0x100
ser.write(struct.pack('B', c))
sum1 = sum1 + c;
c = (address // 0x100) % 0x100
ser.write(struct.pack('B', c))
sum1 = sum1 + c;
c = address % 0x100
ser.write(struct.pack('B', c))
sum1 = sum1 + c;
for j in range(pagesize):
c = buff[address + j]
ser.write(struct.pack('B', c))
sum1 = sum1 + c;
sum1 = sum1 % 0x100
sum1 = (0x100 - sum1) % 0x100
ser.write(struct.pack('B', sum1))
c = int.from_bytes(ser.read(),'big')
if c != NON_ERROR_RES:
c = int.from_bytes(ser.read(),'big')
print('Flush write error')
exit()
count = count + 1
if (count % 10) == 0:
print('.', end='', flush=True)
if (count % 800) == 0:
print('\n', end='', flush=True)
ser.close()
print('\nFlush write complete')