HPS Avalon Master Addressing Issue!
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));