Skip to content

Commit a0bf2d7

Browse files
author
tinyfpga
authored
TinyFPGA B-Series programmer
1 parent 3cce41e commit a0bf2d7

File tree

3 files changed

+521
-0
lines changed

3 files changed

+521
-0
lines changed

Diff for: installer.cfg

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[Application]
2+
name=TinyFPGA Programmer
3+
version=1.0
4+
script=tinyfpgab-programmer.py
5+
console=false
6+
#icon=myapp.ico
7+
8+
[Python]
9+
version=2.7.13
10+
11+
[Include]
12+
packages = serial
13+
intelhex
14+
15+
files = tinyfpgab.py
16+

Diff for: tinyfpgab-programmer.py

+289
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
#!python2.7
2+
import sys
3+
import os
4+
script_path = os.path.dirname(os.path.realpath(__file__))
5+
local_packages_path = os.path.join(script_path, 'pkgs')
6+
sys.path.insert(0, local_packages_path)
7+
8+
import serial
9+
import array
10+
import time
11+
from intelhex import IntelHex
12+
from Tkinter import *
13+
from ttk import *
14+
import tkFileDialog
15+
import threading
16+
import os
17+
import os.path
18+
import traceback
19+
from serial.tools.list_ports import comports
20+
21+
from tinyfpgab import h, TinyFPGAB
22+
23+
24+
################################################################################
25+
################################################################################
26+
##
27+
## TinyFPGA B-Series Programmer GUI
28+
##
29+
################################################################################
30+
################################################################################
31+
32+
r = Tk()
33+
r.title("TinyFPGA B-Series Programmer")
34+
r.resizable(width=False, height=False)
35+
36+
program_in_progress = False
37+
program_failure = False
38+
39+
boot_fpga_b = Button(r, text="Exit Bootloader")
40+
program_fpga_b = Button(r, text="Program FPGA")
41+
program_progress_pb = Progressbar(r, orient="horizontal", length=400, mode="determinate")
42+
43+
program_status_sv = StringVar(r)
44+
45+
serial_port_ready = False;
46+
bitstream_file_ready = False;
47+
file_mtime = 0
48+
49+
def update_button_state():
50+
if serial_port_ready and not program_in_progress:
51+
boot_fpga_b.config(state=NORMAL)
52+
53+
if bitstream_file_ready:
54+
program_fpga_b.config(state=NORMAL)
55+
else:
56+
program_fpga_b.config(state=DISABLED)
57+
58+
else:
59+
boot_fpga_b.config(state=DISABLED)
60+
program_fpga_b.config(state=DISABLED)
61+
62+
63+
########################################
64+
## Select Serial Port
65+
########################################
66+
67+
com_port_status_sv = StringVar(r)
68+
com_port_status_l = Label(r, textvariable=com_port_status_sv)
69+
com_port_status_l.grid(column=1, row=0, sticky=W+E, padx=10, pady=8)
70+
com_port_sv = StringVar(r)
71+
com_port_sv.set("")
72+
select_port_om = OptionMenu(r, com_port_sv, ())
73+
select_port_om.grid(column=0, row=0, sticky=W+E, padx=10, pady=8)
74+
75+
tinyfpga_ports = []
76+
def update_serial_port_list_task():
77+
global tinyfpga_ports
78+
global program_in_progress
79+
80+
if not program_in_progress:
81+
new_tinyfpga_ports = [i[0] for i in comports() if ("0000:0000" in i[2]) or ("1209:2100" in i[2])]
82+
83+
if new_tinyfpga_ports != tinyfpga_ports:
84+
if com_port_sv.get() == "" and len(new_tinyfpga_ports) > 0:
85+
com_port_sv.set(new_tinyfpga_ports[0])
86+
menu = select_port_om["menu"]
87+
menu.delete(0, "end")
88+
for string in new_tinyfpga_ports:
89+
menu.add_command(
90+
label=string,
91+
command=lambda value=string: com_port_sv.set(value))
92+
tinyfpga_ports = new_tinyfpga_ports
93+
94+
r.after(1000, update_serial_port_list_task)
95+
96+
update_serial_port_list_task()
97+
98+
def check_port_status_task():
99+
global serial_port_ready
100+
if not program_in_progress:
101+
try:
102+
with serial.Serial(com_port_sv.get(), 10000000, timeout=1, writeTimeout=0.1) as ser:
103+
fpga = TinyFPGAB(ser)
104+
105+
fpga.wake()
106+
devid = fpga.read_id()
107+
108+
expected_devid = [0x1F, 0x84, 0x01]
109+
if devid == expected_devid:
110+
com_port_status_sv.set("Bootloader active. Ready to program.")
111+
serial_port_ready = True;
112+
update_button_state()
113+
else:
114+
com_port_status_sv.set("Unable to communicate with TinyFPGA. Reconnect and reset TinyFPGA before programming.")
115+
serial_port_ready = False;
116+
update_button_state()
117+
118+
except serial.SerialTimeoutException:
119+
com_port_status_sv.set("Hmm...try pressing the reset button on TinyFPGA again.")
120+
serial_port_ready = False;
121+
update_button_state()
122+
123+
except:
124+
com_port_status_sv.set("Bootloader not active. Press reset button on TinyFPGA before programming.")
125+
serial_port_ready = False;
126+
update_button_state()
127+
128+
r.after(50, check_port_status_task)
129+
130+
check_port_status_task()
131+
132+
133+
########################################
134+
## Select File
135+
########################################
136+
137+
filename_sv = StringVar(r)
138+
139+
def select_bitstream_file_cmd():
140+
filename = tkFileDialog.askopenfilename(
141+
title = "Select file",
142+
filetypes = [
143+
('FPGA Bitstream Files', '.hex'),
144+
('all files', '.*')
145+
]
146+
)
147+
148+
filename_sv.set(filename)
149+
150+
select_file_b = Button(r, text="Select File", command=select_bitstream_file_cmd)
151+
select_file_b.grid(column=0, row=1, sticky=W+E, padx=10, pady=8)
152+
filename_e = Entry(r)
153+
filename_e.config(textvariable=filename_sv)
154+
filename_e.grid(column=1, row=1, sticky=W+E, padx=10, pady=8)
155+
156+
def check_bitstream_file_status_cmd():
157+
global bitstream_file_ready
158+
global file_mtime
159+
160+
if os.path.isfile(filename_sv.get()):
161+
new_file_mtime = os.stat(filename_sv.get()).st_mtime
162+
163+
bitstream_file_ready = True
164+
update_button_state()
165+
166+
if new_file_mtime > file_mtime:
167+
program_status_sv.set("Bitstream file updated.")
168+
169+
file_mtime = new_file_mtime
170+
171+
else:
172+
if bitstream_file_ready:
173+
program_status_sv.set("Bitstream file no longer exists.")
174+
175+
bitstream_file_ready = False
176+
update_button_state()
177+
178+
def check_bitstream_file_status_task():
179+
check_bitstream_file_status_cmd()
180+
r.after(1000, check_bitstream_file_status_task)
181+
182+
check_bitstream_file_status_task()
183+
184+
def check_bitstream_file_status_cb(*args):
185+
global file_mtime
186+
file_mtime = 0
187+
check_bitstream_file_status_cmd()
188+
189+
filename_sv.trace("w", check_bitstream_file_status_cb)
190+
191+
192+
193+
########################################
194+
## Program FPGA
195+
########################################
196+
197+
program_status_l = Label(r, textvariable=program_status_sv)
198+
program_status_l.grid(column=1, row=3, sticky=W+E, padx=10, pady=8)
199+
200+
program_progress_pb.grid(column=1, row=2, sticky=W+E, padx=10, pady=8)
201+
202+
def program_fpga_thread():
203+
global program_in_progress
204+
global program_failure
205+
program_failure = False
206+
207+
try:
208+
209+
with serial.Serial(com_port_sv.get(), 10000000, timeout=1, writeTimeout=1) as ser:
210+
global current_progress
211+
global max_progress
212+
current_progress = 0
213+
214+
def progress(v):
215+
if isinstance(v, int) or isinstance(v, long):
216+
global current_progress
217+
current_progress += v
218+
elif isinstance(v, str):
219+
program_status_sv.set(v)
220+
221+
fpga = TinyFPGAB(ser, progress)
222+
223+
(addr, bitstream) = fpga.slurp(filename_sv.get())
224+
225+
max_progress = len(bitstream) * 3
226+
227+
try:
228+
fpga.program_bitstream(addr, bitstream)
229+
except:
230+
program_failure = True
231+
232+
program_in_progress = False
233+
except:
234+
program_failure = True
235+
236+
current_progress = 0
237+
max_progress = 0
238+
239+
def update_progress_task():
240+
global current_progress
241+
global max_progress
242+
program_progress_pb["value"] = current_progress
243+
program_progress_pb["maximum"] = max_progress
244+
r.after(10, update_progress_task)
245+
246+
update_progress_task()
247+
248+
def program_fpga_cmd():
249+
global program_in_progress
250+
program_in_progress = True
251+
update_button_state()
252+
t = threading.Thread(target=program_fpga_thread)
253+
t.start()
254+
255+
program_fpga_b.configure(command=program_fpga_cmd)
256+
program_fpga_b.grid(column=0, row=2, sticky=W+E, padx=10, pady=8)
257+
258+
def program_failure_task():
259+
global program_failure
260+
if program_failure:
261+
program_status_sv.set("Programming failed! Reset TinyFPGA and try again.")
262+
program_failure = False
263+
264+
r.after(100, program_failure_task)
265+
266+
program_failure_task()
267+
268+
269+
########################################
270+
## Boot FPGA
271+
########################################
272+
273+
def boot_cmd():
274+
with serial.Serial(com_port_sv.get(), 10000000, timeout=1, writeTimeout=0.1) as ser:
275+
try:
276+
TinyFPGAB(ser).boot()
277+
278+
except serial.SerialTimeoutException:
279+
com_port_status_sv.set("Hmm...try pressing the reset button on TinyFPGA again.")
280+
281+
boot_fpga_b.configure(command=boot_cmd)
282+
boot_fpga_b.grid(column=0, row=3, sticky=W+E, padx=10, pady=8)
283+
284+
# make sure we can't get resized too small
285+
r.update()
286+
r.minsize(r.winfo_width(), r.winfo_height())
287+
288+
# start the gui
289+
r.mainloop()

0 commit comments

Comments
 (0)