{"id":20918341,"url":"https://github.com/duartegalvao/arduzynq-tutorials","last_synced_at":"2026-02-12T07:36:50.222Z","repository":{"id":119486211,"uuid":"205360186","full_name":"duartegalvao/ArduZynq-Tutorials","owner":"duartegalvao","description":"Simple tutorials for getting started with programming on Trenz ArduZynq boards.","archived":false,"fork":false,"pushed_at":"2019-09-17T08:27:16.000Z","size":1361,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-11-18T21:13:59.868Z","etag":null,"topics":["arduino-shield","arduzynq","fpga","fpga-board","rtl","te0723","trenz","tutorial","uart","vhdl","vivado","vivado-hls","xilinx","zynq-7000","zynq-7010","zynq-example-project"],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duartegalvao.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-30T10:31:05.000Z","updated_at":"2025-08-11T11:10:06.000Z","dependencies_parsed_at":null,"dependency_job_id":"b98df33a-a7f7-4ade-b5a2-abe441544abf","html_url":"https://github.com/duartegalvao/ArduZynq-Tutorials","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/duartegalvao/ArduZynq-Tutorials","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duartegalvao%2FArduZynq-Tutorials","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duartegalvao%2FArduZynq-Tutorials/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duartegalvao%2FArduZynq-Tutorials/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duartegalvao%2FArduZynq-Tutorials/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duartegalvao","download_url":"https://codeload.github.com/duartegalvao/ArduZynq-Tutorials/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duartegalvao%2FArduZynq-Tutorials/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29361621,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T01:03:07.613Z","status":"online","status_checked_at":"2026-02-12T02:00:06.911Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino-shield","arduzynq","fpga","fpga-board","rtl","te0723","trenz","tutorial","uart","vhdl","vivado","vivado-hls","xilinx","zynq-7000","zynq-7010","zynq-example-project"],"created_at":"2024-11-18T16:38:31.042Z","updated_at":"2026-02-12T07:36:50.206Z","avatar_url":"https://github.com/duartegalvao.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Getting Started with an ArduZynq Board\n\n[Duarte Alexandre Galvão](https://fenix.tecnico.ulisboa.pt/homepage/ist424753) (University of Lisbon - Instituto Superior Técnico)\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/TE0723-03M_0_600x600.jpg)\n\n*Picture source: https://shop.trenz-electronic.de/en/TE0723-03M-ArduZynq-Arduino-compatible-Xilinx-Zynq-7010-FPGA-module*\n\n## Introduction\n\n### Motivation\n\nThis starting guide is ment for people new to using Trenz ArduZynq boards, or FPGA boards in general, since the existing documentation and reference guides are not sufficient for a simple initial use from scratch.\n\nAdditionally, the [board's reference design](https://wiki.trenz-electronic.de/display/PD/TE0723+Test+Board \"TE0723 Reference Design\") requires running scripts that aren't compatible with Vivado's latest version (2019.1 at the time of writing), which is a drawback.\n\n### Goal\n\nThe goal of this tutorial is to run a simple \"Hello World\" on an ArduZynq board, bare metal (no OS underneath), and have its output shown on a console (via UART0).\n\n### Test Board\n\nFor this tutorial the following board was used:\n\n\u003e Trenz Eletronic \"ArduZynq\" TE0723 Arduino Shield SoC module with Xilinx Zynq-7010\n\u003e\n\u003e Vendor Part Number: TE0723-03M\n\nHowever, this tutorial could be applicable to any board of the TE0723 (\"ArduZynq\") family.\n\nThe software used was Vivado HLS 2019.1, and it should work on any version later than 2018.3 (or earlier, by using different board files).\n\n## Overview\n\nThis board contains a Xilinx Zynq-7010 SoC (\"System on Chip\"). Inside, it has a dual-core ARM Cortex A9 (the PS, or \"Processing System\"), as well as a programmable gate array (the PL, or \"Programmable Logic\", which is the actual \"FPGA\" part).\n\nIn this tutorial, you will run a \"Hello World\" on one of the cores of the ARM processor, using the chip's built-in RAM. The program will be loaded via JTAG and the output displayed via UART (both via the same USB port).\n\nLater tutorials will also look at how to make use of the PL.\n\n## Abbreviations\n\n| Abbreviation | Meaning                                       |\n| ------------ | --------------------------------------------- |\n| BSP          | Board Support Package                         |\n| FPGA         | Field-Programmable Gate Array                 |\n| PL           | Programmable Logic                            |\n| PS           | Processing System                             |\n| SoC          | System on Chip                                |\n| UART         | Universal Asynchronous Receiver-Transmitter   |\n\n## Table of Contents\n\n - Tutorial 1 - \"Hello World\" without PL\n   - Step 1.1 - Download Necessary Files\n   - Step 1.2 - Launch Vivado and Create a Project\n   - Step 1.3 - Set-up Block Design\n     - Step 1.3.1 - Understanding the Zynq-UART Connection\n   - Step 1.4 - Generate, Synthesize, Implement and Program\n   - Step 1.5 - Getting Started with SDK\n   - Step 1.6 - Running your Application\n\n More tutorials to be added in the future.\n\n\n\n# Tutorial 1 - \"Hello World\" without PL\n\n## Step 1.1 - Download Necessary Files\n\nTo create a project, first you will need to have the board files and constraints loaded onto Vivado.\n\nThese files are available bundled with the [reference design](https://wiki.trenz-electronic.de/display/PD/TE0723+Test+Board \"TE0723 Reference Design\"). Be careful to download the latest version that is compatible with your Vivado version.\n\nThen, copy the folders inside the \"board_files\" folder onto the \"board_files\" folder of your Vivado installation. For example, if you installed it in the default location, it should be on (in Windows): `C:\\Xilinx\\Vivado\\[VERSION]\\data\\boards\\board_files`.\n\n## Step 1.2 - Launch Vivado and Create a Project\n\nYou can now launch (or re-launch, if it was already opened) Vivado and create a new project.\n\nIn the wizard, choose a name:\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.1.PNG)\n\nOn the next screen, choose RTL Project.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.2.PNG)\n\nHere you can add any sources (any custom IPs you might want, for example). For this tutorial you don't need to anything here.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.3.PNG)\n\nThe constraints are important for this tutorial. You will need to add the constraints when working with PL (which you will later see they are used to route the UART).\n\nThe constraints are in the \"constraints\" folder of the reference design, and you can just add them all here (as shown in the screenshot).\n\nAdditionally, you might want to check \"Copy constraints into project\" if you ever intend to move or delete the reference design.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.4.PNG)\n\nNext, click on \"Boards\", and choose the appropriate board. If you aren't sure which one is it, check the CSV file on the \"board_files\" folder of the reference design.\n\nIn this case, since I am using a TE0723-03M, I will choose the TE0723_M (REV03). Check on the side of the box for the Vendor Part Number.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.5.PNG)\n\nNow, you can just click \"Finish\" to finish creating the project.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.2.6.PNG)\n\n## Step 1.3 - Set-up Block Design\n\nNow that the project is set up, you will need to create a board design, which will model how the hardware is used.\n\nOn the left pane (\"Flow Navigator\"), click on \"Create Block Design\" (under \"IP INTEGRATOR\"). You can choose any design name and click \"OK\".\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.1.PNG)\n\nYou now have an empty block design. The first block (or \"IP\") you should add is the PS, so you can make use of the ARM processor and its I/Os.\n\nPress the \"+\" button, search for the \"ZYNQ7 Processing System\" and press ENTER. The block should be added to the diagram.\n\nNow, click \"Run Block Automation\" (it should appear on a green bar in the top of the diagram). Run with the default settings, and you will get something like this:\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.2.PNG)\n\nBlock automation basically connects automatically the most essential components. In this case, it connected the PS to the DDR RAM and some basic IOs.\n\nYou can see that on this block there are a lot of unused ports. Ideally, these should be removed, to get it down to essentials.\n\nDouble-click on the PS block to open the \"Re-customize IP\" window. Here you can disable all the unnecessary ports.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.3.PNG)\n\nOn the \"MIO Configuration\", you should disable:\n - Memory Interfaces -\u003e Quad SPI Flash\n - I/O Peripherals -\u003e USB 0\n - I/O Peripherals -\u003e SD 1\n - I/O Peripherals -\u003e UART 1\n - I/O Peripherals -\u003e I2C 0\n - I/O Peripherals -\u003e GPIO -\u003e GPIO MIO\n - Application Processor Unit -\u003e Timer 0\n - Application Processor Unit -\u003e Timer 1\n - Application Processor Unit -\u003e Watchdog\n\n(Basically, disable everything but UART 0 on EMIO)\n\nOn the \"Clock Configuration\", you should disable:\n - PL Fabric Clocks -\u003e FCLK_CLK0\n\nOn the \"PS-PL Configuration\", you should disable:\n - General -\u003e Enable Clock Resets -\u003e FCLK_RESET0_N\n - AXI Non Secure Enablement -\u003e GP Master AXI Interface -\u003e M AXI GP0 interface\n\nWhen you click \"OK\", your block diagram should look like this:\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.4.PNG)\n\nSince UART_0 is routed trough EMIO (which goes trough the PL, unlike MIO pins which have defined paths on the device), its port will show up on the block. You now need to connect it to the proper I/O port via the PL.\n\nRight-click anywhere and select \"Create Interface Port\". Choose a name for it (like \"UART_0\"), and find the UART RTL interface. Select it and click \"OK\".\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.5.PNG)\n\nThen, connect the port on the PS to the Interface Port you just created.\n\nTo finish, click on the \"Regenerate Layout\" (![](img/regen.PNG)) button and then on \"Validate Design\" (![](img/validate.PNG)). You should do this every time you change anything on the block design.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.3.6.PNG)\n\nThen, on the Sources panel, right-click on the design_1 source and select \"Create HDL Wrapper\". Here, you can choose the option \"Let Vivado manage wrapper and auto-update\", for ease of use if you want to later change the block design.\n\n### Step 1.3.1 - Understanding the Zynq-UART Connection\n\nThis VHDL wrapper contains the description of the connection of the I/O ports, and it is the starting point for understanding the connection between the Zynq chip and the FTDI FT232H (the chip that handles UART communications via USB). You can open the wrapper by double-clicking on it, and there you will see the `UART_0_rxd` and `UART_0_txd` ports, for receiving and transmitting respectively:\n\n```vhdl\nentity design_1_wrapper is\n  port (\n    DDR_addr : inout STD_LOGIC_VECTOR ( 14 downto 0 );\n    DDR_ba : inout STD_LOGIC_VECTOR ( 2 downto 0 );\n    DDR_cas_n : inout STD_LOGIC;\n    DDR_ck_n : inout STD_LOGIC;\n    DDR_ck_p : inout STD_LOGIC;\n    DDR_cke : inout STD_LOGIC;\n    DDR_cs_n : inout STD_LOGIC;\n    DDR_dm : inout STD_LOGIC_VECTOR ( 1 downto 0 );\n    DDR_dq : inout STD_LOGIC_VECTOR ( 15 downto 0 );\n    DDR_dqs_n : inout STD_LOGIC_VECTOR ( 1 downto 0 );\n    DDR_dqs_p : inout STD_LOGIC_VECTOR ( 1 downto 0 );\n    DDR_odt : inout STD_LOGIC;\n    DDR_ras_n : inout STD_LOGIC;\n    DDR_reset_n : inout STD_LOGIC;\n    DDR_we_n : inout STD_LOGIC;\n    FIXED_IO_ddr_vrn : inout STD_LOGIC;\n    FIXED_IO_ddr_vrp : inout STD_LOGIC;\n    FIXED_IO_mio : inout STD_LOGIC_VECTOR ( 31 downto 0 );\n    FIXED_IO_ps_clk : inout STD_LOGIC;\n    FIXED_IO_ps_porb : inout STD_LOGIC;\n    FIXED_IO_ps_srstb : inout STD_LOGIC;\n    UART_0_rxd : in STD_LOGIC;\n    UART_0_txd : out STD_LOGIC\n  );\nend design_1_wrapper;\n```\n\nThe list below is part of the constraints file related to the UART0. In the `_i_io.xdc` file you will find the following properties:\n\n```\n# UART0 to FTDI\nset_property PACKAGE_PIN H14 [get_ports UART_0_txd]\nset_property PACKAGE_PIN H13 [get_ports UART_0_rxd]\n\nset_property PACKAGE_PIN J15 [get_ports UART_0_ctsn]\nset_property PACKAGE_PIN J14 [get_ports UART_0_rtsn]\n\nset_property PACKAGE_PIN K15 [get_ports UART_0_dsrn]\nset_property PACKAGE_PIN L15 [get_ports UART_0_dtrn]\n\n#NC: UART_0_dcdn, UART_0_ri\nset_property PACKAGE_PIN L14 [get_ports UART_0_dcdn]\nset_property PACKAGE_PIN M15 [get_ports UART_0_ri]\n\nset_property IOSTANDARD LVCMOS33 [get_ports UART_0_*]\n```\n\nThis is establishing where the pins of the chip (designated by a letter and two digits; essentially a coordinate of the pin) are wired to in the board. This information only partially shown in the [board's Technical Reference Manual](https://wiki.trenz-electronic.de/display/PD/TE0723+TRM#TE0723TRM-USB2toJTAG/UARTAdapter \"TE0723 Technical Reference Manual\"), so it is important to look at these constraint files to understand what each pin does.\n\nInspecting the contraints file showed that pins `H14` and `H13` are wired to the FTDI's \"Transmit\" and \"Receive\" pins respectively.\n\nThis architecture is different from that of other Xilinx Zynq-7000 boards, such as Digilent's Zybo and Zedboard, in which the FTDI is wired directly to certain MIO pins (usually 48..49), which have a direct connection to the PS, rather than having to route the UART via the PL.\n\n## Step 1.4 - Generate, Synthesize, Implement and Program\n\nNow, you need to run trough a routine with the end goal of generating a bitstream, a map of the intended state of the PL of our FPGA chip.\n\nBasically, run the following actions on the \"Flow Navigator\", with the default settings:\n - Generate Block Design\n - Run Synthesis\n - Run Implementation\n - Generate Bitstream\n\nFor the last three actions, the status of the operation will appear on the top right of your Vivado window. Wait for each to end before running the next.\n\nIn the end, if everything is done right, you will have a bitstream you can program into your FPGA.\n\n## Step 1.5 - Getting Started with SDK\n\nNow, go to \"File\" -\u003e \"Export\" -\u003e \"Export Hardware\". This will export your hardware definitions to the SDK. Don't forget to tick \"Include Bitstream\".\n\nThen, click \"File\" -\u003e \"Launch SDK\".\n\nOn the SDK, go to \"File\" -\u003e \"New\" -\u003e \"Board Support Package\". This will create the basic software libraries you will need for your application. Make sure to select \"standalone\", since the application is to be run on bare metal.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.5.1.PNG)\n\nIt will then ask for any libraries you might want to include. These are not necessary for this tutorial.\n\nOnce the BSP is created, you can create your application. Go to \"File\" -\u003e \"New\" -\u003e \"Application Project\", choose a name, and make sure to use the existing BSP.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.5.2.PNG)\n\nThen click \"Next\" (not \"Finish\"!) and choose a template. Choose the \"Hello World\", which is usually the default selected. Then press \"Finish\".\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.5.3.PNG)\n\nOn the left pane (\"Project Explorer\") you should see the Hardware Platform (the code that is generated when you \"Export Hardware\"), your newly created application and the BSP.\n\nMake sure that you delete and regenerate the BSP every time you change anything on the block design, since it does not automatically update its drivers.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.5.4.PNG)\n\nUnder your application you will find a \"src\" (sources) folder, and inside you will have some helper libraries (\"platform\" .c and .h), your linker script (\"lscript.ld\") and of course the hello world code itself, \"helloworld.c\":\n\n```c\n#include \u003cstdio.h\u003e\n#include \"platform.h\"\n#include \"xil_printf.h\"\n\n\nint main()\n{\n    init_platform();\n\n    print(\"Hello World\\n\\r\");\n\n    cleanup_platform();\n    return 0;\n}\n```\n\nNotice the included libraries. The \"platform\" has the init and cleanup functions, which intialize UART and deal with the caches, among other possible actions.\n\nThe \"print\" function being used is not from *stdio*, but rather from \"xil_printf\", which is a minimalistic implementation of *printf* created by Xilinx, ideal for very low memory systems. The drawback, however, is that it can't print floating point numbers.\n\n## Step 1.6 - Running your Application\n\nThe application is complete, but before running, let's adjust some properties on the linker script. In the \"Project Explorer\", right-click on the application project and press \"Generate a linker script\".\n\nNote that all memory management here is done by you, the developer. To simplify this tutorial, only the built-in RAM of the chip is going to be used, instead of the DDR that is used by default. This is a small application, so it shouldn't be a problem.\n\nSelect \"ps7_ram_0\" on all the options, and to be safe, increase the stack size to 10KB (add a zero to the end).\n\nIt should look like this:\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.6.1.PNG)\n\nClick \"Generate\" (and overwrite the existing linker script) and the program is now ready to be run on your board.\n\nConnect it to your computer (make sure you are using the board's JTAG USB port and not the USB OTG).\n\nNow, let's program the FPGA. Press \"Xilinx\" -\u003e \"Program FPGA\" and use the bitstream you exported to the SDK earlier (it should appear on the \"Bitstream\" field by default\") and click \"Program\":\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.6.2.PNG)\n\nThe Block Design created earlier should now be programmed on the PL of the Zynq chip. All that's left is loading the application onto the chip and running it.\n\nTo see the output of the program, you will need to open a terminal on your computer, connected to the serial port on which the board is connected. To do so, on the \"SDK Terminal\" pane (that should be on the bottom of the window), click on the \"+\" to add a connection to the terminal.\n\nChoose the correct COM port (this varies from computer to computer, so you might have to try several). Make sure the Baud Rate is 115200, otherwise you will not be able to read the UART output.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.6.3.PNG)\n\nOnce the terminal is connected, you can run the application. For the first time running, you need to right-click on it in the \"Project Explorer\" and press \"Run As\" -\u003e \"Run Configurations...\".\n\nSelect \"Xilinx C/C++ application (System Debugger)\" and press the ![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/new.PNG) button on the top bar to create the new Run configuration.\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.6.4.PNG)\n\nNow click \"Run\".\n\nA \"Hello World\" should appear on the \"SDK Terminal\":\n\n![](https://github.com/duartegalvao/ArduZynq-Tutorials/raw/master/img/screen1.6.5.PNG)\n\nThe \"Hello World\" has successfully run on your board! It is now possible to use the \"run\" button on the top of the window.\n\n# Acknowledgements\n\nTo Professor Horácio Neto, who wrote the equivalent tutorial for Digilent Zybo boards (\"Hardware/Software Co-Design - Introductory Lab, Horácio Neto, February 2019\") upon which this is based on, and to Professor Rui P. Duarte, for the orientation in understanding and deciphering the inner workings of the platform.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduartegalvao%2Farduzynq-tutorials","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduartegalvao%2Farduzynq-tutorials","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduartegalvao%2Farduzynq-tutorials/lists"}