Community
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
Valued Contributor III
1,575 Views

Qsys, How do you determine the Address for an Avalon-MM Block?

Ok, so I've managed to compile my SoC block with Qsys, I had some prior error but it was due to not setting the TOP module correctly.  

 

Now it's compiled and I even managed to add some LEDs signals to confirm this when uploading the .sof to the FPGA. But the problem comes when I try to access the block I created I get some kernel panic messages from ttyS1. I run the program with a remote debugger through ssh, and everything is fine, the open("/dev/mem") and the mmap(...), until I write to the returned pointer.  

 

So all I can guess is that I'm writing to the wrong address. Can somebody point to the right direction on how to this correctly? 

 

______________________________________________ 

 

The problem was that I wasn't using the headers provided by the EDS and defined the wrong starting address for the light-weight H2F bus.
0 Kudos
9 Replies
Highlighted
Valued Contributor III
11 Views

Take a close look at the documentation for mmap. It gives you a pointer to where in your address space it put the physical address you gave it. Say the offset to the register you are looking at is 4 from the start of your device. You need to use a pointer value that is value mmap gives you + 4. Beware of C pointer arithmetic as well. Print out the value returned by mmap and of your pointer and wait long enough for it to get to the screen before you access your device. Confirm that it is using the correct value.

0 Kudos
Highlighted
Valued Contributor III
11 Views

Ok, so this is a picture of how the memory was assigned in Qsys: http://imgur.com/iorpxmq 

 

This is the code I'm trying to run in the SoC http://pastebin.com/ax3qtxxd 

(the define is in hps_0.h and it's assigned to the same address that it's in the Qsys picture) 

 

And this is a picture of DDD running with the remote debugger: http://imgur.com/a/hyhwu
0 Kudos
Highlighted
Valued Contributor III
11 Views

I didn't have time to look at it in detail but I did find a few things: 

  • You shouldn't use a struct to define hardware register layouts. You aren't guaranteed that the compiler will layout memory as you intended. I'd recommend using# define or const to define byte offsets to your registers. 

  • The offset for mmap is wrong. It needs to be the physical address of your registers. I don't recall how to calculate this, so look at some linux examples for SoC. Note that it isn't the address in QSYS. That doesn't take into account the starting address of the interface you are using. 

  • Your HW_SPAN is too big. Use the smallest multiple of the linux kernel page size (usually 512) that will hold all your registers. It would be 1*512 for your application. 

0 Kudos
Highlighted
Valued Contributor III
11 Views

 

--- Quote Start ---  

I didn't have time to look at it in detail but I did find a few things: 

  • You shouldn't use a struct to define hardware register layouts. You aren't guaranteed that the compiler will layout memory as you intended. I'd recommend using# define or const to define byte offsets to your registers.  

 

 

--- Quote End ---  

 

You are right, this version of the code doesn't have the correct declaration. I changed it later to this declaration: 

 

typedef struct __attribute__((packed)) { uint16_t Control, ClockPreScaler, MatchRegister, MatchChannel0, MatchChannel1, MatchChannel2; } PWM_t;  

 

To avoid auto memory alignment. 

 

 

 

--- Quote Start ---  

 

  • The offset for mmap is wrong. It needs to be the physical address of your registers. I don't recall how to calculate this, so look at some linux examples for SoC. Note that it isn't the address in QSYS. That doesn't take into account the starting address of the interface you are using.  

  • Your HW_SPAN is too big. Use the smallest multiple of the linux kernel page size (usually 512) that will hold all your registers. It would be 1*512 for your application.  

 

 

--- Quote End ---  

 

 

All that was taken from one of the examples provided for the development board.
0 Kudos
Highlighted
Valued Contributor III
11 Views

So far I've found some errors in my FPGA design, such routing the wrong CLK nets. ( side note: who does the default template for the development board and duplicates the clock nets and instantiates the wrong ones in the top level module?!?!) 

 

But still I'm getting segmentation faults when trying to write the memory at the specified address! At least now I don't get kernelpanics! yey!
0 Kudos
Highlighted
Valued Contributor III
11 Views

Look at the registers in HPS for the interface to fpga fabric you are using. The interface should be initialized when Linux boots, but there is a lot that can go wrong and cause the bridge to not be initialized.

0 Kudos
Highlighted
Valued Contributor III
11 Views

 

--- Quote Start ---  

Look at the registers in HPS for the interface to fpga fabric you are using. The interface should be initialized when Linux boots, but there is a lot that can go wrong and cause the bridge to not be initialized. 

--- Quote End ---  

 

 

Where should I look for that?
0 Kudos
Highlighted
Valued Contributor III
11 Views

There should be mention of the bridge(s) in the text bthat print when booting

0 Kudos
Highlighted
Valued Contributor III
11 Views

This is what I got: 

altera_hps2fpga_bridge fpgabridge.2: fpga bridge registered as device hps2fpga altera_hps2fpga_bridge fpgabridge.2: init-val not specified altera_hps2fpga_bridge fpgabridge.3: fpga bridge registered as device lwhps2fpga altera_hps2fpga_bridge fpgabridge.3: init-val not specified altera_hps2fpga_bridge fpgabridge.4: fpga bridge registered as device fpga2hps altera_hps2fpga_bridge fpgabridge.4: init-val not specified 

 

 

 

Also, while looking at /sys/class/fpga-bridge/ I found the 3 bridges enabled: 

 

root@socfpga:/sys/class/fpga-bridge# ls fpga2hps hps2fpga lwhps2fpga root@socfpga:/sys/class/fpga-bridge# cat */enable 1 1 1
0 Kudos