Nios® V/II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® V/II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
12600 Discussions

Simple interfacing between Avalon MM Slave and ARM HPS

Altera_Forum
Honored Contributor II
4,565 Views

Hi all, 

 

I'm trying to create a simple example of a master-slave communication between the onboard HPS (running Linux) and the FPGA fabric using a Cyclone V. The method I've followed so far is this: 

 

Firmware: 

- instantiate the HPS in Qsys with nothing but a LWH2F bridge 

- write a simple verilog module (flash_led.v) as an Avalon MM Slave (i.e. it has read, readdata, write, and writedata signals) and connect it to the HPS in Qsys 

- connect everything in a simple top-level verilog module and set the LED output pins to display whatever shows up on the writedata signal 

 

Software: 

- write a simple c program that deals with memory mapping via: 

int fd = open("/dev/mem", (O_RDWR|O_SYNC)); void* slave_base = mmap(NULL, ALT_LWFPGASLVS_SPAN, (PROT_READ|PROT_WRITE), MAP_SHARED, fd, (off_t)ALT_LWFPGASLVS_ADDR); 

- also deal with writing to the slave peripheral via: 

volatile unsigned char* slave_addr = (unsigned char*)slave_base; // the offset of my flash_led component in Qsys is 0x0 so it can be ignored *slave_addr = some_value; 

 

This works for writing to the slave module (I see the LEDs set correctly), but I'm unable to read from it when I try things like "read_value = *slave_addr;" I've seen a few examples online which use the alt_write_word() and alt_read_word() functions, but I haven't been able to get these to do anything for me thus far... Do I need to be doing more with my Verilog module? Is the "address" signal necessary when reading and writing from an Avalon MM slave? I suspect I may have a conceptual misunderstanding of this whole bridging process... Can anyone help me out or point me in the right direction? 

 

For reference, here's the simple flash_led.v verilog module I've been using: 

module flash_led ( input clock, input reset_n, input write, input writedata, input read, output readdata, output led ); reg led_internal; reg stupidconstant = 8'b01010101; assign led = led_internal; assign readdata = stupidconstant; always @(posedge clock) begin if (!reset_n) led_internal <= 4'b0000; else if (write) begin led_internal <= writedata; end end endmodule 

 

John
0 Kudos
10 Replies
Altera_Forum
Honored Contributor II
1,619 Views

Can anyone help me out with this? I've been stuck on the same issue for a few days now... Even if it's just a nudge in the right direction - I'd be happy to know just if my problem is in the software or the firmware. 

 

Thanks, 

John
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Ok, I solved it. In case anyone has the same confusion, here's the essential parts of the software that I was missing: 

 

This might be overkill, but it works if you just map the entire hardware register space into virtual memory: 

#define HW_REGS_BASE ALT_STM_OFST # define HW_REGS_SPAN 0x04000000 # define HW_REGS_MASK (HW_REGS_SPAN-1) 

 

Also, I needed to find the address offset of my module that I added as a component to Qsys (read this from the address map) 

#define MY_MODULE_OFST 0x00000000 

 

Then, ignoring error checking, I took care of memory mapping like this: 

int virtual_base; int fd; fd = open("/dev/mem", (O_RDWR|O_SYNC)); virtual_base = mmap(NULL, HW_REGS_SPAN, (PROT_READ|PROT_WRITE), MAP_SHARED, fd, HW_REGS_BASE); 

 

Finally, reading and writing worked with: 

alt_write_word(virtual_base + ((ALT_LWFPGASLVS_OFST + MY_MODULE_OFST) & HW_REGS_MASK), write_val); read_val = alt_read_word(Virtual_base + ((ALT_LWFPGASLVS_OFST + MY_MODULE_OFST) & HW_REGS_MASK));
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Hi, 

can you explain me what shout I set ALT_STM_OFSET ? 

In "HW_REGES_SPAN" is a span of particular component of IP core or span of HPS LWFPGASLAVES ? 

What is use of "HW_reges_mask" ? 

 

Please help me,I don't have experience to work with Hard processor system ans also don't have much experience to work with Linux..
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Hi, 

 

I am stuck with the same problem as well. I am able to write data from the HPS to the FPGA, but not able to read data back from the FPGA into the HPS. I am using the Lightweight HPS to FPGA bridge in Cyclone V. 

 

I have defined an Avalon-MM slave as follows: - 

 

module scratch_slave_one_byte( input clk, input reset, input write, input writedata, input read, output reg readdata, output reg byte_from_hps, output write_count_w, input byte_into_hps ); reg write_count = 0; assign write_count_w = write_count; always@(posedge clk) begin if (write) begin byte_from_hps <= writedata; end else if (read) readdata <= byte_into_hps ; end endmodule 

 

My C program running in the HPS is as follows: - 

 

#include <sys/mman.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <stdint.h> # include "hps.h" # include <time.h> # include "socal.h" # define ALT_LWFPGASLVS_OFST 0xff200000 # define HW_REGS_BASE (0xfc000000) # define HW_REGS_SPAN (0x04000000) # define HW_REGS_MASK (HW_REGS_SPAN-1) # define MY_MODULE_OFST 0x00000000 # define WRITE 0x00 # define READ 0x04 volatile unsigned char* custom_slave; void *virtual_base; int main() { int fd; if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) { printf( "ERROR: could not open \"/dev/mem\"...\n" ); return( 1 ); } 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 ); } custom_slave = (unsigned char*)(virtual_base + ( (ALT_LWFPGASLVS_OFST + MY_MODULE_OFST + WRITE) & (HW_REGS_MASK))); custom_slave = 0x06; //WRITE BYTE INTO FPGA unsigned char value = custom_slave; //READ BYTE FROM FPGA printf("%d\n",value); //value = alt_read_word(virtual_base + ((ALT_LWFPGASLVS_OFST + MY_MODULE_OFST) & HW_REGS_MASK)); //printf("%d\n",value); cleanup: if( munmap( virtual_base, HW_REGS_SPAN ) != 0 ) { printf( "ERROR: munmap() failed...\n" ); close( fd ); return( 1 ); } close(fd); return 0; } 

 

I connect the readdata [7:0] inputs to 8'b00000011 in the top level module. However, the signal I read into the HPS is always zero. 

 

Any help would be great. Thanks! 

 

Akshay
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

I am now able to read and write 32 bit words using the lightweight HPS to FPGA bridge! 

 

Attaching my code if it might be useful to anyone: - 

 

I have defined a custom Avalon slave defined as follows below. Whenever read, it sends 32'hA5A5A5A5 as the readdata [31:0]. 

 

module scratch_slave_32_bits_rw ( // No conduit input clk, input reset, input read, output reg readdata, input write, input writedata, output reg hps_to_fpga_32_bits //conduit ); reg arbitrary_constant = 32'hA5A5A5A5; always@(posedge clk) begin if(read) readdata <= arbitrary_constant; else if (write) hps_to_fpga_32_bits <= writedata; end endmodule 

 

Top level module is as follows below. I am connecting the top 4 MSB's sent from the HPS to the LEDs on the DE0-Nano-SoC board. 

 

module quartus_scratch_1( input CLOCK_50, output led_values, output hps_memory_mem_a, output hps_memory_mem_ba, output hps_memory_mem_ck, output hps_memory_mem_ck_n, output hps_memory_mem_cke, output hps_memory_mem_cs_n, output hps_memory_mem_ras_n, output hps_memory_mem_cas_n, output hps_memory_mem_we_n, output hps_memory_mem_reset_n, inout hps_memory_mem_dq, inout hps_memory_mem_dqs, inout hps_memory_mem_dqs_n, output hps_memory_mem_odt, output hps_memory_mem_dm, input hps_memory_oct_rzqin ); wire hps_to_fpga_32_bits; assign led_values = hps_to_fpga_32_bits; soc_system soc_system_inst_1( .clk_clk(CLOCK_50), // clk.clk .memory_mem_a(hps_memory_mem_a), // memory.mem_a .memory_mem_ba(hps_memory_mem_ba), // .mem_ba .memory_mem_ck(hps_memory_mem_ck), // .mem_ck .memory_mem_ck_n(hps_memory_mem_ck_n), // .mem_ck_n .memory_mem_cke(hps_memory_mem_cke), // .mem_cke .memory_mem_cs_n(hps_memory_mem_cs_n), // .mem_cs_n .memory_mem_ras_n(hps_memory_mem_ras_n), // .mem_ras_n .memory_mem_cas_n(hps_memory_mem_cas_n), // .mem_cas_n .memory_mem_we_n(hps_memory_mem_we_n), // .mem_we_n .memory_mem_reset_n(hps_memory_mem_reset_n), // .mem_reset_n .memory_mem_dq(hps_memory_mem_dq), // .mem_dq .memory_mem_dqs(hps_memory_mem_dqs), // .mem_dqs .memory_mem_dqs_n(hps_memory_mem_dqs_n), // .mem_dqs_n .memory_mem_odt(hps_memory_mem_odt), // .mem_odt .memory_mem_dm(hps_memory_mem_dm), // .mem_dm .memory_oct_rzqin(hps_memory_oct_rzqin), // .oct_rzqin .scratch_slave_32_bits_rw_0_conduit_end_export(hps_to_fpga_32_bits) // scratch_slave_one_byte.export ); endmodule 

 

Finally, my C program running in the HPS is as follows:- 

 

#include <sys/mman.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # include <stdio.h> # include <stdlib.h> # include <unistd.h> # include <stdint.h> # include "hps.h" # include <time.h> # include "socal.h" # define HW_REGS_BASE (0xfc000000) # define HW_REGS_BASE (0xfc000000) # define HW_REGS_SPAN (0x04000000) # define HW_REGS_MASK (HW_REGS_SPAN-1) # define RW_SLAVE_OFST 0x00000000 volatile uint32_t *custom_slave_rw; void *virtual_base; int main() { int fd; if( ( fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) { printf( "ERROR: could not open \"/dev/mem\"...\n" ); return( 1 ); } 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 ); } custom_slave_rw = (uint32_t*)(virtual_base + ( (ALT_LWFPGASLVS_OFST + RW_SLAVE_OFST) & (HW_REGS_MASK))); uint32_t read_value = *custom_slave_rw; printf("Value read = 0x%08x\n",read_value); //READ 32--BIT-WORD FROM FPGA uint32_t write_value = 0x69696969; custom_slave_rw = write_value; //WRITE 32-BIT-WORD INTO FPGA printf("Value written = 0x%08x\n\n",write_value); cleanup: if( munmap( virtual_base, HW_REGS_SPAN ) != 0 ) { printf( "ERROR: munmap() failed...\n" ); close( fd ); return( 1 ); } close(fd); return 0;  

 

Regards, 

Akshay
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Hello Akshay, Im using your code to test. But I have an error. {Port "scratch_slave_32_bits_rw_0_conduit_end_export" does not exist in macrofunction "soc_system_inst_1"}. Do you have any idea ? Thank you.

0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Hey, 

 

1) Please check if you included the Avalon slave in the Qsys component. 

2) Check if you have exported the port "scratch_slave_32_bits_rw_0_conduit_end_export" as Conduit in the Avalon slave Qsys component. 

 

You could use this well explained blog for reference: https://zhehaomao.com/project/2014/01/02/fpga-series.html 

 

Regards, 

Akshay
0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

Thank you Akshay !

0 Kudos
Altera_Forum
Honored Contributor II
1,619 Views

I really don't get why HW_REGS_BASE (0xfc000000) must be used?! 

Can anybody explain this? 

 

This is the Base Address of the Coresight System Trace Macrocell or not?! 

 

cant we mmap the ALT_LWFPGASLVS_OFST instead?
0 Kudos
APaci1
Novice
1,619 Views

Hi to every one! I'm attempting to do something similar to this question.. I want read/write QSYS on chip memory dual access from HPS running a C app under Linux

 

I make a bootable sd card with angstrom 2018.06 and it runs fine on my self-developed card with CycloneV Soc (!! hard work but it is done!!)

 

So, I connected DS-5 V29 to my card via remote system SH Connection, it works fine following Hello Word for Linux app tutorial!! DS-5 woks well.

 

Then I search to access to ONCHIP mem follwoing examples from LED access as you show here ! Virtual memory access and so on

 

MY PROBLEM is to determine a valid environment IN DS-5 to do it, in terms of libs to include!!!! THERE IS A BUNCH of mman.h, fcntl,h etc etc.. they are under my Linaro distro spl directory

  • If I use GCC compiler , I obtain errors on valid simple code C and I must use ARM-5 compiler
  • Then, I use ARM-5 compiler, but it doenst' find std.io basic libraries, options 0_SYNC and other options in mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0) are not acks correctly
  • THERE IS A OVERVIEW OR A MANUAL TO CREATE A RELIABLE DS-5 ENVIRONMENT to works fine writing HPS C APP???? It is difficult to link and search a bunch of libraries without a guide! Linux libs for mman.h are interconnetcted and so cannot be simply copied under the project folder, but probavly they must set as path..
  • I cannot find any tutorial about this issue!

Do you have solved this bunch?

 

Thanks in advance for any suggestion!

 

 

 

 

 

 

 

 

0 Kudos
Reply