FPGA, SoC, And CPLD Boards And Kits
FPGA Evaluation and Development Kits
5892 Discussions

HPS Avalon Master Addressing Issue!

AAjit2
New Contributor I
1,974 Views

I'm trying to establish an HPS (Master) to FPGA (Slave) communication. To do that, I first built a custom IP in Qsys/Platform Designer with an Avalon MM Slave interface which includes a couple of signals (write, writedata, readdata, chipselect, byteenable etc.) and I tried to communicate through HPS through a C Code. 

I saw several tutorials and examples, and the problem is most use PIO to do this communication which works fine, but when it comes to Avalon Slave custom IP the problem arises when I use the base address. Now when it was PIO it was fairly straight forward, just use the base address to send your data. But in the custom IP you need to assert the write, chipselect, byteenable and other signals while simultaneously sending in your data or reading out data. The problem with that is I have only one address so how do I control all those inputs and read out from the outputs?

I saw online that I have to offset the address by a multiple of 4, I tried that and it still hits a dead end, I tried multiples of 1, 2, and 4 and the offset addresses don't work. The thing is if I could have some reference, or like a map of which address corresponds to which input/output, it would be so much easier. But in all the system generated files I couldn't find that. And now it's like I'm blindly looking around hoping some address works out and it's ridiculous. 

So basically this is for me to test that HPS can exercise master control over custom IP designs in FPGA, and if this works I want to use it for more complex IPs. But to do this I need to able to control individual regs and wires in the IP. But I need to know what I'm missing.

1. Like for the PIO there is no read or write signals yet the information gets transferred, so are these signals generated by the system interconnect? Or do I need to program these individually?

2. How to find the address map to the regs/wires, or what's the data format that I should use to send data?

3. And presently accessing the data gives me a 8 digits of gibberish and random numbers, I tried to check if any particular segment matches the expected output but it doesn't.

Below is the C Code for reference, I've commented out some of my previous attempts

//settings for the lightweight HPS-to-FPGA bridge
#define HW_REGS_BASE ( ALT_STM_OFST )
#define HW_REGS_SPAN ( 0x04000000 ) //64 MB with 32 bit address space this is 256 MB
#define HW_REGS_MASK ( HW_REGS_SPAN - 1 )

//setting for the HPS2FPGA AXI Bridge
#define ALT_AXI_FPGASLVS_OFST (0xC0000000) // axi_master
#define HW_FPGA_AXI_SPAN (0x40000000) // Bridge span 1GB
#define HW_FPGA_AXI_MASK ( HW_FPGA_AXI_SPAN - 1 )

int main() {

//pointer to the different address spaces

void *virtual_base;
void
*axi_virtual_base;
int
fd;
unsigned char
value;
    volatile unsigned char
*blink_mem;
   
uint32_t a, b, c;

void
*h2p_lw_reg1_addr;
void
*h2p_lw_reg2_addr;
void
*h2p_lw_reg3_addr;
//void *h2p_lw_myBus_addr;


void *h2p_led_addr; //led via AXI master
void *h2p_rom_addr; //scratch space via ax master 64kb
void *h2p_rom2_addr;

//Qsys custom IP variables
void *h2p_led_seq; //ledseq sent via AXI master
void *h2p_led_dat; //led data input from HPS
void *h2p_led_out; //led data out sent back from slave
void *h2p_led_rds; //read signal
void *h2p_led_wrs; //write signal

void *sdram_64MB_add;
void
*sdram_16MB_add;


if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) {
printf( "ERROR: could not open \"/dev/mem\"...\n" );
return
( 1 );
}

//lightweight HPS-to-FPGA bridge
virtual_base = mmap( NULL, HW_REGS_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd, HW_REGS_BASE );

if
( virtual_base == MAP_FAILED ) {
printf( "ERROR: mmap() failed...\n" );
close( fd );
return
( 1 );
}

//HPS-to-FPGA bridge
axi_virtual_base = mmap( NULL, HW_FPGA_AXI_SPAN, ( PROT_READ | PROT_WRITE ), MAP_SHARED, fd,ALT_AXI_FPGASLVS_OFST );

if
( axi_virtual_base == MAP_FAILED ) {
printf( "ERROR: axi mmap() failed...\n" );
close( fd );
return
( 1 );
}

//-------------------------------------------------------------
    //Custom Qsys IP test
   
printf("\n\n\n-----------Custom Qsys IP test-------------\n\n");

   
blink_mem = (unsigned char *) (axi_virtual_base + 0x0);
   
printf( "Blink mem is:%d\n", blink_mem);
   
//the address of the read, read_data and write, write_data
  
h2p_led_dat=axi_virtual_base + ( ( unsigned long  )( 0x0 + LEDTEST_1_BASE) & ( unsigned long)( HW_FPGA_AXI_MASK ) );
  
h2p_led_seq=axi_virtual_base + ( ( unsigned long  )( ALT_AXI_FPGASLVS_OFST + LEDTEST_1_BASE) & ( unsigned long)( HW_FPGA_AXI_MASK ) ) + 4;
   
h2p_led_out=axi_virtual_base + ( ( unsigned long  )( ALT_AXI_FPGASLVS_OFST + LEDTEST_1_BASE) & ( unsigned long)( HW_REGS_MASK ) );
   
//h2p_led_rds=axi_virtual_base + ( ( unsigned long  )( 0x0 + LEDTEST_1_BASE) & ( unsigned long)( HW_FPGA_AXI_MASK ) );
    //a=alt_read_word(h2p_led_dat+0);
    //b=alt_read_word(h2p_led_dat+1);
    //c=alt_read_word(h2p_led_dat+2);

    //write into the Qsys IP (expect to see +2 added)
printf( "Qsys IP leddata:%d\n", *((uint32_t *)h2p_led_dat));
//printf( "Qsys IP ledseq:%d\n", a);
//printf( "Qsys IP ledout:%d\n", b);
//printf( "Qsys IP readds:%d\n", c);
   
printf( "Qsys IP ledseq:%d\n", *((uint32_t *)h2p_led_seq));
   
printf( "Qsys IP ledout:%d\n", *((uint32_t *)h2p_led_out));
   
//printf( "Qsys IP rds:%d\n", *((uint32_t *)h2p_led_rds));

   
*(uint32_t *)h2p_led_dat = 0b00000111;
   
*(uint32_t *)h2p_led_seq = 0b00001011;
   
*(uint32_t *)h2p_led_out = 0b00000110;
   
//*(uint32_t *)h2p_led_rds = 4;


   
printf( "Qsys IP leddata:%d\n", *((uint32_t *)h2p_led_dat));
   
printf( "Qsys IP ledseq:%d\n", *((uint32_t *)h2p_led_seq));
   
printf( "Qsys IP ledout:%d\n", *((uint32_t *)h2p_led_out));
   
//printf( "Qsys IP rds:%d\n", *((uint32_t *)h2p_led_rds));



//*(uint32_t *)h2p_led_seq = 0b00000011;
    //*(uint32_t *)h2p_led_seq = 2;
    //*(uint32_t *)h2p_led_rds = 1;

    //printf( "Qsys IP result:%d + 2 = %d\n", *((uint32_t *)h2p_led_seq), *((uint32_t *)h2p_led_out) );
    //printf( "Qsys IP result:%d\n", *((uint32_t *)h2p_led_seq));

0 Kudos
7 Replies
sstrell
Honored Contributor III
1,966 Views

I'm a little confused by your question.  You set the base address in Platform Designer so that a component, like the HPS, can access your custom IP, just like the PIO off-the-shelf IP.  Generating the system creates the files needed (the software handoff files) that make it possible for a software developer to access the hardware.  Are you trying to create a bare-metal application?  What is your target device here (since the flow is different for different families)?

Maybe if you post some or all of the HDL of your custom component, that would better help understand the issue.

For your questions:

1) One of the main ideas of PD is that individual signals are bundled in the interfaces, so you don't need to really think about them until you're creating your own custom IP that makes use of these standard interfaces, like Avalon memory-mapped.  As such, yes, the signals are there.  To easily see the individual signals, select a component in your system design, open the Block Symbol view, and enable the Show signals option.

2) For off-the-shelf IP, you'd look in the user guide for the IP, including the embedded IP peripherals guide for register maps.  For custom IP, you build the register map yourself and, as I mention, set the base address in the tool.  When you generate the system, HTML reports are generated with register maps and other information.  Look in the folder named after your system design to find the generated documentation.

Hope this is useful as a start.

#iwork4intel

0 Kudos
AAjit2
New Contributor I
1,952 Views

I'm a little confused by your question.  You set the base address in Platform Designer so that a component, like the HPS, can access your custom IP, just like the PIO off-the-shelf IP. 

Yes this is correct, as part of accessing it I assigned it an address (0x0007_0000)

Generating the system creates the files needed (the software handoff files) that make it possible for a software developer to access the hardware.  Are you trying to create a bare-metal application?  What is your target device here (since the flow is different for different families)?

Alright, so the board I'm using is the DE0 Nano SoC which has the FPGA and the HPS system in it. What I'm trying to do is to communicate to a custom IP with HPS as master and FPGA as a slave. To do this I'm utilizing the Linux system on HPS to run a C compilation. Hope this clears that 

For your replies:

1) Yes, I'm aware that the signals are bundled together under the interface and I can see them, what I want to know is how I can access them as a Master. So say I have an avalon slave interface with write, writedata, readdata etc. What address do I use on the Master side of things to access the individual signals, because as I understand it, the master/slave needs to have them for the data transfers to take place. The address in this instance refers to the interface as a whole, should I and do I need to address individual signals for the data transfer to take place?

2) For off-the-shelf IP, you'd look in the user guide for the IP, including the embedded IP peripherals guide for register maps.  For custom IP, you build the register map yourself and, as I mention, set the base address in the tool.  When you generate the system, HTML reports are generated with register maps and other information.  Look in the folder named after your system design to find the generated documentation.

2) So are you saying the HTML reports would contain the register address information with which I can access them from the HPS Master? From what I have seen, they only include the declarations and signals but not the address details that'll help me to access individual registers.

 

0 Kudos
sstrell
Honored Contributor III
1,944 Views

"1) Yes, I'm aware that the signals are bundled together under the interface and I can see them, what I want to know is how I can access them as a Master. So say I have an avalon slave interface with write, writedata, readdata etc. What address do I use on the Master side of things to access the individual signals, because as I understand it, the master/slave needs to have them for the data transfers to take place. The address in this instance refers to the interface as a whole, should I and do I need to address individual signals for the data transfer to take place?"

Again, the address is set in Platform Designer and conveyed to software through the handoff files, including .sopcinfo.  I don't understand what you mean by addressing to access the individual signals.  If you do a write to address 0x70000, your custom component, the appropriate signals are enabled by the interconnect to perform the write at that address (write is enabled, data is put on writedata, address is set to appropriate address) and your component must be capable of taking these input signals and storing the data at the appropriate location (its own address 0x0000).  If your component is, say, a 32-bit component, to get to the next register location in it (slaves use word addressing based on their data bus width), you'd increase the master address by 4 (byte addressing), so the master would need to access address 0x70004.

Let me know what you think about this.

#iwork4intel

0 Kudos
AAjit2
New Contributor I
1,925 Views

By individual signals I meant the write, byteenable etc. but you cleared that up when you said the system generates it. I've tried again with the address and it works now. So thank you for that. 

The only issue is the sizing. So say I want to read back the data from the FPGA slave to the HPS master but the FPGA slave register is say 256 bits and the master pointer is 64 bits. I presume this is also an instance where the slave address incremented by 4 (or in this case maybe comes in to access the next set of data? For some reason when I try to do that it doesn't show me the next set. What am I missing?

0 Kudos
sstrell
Honored Contributor III
1,920 Views

Not sure I understand what you mean by "master pointer".  Addressing, as I mentioned previously, is based on the data bus width.  What is the width of the HPS-to-FPGA bridge and what is the width of the data bus of the FPGA slave (responder) component?

#iwork4intel

0 Kudos
AAjit2
New Contributor I
1,916 Views

Because on the HPS side the program is in C, it uses a pointer to access/send data to the given address. And the width of the pointer is 64 bit. This simply means that as a Master the readdata/writedata width is 64 bits. As for the bridge width, both FPGA to HPS and HPS to FPGA bridges are 64 bit wide. As for the FPGA slave the readdata is currently 64 bits because I want to read out the data. But I want to make it wider to say 256 or 512 bits and have the master read it all out. 

0 Kudos
EBERLAZARE_I_Intel
1,869 Views

Hi,

Based on my understanding, it is recommended that both bits are the same for example in your case 64 bit. If the you using different bits, it would cause some issue. 

0 Kudos
Reply