Translate

Monday, 25 February 2019

Run the test driver on the MiniZed board with a standalone Zynq design



Hi !

In this post we will use what has been done for the MicroBlaze standalone design to test our custom IP's driver. If you've missed it, have a look to this post and the previous ones.

2.5 - How to create a standalone driver to handle a custom IP

The goal of this post is quite simple, remove the MicroBlaze that we used for simulation and replace it with a Zynq core to have it running on the MiniZed board.

As this post is quite long, here are the main sections of this post for a quick jump :







Step 1 : Remove the MicroBlaze core from the FPGA design



Stage 1


The first thing to do is to create a copy of the MicroBlaze design.

So go to File, Project and Save as.




Then provide the name of the project and click Ok.




The project is then created and opened in VIVADO, ready to use.


Stage 2


As we are in the project, open the Block Design.

Select all the IPs that are to be replaced : MicroBlaze, Local memory, Reset and interconnect.




Delete those IPs, and confirm delete by clicking Ok.




Now the Block Design should contain our LED IP, its output led_out_0 port and some other reset and clock ports.




Step 2 : Add the Zynq core to the FPGA design



Stage 1


Now we will add the Zynq Core IP.

Click on the Add button, or use CTRL+I to open the search IP window.

Search for Zynq.

Select the provided ZYNQ7 Processing System.




Stage 2


So we get the Zynq core IP, but more important, the tool provides 2 designer assistances that will do part of the job for us !




Read this !

The Zynq core IP is a small box, but it contains all the ARM core details, so it is quite a huge set of parameters !

It is mandatory to edit it to set the configuration, at least to set dedicated IOs to be aligned to how they have been used on the board.


The Run Block Automation assistance will help configure the Zynq core IP. This assistance is proposed because we have configured the project with a board, not only a device. In this case the way the Zynq core has been used on the board is known in a preset file that is associated to the project at its creation. Read the explainations of this assistance pop up windows.




Then the result is a configured Zynq core IP.


Stage 3


As the clock and the reset will be generated by the Zynq core IP, you can delete the clock and reset input ports defined in the MicroBlaze version.

Configuration is done but is not enougth to interface our IP !

We don't care about the GPIO, UART, IIC, SDIO, USB, FCLK_CLK_1 so we can configure the Zynq core to take them out, but the main problem is that we need an AXI Lite bus to let the Zynq core communicate with our IP !! We will have to  add it.




Once configured, we get the new Zynq core IP. Notice that the Run Connection Automation assistance is still pending.




Stage 4


If now we launch the Run Connection Automation, everything is connected by the tool !




To check that everything is correct in our Block design, launch the validation procedure with the F6.




Step 3 : Generate the bitsream



Stage 1


When using the Zynq core IP with the board's preset file, all the dedicated IOs of the Zynq core have been handled properly automatically.

What we still have to do is to provide constraints for the PL section. In our test project we only have to handle our led_out_0 port to associate it with a LED on the MiniZed board.

We will do it manually. It means that we have to create a constraint file. Then we have to add the constraints for pin placement and IO standard. To find these informations we will have to search in the schematics of the board or in the board's provided documentation.

The constraint file creation process is the following.

- Click on Add Source,
- Select Add or Create Constraint,
- Click Next,
- Click on Create File,
- Provide the Constraint file name and select file location (I let VIVADO handle it for me),
- Click OK,
- Click Finish,
- Click Finish.




Stage 2


Now open the just created empty constraint file.

Add the following lines to use the available Green LED of the MiniZed Board.




Stage 3


Everything is set up, launch the bitstream generation by clicking on Generate Bitstream.

Select the number of processor cores to do the job in the Launch Runs pop up.

Click Ok.




The generation begins. On my laptop it took about 3 minutes.


Stage 4


Let's check the LED output has been implemented properly.

Open the design_1_wrapper_io_placed.rpt file

in the \test_proj_zynq\test_proj_zynq.runs\impl_1\ folder

Find the line of our led_out_0 pin an check the E13 and the LVCMOS33 values.




Ok, so everything is ok !




Step 4 : Generate the test software in SDK



Stage 1


So to create the SDK project two things to do.

First, Export the hardware and include the bitstream file in order to configure the FPGA from SDK.




And then launch SDK.




Stage 2


When SDK opens, it created the Hardware Platform project, including our driver.




Stage 3


The second thing to do is to create the Zynq's FSBL project. The FSBL is mandatory. It has to be executed first, because it will initialize the Zynq core registers and let it behave as expected !

Create a new application with, File, New, Application Project.




Then provide the application's name.

In the mean time create the BSP by clicking Create New, and select Next.




Select the FSBL application template, click Finish.




Now we have the projects for FSBL (along with the BSP project).




Stage 4


Next step is to create the test application.

So repeat the procedure, use the existing BSP and select the Empty Application template.

Then, copy the same main.c file from the last post form the MicroBlaze design.

This is where it is very powerfull !

As the driver handles everything specific to hardware, the same application can be executed on the MicroBlaze or the ARM CPU !

Check that the application compilation is done without errors.




Now we're ready to configure the bitstream on the MiniZed board and to run the test application.



Step 5 : Test on the MiniZed Board



Stage 1



Warning !

Currently the design has the BLINKING generic parameter set to 10 for simulation !!

If you want to see the LED blink on the board you have to generate again the bitstream after setting the BLINKING generic parameter to 10_000_000.


When in SDK, the first thing to do is to configure the FPGA with the bitstream file.

So go to Xilinx, Program FPGA.

In the pop up window click on Program.




When it is done, the board is in reset state, nothing is running.

As you can see, the blue LED indicates the FPGA's configuration is done.

Our green LED is off.




Stage 2


The next step is to run the FSBL application in order to initialize the Zynq core.

Right click on the Zynq_fsbl application project.

Then Run as and Launch on hardware (System debugger).




At this point Zynq core has run the FSBL application and is in a waiting loop. The board's state did not change.


Stage 3


Last step, we will launch the test application in debug mode so we can do some step by step execution to see the different actions of the application.

Right click on the test_app application project.

Then Debug as and Launch on hardware (System debugger).

Click yes to stop the FSBL execution.

And now we are stopped on the first breakpoint of the application execution.

You can use F6 to step over each line in the source code.

You will see that the LED was :

- Powered ON,
- Powered OFF,
- Blinking !



And that's it !!!














Post Conclusion
Now we have :

- Used a Zynq Core IP in a design,
- Created a constraint file,
- Generated a bitstream,
- Generated a FSBL application,
- Generated a test application,
- Execute the test application on the board using the SDK debugger.

This is it. We've covered the main parts of designing a custom IP and use it in a standalone software application using its custom device driver.

Now I'll try the big part, doing the same thing under PetaLinux !


Friday, 15 February 2019

How to create a standalone driver to handle a custom IP



Hi !

In this post we will create a standalone driver to handle our custom IP.

There are several goals here :

- Using a driver will encapsulate in it all the specific hardware knowledge of the IP, thus providing simple actions usable by the application without bothering with all the hardware implementation details.

- Having a driver ready for an IP will let the tools automatically import the driver into the BSP each time you use the IP in a design. No need to manually handle adding sources to the software project.

This post will be based on the low level software functions we wrote in the following post:

2.4 - How to create low level Software functions to handle a custom IP


As this post is quite long, here are the main sections of this post for a quick jump :







Step 1 : Analysis of the generated driver template


When we used the custom IP generation wizzard, the tool provided us a driver template. In this section we will analyze its content.


Stage 1


The driver's repository is divided into 2 folders.

The first one is the \data folder which contains files to customize the driver's generation.

The second one is the \src folder which contains your C sources files.

This structure is mandatory, and you can only customize the \data files or edit your source files by following the rules for each of them.


Stage 2


The led_test_ip.mdd file in the \data folder

This file stands for Microprocessor Driver Definition.

It is associated to its own language with specific keywords, as defined in the UG1138 from the Xilinx's website.

The content of this file can be quite simple or it can be much more rich for complex drivers and advanced users. In our example it will be very light.


The led_test_ip.tcl file in the \data folder

This file uses the .mdd file to customize the driver depending on the .mss file options.

The main interest of this process, is to automatically convert the HDL generic parameters of the IP into C constants.

During the driver creation and insertion into the BSP, the tool will generate the led_test_ip_g.c file. The _g extension stands for generated.

This file contains a configuration table which contains a list of parameters for each instance found in the design.

The tcl file contains a first command xdefine_config_file where you list the parameter fields you need to get in the configuration structure. This structure will be available in the led_test_ip_g.c.

But to be compiled these parameters have to be declared in a .h file somewhere. This is done by the second command of the tcl file xdefine_include_file, where you list the same parameters, which will be inserted in the xparameters.h file and so be declared.

This process is very cool to let the driver access the IP's configuration parameters.

In the xdefine_config_file, be carefull, the IP name you provide has to be the same as the one you use in your C files ! As it will be inserted at the beginning of the variables' name !


Stage 3


The content of the sources depends on the complexity of the driver and the associated IP.

But the minimum structure is the main .c file, a .h file and the make file.

If you need more files then Xilinx provides a set of rules to follow if you want to keep the Xilinx's way of driver coding.

The led_test_ip.h file in the \src folder

The custom IP wizzard geneated a set of 4 registers as we asked. So they are in the HDL file and their offsets are automatically provided in the .h file.




The .h file will also provide macro functions for low level read and write access. These macros are only a renaming of the basic Xilinx's macros.




The led_test_ip.h file in the \src folder

This file is generated empty, so we will have to write the driver's functions in it.




Step 2 : Understand the driver's architecture


The driver definition in the Xilinx's way uses some rules, resources and organization that I will try to summarize in this section.


Stage 1


The first major element is the configuration structure, let's call it ip_name_Config. This structure is the one described before that is automatically initialized by the tool will the hardware parameters of the IP.

The second major element is the structure that contains all the running parameters for an instance of the IP, let's call it ip_name.

The functions that the driver will provide are initialisation functions and functions that shoud hide all the low levels actions and resources.

All the functions should only manipulate elements of the structures defined. And so, the functions only receive pointers on these structures. In some way the functions manipulate "virtual" resources. Thoses resources become real when in the application using the driver, variables are declared for the structures. If you declare several instance structure variables, you can handle several instances of the IP using the same driver.


Stage 2


Here is a synopsis of the overall architecture.




The sinit.c file is not mandatory. It is used by Xilinx in some drivers and not in others. The main goal is to isolate the initialize sequence, but you can do it in your application if you want.




Step 3 : Driver's file content description


In this section I will provide my code for this simple test driver.


Stage 1


For the led_test_ip_g.c file we can see the coherency between the VHDL input file, the tcl driver configuration file and the generated file.




Stage 2


For the led_test_ip_sinit.c file we can see that the first action is to get the Config structure with the LookUpConfig function and then pass both Instance and Config structures to the CfgInitialize function for initialization sequence.

The Initialize function beeing the one call from the application to initialize the driver's instance of the DeviceId instance of the IP.




Stage 3


The led_test_ip.c file is the main driver's file. It contains the CfgInitialize function for drive's instance intialization and all the functions that will provided to the application.

As this test driver only does a few things the CfgInitialize function does almost nothing.
The first thing is to set up the IsReady flag, it will be used to avoid doing initialization again.

Then it will initialize the base address of the custom IP, which is requiered for all physical read/write accesses.




Then we will find the fonctions for the application. They are associated to low level actions : set the LED ON, set the LED OFF and set the LED blinking !

The application does not have to care how it is handleds in the hardware of the custom IP.






Step 4 : Example application description


In this section I will provide my code for this simple test application.


Stage 1


For the main.c file we can see it is very ligth. An initialization step and then simple action requests and that's it !

And this is only because the driver does all the job !




Stage 2


So the SDK project view is the following. You can see that everything is in place and that the elf file is generated.




Stage 2


So if I launch the simulation, results will be the same as in the raw low level version




And that's it for now !







Post Conclusion
Now we have :

- Analyzed the goal of a driver and the standard structure for Xilinx compliant drivers,
- Detailled the content of our test driver,
- Detailled the content of our test application based on the driver,
- Seen that the driver is automatically provided in th BSP for the Hardware platform created with out test custom IP,
- Simulated the software to achieve the expected behavior of the software.

So now we have a clean driver for a standalone application.

Next I will try to do the same thing but for a Linux application !