Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
9 years ago

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.

9 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- 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.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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!
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- 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?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

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

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    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