As I've recently covered Xilinx's launch of their new SoM, the Kria K26, I decided it was a good time to pull out one of my other SoM boards to do a quick tutorial on getting started with a SoM and baseboard for development purposes.
As I mentioned in my previous article, SoMs have been gaining more and more popularity in the FPGA development world due to their extra level of hardware flexibility they offer and cost-effectiveness. However another key, yet subtle advantage of SoM FPGA boards that I recently discovered is that they tend to be more likely to be laid out for user-configurable voltage I/O banks for the FPGA.
For those not familiar, many FPGA chips have their internal logic (which I like to refer to as fabric) divided up in sections based on the power rails it is within the closest proximity to. This ensures proper power distribution to the entirety of the fabric within the FPGA. Any I/O package pins that are connected to a given section of fabric are constrained to operate at the section's supply voltage for their reference voltage. This is why, for example, if you try to put a 3.3v I/O signal on a pin that's in the same section of fabric as a 1.8v I/O signal, the IDE tool (Vivado in this case) will throw an error in the place & route stage.
I started a project recently originally on one of the Arty FPGA development boards, but hit a wall when I tried to set a few of the FPGA's package pins to operate at 1.8V instead of the default 3.3V. The 1.8V peripheral interface that I had implemented was showing unexpected and random behavior. Upon probing it with a DMM, I found that they were still operating at 3.3V instead of 1.8V.
After inspecting the Arty schematic I found that the voltage rails feeding each of the voltage banks of the FPGA chip were hardwired to a 3.3V rail and there was nothing I could do as a user to change it. I then dung through the entirety of my FPGA development board collection only to discover they all had their voltage banks hardwired to rails.
A deep dive into the FPGA development board market revealed that many FPGA development boards below the $2000 - $10, 000+ price point tend to have the voltage I/O banks routed to static power rails; and the majority of the time is 3.3v.
Overall, I am writing this project as an example of how to select a SoM development platform and get it set up since I feel as though it is an important concept for any FPGA developer/engineer to be familiar with.
Note: While I am using Vivado/Vitis version 2019.2, all instructions below should be compatible with all later versions of Vivado/Vitis unless otherwise stated.Selecting a SoM
Selecting a SoM FPGA board is pretty straightforward in that the focus is boiled down to the FPGA chipset and amount of physical memory such as DDR.
I really like Xilinx's Artix chipset for applications that I need to keep the cost on the lower end of as well as when I have lower power constraints I need to meet (a soft processor typically draws much less average power than a physical processor built into an FPGA). My design also has the requirement to keep all data being processed within the FPGA chip using BRAM instead of using external DDR.
These constraints landed me on Trenz Electronic site looking at their 4x5 SoM lineup, specifically the TE07xx series of SoM boards based on Xilinx's Artix chipset. I settled on the TE0711 as it didn't have any DDR and boasted the commercial grade Artix-7 XC7A35T-2CSG324C. It was also the more cost effective option coming in at about $120.
As I mentioned, I recently found that many FPGA development boards below the $2000 - $10, 000+ price point tend to have the voltage I/O banks routed to static power rails; and the majority of the time is 3.3v.
This presented a huge challenge for me as the project I was starting required interface with a peripheral that was all 1.8v I/O and couldn't afford the latency of conversion circuitry. My budget also put me well below the $2000 - $10, 000+ range. This ultimately led me to discover the series of SoM baseboards from Trenz Electronic as I finally found theirs baseboards allowed for me to set the voltage rails supplying the FPGA to either 1.8v, 2.5v, or 3.3v via a jumper/dip switch configuration.
The TE0701 fit the rest of my requirements with an FMC connector, PMODs, and coin cell slot. It also totaled out as just a tad over $300. Brining my modularized FPGA development solution for this project to just under $450.Install Vivado Board Definition Files
I'm a fan of Trenz Electronic partially because of their well laid out Wiki with resources and documentation for all of their development boards. In the download area for the TE0711 board, the Vivado board definition files are provided in the base reference design from Trenz Electronic.
Be sure to grab the board definition files for the version of Vivado you are running, otherwise you may encounter unexpected and/or unfixable errors in your design.
To install in Vivado, copy and paste all contents (excluding the.csv file) of the board_files directory in the test_board reference design downloaded into Vivado's installation directory (<Vivado install path>/data/boards/board_files).
If Vivado was running when the board files were copied into its installation directory, it will need to be restarted before it detects the new files.Create Vivado Project
After installing the board definition files for the TE0711, launch Vivado and create a new project targeting the TE0711 board.
From the Flow Navigator window, select the option to create a new block design for the project. Once opened, add a MicroBlaze processing system IP block to the design. This will trigger the Block Automation option to appear to apply the bare necessity infrastructure for the MicroBlaze soft processor. I also like to add the interrupt controller using the block automation.
After running Block Automation, the Connection Automation option will appear to generate the main clock oscillator and external reset signal connections. Check the box for All Automation then click ok to running the Connection Automation.
Once the Connection Automation has completed, the layout might look messy. Use the Regenerate Layout option from the Block Design toolbar to clean it up before validating the design. To validate the design, use the Validate Design option from the Block Design toolbar, then save the design.
Once the block design is complete, a top level HDL wrapper needs to be created for it to instantiate it. Right-click on the block design file in the Sources hierarchy and select Create HDL Wrapper.... You can then select if you want Vivado to dynamically update it when changes are made to the block design or if you prefer to update it manually.
With a preliminary block design for the SoM FPGA board in place, I want to add the SoM FPGA board board specific constraints. For the TE0711 board, these constraints are provided in the reference design under ./test_board/constraints.
Select the Add Sources option from the Flow Navigator and tick the option to Add or create constraints. Using the Add Files option point to the constraints files from ./test_board/constraints to copy into the Vivado project.
When a constraints set in a Vivado project is comprised of multiple constraints files, a specific constraints file must be set as the target constraints file for Vivado. All of the constraints file in the set are implemented in the design while the target constraints file is the file Vivado writes Set the constraints titled vivado_target as the target constraints file.
Looking into the constraints set for the TE0711, I noticed the SoM has three onboard LEDs (two green and one red), so I went back to the block design to add an AXI GPIO IP block to control them.
After adding the AXI GPIO, run the resultant connection automation and set the Select Board Part Interface for the GPIO to leds (Module LEDS) to route it to the 3 LED signals called out in the _i_io.xdc constraints file.
Run the connection automation then regenerate & revalidate the block design.
Once the block design is successfully validated and saved, the design is complete for the SoM itself, and the configurations for extending out through the baseboard can be added.Configure TE0701 Baseboard for Desired Voltages on IO Banks
Those those not familiar with using a SoM with baseboard configuration for FPGA development, it's worth mentioning that there are no other physical connections to the SoM aside from the high-density connectors it uses to seat onto the baseboard. This can mean that certain baseboards will have some form of hardware configuration in the form of switches or jumpers that need to be set prior to powering on the setup.
The first thing that needs to be done on the TE0701 baseboard before the TE0711 can be powered on, is to configure the DIP switches & jumpers to set the IO voltage rails for the FPGA chip. Then the enable line for the JTAG interface needs to be set to route the JTAG lines to the SoM's FPGA instead of the SoM's CPLD for the host PC to program. Finally, the voltage for the USB bus also needs to be set to either use the 5.0V rail or look for an external voltage on another connector.
There are several different options for setting the voltage rail values for the FPGA. Since I am needing the rails to be set to the user-defined value of 1.8V there are two main steps in that configuration on the TE0701:
- Set VIOTA and VIOTB to use the FMC_VADJ voltage.
- Set the FMC_VADJ voltage to 1.8V.
Jumpers J17, J16, J21 are used to set the reference voltages for VIOTA and VIOTB. To set the reference voltage to FMC_VADJ, use the following configuration:
- J16 = jumper pin 1 to pin 2
- J17 = leave open, no jumper
- J21 = jumper pin 2 to pin 3
DIP switch S4 is used to configure the desired voltage of FMC_VADJ. Since I need them to be 1.8V, I set the switches as such:
- DIP S4: S4-1 = on / S4-2 = off / S4-3 = on / S4-4 = off
According to the TRM for the TE0701 (also see screen grabs below), to set the JTAG enable line for the SoM's FPGA on the TE0701, configure DIP switch S3 to the following:
- DIP S3: S3-1 = off / S3-2 = off / S3-3 = on / S3-4 = off
Finally, set the USB bus voltage to 5.0V with the 200pF decoupling capacitor looped into the circuit using jumpers J9, J19, and J20:
- J9 = jumper pin 1 to pin 2
- J19 = jumper pin 1 to pin 2
- J20 = jumper pin 1 to pin 2
Trenz's SoM boards and corresponding baseboards connect together via their B2B (board to board) interface using Samtec Razor Beam™ LSHM series connectors. These connectors are hermaphroditic, which means they don't have different male versus female connectors. The same single connector is compatible for connection with itself mechanically which results in the pinout mapping the of odd numbered pins of the first connector connecting to the even numbered pins of the second and vice versa.
Looking at the block diagrams for the TE0711 and TE0701 from their respective TRM Wiki pages, one can get a general idea of what peripherals on the baseboard can be routed to which I/O pins of the FPGA (JM1 connects to JB1, JM2 connects to JB2, and JM3 connects to JB3).
Since the Vivado project is targeting the TE0711 board using board definition files, I decided to take advantage of the board component list tab in the block design's sources window. This board component list tab makes connecting peripherals in the block design easier when using a development board that has a known pinout.
Right-click on the desired board component in the Board tab of the sources window (which will appear when the block design is open) and select the Connect Board Component... option. A window will appear with a list of the compatible IP blocks for use with the given peripheral. After selecting, run the resulting Connection Automation that appears.
To start off, I connected the system clock, QSPI flash external memory, FPGA reset, and UART interface for the host PC COM port connection.
The system clock is simply connected to a clocking wizard IP and the FPGA reset goes to the corresponding Processor System Reset (but you'll notice that we manually connected that in previous steps so it will already show as connected in the Board tab, same goes for the Module LEDS we connected to an AXI GPIO IP block). Here's the IP blocks I chose for the QSPI flash external memory and UART interface for the host PC COM port:
- BASE UART0 - AXI Uartlite
- QSPI Flash - AXI Quad SPI
- FT2232H Channel A - leave unconnected, already using BASE UART0
- FT2232H Channel B - leave unconnected, already using BASE UART0
The board presets for connecting the general purpose input or output peripherals between the TE0711 and its baseboard via its JM1, JM2, and JM3 B2B connectors are labeled as J1, J2, and J3 meaning:
- J1 = (TE0711 JM1)/(TE0701 JB1)
- J2 = (TE0711 JM2/TE0701) JB2
- J3 = (TE0711 JM3/TE0701 JB3)
Since I couldn't find any documentation to correlate the J1/J2/J3 connections of the general purpose I/Os in the board component list in Vivado to the pins on the TE0711's JM1/JM2/JM3 connectors, I just connected all of them and ran Synthesis to see which package pins of the FPGA it ended up putting them on. Knowing which packages pins each general purpose I/O is routed to meant I could then use the 4x5 Series Pinout Tracelength spreadsheet tool from the Trenz wiki to determine which specific connectors on the TE0701 baseboard each signal was going to.
Again, right-click on each of the remaining general purpose I/Os in the Board tab of the sources window (which will appear when the block design is open) and select the Connect Board Component... option. I thought it would be useful to dedicate this Vivado project as a template project for the TE0711 SoM with TE0701 baseboard by connecting the rest of the general purpose I/Os to AXI GPIOs as a sort of placeholder:
- ASIO GPIO - leave unconnected, throws an error.
- Baseboard LEDS - leave unconnected, already using Module LEDS
- J1:P0 - shares bits with uart0, so can't be connected at the same time.
- J1:P0_6bits - shares bits with 8-bit P0 so can't connect.
- J1:P1A - AXI GPIO
- J1:P1B - AXI GPIO
- J1:P1C - AXI GPIO
- J1:P1D - AXI GPIO
- J2:P2A - AXI GPIO
- J2:P2B - AXI GPIO
- J2:P2C - AXI GPIO
- J3:P3A - AXI GPIO
- J3:P3B - AXI GPIO
Note: I did also find that the constraints file (_i_io.xdc) for Module LEDS had an error, the pins for LED and LED were swapped.
I'm a big fan of grouping IP block into different hierarchy when I have a block design that's starting to get cluttered. So I decided to group all IP blocks whose signals when through the same B2B connector (JM1, JM2, JM3) into their own respective hierarchies.
The IP blocks that connected to peripherals living on the TE0711 itself such as the Module LEDS I decided to leave out on the top level of the block diagram. This made a nice visual representation in the block diagram of what goes where between the SoM and its baseboard (or it at least makes my OCD brain happy).
After regenerating the layout and revalidating the design, save the block design then re-create a new HDL wrapper for it.Generate Bitstream and Export Hardware
With the SoM + baseboard design completed, run synthesis, implementation and generate a bitstream for the design to verify there are no errors or critical warnings. Then export the hardware platform for Vitis to use to create an embedded application to run on the MicroBlaze soft processor.
Select the Export option from the File menu and choose to Export Hardware...
Be sure to check the option to have the bitstream included in the exported hardware platform and the desired output path is set. Once the hardware platform is exported, it will be time to launch Vitis and create the embedded application for the MicroBlaze.
Since this project post has far exceed the original length that I thought it would, I will make the embedded application development in Vitis a separate post that should go up within a week or so of this post.