dpavlin / esp32ecp5

micropython ESP32 programmer/flasher for ECP5 JTAG

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ESP32 JTAG tap walker for ECP5

This is micropython running on ESP32 to allow JTAG programming and flashing of Lattice ECP5 FPGA JTAG. A simple way in about 700 lines of code.

Usage

Skip this step if you have ESP32 on some development board with USB-serial module. If you have ESP32 on ULX3S board, you need to download passthru bitstream for ULX3S, Choose appropriate for your board and ECP5 chip and upload passthru bitstream to flash

ujprog -j flash passthru.bit

Download micropython for ESP32 I do not use "stable" version like "esp32-idf3-20190529-v1.11.bin". I use idf3 daily fresh version like in this example, but I can't link as filename parts "20191103" and "549-gf2ecfe8b8" change every day.

wget https://micropython.org/resources/firmware/esp32-idf3-20191103-v1.11-549-gf2ecfe8b8.bin

Upload micropython to ESP32

esptool.py --chip esp32 --port /dev/ttyUSB0 erase_flash
esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 460800 write_flash -z 0x1000 esp32-idf3-20191103-v1.11-549-gf2ecfe8b8.bin

Power off and on ESP32

Connect over USB-serial

screen /dev/ttyUSB0 115200

To automate further use, it is good to setup ESP32 to automatically bring up networking and services after power up. This is done using auto-executable file named "main.py".

Choose either: (copy-paste to usb-serial python prompt ">>>")

setup as client that logs on to WiFi access point (home internet router), replace "accesspoint" and "password" with proper logins for your WiFi router:

f=open("main.py","w")
f.write("import network\n")
f.write("sta_if = network.WLAN(network.STA_IF)\n")
f.write("sta_if.active(True)\n")
f.write('sta_if.connect("accesspoint", "password")\n')
f.write("import uftpd\n")
f.close()
import webrepl_setup

if client can't connect it will continuoulsy retry, printing failure messages. Then it will be difficult to type at usb-serial prompt. To stop it, type blindly or copy-paste:

sta_if.disconnect()

or setup as access point:

f=open("main.py","w")
f.write("import network\n")
f.write("ap_if = network.WLAN(network.AP_IF)\n")
f.write("ap_if.active(True)\n")
f.write('ap_if.config(essid="accesspoint", password="password")\n')
f.write("import uftpd\n")
import webrepl_setup

It will prompt to ask few questions: Enable "webrepl" by choosing "E". Type and repeat any password you like, "webrepl" service will later ask for this password. Finally agree to reboot ESP32. After reboot and successful WiFi connection, it will print its IP address. You can always soft-reboot again to see IP address if you press Ctrl-D on empty python prompt:

>>> Ctrl-D

with web browser open micropython webrepl, enter IP address of ESP32 and upload "ecp5.py", (optionally also "uftpd.py" if you want FTP server, read below) and some bitstream file like "blink.bit" or "blink.bit.gz" (compressed with gzip -9) to the root of ESP32 python FLASH filesystem

List directory to see if the files are uploaded:

import os
os.listdir()
['boot.py', 'ecp5.py', 'main.py', 'blink.bit']

Yes there it is, let's try:

import ecp5
ecp5.prog("blink.bit") 
99262 bytes uploaded in 142 ms (675 kB/s)

ecp5.prog("filepath_or_url") uploads to FPGA SRAM.
ecp5.flash("filepath_or_url", addr=0x000000) uploads to SPI CONFIG FLASH

upload to FLASH will start at byte address specified by "addr". which should be 4K even - lower 12 bits must be 0x000

If file ends with "*.gz", it will be decompressed on-the-fly.

linux$ gzip -9 blink.bit
>>> ecp5.prog("http://192.168.4.2/blink.bit.gz")
>>> ecp5.flash("blink.bit.gz")

For bitstreams stored on the web server or SD card, ".bin" files are recommended, with bitstream compression enabled using --compress option from trellis tools. For bitstreams stored on ESP32 internal FLASH, ".bin.gz" is recommended for FLASH space saving.

SD card usage (SPI at gpio 12-15):

import os,machine
os.mount(machine.SDCard(slot=3),"/sd")
os.listdir("/sd")

"slot=3" must be specified to prevent using SD card MMC mode. MMC mode is about 2x faster but currently it doesn't work together with this ecp5.py programmer.

Here I have "uftpd.py" which came from original ESP32 FTP server with my small modifications to support "ecp5.py" programmer. Install FTP server by uploading "uftpd.py" file to the root of ESP32 filesystem: and start it with:

import uftpd
FTP server started on 192.168.4.1:21

Get ftp client "ftp" or "lftp". I tried them both and they work, other clients I haven't tried...

apt-get install ftp lftp

Connect with ftp client to ESP32, type ENTER at (empty) password

ftp 192.168.4.1
Connected to 192.168.5.72.
220 Hello, this is the ESP8266.
230 Logged in.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>

Try to list files, it should work like this:

ftp> ls
200 OK
150 Directory listing:
-rw-r--r-- 1 owner group        137 Jan  1 00:03 boot.py
-rw-r--r-- 1 owner group        128 Jan  1 00:05 main.py
-rw-r--r-- 1 owner group         14 Jan  1 00:05 webrepl_cfg.py
-rw-r--r-- 1 owner group      19482 Jan  1 00:09 uftpd.py
-rw-r--r-- 1 owner group      22777 Jan  1 00:10 ecp5.py
-rw-r--r-- 1 owner group       5505 Jan  1 00:13 passthru21111043.bit.gz
226 Done.

If you don't see listing similar to this, something is incompatible, try to toggle "passive" FTP mode. If FTP client is behind the firewall it may work with passive mode on, close/open connection or try another FTP client.

ftp> passive
Passive mode on.
ftp> close
ftp> open 192.168.4.1

Besides normal FTP commands like "ls", "cd", "mkdir", "rmdir", "put", "get", "del", it also accepts "site" command to read file from ESP32 local filesystem (FLASH or SD card) and program FPGA:

ftp> site http://192.168.4.2/blink.bit
... will program remote file to FPGA using
... ecp5.prog("/http:/192.168.4.2/blink.bit")
ftp> site filename.bit
... will program local file to FPGA using
... ecp5.prog("filename.bit")

It is possible to directly program a "*.bin" file (not gzipped) from "ftp>" prompt directly to FPGA or FLASH using special destination file name "fpga" or "flash":

ftp> put blink.bit fpga
ftp> put blink.bit flash

NOTE: special destination file names "fpga" and "flash" are used for direct programming and they don't relate to actual files on ESP32 filesystem.

if using "lftp", syntax is different, use option "-o" like this:

lftp 192.168.4.1:/> put blink.bit -o fpga
lftp 192.168.4.1:/> put blink.bit -o flash

To automate upload from linux shell, enable ftp auto-login in "~/.netrc":

cat ~/.netrc
default login anonymous password user@site

A simple shell command can upload bitstream with FTP and program ECP5:

cat /usr/local/bin/ftpecp5prog 
#!/bin/sh
ftp ${1} <<EOF
put ${2} fpga
EOF

use it as:

ftpecp5prog 192.168.4.1 blink.bit

If FTP server is running and you try to program from "webrepl" and it fails with a memory allocation error:

ecp5.flash("blink.bit.gz")
MemoryError: memory allocation failed, allocating 32768 bytes

Yes it happens to me all the time :). "esp32ecp5" constantly runs near out of memory. Either disable FTP server by removing "import uftpd.py" from "main.py" file and rebooting, or try workaround from ftp> commandline to issue any "site" command just to let FTP server import ecp5 and then memory situation will be better for ecp5.flash() from "webrepl"

... linux commandline
ftp> site blink.bit.gz
... webrepl
import ecp5
ecp5.flash("blink.bit.gz")

JTAG info

JTAG STATE GRAPH

TODO

[x] on-the-fly gzip decompression
[x] read flash content
[x] from read, decide if block has to be erased
[x] fix HTTP GET for binary file
[ ] write disk image to SD card https://docs.micropython.org/en/latest/library/uos.html
[x] reuse currently separated code for file/web bit/bit.gz
[x] integrate with ftp server like https://github.com/robert-hh/FTP-Server-for-ESP8266-ESP32-and-PYBD
[ ] integrate with webrepl and file browser like https://github.com/hyperglitch/webrepl
[x] ecp5.prog() should return True if OK, False if FAIL
[x] optimize send_bit, n-1 bits in loop and last bit outside of loop
[x] while read flash until same content as file, with retry
[x] more progress for flashing
[x] ftp put fpga/flash reports Done/Fail

About

micropython ESP32 programmer/flasher for ECP5 JTAG


Languages

Language:Python 100.0%