I have a ZCU102 programmable logic (PL) design that was given to me that works in Linux (petalinux 2017.3). However, the performance was not sufficient, as I need to be able to service the PL within a millisecond, as his buffers are not that big. Therefore I am attempting to port it to run as a standalone.
The PL has a set of base registers it uses for control/status, and uses AXI DMA to transfer data at a high rate of speed to the software. In Linux, the software performed a ioremap() on the physical address of the register base address, then it accessed it as if it were memory, using control registers to turn on and off the AXI DMA.
My assumption is that standalone software on xilinx doesn't need to do the ioremap(), and I searched far and wide to find some document that contradicted this or presented a standalone version of ioremap(), but could not find anything.
However, when I try to access this memory directly from the standalone application, the application appears to halt. Was there something I should have done before accessing the memory?
In case it's not simple and obvious what I'm doing wrong, here is more detail:
Here's what I did in the SDK:
a) create a Hardware Platform Specification project based on the HDF I got from vivado
b) create a standalone application project that uses the Hardware Platform in step 1. Have this simple program read a specific offset into the control registers that should reveal a simple word like 0xCAFEF00D. Print it out.
c) program the FPGA using the bitstream file with the SDK over jtag, and
d) debug the program using jtag
Unfortunately, the program runs for a bit, but is unable to read the register. As soon as my program accesses the PL's register memory, the program execution stops. Or hangs. Or something. The exeuction just appears to stop as far as I can tell in the IDE.
I tried reading the register with Xil_In32(), and also plainly with "volatile uint32_t tmp = *(BASE_ADDRESS)", but they both failed in the same way.
I could find no online documentation about reading PL memory with a standalone application, and I would be very happy to hear that I missed some important document or video tutorial that would tell me all the things I am doing wrong.
Here is the simple code I'm trying to run. When it runs, the only output I get is the line that prints "Application start". When I debug, I can verify that the first attempt to read the PL's memory causes the death of the program.
volatile uint32_t *BASE_ADDRESS = 0xA0000004;
print("------ Application Start -------\n\r");
uint32_t serialnum = *(BASE_ADDRESS);
printf("Got serial number 0x%x\n\r", serialnum);
Here is the output of the hdf showing memory layout:
After programming the FPGA, you need to do additional register configuration to enable accesses to PL. If you're using GUI debugger, this will be done based on "PL Powerup" option in the debug config. If you're using commandline debugger, you need to run a couple of commands, which are part of psu_init.tcl, in your HW project. The sequence should look like something below.
Thank you @sadanan.
Can you point me to the documentation that this is described in?
I will eventually need to know how to do this within software/firmware, so it could be done in a production environment (i.e. a product that is in the field, and not connected to a debugger). I assume the documentation that describes your procedure will explain the reason this is necessary, and how to do it in the program.
I will find out more details about the docs. This code is also part of FSBL, so in production environment, you should get this automatically (unless you're using a custom bootloader, in which case you would need to run the functions from psu_init.c)