Skip to content

Instantly share code, notes, and snippets.

@LingDong-
Created June 1, 2023 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LingDong-/0c917b3f37e042807e311cd3b99a00d3 to your computer and use it in GitHub Desktop.
Save LingDong-/0c917b3f37e042807e311cd3b99a00d3 to your computer and use it in GitHub Desktop.
(minimal) TI MSP430 μC 1,2,4 Family BSL flasher (slau319af)
"""
bsl124.py
(minimal) TI MSP430 1,2,4 Family BSL flasher
using pyserial, works on windows, mac, and linux
- implementation of slau319af.pdf
- programming MSP430 chips via USB-TTL / FTDI / ...
- supports Intel HEX format
- supports F1xx, F2xx, F4xx, G2xx3 chips
usage:
python3 bsl124.py -p /dev/cu.usbserial-110 -i blink.hex
hardware connection example:
____3V3______ 5V 3V3
| | | +---------+ |
+-------+ +-----------+ +--|VI GND VO|--+
+---+ | VCC | | VCC | | +---------+ |
| 5V| | TX|---|BSLRX(P1.5)| =10uF | =10uF
| D+|---|D+ RX|---|BSLTX(P1.1)| |______GND______|
| D-|---|D- DTR|---|RST |
|GND| | RTS|---|TEST | RST--[10Kohm]->3V3
+---+ | GND | | GND | TEST-[10Kohm]->GND
USB +-------+ +-----------+ 3V3--[100nF ]->GND
CH340C MSP430G2553 3V3--[100nF ]->GND
- I use CH340C but you should be able to use any
USB to serial/UART/TTL/RS-232 chips
- FTDI cables often don't have DTR line (only CTS/RTS),
so you might need a breakout board / custom PCB
- check the datasheet of your chip for assignment
of the BSL TX/RX pins, they're different from TXD/RXD
example hex file for G2553, for your testing convenience:
:10C00000314000040C43B0120AC02183B240805A70
:10C010002001F2432200F2432A005C4221007CE32B
:10C020003CF0FF00C24C21005C4229007CE33CF064
:10C03000FF00C24C2900B140102700002C413C53A6
:0CC04000814C00002C410C93F923E73FD9
:02FFFE0000C041
:040000030000C00039
:00000001FF
- this code blinks all the pins on PORT1 and PORT2,
connect an LED to any.
- you can use msp430-elf-gcc and msp430-elf-objcopy
(available from TI's website) to make hex files.
example output from bsl124.py:
====== parsing ihex file ======
block sizes: [16, 16, 16, 16, 12, 2]
===== opening serial port =====
/dev/cu.usbserial-110
== sending BSL init sequence ==
========== mass erase ==========
SYNC ACK. CMD ACK.
=== sending default password ===
SYNC ACK. CMD ACK.
====== sending RX blocks ======
1 / 6 ... SYNC ACK. CMD ACK.
2 / 6 ... SYNC ACK. CMD ACK.
3 / 6 ... SYNC ACK. CMD ACK.
4 / 6 ... SYNC ACK. CMD ACK.
5 / 6 ... SYNC ACK. CMD ACK.
6 / 6 ... SYNC ACK. CMD ACK.
=== loading program counter ===
SYNC ACK. CMD ACK.
DONE.
(c) lingdong 2023, MIT License
"""
import serial # pyserial.readthedocs.io
import time
import sys
DTRRTS_NOT_INV = 0
ARGS = {
'-p':"/dev/cu.usbserial-110"
}
frame_state = -1
ser = None
ckl = 0
ckh = 0
for i in range(1,len(sys.argv),2):
try:
k = sys.argv[i];
if k == "--help" or k == '-h':
print("usage:\n\tpython3 bsl124.py -p [port] -i [file.hex]")
exit(0);
v = sys.argv[i+1];
ARGS[k] = v
except Exception as e:
print("ERR: bad arg:", k)
exit(1)
def parse_ihex(filepath):
lines = [x.strip().split(':')[1] for x in open(filepath,'r').read().replace("\r","\n").split('\n') if len(x.strip())];
recs = []
for l in lines:
typ = int(l[6:8],16)
num = int(l[0:2],16)
if (num > 250):
print("ERR: ihex record too long (250 max.): ",l)
exit(1);
if (num & 1):
print("ERR: ihex record length not even: ",l)
exit(1);
if (typ == 0):
recs.append({
'bcnt': num,
'addr': int(l[2:6],16),
'data': [int(l[i:i+2],16) for i in range(8,len(l)-2,2)]
})
return recs
def serial_open():
global ser
ser = serial.Serial(
port=ARGS['-p'],
baudrate=9600,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_EVEN,
stopbits=serial.STOPBITS_ONE,
#rtscts=True,
#dsrdtr=True,
timeout=2,
)
print(ser.name)
def set_dtr(v):
ser.dtr = not (v ^ DTRRTS_NOT_INV)
time.sleep(0.05)
def set_rts(v):
ser.rts = not (v ^ DTRRTS_NOT_INV)
time.sleep(0.05)
def send_sync():
send_byte(0x80);
ret = read_byte()
if (ret == 0x90):
print("SYNC ACK.",end=' ',flush=True)
else:
print("SYNC NOT ACK:",ret);
exit(1);
def init_seq():
set_dtr(0)
set_rts(0)
time.sleep(0.1);
set_rts(1);
set_rts(0);
set_rts(1);
set_rts(0);
set_rts(1);
set_dtr(1);
set_rts(0);
time.sleep(0.2);
def send_byte(b):
global frame_state, ckl, ckh
ser.write(bytes([b]))
if frame_state != -1:
if frame_state:
ckh ^= b
else:
ckl ^= b
frame_state ^= 1
def read_byte():
return int.from_bytes(ser.read(1),'little');
def start_frame():
global frame_state, ckl, ckh
send_sync();
ckl = 0
ckh = 0
frame_state = 0
def end_frame():
global frame_state, ckl, ckh
frame_state = -1
send_byte(ckl^0xff)
send_byte(ckh^0xff)
ret = read_byte()
if (ret == 0x90):
print("CMD ACK.")
time.sleep(0.2)
else:
print("CMD NOT ACK:",ret);
exit(1);
def cmd_load_pc():
start_frame();
send_byte(0x80);
send_byte(0x1A);
send_byte(0x04);
send_byte(0x04);
send_byte(0xFE);
send_byte(0xFF);
send_byte(0xFF);
send_byte(0xFF);
end_frame();
def cmd_rx_password0():
start_frame();
send_byte(0x80);
send_byte(0x10);
send_byte(0x24);
send_byte(0x24);
send_byte(0xFF);
send_byte(0xFF);
send_byte(0xFF);
send_byte(0xFF);
for i in range(0,0x20):
send_byte(0xFF);
end_frame();
def cmd_mass_erase():
start_frame();
send_byte(0x80);
send_byte(0x18);
send_byte(0x04);
send_byte(0x04);
send_byte(0xFF);
send_byte(0xFF);
send_byte(0x06);
send_byte(0xA5);
end_frame();
def cmd_rx_data(rec):
# print(rec);
start_frame();
send_byte(0x80);
send_byte(0x12);
l1l2 = rec['bcnt']+4;
send_byte(l1l2);
send_byte(l1l2);
send_byte(rec['addr']&0xFF);
send_byte((rec['addr']>>8)&0xFF);
send_byte(rec['bcnt']);
send_byte(0);
for i in range(rec['bcnt']):
send_byte(rec['data'][i])
end_frame();
print("====== parsing ihex file ======");
recs = parse_ihex(ARGS['-i'])
print("block sizes:", [x['bcnt'] for x in recs])
print("===== opening serial port =====");
serial_open();
print("== sending BSL init sequence ==");
init_seq();
print("========== mass erase ==========");
cmd_mass_erase();
print("=== sending default password ===");
cmd_rx_password0();
print("====== sending RX blocks ======");
for i in range(len(recs)):
print(i+1,'/',len(recs),'...',end=' ',flush=True);
cmd_rx_data(recs[i]);
print("=== loading program counter ===");
cmd_load_pc();
print("DONE.")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment