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?

Hi,

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.

Cheers,
Tom

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 ?

That does make sense.

Attached is my current schematic (power is on another page). It’s mostly based off of the icebreaker schematic with the ftdi chip left off. Current plan is to spin another tiny board with just the ftdi chip and supporting circuitry for initial programming (or tap the lines from my icebreaker) then try your bootloader for successive firmware updates.

The pins chosen for USB etc are the same as what luke valenty used, looking at the pcf file in your git it looks like while may I may need to switch a couple pins they are all gpio and all there. Am I obviously missing anything that your boot loader would need?

I don’t see any problem with the including the boot loader helper as part of my application. The dfu configuration actually looks friendlier than my current programming configuration. Getting full USB compliance going sounds like quite a feat!

The intent of this board isn’t really to copy the icebreaker or tinyfpga, more to quickly prove to myself that this platform is viable for (open source) production purposes (even though I have already sunk months into the verilog design) and to get the project away from the breadboard/dev board stage. I haven’t picked a license yet but the current plan is to post up full source code and schematics once things are at a mostly-working stage.

I’m planning to lay this board out this week as a somewhat roomy 4 layer board, keep it big, easy, and loaded with test points, before shrinking things down with the adc, dac, etc (currently on separate boards) included. The verilog I have been prototyping on the icebreaker is for eurorack and/or standalone audio synthesizer purposes, so it does not need to communicate via usb at all. The usb is strictly for firmware update purposes.

Thanks for your help!

Huh picture is a bit low resolution to really check anything.

Things to pay attention to:

  • All 3 USB pins on the same IO bank (so all IOB_xxx or all IOT_xxx). 1.5k resistor for pull up line to D+ and then 47R resistors as series termination for the USB data lines.
  • 12 MHz clock input on same pin as the icebreaker (36 IIRC)
  • Make sure the other pin on the same IO tile is only used for output and not input (since that line will be unusable for input due to PLL constrains using that IO tile input path)
  • Flash must have enough space for the equivalent of 4 bitstreams.
  • Ideally flash should also support the “get uid” command (that’s used to generate a serial number automatically)
  • Need a ‘user’ button to be able to enter boot loader mode
  • Ideally a RGB led is used to report the current state (like it blinks fast in DFU mode), but that’s optional.

Got it!
Clock input is on pin 35 (same as icebreaker), how would I find out what the other pin on the same IO tile is?

Is “get uid” same as “Read Unique ID”? I currently have the same/similar flash as the one on the icebreaker on there, W25Q128JVSIM.

The other pin is pin 37. (and I was wrong, it’s not the same IO tile, it’s the adjacent IO tile since the PLL spans 2 tiles).

Yeah, Read Unique ID. The flash from the icebreaker is fine.