Compiling and flashing a bootloader on SAMD21 MCU using ST-Link V2

Some time ago I decided to build a Voron V2 3D printer. Mainly because my Tronxy X5S is not really reliable. I got Prusa MK3S clone, which is excellent, but it is hard to enclose to print ABS with it. The Voron is a beast of a machine with 4 independent Z steppers, for a total of 7 steppers on a machine with single extruder. This was a challenge as my PrntrBoard V2 could handle max of 6 stepper motors.

In the mean time I discovered that the Klipper firmware can run two boards, for example one with the 4 Z steppers and another with the A, B (Voron V2 is a CoreXY machine) and E steppers. That was cool, but a bit of a waste of electronic components. Then some pointed me to the HUVUD tool board a very nice small board designed to fit on the back of a NEMA 17 stepper motor. This board can control the extruder stepper, the hotend and the extruder fans.

There were two things I was not very fond of: first the board was using CAN interface and that would need extra wiring and USB->CAN adapter. The board was using STM32 MCU which is now quite rare and expensive due to the global chip shortage.

I set and re-designed the HUVUD board, got rig of the CAN bus and replaced it with USB control. Then I replaced the MCU with SAMD21E16 chip. Initially I tried E15, but the flash was not big enough.

Klipper seems to have support for this chip, there is Arduino Core and some cheap prototyping boards (Seeeduino Cortex M0+ – for example).

Finally to the topic at hand: how does one flash a bootloader onto SAMD21 MCU – which is quite handy for updating the firmware over USB. A quick google search would reveal several lengthy articles. The most useful one I found was from Adafruit. Alas this usually involves using a J-Link adapter and there are quite expensive. You can get clones from china, but they don’t work.

So here is my attempt to distill the information on the topic. First the bootloader code – the best place I found for this code is the Arduino Core for SAMD21 on github. In that repository there is a folder called bootloaders and inside there is a folder called “zero” – that contains the Arduino bootloader code.

There are excellent instructions in the README how to modify the code for your board – mainly define what pins your board uses for LED(s),  most of these are optional like the TX/RX LEDs. By default this code is for SAMD21x18 series MCU, but it works just fine on the versions with smaller flash. You can modify the bootloader_samd21x18.ld file and change the flash size to match your chip. Compiling the code is easy just use make with a parameter for your board. There is a shell script ( that compiles the code for a variety of boards – you can see how the parameters are defined there.

When you are done compiling the bootloader, by default you will have a .hex and a .bin file in the current folder. There is also a .elf file in the build/ folder, but we are not going to need that.

Connecting the debug adapter to the board: You need to connect the following signals from the ST-Link to your board (SWDIO, SWCLK, RST, GND). You can also power your board from the ST-LINK V2 adapter 3.3V supply, but that provides only minuscule amount of power.

You would need openocd to program the bootloader. I got the default version that comes with Ubuntu 20.04 (0.10.0), allegedly even version 0.9 would work, but YMMV.

Before we proceed you need to add 64 bytes of values 0xFF to your binary file with the bootloader code. Allegedly this is to work-around a bug in the openocd code. Without this padding you would get  errors in the verification step on the last page of the bootloader code. The value 0xff is the default value of the flash when the chip is erased.

To generate a file with 64 values of 0xff, I used the following command, courtesy of slashdot:

dd if=/dev/zero ibs=1 count=64 | tr "\000" "\377" >paddedFile.bin

Then just concatenated the two files together with

cat samd21_sam_ba_huvud_07s.bin paddedFile.bin>fw.bin

Here ‘samd21_sam_ba_huvud_07s.bin’ is the name of my compiled bootloader and paddedFile.bin is the file from the previous step.

Start openocd with the following magic command:

openocd -f interface/stlink-v2.cfg -c 'set CHIPNAME at91samd21e15; set ENDIAN little; set CPUTAPID 0x0bc11477; source [find target/at91samdXX.cfg]'

You may have to modify the MCU model (I used Samd21e15 chip, put your exact chip version there). You would see some console output similar to this:

Open On-Chip Debugger 0.10.0
Licensed under GNU GPL v2
For bug reports, read
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
none separate
adapter speed: 400 kHz
Info : Unable to match requested speed 400 kHz, using 240 kHz
Info : Unable to match requested speed 400 kHz, using 240 kHz
Info : clock speed 240 kHz
Info : STLINK v2 JTAG v31 API v2 SWIM v7 VID 0x0483 PID 0x3748
Info : using stlink api v2
Info : Target voltage: 3.250331
Info : at91samd21e15.cpu: hardware has 4 breakpoints, 2 watchpoints

The program would appear to hang there, but no to worry, open another terminal window and type

telnet localhost 4444

This would open a telnet session to the openocd server. By default the openocd server listens for telnet connection on port 4444 and GDB connection on port 3333.

In the telnet terminal you would see something like:

Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger

This is the openocd command prompt and we are ready to send commands.

Send the following two commands first. Note that you would not get any response after the init command.

reset init

You would get a reponse after the ‘reset init’ command, some variation of the following:

target halted due to debug-request, current mode: Thread 
xPSR: 0x61000000 pc: 0x00000848 msp: 0x20000ffc

The pc, msp and xPSR register may hold different values for you.

You can erase the whole chip with the following command:

at91samd chip-erase
Note that this would erase all code stored on the chip, so proceed with caution.
Now we are ready to write the bootloader code. Send the following command:
load_image fw.bin 0x00000000 bin
Here fw.bin the the file we produced by concatenating the compiled bootloader code and the 64 byte padding file. The 0x00000000 is the start address in the flash where the code would be programmed and ‘bin’ is the file format.
Note the path name is relative to the folder where the openocd server was started, not the folder where the telned session is started. If you get an error “couldn’t open <path to>/fw.bin” it is most likely the openocd program can not open the path from its current location.
If all is well you would get something like the following response:
> load_image fw.bin 0x00000000 bin 
4924 bytes written at address 0x00000000
downloaded 4924 bytes in 0.291628s (16.489 KiB/s)

Now it is important to verify that the code was written to the flash correctly:

verify_image fw.bin 0x00000000 bin

Here again fw.bin the path to the firmware file and 0x00000000 is the start address in the flash where the code was written.

If all is well you would get something like the following response:

> verify_image fw.bin 0x00000000 bin
target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0x20000ffc
verified 4924 bytes in 0.459733s (10.460 KiB/s)

The time, number of bytes and speed will vary from system to system. If you get flash errors, for example:

target halted due to breakpoint, current mode: Thread 
xPSR: 0x61000000 pc: 0x2000002e msp: 0xfffffffc
Error: checksum mismatch - attempting binary compare
diff 0 address 0x000012c0. Was 0xff instead of 0x24
diff 1 address 0x000012c1. Was 0xff instead of 0x06
diff 2 address 0x000012c2. Was 0xff instead of 0x00
diff 3 address 0x000012c3. Was 0xff instead of 0x01

Verify that you erased the chip before attempting to program the code and you followed the padding instructions earlier. The example above was due to me not following the padding and I was always getting these errors in the last 58 bytes of the code.

To close the telnet session you can type ‘exit’, note that this would not exit the openocd server we started in the other window. You can connect to the server again with the telnet command.

Minimal Zephyr OS on RISC-V and other tests


This is a followup article on my endeavors to run RISC-V soft core on Lattice ECP5 series FPGA.

I moved all my changes to a new github repository. This contains all modifications I’ve made to the original litexOnColorlightLab004 code.

The CPU reports that it’s running at 198MHz (It is a bit too high to be believable, but its working). I also managed to enable a few of the hardware components connected to the FPGA:

    • The 4MB SDRAM is running at 66MHz (running it at higher frequency makes the memory test fail).
    • Configured the CPU with 32KB cache.
    • Enabled the 4MB SPI flash, so now it can be used to binaries.
    • Enabled one of the Ethernet PHYs (net-boot works about half the time).

I also managed to flash the FPGA configuration to the flash, so you don’t have to load it every time.

In my previous article I had some trouble with my hacked JTAG probe. It was not working very well – about 2/3 of the time it would not upload the FPGA configuration correctly etc. The issue turned up to be quite simple – I was using bad cables to connect the blue pill board to the JTAG connector.

First thing’s first, assuming you have all litex and yosys software installed from the previous article. Simply clone the following github repository:

Go to the riscvOnColorlight-5A-75B folder and run:

./ --build

Build the test firmware:

cd firmware
cd ..

And load it with the lxterm tool (run this in a separate terminal):

~/.local/bin/lxterm /dev/ttyUSB0 --kernel firmware/firmware.bin

Reload the FPGA configuration and reset the board with:

./ --load

I switched the default cable type to ‘dyrtyJtag’ so you don’t have to type it anymore.

You wold see a new boot scree with the following text in the lxterm window:

[LXTERM] Starting....
        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
   Build your hardware, easily!

 (c) Copyright 2012-2020 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Jul 26 2020 02:12:52
 BIOS CRC passed (6b395de0)

 Migen git sha1: 7bc4eb1
 LiteX git sha1: 1fdffdfd

--=============== SoC ==================--
CPU:       VexRiscv @ 198MHz
BUS:       WISHBONE 32-bit @ 4GiB
CSR:       8-bit data
ROM:       32KiB
SRAM:      8KiB
L2:        32KiB
MAIN-RAM:  4096KiB

--========== Initialization ============--
Ethernet init...
Initializing DRAM @0x40000000...
SDRAM now under software control
SDRAM now under hardware control
Memtest at 0x40000000...
Memtest OK
Memspeed at 0x40000000...
Writes: 461 Mbps
Reads:  382 Mbps

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
[LXTERM] Received firmware download request from the device.
[LXTERM] Uploading firmware/firmware.bin to 0x40000000 (14852 bytes)...
[LXTERM] Upload complete (3.2KB/s).
[LXTERM] Booting the device.
[LXTERM] Done.
Executing booted program at 0x40000000

--============= Liftoff! ===============--

Hello RISC-V core on Lattice EPC5 FPGA
Testing software built Jul 26 2020 02:15:37

Available commands:
help                            - this command
reboot                          - reboot CPU
led                             - led test
dhry                            - Dhrystone benchmark

I added the ability to run the Dhrystone benchmark to the test firmware. You can try it by issuing the ‘dhry’ command. On my board it looks like this:


Dhrystone Benchmark, Version 2.1 (Language: C)

Program compiled without 'register' attribute

Execution starts, 200000 runs through Dhrystone
Execution ends

Final values of the variables used in the benchmark:

Int_Glob:            5
        should be:   5
Bool_Glob:           1
        should be:   1
Ch_1_Glob:           A
        should be:   A
Ch_2_Glob:           B
        should be:   B
Arr_1_Glob[8]:       7
        should be:   7
Arr_2_Glob[8][7]:    200010
        should be:   Number_Of_Runs + 10
  Ptr_Comp:          1073756824
        should be:   (implementation-dependent)
  Discr:             0
        should be:   0
  Enum_Comp:         2
        should be:   2
  Int_Comp:          17
        should be:   17
  Ptr_Comp:          1073756824
        should be:   (implementation-dependent), same as above
  Discr:             0
        should be:   0
  Enum_Comp:         1
        should be:   1
  Int_Comp:          18
        should be:   18
Int_1_Loc:           5
        should be:   5
Int_2_Loc:           13
        should be:   13
Int_3_Loc:           7
        should be:   7
Enum_Loc:            1
        should be:   1
        should be:   DHRYSTONE PROGRAM, 1'ST STRING
        should be:   DHRYSTONE PROGRAM, 2'ND STRING

Microseconds for one run through Dhrystone: 4.11 
Dhrystones per Second:                      243186.4 
DMIPS                                       138.40 


An alternative command to load the FPGA configuration a bit faster is

openFPGALoader -c dirtyJtag -r build/colorlight_5a_75b/gateware/colorlight_5a_75b.bit

If you are happy with the configuration you can save it to the flash memory and it will be loaded automatically when you power the board on:

openFPGALoader -c dirtyJtag -f build/colorlight_5a_75b/gateware/colorlight_5a_75b.bit

How to compile and run Zephyr OS

If you have never heard of Zephyr OS you can read more about it on the project page. In short it is real-time OS similar to mbed and FreeRTOS. Why not Linux? Well the board has limited memory (4MB) and running Linux would be a challenge – not impossible, but not practical.

Most of the instructions are taken from this article. I did some modifications that are needed for the Colorlight board.

Install the Zephyr prerequisites – instructions from this article. Follow the steps up to #5. Skip step #4.3, we already did the udev rules in my previous tutorial. We would build the sample code a bit differently. Why, you ask? Well, the Zephyr OS already supports a variation of the litex generated RISC-V SoC, that however is different from the hardware configuration we have, so we’ll have to modify some things to get it to work.

Modify the board DTS code

In my repository folder (riscvOnColorlight-5A-75B) there should be a sub-folder called zephyr. Copy these modified files to the following locations:

$COLORLIGHT/zephyr/riscv32-litex-vexriscv.dtsi to zephyrproject/dts/riscv/riscv32-litex-vexriscv.dtsi
$COLORLIGHT/zephyr/litex_vexriscv.dts to zephyrproject/boards/riscv/litex_vexriscv/litex_vexriscv.dts

Why these changes. We are editing the hardware configuration for the OS to match the hardware we have generated with the litex software. In the future I hope I can automate this step.

Note if you are wondering what are all the magic numbers in the dts file. They are addresses in memory where the control registers for the peripherals are. You can find a full list of these registers in a file called ‘csr.json’ in the $COLORLIGHT/build/colorlight_5a_75b folder.

Modify the board configuration

Go to the hello_world sample project  in zephyr and create a build folder:

cd zephyrproject/samples/hello_world
mkdir build
cd build
cmake -DBOARD=litex_vexriscv ..

Now before you continue we have to change the OS default configuration – this removes support for networking and some device drivers that we don’t have.

Copy the simplified .config file:

$COLORLIGHT/zephyr/.config to zephyrproject/samples/hello_world/build/zephyr/

Build the Zephyr OS code

Now we are ready to build the hello_world example:

cd zephyrproject/samples/hello_world/build

If the build completes with no errors there should be a binary file zephyr.bin in the build/zephyr folder.

Let’s try to run the compiled binary on the FPGA board. Start the lxterm command in a new terminal window:

cd zephyrproject/samples/hellow_world/build
~/.local/bin/lxterm /dev/ttyUSB0 --kernel zephyr/zephyr.bin --speed 38400

Now reset your FPGA board – either load the FPGA configuration again or if you have stored the configuration in flash, power down and then back up.

You would see the following text in the ‘lxterm’ boot screen:

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
[LXTERM] Received firmware download request from the device.
[LXTERM] Uploading zephyr/zephyr.bin to 0x40000000 (41184 bytes)...
[LXTERM] Upload complete (3.2KB/s).
[LXTERM] Booting the device.
[LXTERM] Done.
Executing booted program at 0x40000000

--============= Liftoff! ===============--
*** Booting Zephyr OS build zephyr-v2.3.0-1314-g52f993de1172  ***
Hello World! litex_vexriscv


Congratulations you have booted the zephyr OS, executed a sample app and now you have access to the Zephyr simple shell module.

You can press <tab><tab> to get a list of the shell commands. It is not much but as far as examples go it is enough.


Running RISC-V core on small FPGA board


I took a detour from my usual 3D printing and motor driving hobby this weekend. I have always been fascinated by the flexibility of FPGAs. They are this magical hardware you can make do whatever you want. Though the tools for programming FPGAs have been lets say “complex”.

A while back (14 years or so) I did learn a bit of VHDL. I managed to program one Xilinx CPLD to decode IR signal from a remote control. But the experience was quite an endeavor. Now to present day there has been quite a bit of progress and I managed to compile and run a RISC-V core in one day.

The hardware

A few months ago I read an article on about the Colorlight 5A-75B board. Chubby75 managed to reverse engineer the schematics and program the FPGA to blink a led. While not earth shattering demo, the board itself is quite interesting. The FPGA is from the Lattice EPC5U family with 25k LUTs, quite modest in size, but there is 4MB of SDRAM and two gigabit Ethernet PHYs + a whole bunch of IO pins. The board’s original purpose is to drive led matrix panels, which is also interesting thing to do, but that is not the point of this article.

I ordered two of these from and after a month or so they arrived. At the time there was not much to do besides blink the led on the board. I did try to find more info how to get started with risc-v, but at the time it was quite involved with importing VexRiscv CPU implementation and a whole bunch of configuration I had no clue how to do. So the boards went on the shelf waiting for more inspiration.

The software

Note: I use Ubuntu 20.04 for my developer workstation and the instructions would assume you have similar Linux setup.

My patience was rewarded. Some clever and dedicated people did all the hard work. Enter project LiteX. This is fascinating work wich removes a whole lot of menial tasks with regards to IP configuration. You can read a more detailed comparison with Xilinx’s Vivaldo product on bunnie’s blog.

This is the short version of the tutorial. I’ll walk you trough the steps in more details assuming (like me) you are not a seasoned FPGA designer.

The JTAG cable and software

First thing you need to configure an FPGA chip is JTAG cable. Sadly there are so many options and not a single perfect one. The one I followed is called DirtyJTAG – a project to utilize a STM32 blue pill board as USB to JTAG adapter. Why that one – well I have a stash of blue pill boards in one of my drawers for such an occasion.

First you have to flash the DirtyJTAG firmware on your blue pill board. Luckily the instructions on the DirtyJTAG project page are well detailed. I opted for compiling the firmware and flashing with stlinkV2 adapter, but you can download a pre-compiled binary and use serial port to upload the firmware.

Next you have to install the UrJTAG software. Don’t install the ubuntu package – it is not up to date and does not have the DirtyJTAG cable support. You have to download the latest source code and compile it. This page has instructions how to do that. You will have to add rules to grant access to your USB blue pill board, so you don’t have to run the jtag command as root all the time.

The following may seem like black magic, but I’ll try to explain what it does:

as root create a file named /etc/udev/rules.d/99-dirtyjtag.rules, for example use this command:

sudo nano /etc/udev/rules.d/99-dirtyjtag.rules

add the following two lines to the file:

# dirty JTAG 
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="1209", ATTRS{idProduct}=="c0ca", MODE="0664", GROUP="plugdev"

Save the file and exit the editor. Wait, what just happened? There is a subsystem in Linux called udev that manages plug an play events. We added a rule to that subsystem saying when a USB device with the selected vendor ID and product ID is plugged in the “owner group” of that device should be the  group called “plugdev” also the group would have read/write access to that device.

Now to complete this step we need to run tree more commands:

sudo udevadm control --reload-rules
sudo udevadm trigger
sudo usermod -a -G plugdev $USER

The first two would force the udev subsystem to reload the rules from the files. The third line would add the current user to the plugdev group so we can get access to the device.

Unfortunately for the last step to take effect you would have to log out and log back in the Linux OS and no opening a new terminal window does not count.

With all that out of the way, you should be able to plug your blue pill JTAG adapter and run the ‘jtag’ command. You should see something like:

$ jtag
UrJTAG 0.10 #
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors

UrJTAG is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
There is absolutely no warranty for UrJTAG.

warning: UrJTAG may damage your hardware!
Type "quit" to exit, "help" for help.


Enter the ‘cable dirtyjtag’ command, then ‘detect’. Assuming all is configured it would take a while and return nothing, but you won’t see any errors at this point. If you see anything that says ‘libusb…..something open something’ the most likely cause is that the device access is not correct and you have to redo the udev rules.

The openFPGALoader software

Next we have to install and configure the openFPGALoader software (I know the almost camel case name is confusing). This code can use the JTAG cable to load new FPGA configuration to the board. The steps to compile and install are straight forward. Don’t disable anything, use the defaults.

Cable hookup

At this point you are ready to connect the JTAG cable to the 5A-75B board.

Use the following diagram:

STM32 (blue pill)
PA4 TRST (not used)
PA5 SRST (not used)
3.3V (do not use)

You do need the separate power to the 5A-75 board as shown on the big black connector in the lower right corner. I tried to use the 3.3V from the blue pill board, but it was not enough to power the 5A-75 reliably.

Power the blue pill adapter (connect the USB). Run the ‘jtag’ command from the previous section. Send the ‘cable dirtyjtag’ and ‘detect’ command, this time you should see:

$ jtag

UrJTAG 2019.12 #a10945c7
Copyright (C) 2002, 2003 ETC s.r.o.
Copyright (C) 2007, 2008, 2009 Kolja Waschk and the respective authors

UrJTAG is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
There is absolutely no warranty for UrJTAG.

warning: UrJTAG may damage your hardware!
Type "quit" to exit, "help" for help.

jtag> cable dirtyjtag
jtag> detect
IR length: 8
Chain length: 1
Device Id: 01000001000100010001000001000011 (0x41111043)
Manufacturer: Lattice Semiconductors (0x043)
Unknown part! (0001000100010001) (/usr/local/share/urjtag/lattice/PARTS)

Blink LED test (optional)

The canonical blinking led test can be performed at this time. Clone the following GitHub repository

Go the Colorlight-5A-75B folder and run:

openFPGALoader -c dirtyJtag blink.bit

Yes the name here is slightly different while UrJTAG uses ‘dirtyjtag’ as cable name on the openFPGALoader the J is capital.

This command would load the blink.bit configuration file on the FPGA and you would see the green led on the board blinking.

Note: this FPGA configuration is compiled for the version 7.0 of the 5A-75B board, if you have a different board version this will not work for you as the led is connected to a different pin. To compile the blink example for a different board revision you would need the yosys software.

The yosys software

Do not install the ubuntu packaged version of yosys, it is old and does not have all the feature we need to run LiteX.

First we would need to install a few dependent projects: Project Trellis and nextpnr. Start with Project Trelis. The instructions are very simple. The only mistake I made was to skip the –recursive flag when cloning git the repository. Just run the commands exactly as described in the project page and it would be fine.

Next is the nextpnr code. In the project page there are several configurations described, we only need the ECP5 configuration. Make sure you have all the prerequisites installed. Scroll down to the nextpnr-ecp5 section and run the 3 commands to build and install the software.

Finally we are ready to compile the yosys software. Read the project page instructions in the Setup section. Then clone the repository and run:

make config-clang
make test

If all tests pass at this point you can run

sudo make install

The LiteX software

Finally we are approaching the end of the software configuration journey. This is the last step. You can follow the LiteX software installation page. I’ll repeat the instructions with small modifications that helped me.

Make a folder where you want to install the LiteX software – it downloads quite a few sub packages. Let’s call this folder ‘litex’:

$ mkdir litex
$ cd litex
$ wget
$ chmod +x
$ ./ init install --user

Now it would complain that ~/.local/bin is not in the path. Add it:

$ export PATH=$HOME/.local/bin:$PATH

Download the risc-v gcc compiler:

$ ./ gcc

At the end it would tell you to add the risc-v gcc compiler to the path by running this command:

$ export PATH=$PATH:$(echo $PWD/riscv64-*/bin/)

Verify that you can run the risc-v gcc compiler:

$ riscv64-unknown-elf-gcc --version

Now we are ready to compile the RISC-V SoC and upload it to the board.

Compiling the LiteX RISC-V SoC

Exit the LiteX folder and checkout the litexOnColorlightLab004 github repository.

Run the following command to build the FPGA configuration. We would build the configuration to verify all software pieces are correctly installed, do not load it to the FPGA yet.

Go to the litexOnColorlightLab004 folder and run:

./ --build

Hopefully all should go well and there would not be any errors. Now you have to make some decisions. The original code would user the pins on the J1 connector for serial communication, however to do so it needs to modify the hardware on the board. The modification involves removing the U28 buffer and soldering some bridge wires in its place. See the prerequisites section.

Another option is to use the J19 connector, but we’ll have to sacrifice the button and the led. I personally went with that direction since it is less invasive.

Code modifications to use J19 connector:

changes in
line 38 - delete: "platform.add_extension(_serial)"

line 46 - change the following 2 lines:
            integrated_main_ram_size = 0x4000,
            uart_name                = "serialJ1")
            integrated_main_ram_size = 0x4000)

line 51 - change:
        self.submodules.crg = CRG(platform.request("clk25"), ~platform.request("user_btn_n"))
        self.submodules.crg = CRG(platform.request("clk25"))

line 55,56,57 - delete these 3 lines:
       user_leds = Cat(*[platform.request("user_led_n", i) for i in range(1)])
       self.submodules.leds = Led(user_leds)

changes in firmware/main.c

line 93: change the code in led_test(void) to

static void led_test(void)
	printf("led_test is disabled\n");
#if 0	
	int i;
	for(i=0; i<32; i++) {

We removed the user led and the custom serial port definition. We also removed the reference of the user button.

Now we can continue with the original instructions. Build the FPGA configuration again:

./ --build

Build the RISC-V firmware code

cd firmware
cd ..

Connect serial cable to the J19 connector. Please use 3.3V USB serial adapter not real RS232. Don’t forget to connect TX on the adapter to RX on the J19 connector and RX on the adapter to TX on the J19.

You can run minicom to read the serial output. Connect at 115200 bps 8N1.

Load the FPGA firmware to the board:

./ --load --cable dirtyJtag

After it completes you should see the LiteX bootloader come up on the serial port:

        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
   Build your hardware, easily!

 (c) Copyright 2012-2020 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Jul 18 2020 22:47:39
 BIOS CRC passed (48dcc56e)

 Migen git sha1: 731c192
 LiteX git sha1: 63c19ff4

--=============== SoC ==================--
CPU:       VexRiscv @ 25MHz
BUS:       WISHBONE 32-bit @ 4GiB
CSR:       8-bit data
ROM:       32KiB
SRAM:      8KiB

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
No boot medium found

--============= Console ================--


This is the output of the LiteX BIOS code. It tries to load the RISC-V code from the serial port but fails.

Note: sometimes the openFPGALoader would load the configuration on the FPGA, but it would fail to reset it. This was an issue with the cables I used to connect the blue pill board to the JTAG port. I changed the wires and the stability improved a lot.

To complete the boot process, exit the minicom program and run the following command (while still in the litexOnColorlightLab004 folder):

lxterm /dev/ttyUSB0 --kernel firmware/firmware.bin

Note: in my setup the USB to serial adapter is /dev/ttyUSB0, in you case it may be something different for example /dev/ttyACM0.

This is a serial terminal which intercepts the firmware load request and is going to download the file firmware/firmware.bin to the RISC-V CPU.

Now load the board configuration again running:

./ --load --cable dirtyJtag

You will see the following output from the lxterm program:

[LXTERM] Starting....

        __   _ __      _  __
       / /  (_) /____ | |/_/
      / /__/ / __/ -_)>  <
   Build your hardware, easily!

 (c) Copyright 2012-2020 Enjoy-Digital
 (c) Copyright 2007-2015 M-Labs

 BIOS built on Jul 18 2020 22:47:39
 BIOS CRC passed (48dcc56e)

 Migen git sha1: 731c192
 LiteX git sha1: 63c19ff4

--=============== SoC ==================--
CPU:       VexRiscv @ 25MHz
BUS:       WISHBONE 32-bit @ 4GiB
CSR:       8-bit data
ROM:       32KiB
SRAM:      8KiB

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
[LXTERM] Received firmware download request from the device.
[LXTERM] Uploading firmware/firmware.bin to 0x40000000 (7856 bytes)...
[LXTERM] Upload complete (9.0KB/s).
[LXTERM] Booting the device.
[LXTERM] Done.
Executing booted program at 0x40000000

--============= Liftoff! ===============--

Hello RISCv software defined CPU
Testing software built Jul 18 2020 23:12:43

Available commands:
help                            - this command
reboot                          - reboot CPU
led                             - led test

Enter the “led” command:

led_test is disabled

Remember that we disabled the led test earlier? This shows that our modified code is executing on the CPU.


Soldering robot V2

My first iteration of the soldering machine was based on Prusa MK3 chassis. It worked well enough but the wiring was very messy and I was not happy with it. It was more of an experimental platform than something useful.

For V2 I decided to use an old MendelMax 3 chassis that I had. As 3d printer that was quite outdated, but the motion platform was sturdy and reliable.

I re-used most of the carriage design from the first version. I added a GoPro fixture, so I can mound an LED light on the carriage itself instead of the side of the machine. In theory this should provide more consistent illumination for the camera.

I was also not happy with the fume exhaust design on the V1. It was using a small 40mm fan that was very noisy, the carbon activated filter piece was very small and it looked very ugly.

For the V2 I decided to put the fan and filter on top of the machine, next to the solder wire motor/extruder. It took quite a bit of experimentation to find the right hose to connect the two. I tried thin silicone hose, that was too thin and the walls would collapse during movement. I tried thicker vinyl hose but that was too rigid and would obstruct the movement of the head. Finally I settled on a corrugated PVC hose – it is flexible enough and would not collapse on it own.

The other experiment was to find what size fan I should use. I tried 60mm, 70mm and 80mm axial fans but they would not provide sufficient airflow, when the filter mount was attached. I finally settled on a 7035 centrifugal fan. I started with 120mm centrifugal fan, but that was too big and loud.

Here is a video of the fume exhaust system in action:


TMC2130 – setback

Well, my enthusiasm for the TMC2130 driver was premature. Faith was not kind and I discovered several design flaws after I ordered a bunch of assembled boards.

First I somehow completely missed the 5V power pin to the driver. So initially it was as dead as a door nail. I also discovered one of the config pins was not properly grounded – but that was not a big deal.

After a few bodge wires the driver sill would not respond to SPI commands. This was a rather frustrating thing and I remember having similar experience with the first PrntrBoard with 2130 drivers. Back then I had to wire a separate clock signal to each driver to get them to work.

When reading the datasheet of the 2130 chip it describes that if one connects the clock pin to the ground the chip would use an internal clock generator, but something is amiss and it does not seem to be working correctly in my version.

So back to the drawing board. I updated the PrntrBoard V2 to have a driver clock signal and now have to order new sets of PCBs.

Quite annoying. If you have a clue why the build-in clock is not working on these I would appreciate the hint.

High voltage motor driver design using TMC2130

The good old TMC2130 chip has fallen out of favor thanks to newcomers like the TMC2208/9. It is still top-shelf stuff and the preferred driver by Prusa for the Einsy Rambo as well as their MMU control board.

New chips are cheaper and cad drive more current, but the 2130 sill has one thing you can’t beat – it can handle voltages up to 46V.

Here is an example of a motor driver in the same PCIe form factor with external 3.5mm power terminal block. This allows the driver to use high voltage for example 36V or 42V to drive beefier motor.

The solder jumper on the bottom can be shorted and then the driver would take power from the carrier board.

Thermal test TMC2209 driver @1.7A RMS

I wanted to push my TMC2209 driver design to high-er current. The driver chip is relatively small and even at moderate 1.3A RMS motor current it gets very hot very fast.

Now to be fair 1.3A RMS is probably more than enough to drive most NEMA17 stepper motors. However every once in a while one can get a 1.6A motor or in my case a 1.7A motor. Now in most cases it is not required that you drive the motor with it’s maximum rated current, I just wanted to push the driver and see how it fairs under load.

Here is a picture of my very messy desk with the test setup:

I have my 1.7A NEMA17 motor on a linear rail I used for the test. Above it you can spot my Seek Compact Pro thermal camera. It is not the most accurate instrument, but does the job +/- 5 degree C.

The driver board has one 14x14x7mm heat sink on the driver chip and one 25x25x5mm heat sink on the back of the board, There is also a low RPM 5V 40mm fan blowing air horizontally across the driver boards.

First I configured the driver to use 1.6A RMS current and run a series to G1 X100;G1 X0 commands to move the axis back and forth. I used relatively slow speed, because from my experience this heats the driver the most. This test was uneventful (aka no smoke or major errors), so I proceeded to configure the driver to use 1.7A RMS current.

Here is a picture of the temperature of the board after about 15 minutes of moving the axis back & forth:

The hottest spot is around 54C. While the colors are very dramatic, this is quite cool for this type of setup.

The back side was about 45C:

In conclusion the test was very successful. In previous experiments the drivers would heat up to 70C. In this setup 54C was quite reasonable for the amount of current the driver was handling.

PrntrBoard gets upgraded to 480MHz CPU!!!

I was perusing trough the parts catalog offered by JLCPCB for their assembly service and found this awesome micro controller  STM32H750VB it is quite an upgrade over the good old F407 part. It runs newer Cortex-M7 ARM core, it has double precision FP unit and can run at sweet 480MHz. Best of all it was mostly pin compatible with the F407. I had to re-route one side of the pins, but it was fairly quick.

The only down side is that the build-in flash is a bit limited – 128KB, but I think I can work with that. I’ll order some boards with that processor once the factories in China are bully back in business.

The updated design is on my github page in the “new_cpu” branch.

LCD connector weirdness

There is no shortage of weirdness when it comes to the popular RepRap LCD connectors. The traditional connector is dual 10-pin IDC male sockets.

Alas it appears that someone made a mistake in the original schematics, so now some LCD panels have the connectors backwards. For example the FYSETC Mini 12654 Panel.

I had to create this small adapter to easily flip the direction of the wires:

Here it is i use in my PrntrBoardV2 test prototype: