After exploring in Part 1 what we got with the Arty board, and in Part 2 what tools we are going to use, it is time to spring into action and build an Infra-Red thermal detector based on the Arty board. For the sensor, I’m going to use the Panasonic  AMG8833AMG8833 Grid-Eye , more specifically I’m using the Maxim MAXREFDES131 board, which I had the chance to road test last year (1-Wire® Grid-EYE® Sensor w/Arduino-Compatible PCB - Review). This board supports both OneWire and I2C connections to the sensor. I will be using the I2C connection to drive the sensor.

 

If you want to know more...

Panasonic  AMG8833AMG8833 Grid-Eye

Maxim MAXREFDES131

 

 

For this project, the idea is to build a detector, which would trigger an alarm when a change in temperature is detected.

Basically, the system will need to be able to:

  • manage monitored zones: the field of view of the Grid-Eye sensor will be split in 4 regions, and each region can be enabled/disabled independently;
  • set temperature threshold: this is the temperature that will trigger the alarm. Normally, for thermal detection, you can use the temperature reading either for absolute or differential check. In case of absolute check, the reading is compared against a preset threshold value, and if it equal or greater than the reference, the alarm will set off. For the differential temperature, you need to have a background reference temperature, which will be subtracted from the reading, and such difference will be compared to the set threshold, setting off the alarm if equal or greater;
  • acquire the background frame: this is the reference frame used for temperature differential check;
  • reset the alarm: well, I think this is self-explanatory! :-)

 

The challenge is to provide a “good enough” user interface, leveraging only the basic I/O devices present on the Arty board (switches, buttons and LEDs). I could have used a more sophisticated approach to provide a richer user interface, but I really would like the board to be self-contained, without the need to plug anything but the power supply and the Grid-Eye.

 

One note about the project: the system really doesn't exploit the FPGAs potential, and would probably be better (and cheaper) to realise it using one of the more common microcontroller boards. I chose it because I believe it still makes a good example of a simple System on Chip (SoC) application and, hopefully, will provide some insights for those who are just starting to experiment with this technology.

 

Lets now sketch our system. Below you can appreciate the system in its simplest form: there is the processing unit, some memory, an I/O controller (GPIO) and an I2C controller for the Grid-Eye sensor. Although such minimal system works, for the actual final system that will be created on the FPGA, I will include extra components, since I also want to experiment with the other parts available on the board.


System sketch

 

 

The system is put together using the powerful Vivado IP Integrator, without the need to write a single line in any HDL language. This really shows the power of those “high level” tools, where you don’t need to deal with the details of the RTL design while creating your system. For a maker, this is definitely great news, as it does simplify and speed up the development time significantly.

There is a flip side though: hiding the details, you never really know what is happening “under the bonnet”, which spells troubles if, at some point, anything goes wrong! On a positive note, Vivado’s log files are quite verbose, and there are plenty of them, produced at each stage of the processing, making it a little easier to debug issues.

 

The choice of using IP cores and build the system around the MicroBlaze soft core processor saved quite a lot of time on the hardware design, although some of it had to be spent familiarising with the Xilinx software libraries while developing the firmware. For all those makers thinking of stepping into the FPGA’s world, but still hesitant because they fear they are lacking digital design skills, I think this approach is the one offering the path of least resistance: moving the complexity from hardware to software design, where most people feel more confident, surely gives the necessary boost to make the leap.

 

Obviously, my project could be completely realised usign RTL design techniques, writing all the modules from scratch in HDL (VHDL or Verilog) , but as first approach, I though it would be more valuable to explore the block design way. Nevertheless, I’m planning to re-implement the design without using IP cores, by writing all the modules from scratch in VHDL. That way, I will also be able to avoid using the MicroBlaze, and implement everything using only simpler finite state machines. But this is a subject for another blog...

 

Lets fire up Vivado and start designing the hardware we are going to map into the FPGA's fabric. As anticipated, to make  the process as easy as possible, I will be using the Block Design feature, and work with the IP Integrator. The nice thing about using the block design is that, every time you add a new IP core to your design, you can leverage the Designer Assistance wizard tools:

 

  • the Block Automation wizard: guides you through the customisation of the IP block;
  • the Connection Automation wizard: helps connecting correctly the blocks bewteen them and with the external ports.

 

But you always have to keep your eyes open though: as smart as these tools can be, some times they can exercise a bit too much "creativity" while inferring what you want to do with the new module, creating some bizarre connections between the ports.

Also, to benefit the most of the wizards, the blocks need to be created and connected following a logic order, otherwise you could end up again with the tool trying to infer your intention (and fail!).

 

Once a new project has been created in Vivado, the next step is to create a block design, which will open a nice and clean Diagram window, where we can start adding our blocks by clicking on the "+" button. This brings up the IP Library navigation popup, where the wanted IP can be selected.

 

Below you will find a slide-show photo gallery, illustrating all the steps taken to create the design, with relative comments.

 

{gallery:autoplay=false} Vivado Hardware Design Steps
Add Clock

Step 1 - Clock setup: Add the DDR Clock and System Reset by selecting them from the "Board" tab, right-click on the selected item, and click on "Auto Connect". Customise the Clock block by double-clicking on it, and in Board tab select "Reset" for "EXT_RESET_IN", and in

"Output Clock" tab, select "clock_out2" and set 200MHz as frequency, then select "Reset Active Low" for Reset Type. Run the Connection Automation wizard, and accept all the defaults.

Add External Memory
Step 2 - Add External Memory: Add the 256MB RAM and 16MB Flash external memory. This can be done by clicking on the "Board" tab, and selecting DDR3 SDRAM and QUAD SPI Flash. Right-click on the selected item, and click on "Auto Connect" in the popup menu. Manually remove the "sys_rst" port created by the wizard, and customise the DDR by doble-clicking on the "mig_7series_0" block. On the page "Memory Options" of the wizars, deselect the box "Select Additional Clocks(if required)". On the page "FPGA Options", select "Enabled" for "XADC Instantiation".

Add I/O blocks
Step 3 - Add I/O ports: Add all the external ports to the design. This can be done by clicking on the "Board" tab, and selecting the following I/O ports: 2 RGB LEDs, 4 LEDS, 4 Push Buttons, 4 Switches, I2C on J3 and USB UART. Right-click on the selected item, and click on "Auto Connect" in the popup menu. Customise "axi_iic_0", setting 400KHz as frequency in the tab "IP Configuration" tab. Customise "axi_uartlite_0", setting 115200 as Baud rate in the "IP Configuration" tab. Customise "axi_gpio_1", checking the box "Enable Interrupt" on the "Board" tab.

Add MicroBlaze
Step 4 -Add MicroBlaze: Add Microblaze IP from the IP Catalog, and customise it by running the Block Automation wizard. It is important to add local memory (128KB) and some cache (8KB) at this stage, so that the wizard will also create the BRAM blocks. We also want to select the "Interrupt Controller" checkbox, which will add an AXI Interrupt Controller block to the design (we will need interrupts to capture use input). For the clock connection, select "/mig_7series_0/ui_clk".

Auto connect blocks
Step 5 - Connect the blocks: Run the Connection Automation wizard to create all the connections between the blocks. For all the AXI related selection, just use the suggested default value. For the "mig_7series_0" clocks, choose "/clk_wiz_0/clk_out1" for  "sys_clk_i" (100MHz) and "/clk_wiz_0/clk_out2 " for  "clk_ref_i" (200MHz). Leave "sys_rst" unconnected. For the "axi_quad_spi_0" clock, select //mig_7series_0/ui_clk".

Interrupt connection and final viewStep 6 - Interrupt Setup: All the interrupt signals need to be connected to the interrupt controller. To do that, the "microblaze_0_xlconcat" needs to be customised (by double-clicking on the block), and the number of ports need to be set to 4. Then the interrupt signal from the I2C , UART, GPIO1 and QUAD SPI blocks need to be connected to the xlconcat block inputs. This completes the design of the hardware.

 

 

Couple of notes on the design illustrated above: you might be wondering why the "ui_clk" clock signal (81MHz), generated by the DDR memory controller, has been chosen to drive all the clock lines to the other blocks, when the board provides a 100MHz clock, or I could have used the 100MHz and 200MHz clock signal generated by the clock wizard block.

There are 2 reasons for it: the first is that the AXI slave interface of the DDR memory controller works with the clock generated by ui_clk, so no matter how fast the rest of the system is, this is were the bottleneck is.

The second I believe it is somehow related to the first one: when you drive the other modules using a faster clock, for instance a 100MHz clock, the implementation will report a negative slack timing failure for some of the paths. I haven't had time to investigate the issue, but I think to solve it I would need to introduce some registers in the failing paths, which basically translates into "slowing down" that path. Therefore, to play safe, my choice to use the slowest clock in the system as source for the rest.

 

The other comment is related to the input buttons and switches: I have not created a debouncer for them. There are plenty of ready made modules on the internet I could have borrowed to create the HDL source module to add to the system, but the design is already quite busy as it is, without adding further blocks. Moreover, when testing, I didn't have problems using them, so for the time being I will leave the debouncer circuit out (another item in my to-do list for the RTL implementation...).

 

The design of the system is now complete, but we still need to do 2 things before starting the build process to generate the bitstream to program the Spartan-7:

 

  • create HDL wrapper for the project
  • create the constraints file for the implementation

 

The HDL wrapper, as the name implies, creates the top module for the system, which "glues" together all the components of the system. You don't need to write it as Vivado will generate it for you. All you need to do is,under the "Sources" tab, right-click on the block design name, and click on  "Create HDL wrapper...", and let Vivado take care of managing the file. The HDL language used for the wrapper will depend on the setting chosen as HDL language for the project (in  "Project Settings").

 

Generally speaking, since we imported the board definition file into Vivado, and we specified it when creating the board, Vivado can fetch the information about the board's hardware components and ports automatically. There are some properties we still need to set though, to avoid errors during the implementation/bitstream generation phase, and this is the reason why I created the constraint file "fixes.xdc". Below you can find the content of the file:

 

set_property CLOCK_DEDICATED_ROUTE BACKBONE [get_nets ublaze_design_i/clk_wiz_0/inst/clk_in1_ublaze_design_clk_wiz_0_0]

## Configuration options, can be used for all designs
set_property BITSTREAM.CONFIG.CONFIGRATE 50 [current_design]
set_property CONFIG_VOLTAGE 3.3 [current_design]
set_property CFGBVS VCCO [current_design]
set_property BITSTREAM.CONFIG.SPI_BUSWIDTH 4 [current_design]
set_property CONFIG_MODE SPIx4 [current_design]

## SW3 is assigned to a pin M5 in the 1.35v bank. This pin can also be used as
## the VREF for BANK 34. To ensure that SW3 does not define the reference voltage
## and to be able to use this pin as an ordinary I/O the following property must
## be set to enable an internal VREF for BANK 34. Since a 1.35v supply is being
## used the internal reference is set to half that value (i.e. 0.675v). Note that
## this property must be set even if SW3 is not used in the design.
set_property INTERNAL_VREF 0.675 [get_iobanks 34]

 

Line 1 was added to avoid the implementation to fail because of a sub-optimal clock placement. The rest of the file is taken from the constraints file provided by Digilent for the board (rev.B), and avoids Vivado complaining during the bitstrem generation step.

 

Now we all set, and we can start the build process. As mentioned in my previous blog, it consists of the following steps:

 

  • Run Synthesis
  • Run Implementation
  • Generate Bitstream

 

Clicking on "Run Synthesis" in the "Flow Navigation" window you kickstart the sysnthesis process. You can now sit back and relax, because the Synthesis step takes a good 15 minutes, when running on my computer, which is equipped with 8th gen Intel core i7-8550U, 16 GB of RAM and 512 GB of SSD HD.

 

On successful completion, you can start the Implementation process by clicking on "Run Implementation" in the "Flow Navigation" window. Again, the implementation won't take as long as the synthesis, but still will take another 5 minutes of your time.

 

Once that completes without error, you can click on "Open Implemented Design" to access all the reports generated by the tools. There are lots of information, including timing reports and power consumption estimates (see the slideshow below), that you can drill down to gain insights on how your design has been mapped onto the FPGA fabric and how well it performs. If you click on "Schematic", you can also take a look at the actual RTL schematic created from your design. This is the place where you can find out about the details of each path and, if needed, for example make modifications to add a buffer or a register.

 

{gallery} Implementation Reports

Implementation View

Implementation Technology Schematic and Time Summary Report

Power Summary

Power Estimation Summary

RTL Schematic View

RTL Schematic View

 

Now, the last step of the build: the Bitstream generation. No more coffee needed, as this is usually the fastest step of the whole process, taking just about 2 minutes.

 

With the hardware design now complete, we need to test it on the board. Since we designed a system that, out of the box, does nothing, downloading the bitstream to the board, using the Hardware Manager, won't really give us any feedback on the quality of the build. We need to write some testing software that we can run on our system, than can show us the hardware works as expected.

 

This is where the choice of using a MicroBlaze-based design pays off: for such processor, we can leverage the nice integration between the Vivado tool and the Eclipse-based Xilinx Software Development Kit (SDK), which will create all the necessary framework for developing on the hardware we just implemented on the Spartan-7.

 

From the Vivado tool, clicking on "File->Export->Export Hardware", you will be presented with a dialog, asking you where to export the hardware definition files, and giving you also the choice to export the bitstream file . Exporting it to "Local to Project", will keep both the hardware project files and the software development files inside the root project folder defined while creating the Vivado project, which is useful if you want to keep the whole project self-contained.

 

To start the SDK, from Vivado, click "File->Launch SDK", and the Eclipse-based development environment will open, and create the software support package for your hardware design. On opening, you will be greeted with the Hardware Platform Specification, which contains all the information about all the devices used in your hardware, and all the addresses where the memory-mapped devices can be accessed.

 

SDK - Hardware Support

 

Let's  now create a test application, by clicking  "File->New->Application Project" from the SDK top menu. This will open the create project wizard where, besides the usual setting the name and location for the project, we can also select what kind of application we would like to create. It offers several project templates to choose from, to test our board, including the classic "Hello World" application (it writes the famous "Hello World!" string on the UART port). Although tempting, I prefer to test it with the "Peripheral Tests" application, which will run some tests on the hardware (LEDs, Buttons, Interrupt controller, etc), and reports back the results via UART.

 

SDK - Board Support Package

 

The wizard creates the Board Support Package, which contains the software libraries supporting the board hardware the modules created in the FPGA, and the skeleton of the Peripheral Tests application.

 

SDK - BSP and Peripheral Test Application

 

Now, we can build our application, and run it on the Arty. The SDK can also download the bitstream to the board (this is why it is useful to include it when exporting the hardware from Vivado), so we can do that first, to make sure the Spartan-7 is programmed (assuming the board is connected via USB to the machine running the SDK).

Before running the application on the hardware, we need to connect the SDK Terminal tool to the UART of the board, so we can capture the output from the application. Alternatively, you can also use PuTTy or any other communication tool you are used to.

 

To run the application, select "Run As->Launch on Hardware" from the drop-down menu brought up by right-clicking on the top of the application tree in the Project Explorer window.

If all is OK, you should see an output from the Terminal, similar to the one below, and the RGB LEDs on the Arty should flash (once per colour).

 

build test

 

This completes the hardware part of the design. In the next blog, I will show the design and development of the software part of the project.

 

 

 

The Digilent Arty S7 Series
The Digilent Arty S7: An Unexpected journey - Part 1 - The Board
The Digilent Arty S7: An Unexpected Journey - Part 2 - The Tools
The Digilent Arty S7: An Unexpected Journey - Part 3 - To the drawing board
The Digilent Arty S7: An Unexpected Journey - Part 4 - The Code