HPS2FPGAmapping
SoCFPGA: Mapping HPS Peripherals, like I²C or CAN, over the FPGA fabric to FPGA I/O and using embedded Linux to control them (Intel Cyclone V)
Install / Use
/learn @robseb/HPS2FPGAmappingREADME
Mapping HPS Peripherals, like I²C or CAN, over the FPGA fabric to FPGA I/O and using embedded Linux to control them

Development Boards for Intel SoC-FPGA allow often only a simple access to FPGA I/O-Pins. The only way to use HPS-Hard-IP Interfaces with these boards is the routing over the FPGA fabric.
For example, the Terasic DE10-Nano development Board with an Intel Cyclone V SoC-FPGA has an Arduino UNO compatible socket. This is a nice feature, because it is possible to use nearly any Arduino Shield from the huge Arduino community with SoC-FPGA’s. Here are also all digital Pins connected to FPGA I/O Pins. With the Intel NIOSII-Softcore processor and some Soft-IP it is not too complicated to interact with these shields. But if the target applications require the connection of the capabilities of an embedded Linux system, running on the HPS, it will be. One reason is, that I only could find one official guide (AN 706), with a golden reference design witch shows only a chapter of the development process.
With this following step by step guide I will give a complete description and I will also shown as an example, how to transmit CAN-Bus Packages with a simple Linux Python script running on an embadded Linux by using an Arduino Shield with the Terasic DE10-Nano board.
This project is a part of my rsYocto embedded Linux system, that I developed during my master study and I use it here as a reference.
Note: This project is a bit out of date.... I completely redesigned the rsyocto build system (part 2-6). Please follow Part 1 and consider my custom rsyocto version guide. Then you can continue with part 5 to create your Device Tree and with part 7+. In the future I will update this guide... Many Thanks.
The build flow of rsYocto shows the interaction of all required parts.

1. Part: Creating the FPGA configuration
The first part of this project is the creation of a Quartus Prime FPGA project to configure the ARM Cortex A9 Hard Processor System (HPS) and the routing of HPS Bus Interfaces through the FPGA fabric. At the end will be the generation of a FPGA configuration file, that can be loaded by the secondary bootloader as shown in the next parts.
-
Use Terasic’s System Builder to generate a new Intel Quartus Prime project with the right I/O-Pin mapping
-
Open this Quartus Prime Project and create a new Platform Designer model
-
Insert the component “Arria V/Cyclone V Hard Processor System” to this model
-
It should look like this:

-
Note: Do not change the name “hps_0”! With a different name some errors could occure in the device tree building process of the Linux system
HPS component configuration
-
Open the HPS component Editor and select the “FPGA Interfaces”-Tab
-
Here you can configure the system on your own wishes
-
It makes sense to enable all AXI Bridges, they are not required for this project, but if a Linux application tries to access on a disabled bridge address a Linux Kernel panic will be occured.
-
I choose the following configuration:

-
Special Resets-, Interrupts- or DMA-Settings are not required
-
Continue with the “Peripheral Pins”-Tab
-
For the usage of DE10-Nano`s HPS components choose the following settings:
| Peripheral Name | Status | Addional Settings |:--|:--|:--| | Ethernet Media Access Controller 1 (EMAC1) | HPS I/O Set 0 | EMAC1 mode: "RGMII" | SD/MMC Controller (SDIO) | HPS I/O Set 0 | SDIO mode ="4-bit Data" |USB Controller 1 (USB1) | HPS I/O Set 0 | USB1 PHY interface mode="SDR with PHY clock output mode" | UART Controller 0 (UART0) | HPS I/O Set 0 | UART0 mode="No Flow Control" | I2C Controller 0 (I2C0) | HPS I/O Set 0 | I2C0 mode="I2C"
-
This gives the Linux system SDMMC as boot source
-
To map the I²C-, SPI- , UART- and CAN-Bus to the Arduino interface* by selecting these points addionaly:
| Peripheral Name | Status | Addional Settings |:--|:--|:--| | UART Controller 1 (UART1) | FPGA | UART0 mode="Full" | I2C Controller 1 (I2C1) | FPGA | I2C1 mode="I2C" | SPI Controller 0 (SPI0) | FPGA | SPI0 mode="Master" | CAN Controller 0 (CAN0) | FPGA | -
-
Open the “SDRAM”-Tab (Do not change the settings of the "HPS-Cock"-Tab)
-
In my GitHub repository is the .qprs-memory configuration file "D10STDNANO_DDR3.qprs" included
-
Copy this file to your Quartus Prime project folder and click inside the HPS component editor and presents-bar the "new"-button

-
A new preset window appears, select the .qprs-file and name it.

-
Again, close the preset window, select in the list the previously imported preset and click apply to execute the configuration
-
At this point HPS configuration is done (Press Finish to close the window)
HPS interconnection
-
The only necessary connection to use the HPS is: clk_0:clk_in_reset --> hps_0:h2f_cold_reset
-
Export the SPI-, UART- ,I2C-, CAN-, memory and hps_IO by double clicking on the export text file

-
Additionally connect PIO (Parallel I/O) Intel FPGA IP-modules to a HPS-to-FPGA interface to LEDs or key-switches

-
Generate with "System/Assign Base Addresses" memory addresses of the HPS Bridge interfaces
-
Finally press the "Generate HDL..."-button to build the final platform
Import the HPS Platform to Quartus Prime
-
Add the ".qip"- and the ".sip" from the Platform Designer to the project files
-
Use following Verilog code inside the top level file to import this HPS-model:
base_hps u0 ( /////////////////////////////////////////////////// CLOCKS ////////////////////////////////////////////////////// .clk_clk (CLOCK_50), ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////// HPS ////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////// Onboard DDR3 1GB Memmory /////////////////////////////////// .hps_0_ddr_mem_a ( HPS_DDR3_ADDR ), .hps_0_ddr_mem_ba ( HPS_DDR3_BA ), .hps_0_ddr_mem_ck ( HPS_DDR3_CK_P ), .hps_0_ddr_mem_ck_n ( HPS_DDR3_CK_N ), .hps_0_ddr_mem_cke ( HPS_DDR3_CKE ), .hps_0_ddr_mem_cs_n ( HPS_DDR3_CS_N ), .hps_0_ddr_mem_ras_n ( HPS_DDR3_RAS_N ), .hps_0_ddr_mem_cas_n ( HPS_DDR3_CAS_N ), .hps_0_ddr_mem_we_n ( HPS_DDR3_WE_N ), .hps_0_ddr_mem_reset_n ( HPS_DDR3_RESET_N ), .hps_0_ddr_mem_dq ( HPS_DDR3_DQ ), .hps_0_ddr_mem_dqs ( HPS_DDR3_DQS_P ), .hps_0_ddr_mem_dqs_n ( HPS_DDR3_DQS_N ), .hps_0_ddr_mem_odt ( HPS_DDR3_ODT ), .hps_0_ddr_mem_dm ( HPS_DDR3_DM ), .hps_0_ddr_oct_rzqin ( HPS_DDR3_RZQ ), /////////////////////////////////////////// HPS Ethernet 1 ////////////////////////////////////////////// .hps_0_io_hps_io_emac1_inst_TX_CLK ( HPS_ENET_GTX_CLK ), .hps_0_io_hps_io_emac1_inst_TXD0 ( HPS_ENET_TX_DATA[0] ), .hps_0_io_hps_io_emac1_inst_TXD1 ( HPS_ENET_TX_DATA[1] ), .hps_0_io_hps_io_emac1_inst_TXD2 ( HPS_ENET_TX_DATA[2] ), .hps_0_io_hps_io_emac1_inst_TXD3 ( HPS_ENET_TX_DATA[3] ), .hps_0_io_hps_io_emac1_inst_RXD0 ( HPS_ENET_RX_DATA[0] ), .hps_0_io_hps_io_emac1_inst_MDIO ( HPS_ENET_MDIO ), .hps_0_io_hps_io_emac1_inst_MDC ( HPS_ENET_MDC ), .hps_0_io_hps_io_emac1_inst_RX_CTL ( HPS_ENET_RX_DV ), .hps_0_io_hps_io_emac1_inst_TX_CTL ( HPS_ENET_TX_EN ), .hps_0_io_hps_io_emac1_inst_RX_CLK ( HPS_ENET_RX_CLK ), .hps_0_io_hps_io_emac1_inst_RXD1 ( HPS_ENET_RX_DATA[1] ), .hps_0_io_hps_io_emac1_inst_RXD2 ( HPS_ENET_RX_DATA[2] ), .hps_0_io_hps_io_emac1_inst_RXD3 ( HPS_ENET_RX_DATA[3] ), /////////////////////////////////////// SD Card (boot drive) ////////////////////////////////////////// .hps_0_io_hps_io_sdio_inst_CMD ( HPS_SD_CMD ), .hps_0_io_hps_io_sdio_inst_D0 ( HPS_SD_DATA[0] ), .hps_0_io_hps_io_sdio_inst_D1 ( HPS_SD_DATA[1] ), .hps_0_io_hps_
