Agilex5 HPS running bare-metal code does not access FPGA fabric - Agilex5 HPS running bare-metal code does not access FPGA fabric
I started with the following "Hello World" HPS OCRAM example: https://altera-fpga.github.io/rel-25.1/baremetal-embedded/agilex-5/e-series/premium/ug-baremetal-agx5e-premium/ I built the GHRD image with FPGA boot load set to "fabric first" and compiled the C code. With these changes, I am able to run the code and I can see the heartbeat LED toggle on the A5E premium development kit board. I am also able transmit data by writing the UART transmit register with my REG32 macro. However, I cannot access either H2F or LWH2F interfaces. I put Signal Tap on all arvalid/awvalid signals I and I do not see them toggle (I sanity checked the setup using the heartbeat counter). After looking at the documentation and the provided bare-metal drivers code, I cobbled together the following code to attempt to enable the HPS2 FPGA bridges: #define REG32(address) (*(volatile uint32_t*)address) #define REG64(address) (*(volatile uint64_t*)address) // Read the Reset manager registers uint32_t value32; value32 = REG32(0x10D1102C); printf("Reset manager initial value = 0x%08x \n", value32); // Drop the reset for SOC2FPGA bridges REG32(0x10D1102C) = 0; value32 = REG32(0x10D1102C); printf("Reset manager value after modification = 0x%08x \n", value32); printf("Enable FPGA bridges (NOTE: is this really an enable?)\n"); REG32(0x10D1205C) = 0x3; value32 = REG32(0x10D1205C); printf("Bridge enable register value after modification = 0x%08x \n", value32); Running this code I see: Reset manager initial value = 0x0000004f Reset manager value after modification = 0x00000000 Enable FPGA bridges Bridge enable register value after modification = 0x00000003 However, this loop does not show AWVALID come up on either AXI interface (I tried two different write macros to see if there is a difference): while (1) { printf("H2F: FPGA OCRAM write\n"); REG64(0x40000000) = 0x11223344; printf("H2LWF: LED controller write\n"); mem_quick_write_32(0x20010080, 0); } I feel like I am missing something obvious (like another enable) but I keep going over the code examples and the documentation and I can't find anything that could help. Any help is greatly appreciated.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi nhadzic, I will transition this thread to community support since the issue has been resolved. Thanks Regards Kian
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
I think I am all set. To summarize: I never figured out how to run true bare metal (my original track) However, I am now using FreeRTOS as Radu suggested which is working out well I will mark Radu's FreeRTOS instructions as the resolution. Once again, thanks to all that helped.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
You can create an intermediate JIC with uboot to load the sdimage via TFTP and write to SD. Flash the uboot JIC load the SD image via TFTP Write the SD image to the card Flash the JIC build for your App (to boot from SD card) You can follow the steps shown here: https://altera-fpga.github.io/rel-24.2/embedded-designs/agilex-5/e-series/premium/boot-examples/ug-linux-boot-agx5e-premium/#boot-from-sd-card14 Go to section " Create Helper JIC " and follow the steps shown. The steps shown there is for eMMC but you can easily adapt it for SD card. Note: Make sure to enable the proper GMAC module for your board when building uboot For all boards except eMMC/NAND board, we need GMAC2 instance
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Success! With the 25.3.1 version I am able to build the GHRD and combine it with my FreeRTOS build. Now that I have some hands on work with FreeRTOS, I will continue using it instead of the bare-metal approach. Edit: I removed the part where I claimed I can do all updates through the QSPI burn. I changed the system revision ID in the and I cannot see the new value until I burn the SD card. This makes sense when I look at the serial console: Starting the bridge sample application Read 251000 bytes from sdmmc drive successfully Bitstream data send successfully bitstream configuration successful Bitstream loaded successfully I have one final question regarding the SD card usage. The bridge example runs from the SD card which is still a manual step to remove the card, burn it and then re-install. Is there an easy way to include the OS as a part of the SOF/qspi_image.jic? If not, I will just burn the SD card when I update the test program. It may be less efficient but at least I can now start my HW test.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Today I followed the build steps outlined by Radu and I was able to build and run the Free RTOS image using the downloaded GHRD image. The serial output matches what he posted. Once I got everything set up, the process was simple and I was able to burn the QSPI image even with the DIP switches set to AS4 (just like zamroodh said). Thanks again to both! This is great progress. However, I cannot use my own GHRD image yet. I have Quartus 25.3 installed so I re-downloaded both the 25.3 Quartus project (a5ed065es-premium-devkit-debug2-legacy-baseline.zip) and I updated the freertos source to 25.3 tag. With this combination, I get the following output when I use the project as-is (no RTL changes): ERROR: CLKMGR: Timed out to satisfy the PLL mask ERROR: SOCFPGA: Failed to initialize the clock manager PANIC at PC : 0x000000000000400c I noticed that the FPGA image in Radu's example came from the 26.1 directory (agilex5_dk_a5e065bb32aes1_gsrd.baseline-a55) which is a 25.3.1 project and it fails the compile in 25.3 due to missing IP. The next step is to install 25.3.1 overnight to build that image and see what happens.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Thanks. As you said, remote power cycle will not be a problem. I'll give it a try and report back.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
With above steps and the switchs in default position, we are able to program the device. But we need to perform a powercycle after the programming. We use a network enabled power controller to toggle the device power.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Thanks for the reply. I am familiar with the QSPI burn process, however, I thought I needed to set the SW27 switch back to AS4 in order to boot the new image. That would mean I still need to be physically in the lab in order to update the image so the process is not completely remote. Am I misunderstanding the process?
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi nhadzic , You could upload the JIC to the system with one command. Run jtagconfig command, you will get something similar to the following $ jtagconfig 1) Agilex 5E065B Premium DK [1-10.1] 4BA06477 ARM_CORESIGHT_SOC_600 0364F0DD A5E(C065BB32AR0|D065BB32AR0) 020D10DD VTAP10 here we can see that A5E is at index 2, now with that info we could directly load the JIC to the device with the following command $ quartus_pgm -c 1 -m jtag -o "pvi;qspi_image.jic@2" this will upload qspi_image.jic to the device and it is expected in the current folder. You can refer the steps RaduB_Altera posted to build FreeRTOS samples which will produce the JIC images for you if you are going that route. PS: Assuming that you are using Quartus version 25.3
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
I admit I may be going about this the wrong way. My goal is to be able to remotely update both the FPGA image and the test code through JTAG using quartus_pgm. So far, all OS examples I have seen require the sequence of "DIP switch to JTAG, burn the JIC file, DIP switch to AS4" + possible SD card burn. I've done that several times as I went through tutorials and it felt like an overkill for what I am trying to do. So through experimentation I was able to take the OCRAM "hello world" example, purely load it through the JTAG and execute the code. But the problem is I can't seem to access FPGA bridges with this method. Is there a way to update both the image and the FreeRTOS code through JTAG (or any other fully remote method). If so, then I will gladly switch to FreeRTOS since it will likely help with other setup as well. Thanks in advance.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi Nhadzic, Can you share more on why 1-task FreeRTOS doesn't meet your needs here but Bare Metal does? FreeRTOS is a very thin scheduler, and when run with only 1 task is near identical to Bare Metal. Thanks.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi, If you only need this for validating the IP in the fabric, and do not want to use the RTOS, I reccomend to use U-Boot applications. They run inside U-Boot, but have separate source code and can be compiled individually. See below a complete example on how to do it: # top folder sudo rm -rf artifacts mkdir artifacts cd artifacts export TOP_FOLDER=`pwd` # compiler toolchain cd $TOP_FOLDER wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/\ arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz tar xf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz rm -f arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz export PATH=`pwd`/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-linux-gnu/bin/:$PATH export CROSS_COMPILE=aarch64-none-linux-gnu- # quartus export QUARTUS_ROOTDIR=~/altera_pro/25.3.1/quartus/ export PATH=$QUARTUS_ROOTDIR/bin:$QUARTUS_ROOTDIR/linux64:$QUARTUS_ROOTDIR/../qsys/bin:$PATH # sof cd $TOP_FOLDER wget -O ghrd.sof https://releases.rocketboards.org/2026.01/gsrd/agilex5_dk_a5e065bb32aes1_gsrd.baseline-a55/baseline_a55_hps.sof # atf cd $TOP_FOLDER rm -rf arm-trusted-firmware git clone -b QPDS25.3.1_REL_GSRD_PR https://github.com/altera-fpga/arm-trusted-firmware cd arm-trusted-firmware make -j 48 PLAT=agilex5 bl31 cd .. # u-boot cd $TOP_FOLDER rm -rf u-boot-socfpga git clone -b QPDS25.3.1_REL_GSRD_PR https://github.com/altera-fpga/u-boot-socfpga cd u-boot-socfpga sed -i 's/u-boot,spl-boot-order.*/u-boot\,spl-boot-order = \&mmc;/g' arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi sed -i '/&nand {/!b;n;c\\tstatus = "disabled";' arch/arm/dts/socfpga_agilex5_socdk-u-boot.dtsi ln -s ../arm-trusted-firmware/build/agilex5/release/bl31.bin cat << EOF > config-fragment CONFIG_BOOTDELAY=2 CONFIG_BOOTFILE="Image" CONFIG_NAND_BOOT=n CONFIG_SPL_NAND_SUPPORT=n CONFIG_CMD_NAND_TRIMFFS=n CONFIG_CMD_NAND_LOCK_UNLOCK=n CONFIG_NAND_DENALI_DT=n CONFIG_SYS_NAND_U_BOOT_LOCATIONS=n CONFIG_SPL_NAND_FRAMEWORK=n CONFIG_CMD_NAND=n CONFIG_MTD_RAW_NAND=n CONFIG_CMD_UBI=n CONFIG_CMD_UBIFS=n CONFIG_MTD_UBI=n CONFIG_ENV_IS_IN_UBI=n CONFIG_UBI_SILENCE_MSG=n CONFIG_UBIFS_SILENCE_MSG=n CONFIG_DISTRO_DEFAULTS=n CONFIG_HUSH_PARSER=y CONFIG_SYS_PROMPT_HUSH_PS2="> " CONFIG_USE_BOOTCOMMAND=y CONFIG_BOOTCOMMAND="mmc rescan;load mmc 0:1 \${loadaddr} ghrd.core.rbf;fpga load 0 \${loadaddr} \${filesize};bridge enable; load mmc 0:1 0x90000000 fpga_test.bin" CONFIG_CMD_FAT=y CONFIG_CMD_FS_GENERIC=y CONFIG_DOS_PARTITION=y CONFIG_SPL_DOS_PARTITION=y CONFIG_CMD_PART=y CONFIG_SPL_CRC32=y CONFIG_LZO=y CONFIG_CMD_DHCP=y CONFIG_API=y CONFIG_EXAMPLES=y CONFIG_SYS_MMC_MAX_DEVICE=1 EOF # enable u-boot applications sed -i '/extra-$(CONFIG_PPC) *. += sched/a extra-y += fpga_test' examples/standalone/Makefile sed -i 's/LOAD_ADDR:.*/LOAD_ADDR:=0x90000000/g' examples/standalone/Makefile sed -i '/# Disable LTO/a CFLAGS_REMOVE_fpga_test.o := $(LTO_CFLAGS)' examples/standalone/Makefile # enter source code for the u-boot application cat << 'EOF' > examples/standalone/fpga_test.c #include <exports.h> int fpga_test(int argc, char *const argv[]) { unsigned long addr; unsigned long val; volatile uint32_t *reg; int i; app_startup(argv); if (get_version() != XF_VERSION) { printf("ABI version mismatch!\n"); return 1; } printf("FPGA fabric test\n"); printf("argc = %d\n", argc); for (i = 0; i < argc; i++) printf("argv[%d] = \"%s\"\n", i, argv[i]); if (argc < 2) { printf("Usage: go <load_addr> <address> [value]\n"); printf(" address: memory/register address to access\n"); printf(" value: if provided, write this value first\n"); return 1; } addr = simple_strtoul(argv[1], NULL, 16); reg = (volatile uint32_t *)addr; if (argc >= 3) { val = simple_strtoul(argv[2], NULL, 16); printf("Writing 0x%08lx to 0x%08lx\n", val, addr); *reg = (uint32_t)val; } printf("Read 0x%08lx => 0x%08x\n", addr, *reg); return 0; } EOF # build u-boot make clean && make mrproper make socfpga_agilex5_defconfig ./scripts/kconfig/merge_config.sh -O . -m .config config-fragment make -j 64 cd .. # build hps.jic and core.rbf cd $TOP_FOLDER quartus_pfg -c $TOP_FOLDER/ghrd.sof ghrd.jic \ -o device=MT25QU128 \ -o flash_loader=A5ED065BB32AE6SR0 \ -o hps_path=$TOP_FOLDER/u-boot-socfpga/spl/u-boot-spl-dtb.hex \ -o mode=ASX4 \ -o hps=1 # build sd card cd $TOP_FOLDER sudo rm -rf sd_card && mkdir sd_card && cd sd_card wget https://releases.rocketboards.org/release/2020.11/gsrd/tools/make_sdimage_p3.py sed -i 's/\"\-F 32\",//g' make_sdimage_p3.py chmod +x make_sdimage_p3.py mkdir fatfs && cd fatfs cp $TOP_FOLDER/u-boot-socfpga/u-boot.itb . cp $TOP_FOLDER/ghrd.core.rbf . cp $TOP_FOLDER/u-boot-socfpga/examples/standalone/fpga_test.bin . cd .. sudo python3 make_sdimage_p3.py -f \ -P fatfs/*,num=1,format=vfat,size=20M \ -s 32M \ -n sdcard.img cd .. At the end you will have the following files: $TOP_FOLDER/ghrd.hps.jic - QSPI image $TOP_FOLDER/sd_card/sdcard.img - SD card image Then write the JIC and SD card image, boot the board and let U-Boot run its 'boot' commad which will load the core.rbf, then load the custom u-boot application at address 0x90000000: mmc rescan; load mmc 0:1 ${loadaddr} ghrd.core.rbf; fpga load 0 ${loadaddr} ${filesize}; bridge enable; load mmc 0:1 0x90000000 fpga_test.bin Then it will drop to U-Boot console, and you can run the sample u-boot application. The code provided above is similar with the devmem2 application, in that it just reads and writes memory. Here is an example usage that reads the Sysid, then reads the OCRAM, writes another value to OCRAM, then reads it back: SOCFPGA_AGILEX5 # go 0x90000000 0x20010000 ## Starting application at 0x90000000 ... FPGA fabric test argc = 2 argv[0] = "0x90000000" argv[1] = "0x20010000" Read 0x20010000 => 0x00000001 ## Application terminated, rc = 0x0 SOCFPGA_AGILEX5 # go 0x90000000 0x40000000 ## Starting application at 0x90000000 ... FPGA fabric test argc = 2 argv[0] = "0x90000000" argv[1] = "0x40000000" Read 0x40000000 => 0x00000000 ## Application terminated, rc = 0x0 SOCFPGA_AGILEX5 # go 0x90000000 0x40000000 0x12345678 ## Starting application at 0x90000000 ... FPGA fabric test argc = 3 argv[0] = "0x90000000" argv[1] = "0x40000000" argv[2] = "0x12345678" Writing 0x12345678 to 0x40000000 Read 0x40000000 => 0x12345678 ## Application terminated, rc = 0x0 SOCFPGA_AGILEX5 # go 0x90000000 0x40000000 ## Starting application at 0x90000000 ... FPGA fabric test argc = 2 argv[0] = "0x90000000" argv[1] = "0x40000000" Read 0x40000000 => 0x12345678 ## Application terminated, rc = 0x0 You would change the U-Boot application according to your needs, then just run 'make' in the U-Boot folder to rebuild the app. You could write the app back on the SD card, but you could also TFTP over network, to speed up iteration time. Also, you could download the core.rbf over network too, to reduce time. And if you do massive changes in the hardware design, and you need to also change the jic, you could switch to configuring with an rbf with the Quartus Programmer instead. Thank you, Radu
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi Radu, Thank you so much for the pointers. I did find the bridge helper code last week and I used it as a reference for my code but never thought to compile it straight up. Today I did the compile and I can see the code go through the correct test sequence ending with "Bridge Test is successful!". Then I inserted H2F and H2LW direct write operations at the start of the bridge_disable function (before any disables are done) but I still do not see any accesses in SignalTap. I am using the physical address to attempt accesses to the fabric which I assumed would works since the core is in the bare metal mode. Is this the wrong way to do this? For example, the reset manager is accessed through '/dev/rstmgr' and the grep does not find anything for the fabric memory map. FYI, the goal is to be able to do a sanity check of my custom HW connected to the HPS before I hand it off to the FW team which will run the full OS stack. I prefer not to run an RTOS but I will definitely give it a try if nothing else works. I'll keep digging.
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Looked more closely in the bare-metal repo, and found this: https://github.com/altera-fpga/baremetal-drivers/blob/QPDS25.1_REL_GSRD_PR/helpers/bridge_helper.cpp . It appears to implement the correct sequence for enabling the bridges. Regards, Radu
Replies:
Re: Agilex5 HPS running bare-metal code does not access FPGA fabric
Hi, I do not have time to look into it now, and will be out Monday But if you want to use FreeRTOS, see below the instructions on how to make it work there: # install cmake and ninja build tools sudo apt-get install cmake ninja-build # create a top folder sudo rm -rf artifacts && mkdir artifacts && cd artifacts export TOP_FOLDER=`pwd` # add quartus tool to path export QUARTUS_ROOTDIR=~/altera_pro/25.3.1/quartus/ export PATH=$QUARTUS_ROOTDIR/bin:$QUARTUS_ROOTDIR/linux64:$QUARTUS_ROOTDIR/../qsys/bin:$PATH # download toolchain and add to path cd $TOP_FOLDER wget https://developer.arm.com/-/media/Files/downloads/gnu/14.3.rel1/binrel/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz tar xf arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz rm -f arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf.tar.xz export PATH=`pwd`/arm-gnu-toolchain-14.3.rel1-x86_64-aarch64-none-elf/bin/:$PATH # get freertos cd $TOP_FOLDER git clone https://github.com/Ignitarium-Technology/freertos-socfpga cd freertos-socfpga git checkout -b test v25.4 git submodule update --init --recursive # get sof file cd $TOP_FOLDER wget -O ghrd_a5ed065bb32ae6sr0.sof https://releases.rocketboards.org/2026.01/gsrd/agilex5_dk_a5e065bb32aes1_gsrd.baseline-a55/baseline_a55_hps.sof # build the bridge example cd $TOP_FOLDER/freertos-socfpga/samples/bridge cmake -B build . -G Ninja -DSOF_PATH=$TOP_FOLDER/ghrd_a5ed065bb32ae6sr0.sof cmake --build build --parallel -t sd-image Once you build it,you will get the following files: JIC QSPI Image: $TOP_FOLDER/freertos-socfpga/samples/bridge/build/sd_atf_binaries/qspi_image.jic SD Card Image: $TOP_FOLDER/freertos-socfpga/samples/bridge/build/sd_atf_binaries/sd.img Write the above images and boot the board. You will see this: ... NOTICE: DDR: Reset type is 'Power-On' NOTICE: IOSSM: Calibration success status check... NOTICE: IOSSM: All EMIF instances within the IO96 have calibrated successfully! NOTICE: DDR: Calibration success NOTICE: DDR: ECC is enabled NOTICE: IOSSM: Memory initialized successfully on IO96B NOTICE: ###DDR:init success### NOTICE: DFI interface selected successfully to SDEMMC NOTICE: SOCFPGA: SDMMC boot NOTICE: BL2: v2.13.0(release): NOTICE: BL2: Built : 20:29:07, Feb 13 2026 NOTICE: BL2: Booting BL31 NOTICE: SOCFPGA: Boot Core = 0 NOTICE: SOCFPGA: CPU ID = 0 NOTICE: SOCFPGA: Setting CLUSTERECTRL_EL1 NOTICE: BL31: v2.13.0(release): NOTICE: BL31: Built : 20:29:07, Feb 13 2026 Starting the bridge sample application Read 217000 bytes from sdmmc drive successfully Bitstream data send successfully bitstream configuration successful Bitstream loaded successfully Starting h2f sample Write data buffer 1 : 1111111111111111 buffer 2 : 2222222222222222 Writing data to memory 0x40000000 Writing data to memory 0x7ffffff8 Reading data from memory 0x40000000 Reading data from memory 0x7ffffff8 Read data buffer 1 : 1111111111111111 buffer 2 : 2222222222222222 Validating the buffers Buffer validation successful HPS2FPGA sample completed successfully Completed h2f sample Starting lwh2f sample SYSID_ID : 1 WRITE DATA write buffer : 11111111 READ DATA read buffer : 11111111 LWHPS2FPGA sample completed successfully Completed lwh2f sample Bridge sample completed I actually prefer using an RTOS versus pure bare-metal, as it offers a lot of convenience. If you do not need the features, you can just put all your code in a single task (like the above example) and ignore them. Note the above example uses HPS First (the default for the GSRD) and it configures the fabric with the file core.rbf which it builds and puts in the SD card image. It also uses DDR instead of OCRAM. Regards, Radu - 2026-02-13
external_document