Sorry, you need to enable JavaScript to visit this website.

Talking to a custom peripheral (bare metal)

This is a continuation of this blog post, where we created our own custom peripheral.  If you have not already done this, go though the how-to and come back here when you are done.

The github project can be found here.  Enjoy!

Ok, we have generated our bitstream and are ready to export our hardware to SDK.  Go to File -> Export -> Export Hardware to SDK ...  Make sure you select "Launch SDK" from the options.

Once SDK launches we are going to actually follow all of the exact same steps in this blog post.  I highly recommend going all the way through that post, as it will validate that your custom peripheral project was created correctly.  If you successfully see Hello World! on the screen, come back here and continue.

If you remember within the "Create or Import a Custom Peripheral" wizard we selected an option that created software templates for us to help talk to our custom peripheral.  We need to find these and add them to our project.  There is actually just a single file in this case that we are interested in, and that is simple_register.h found here:

C:\Xilinx\Projects\zed_first_custom_hw\zed_first_custom_hw.srcs\sources_1\edk\proc_system\drivers\simple_register_v1_00_a\src

Really buried, I know.  But it's location actually does make a lot of sense.  It is in the drivers folder of our processor system.  And that is exactly what it is, a very simple driver that handles the communication to our hardware peripheral.  This is no different than someone writing a PCIe or USB driver (cool hu?), just much, MUCH simpler.

Your SDK Project Explorer should look something like this:
 

 
Open up a My Computer from the start menu and navigate to:
 
C:\Xilinx\Projects\zed_first_custom_hw\zed_first_custom_hw.srcs\sources_1\edk\proc_system\drivers\simple_register_v1_00_a\src
 
Now, grag the simple_register.h file into the src folder within the hello_world_0 project.  Note: you can import the file via SDK, but it is kind of a pain in my mind, so I do it this way.  Your project tree should now look like this:
 
Congratulations, you just imported your first driver!
 
Ok, now let's take advantage of it.  We need to modify the helloworld.c file to include our driver file, as well as execute the read and write functions within it.  Here is my code:
 
 
/*
 * helloworld.c: simple test application
 */
 
#include
#include "platform.h"
 
#include "simple_register.h"
 
#define SIMPLE_REGISTER_BASE_ADDRESS 0x64800000
#define REGISTER_0 0
 
int main()
{
// our variables that we will be using to read and write to our hardware register
int current_value;
int write_value = 123456789;
int read_value = 0;
 
    init_platform();
 
 
    printf("Application Loaded.\r\n\r\n\r\n");
 
    printf("Getting current register value ... ");
 
    // read out the current value from our peripheral, at register zero
    current_value = SIMPLE_REGISTER_mReadReg(
    SIMPLE_REGISTER_BASE_ADDRESS,
    REGISTER_0
    );
 
    printf("Done.\r\n");
 
    printf("Register value = %i\r\n\r\n",current_value);
 
    printf("Writing %i to the hardware register ... ", write_value);
 
    // write our value to our peripheral at register 0
    SIMPLE_REGISTER_mWriteReg(
    SIMPLE_REGISTER_BASE_ADDRESS,
    REGISTER_0,
    write_value
    );
 
    printf(" Done.\r\n");
 
    printf("Reading register value ... ");
 
    // read out the current value from our peripheral, at register zero
read_value = SIMPLE_REGISTER_mReadReg(
SIMPLE_REGISTER_BASE_ADDRESS,
REGISTER_0
);
 
    printf("Done.\r\n");
 
    printf("Register value = %i\r\n\r\n",read_value);
 
    printf("Exiting Application, ta ta!\r\n");
 
    cleanup_platform();
 
    return 0;
}
 

 
And the output:
 
 
    Application Loaded.
 
 
    Getting current register value ... Done.
    Register value = 0
 
    Writing 123456789 to the hardware register ...  Done.
    Reading register value ... Done.
    Register value = 123456789
 
    Exiting Application, ta ta!

 
Well there ya have it!  Creating and talking to a custom peripheral using Zynq.  

Comments

Zynq Geek, thanks for usefull blog posts!

Now I would really like a titutorial showing how to make a Linux driver for this simple peripheral.

I'm workin on it! I'm hoping to have it done in the next few days.

And thanks for the support! I'm glad you are finding them useful!

Hi,

I also look to see how to read/write hardware register in linux.

After this, the next step is a high speed transfer :-).

I do not see the time ...

Kappasm

Awesome tutorial, I look forward to reading the tutorial about reading the peripheral from Linux.

Best Regards,

Romel Torres

Very nice of you all these tutorials. Thank you very much.

I just finished the custom peripheral tutorial and I found a little problem with the "simple_register.h" file. It includes "xbasic_types.h" which is not found by the compiler.

On the other hand, within PlanAhead, I have got critical warnings during the bit generation, e.g. "[Constraints 5] Cannot loc instance 'processing_system7_0_PS_PORB_pin_IBUF' at site B5..."

Anyway, it works. I just ignored the warnings and I changed a type used within "simple_register.h", but I would like to know if anybody has found any of these problems?

Thanks,

Yaset

I also had the problem that the compiler could not find "xbasic_types.h". I think that when building the standalone BSP if there is no the design in the PL fabric the "common_v1_00-a" does not get added to lib src.

Therefore my workaround for the time being is to add something into the fabric to allow the BSP to be more "complete" !

Although adding something to the fabric seems to work, the recommonded solution according to this:
http://www.xilinx.com/support/answers/54352.html
is to simply change #include "xbasic_types.h" -> #include "xil_types.h". Then it compiles with no error.

I actually ran into a similar problem as well - but I can't for the life of me remember how I fixed it. I went back through and followed my how-to step by step and couldn't recreate the problem. Thoughts on what step you might have done something different on?

You are talking about the critical warnings I suppose. I don't have any idea where this come from. I checked your steps once again and there is no visible difference.

I will update since I'm using the 14.1 version. Then, I'll see if I still have those warnings.

Hmm .. not good that it doesn't work on 14.1. If you could post your findings after moving to 14.2 that would be very helpful!

Well I updated to the 14.2 version and I'm still having the critical warnings... Let's forget about it, the answer will come to us later, I hope :-). Thanks

Sorry, I had not seen your answer.

In fact the tutorial works as I said before, even with the warnings. I was just wondering where do they come from. I think I didn't have these warnings the first time I generated a bit file.

That brings up a good point - Warnings are often part of development with respect to FPGA's. This would be a good topic to touch on. I am working on a few deep-dive how-to's for our tools, i'll incorporate the warnings into them.

This comment has been removed by the author.

Hi guys! I have a problem at the end of the tutorial... When I am trying to program the FPGA to try it, the SDK hangs and says:
"ERROR: Unexpected error while parsing XMD response XXX: com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: invalid number or unquoted string near"
Any idea??

Helena ... this might be a good one to post to the zedboard.org forums. That sounds like a tool installation problem if you ask me.

This all makes sense, but I would think that once you have your system setup in XPS and export it to SDK, it would actually copy or reference all your custom peripheral drivers.

Also, I don't understand why there is a "generic" driver with no files in it representing all of my custom peripherals.

To really draw this already too long comment out, why wouldn't XPS generate some kind of header file that has all the base address defines in it. Its very well defined what they are in XPS.

So, I spent ours trying to find documentation of where SDK puts the defines for the base addresses to no avail. This morning, I stumbled upon xparameters.h, which has them all!

Good work on your blog.

Thanks for putting in the work to find this Peter! I'll update the blog post with this information. Thanks again!

On the other hand, within PlanAhead, I have got critical warnings during the bit generation, e.g. "[Constraints 5] Cannot loc instance 'processing_system7_0_PS_PORB_pin_IBUF' at site B5..."

http://www.buyadrugtest.com/

Instead of a simple read/write register, the register I made swapped the bytes on read. However, when I ran the application the bytes were not swapped. I'm assuming this is because the value is being write-allocated in the cache and the read is never getting to my actual hardware peripheral. Is there a method for forcing a load/store to travel all the way to the hardware peripheral?

The float reading and write part is not documented.
Here's how I did it:
float ia = 0.707f;
printf("test_ia = 0x%08x\r\n", *(int*)&ia);

another alternative is to declare an union:
union u_type{
u32 i;
float f;
};

Write values:
SIMPLE_REGISTER_mWriteReg(SIMPLE_REGISTER_BASE_ADDRESS,REGISTER_1,*(u32*)&ia);
or
union u_type cnvrta;
SIMPLE_REGISTER_mWriteReg(SIMPLE_REGISTER_BASE_ADDRESS,REGISTER_1,cnvta.i );

Read values:
cnvrta.i = SIMPLE_REGISTER_mReadReg(SIMPLE_REGISTER_BASE_ADDRESS,REGISTER_1);
printf("Register value = 0x%08x %f\r\n\n",cnvrta.i, cnvrta.f);

Hope this is useful for someone.
Thanks !

There is a bug with the linux version wherein if "Launch SDK" is selected, it is unable to compile the code. The workaround for that is to launch SDK independently. My question is, can anyone please give some steps to create the correct project configuration in SDK, just like export to SDK would ? I am really stuck with that issue. Any help is appreciated.

Thanks for the post. However I have some problems with reading from the peripherial. Reading attemp returns the error "Error while handling inferior event:
Remote failure reply: E01". Has anyine come accross this problem? Thank you.

Hi,

I want to write float value to a register which is 20 bit 7 bits representing the numbers above the decimal point and 13-bits representing the value below the decimal point.

How i will write to this register from xsdk.

I am working with Zedbaord.

waiting for kind reply.

Regards