Spinning a prototype based on the Icebreaker cchematic

I’ve been prototyping a design (a synthesizer module) on the icebreaker board for the last month or so and i think its time to get it off the breadboard.

My plan was (for a first spin) use the same ftdi chip, fpga, and flash scheme that is used on the icebreaker with the hopes that I can keep programming it in the same way (currently using fpgawars/apio).

I use diptrace so I would be re-laying out the board using the icebreaker schematic as a reference as opposed to actually expanding the icebreaker schematic. Also adding several ADCs, DACs, and other application specific circuitry.

Is there anything I should watch out for or think about before getting into detailed design/layout?

Is there a straightforward way to program the flash using the open source toolchain without the FTDI chip?


If you want to eliminate the ftdi chip you’re best to consider a design based on fomu (https://github.com/im-tomu/fomu-hardware). It uses the valentyusb hdl library to bit bang usb and manage the flash using dfu.


Hi, yep. I hadn’t seen the fomu but I also have luke valenty’s tinyfpga bx and had seperately come to the conclusion his bootloader was probably the way to go.

He has a version of the bootloader with pin definitions for the icebreaker on the github:

Where I am at at the moment is still similar to the icebreaker but pushing the ftdi chip offboard to be used only for initial programming then plan on updating the firmware with the TinyFPGA bootloader.

The tinyfpga-bootloader code in that repo (1) is for the icebreaker-bitsy, which is an unreleased board. (2) It doesn’t work …

I would encourage you to look at https://github.com/smunaut/ice40-playground/tree/master/projects/riscv_usb which contains a working USB implementation that works on the icebreaker and supports DFU firmware upgrade. And I’d be happy to help you adapt it to your custom board.

Hi tnt, thanks for replying

I saw that code was for an unreleased board but the pin definitions matched the icebreaker and I figured that would be enough, did not realise it did not work!

I was looking at that riscv_usb implementation. I wasn’t quite sure what to look at there. Is that implementing a full CPU and then implementing USB within that? Or is the USB bootloader seperate from the CPU?

My goal here is just to be able to update firmware over USB, if I were to use this method what would that look like from the firmware upload side on the PC? Apio still usable?

tinyfpga prog was originally written for another ice40 family that has much faster fabric than the UP5k used in the icebreaker and as such it actually doesn’t meet timings, among the other issues it has … At some point I did manage to get it recognized with some hacking, but questionable stability.

The code in riscv_usb is similar to what you would find in a classic microcontroller with USB. There is a dedicated hardware USB block that handles the low layers of USB (so it’s not bit-banged or anything like that, it’s a true hardware USB to meet all the critical timings of USB), but the higher level of the USB stack are running on a riscv CPU. (eventually I’d like to get it running on a smaller cpu than a risc-v, it’s WiP). tinyprog is “all hardware” but it also doesn’t pass the USB compliance tests at all, while here I was aiming for full compliance with the spec for maximum compatibility.

However the way it’s designed to work is to have a separate “boot loader” bitstream in flash that’s triggered for instance when a given button is pressed at bootup. So the way I did it so far is to have the default bitstream be a very simple one that just looks at the button state to decide what bitstream to boot ( https://github.com/smunaut/ice40-playground/tree/usb/projects/boot_stub ). Then depending on that it will either boot the “bootloader” bitstream, or the “application” bitstream. Then in the application bitstream itself, if it’s a “usb-based bitstream”, include DFU descriptors there to allow reboot from application to bootloader, or if the application bitstream doesn’t use USB at all, just include a small helper that reboots into bootloader mode when a button is pressed for a long time for instance ( https://github.com/smunaut/ice40-playground/blob/usb/projects/riscv_usb/rtl/dfu_helper.v ).

On the PC side the way it would look (assuming your application bitstream has no USB support at all), well when you plug the board, by default it doesn’t do anything. But if you power it while pressing the button, then it boot in DFU mode and shows up as a normal DFU device to your PC where you can use dfu-util to upload a bitstream. Or you can also press that button for X seconds and it would also reboot in that mode. So to upload a new bitstream you’d need to do either of those to get it to show up on the PC, and then use dfu-util to load the new bitstream and reboot in application mode.

I don’t use APIO but it looks like it has DFU support and so you’d probably just need to add an entry for your board in the boards.json file and then upload from APIO should work. Althouh you’ll need to manually get the board to DFU mode first. (unless your application bitstream has USB support itself and can accept the command to reboot to DFU programatically).

Does that make sense ?