We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

The Zynq PS/PL, Part Four: Adam Taylor’s MicroZed Chronicles Part 24

by Xilinx Employee ‎03-17-2014 05:00 PM - edited ‎01-07-2016 05:18 PM (293,115 Views)

By Adam Taylor


Recapping on the Zynq PS/PL interface; to date we have examined the interfaces between the PS (processor system) and the PL (programmable logic) side of the Zynq All Programmable SoC. We’ve created a simple peripheral using the Vivado Design Suite, used SDK to communicate with the new peripheral, and we ran a self test on the peripheral. However, the peripheral that we created contained no functionality beyond four registers, which we could read from and write to. In the real world, we’ll want the peripheral to do something useful.


We will be again using Vivado to add real-world functionality to this peripheral.


The first thing to do is open the Vivado project and the block diagram that contains the peripheral we created. Right click on the peripheral and select the “Edit in IP Packager option.” This will open the IP Packager view in a new window which enables you to edit and update the peripheral.




Figure 1.jpg 




This view looks resembles the standard project flow with the exception of the Package IP peripheral window. Beneath the design sources window, you will find two files that were created during the peripheral creation process.





Figure 2.jpg



These files are named:


Adams_Peripheral_v1_0.vhd – Top Level architectural files where you would define user I/O that leaves the module.


Adams_Peripheral_V1_0_S00_AXI.vhd – RTL file, which contains the functional AXI interface including the four registers initially created.


Both of these files include comments as to where the user code is to be inserted:



Figure 3.jpg



For this example, I am going to introduce use the first register as a control register. Specific bits in this register define whether the contents of registers 2 and 3 are to be added, subtracted, or multiplied together. The result of the operation will be stored in the fourth register. We make the fourth register read-only with respect to the microprocessor to ensure that the microprocessor cannot corrupt the results. In addition, the peripheral will be able to generate an interrupt if enabled by the control register.


The first step in the definition is to declare the four registers, the first three as output registers and the final one as an input register. (If we wanted to we could implement this function here however I am doing it at the top level to demonstrate what will be required on more complex functions).


I also edited this file to prevent the processor from writing to the fourth register by making it read-only.


Within the top level file I created an interrupt output and added the simple functional code within the architecture to perform the operations we desire.



Figure 4.jpg 



Having added in all the necessary user VHDL, I synthesised the project to ensure I had not made any errors before I packaged the IP and returned to my project within Vivado. However, before I packaged the IP on the packager page, I incremented the version number to reflect the code changes. Clicking on re-package will run the packager and close the project, returning you to the original Vivado project.


Once back within the project that uses the peripheral, we can run the IP status report (under tools -> Reports -> Report IP status) to show the updated version being used within the design.



Figure 5.jpg



Now, the project needs then to be rebuilt prior to exporting to SDK. Within the SDK, we can use the same functions that we used before to write to and read from this peripheral. However, this time the self-test should fail as the final register cannot be written during the test.



Figure 6.jpg 




The first test is to add together the two contents stored within register 2 and 3 using command 1 in register 0:



Figure 7.jpg




In the second test, we multiply the contents of register 2 and 3 together using command 2 in register 0:



Figure 8.jpg



In the final test, we subtract register 3 from register 2 using command 3 in register 0:



Figure 9.jpg



All of these tests use a polled approach. That’s OK because the simple add, subtract, and multiply functions complete within one clock cycle. However, more complicated multi-cycle functions require the use of an interrupt, which we will look at next time.



Please see the previous entries in this MicroZed series by Adam Taylor:


The Zynq PS/PL, Part Three: Adam Taylor’s MicroZed Chronicles Part 23


The Zynq PS/PL, Part Two: Adam Taylor’s MicroZed Chronicles Part 22


The Zynq PS/PL, Part One: Adam Taylor’s MicroZed Chronicles Part 21


Introduction to the Zynq Triple Timer Counter Part Four: Adam Taylor’s MicroZed Chronicles Part 20


Introduction to the Zynq Triple Timer Counter Part Three: Adam Taylor’s MicroZed Chronicles Part 19


Introduction to the Zynq Triple Timer Counter Part Two: Adam Taylor’s MicroZed Chronicles Part 18


Introduction to the Zynq Triple Timer Counter Part One: Adam Taylor’s MicroZed Chronicles Part 17


The Zynq SoC’s Private Watchdog: Adam Taylor’s MicroZed Chronicles Part 16


Implementing the Zynq SoC’s Private Timer: Adam Taylor’s MicroZed Chronicles Part 15


MicroZed Timers, Clocks and Watchdogs: Adam Taylor’s MicroZed Chronicles Part 14


More About MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 13


MicroZed Interrupts: Adam Taylor’s MicroZed Chronicles Part 12


Using the MicroZed Button for Input: Adam Taylor’s MicroZed Chronicles Part 11


Driving the Zynq SoC's GPIO: Adam Taylor’s MicroZed Chronicles Part 10


Meet the Zynq MIO: Adam Taylor’s MicroZed Chronicles Part 9


MicroZed XADC Software: Adam Taylor’s MicroZed Chronicles Part 8


Getting the XADC Running on the MicroZed: Adam Taylor’s MicroZed Chronicles Part 7


A Boot Loader for MicroZed. Adam Taylor’s MicroZed Chronicles, Part 6 


Figuring out the MicroZed Boot Loader – Adam Taylor’s MicroZed Chronicles, Part 5


Running your programs on the MicroZed – Adam Taylor’s MicroZed Chronicles, Part 4


Zynq and MicroZed say “Hello World”-- Adam Taylor’s MicroZed Chronicles, Part 3


Adam Taylor’s MicroZed Chronicles: Setting the SW Scene


Bringing up the Avnet MicroZed with Vivado






by Visitor pfxr
on ‎06-11-2014 07:51 AM

Hello Adam,

First of all, thank you for your great tutorials. It has helped me a lot.
I would like to ask you if you can send me the source code of the block you created in this tutorial. Because i'm trying to do that simple calculator you like you did, but for some reason i'm failing.

Many thanks,
Pedro Rodrigues

by Observer taylo_ap
on ‎06-11-2014 12:06 PM



I have emailed Steve the source code so he can attach it, you will need to copy and paste into two vhdl files and import it into the IP catalogue for use within Vivado.


The source code is actually for part 25 as I cannot find part 24 however they are the same except for the process marked with a comment --add user code here within the first file. You can edit the process inlne with the code snippet above to implement the calculator.


Thanks for reading and please spread the word



by Xilinx Employee
on ‎06-11-2014 02:15 PM

I have attached the source file from Adam. It is in Microsoft Word format.

by Newbie tmco
on ‎06-18-2014 01:32 AM

Thanks Adam, nice tutorial.


I have implemented such a calculators on my PL succesfully. However, I am stucked in interrupt generation. For example, I am trying to generate an interrupt signal from the calculator block when the result is equal to zero, and toggle the LED status on PS part. 


I modified my verilog code to output a "irq" wire and connected to ZYNQ PS system. However, no relevant drivers were generated from BSP. On the other hand, it seems that I can check "ENABLE interrupt support" when I create such a AXI Custom IP. Should I do that?


Anyway, could you show me how to use such a PL-PS interrupt signal, especially in the SDK part?



by Observer taylo_ap
on ‎06-18-2014 08:55 AM



Thank you for reading and the comment. Having thought about this subject I think it would make a good topic for the next blog in the series so I will generate an example and blog over the weekend hopefully this will be of use. 



by Newbie niky0913
on ‎06-18-2014 10:05 PM

Thanks Adam,

Thanks for you kind explanation about how to use zynq resource Smiley Happy

I had the same result as you showed this post, but I don't know the reason why can I read Final Register...

Could you shed me some light?

(*)And I am looking forward to see your post abount PL-PS interrupt. Like Yukai.)

by Visitor pfxr
on ‎07-10-2014 06:32 AM


I'm sorry to bother again. I'm having trouble to get this to work.
I've created the block exactly like you did, and i've ran the self-test, till here everything went fine, my problem is to get the block to run the code i want.

I've downloaded the code you attached and put it into my block, then i synthesized it, and repackaged it. Then back in the main project I synthesized, implemented and generated bitstream and exported it to SDK. However, i ran the self-test and it continues printing "Self-Test read/write passed" when it should say it has failed. However i still tried to implement the code in C to write on the registers and print me the result but it fails.

I'm stuck in here for weeks and i can't figure out what i'm doing wrong.
Am I missing some step on repackaging the block?

Thank you again, and sorry for my bad english,
Pedro Rodrigues

by Observer taylo_ap
on ‎07-15-2014 01:14 PM



you can read the final register in the module as it is generated, you need to hand edit the file <your>_Perihperal_v1_0_S00_AXI.vhd under the write process (sadly not named) by beneath the comment 


--Implement memory mapped register select and write logic generation


You need to comment out the ability of reg3 to be updated e.g.


-- slv_reg3(byte_index*8+7 downto byte_index*8) <= S_AXI_WDATA(byte_index*8+7 downto byte_index*8);

by Observer taylo_ap
on ‎07-15-2014 01:16 PM



It is no trouble at all can you send me an archived version of your project and I will take a look at it for you email aptaylor@theiet.org





About the Author
  • Be sure to join the Xilinx LinkedIn group to get an update for every new Xcell Daily post! ******************** Steve Leibson is the Director of Strategic Marketing and Business Planning at Xilinx. He started as a system design engineer at HP in the early days of desktop computing, then switched to EDA at Cadnetix, and subsequently became a technical editor for EDN Magazine. He's served as Editor in Chief of EDN Magazine, Embedded Developers Journal, and Microprocessor Report. He has extensive experience in computing, microprocessors, microcontrollers, embedded systems design, design IP, EDA, and programmable logic.