Nios® II Embedded Design Suite (EDS)
Support for Embedded Development Tools, Processors (SoCs and Nios® II processor), Embedded Development Suites (EDSs), Boot and Configuration, Operating Systems, C and C++
Announcements
Intel Support hours are Monday-Fridays, 8am-5pm PST, except Holidays. Thanks to our community members who provide support during our down time or before we get to your questions. We appreciate you!

Need Forum Guidance? Click here
Search our FPGA Knowledge Articles here.
12409 Discussions

Simple interfacing between Avalon MM Slave and ARM HPS

Altera_Forum
Honored Contributor II
3,452 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
506 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
Altera_Forum
Honored Contributor II
506 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));
Altera_Forum
Honored Contributor II
506 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..
Altera_Forum
Honored Contributor II
506 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
Altera_Forum
Honored Contributor II
506 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
Altera_Forum
Honored Contributor II
506 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.

Altera_Forum
Honored Contributor II
506 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
Altera_Forum
Honored Contributor II
506 Views

Thank you Akshay !

Altera_Forum
Honored Contributor II
506 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?
APaci1
Novice
506 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!

 

 

 

 

 

 

 

 

Reply