- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all!
I'm having some trouble designing an Avalon MM slave component. I’m new with FPGA and probably is something really easy to fix. I’m using Quartus prime (15.1) and a Max10 FPGA development kit. I’d like to understand the right way to implement a custom Avalon MM salve component and to integrate it into Qsys to read/write registers from NIOS processor. At moment I can write and read the registers from the processor but something strange is happening into the memory. The component is using 8 bits address and 4 test registers LED0, LED1, LED2, LED3. When I try to write the registers with 4 different values it seems that the values are shifted by 1 location (a word) and the last value is written in all the rest of the memory space allocated to the component. The component address assigned in Qsys is 0x9400 and the picture attached shows the content of the memory in debug mode in Eclipse. Verilog code and C code are also attached. Does anybody have a good idea about a solution? Thanks Verilog component code: // testSlave.v `timescale 1 ps / 1 ps module testSlave ( input [7:0] avs_testSlave_address, // testslave.address input avs_testSlave_read, // .read output [31:0] avs_testSlave_readdata, // .readdata input avs_testSlave_write, // .write input [31:0] avs_testSlave_writedata, // .writedata output avs_testSlave_waitrequest, // .waitrequest input clock_testSlave_clk, // clock_testSlave.clk input reset_testSlave_reset // reset_testSlave.reset ); reg [31:0] LED0,LED1,LED2,LED3; reg [31:0] avs_testSlave_readdata_; assign avs_testSlave_readdata = avs_testSlave_readdata_; always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset) begin //write if(reset_testSlave_reset == 1) //if(!reset_testSlave_reset) begin LED0 <= 0; LED1 <= 0; LED2 <= 0; LED3 <= 0; end else if(avs_testSlave_write) begin case(avs_testSlave_address) 0: begin LED0 <= avs_testSlave_writedata; end 1: begin LED1 <= avs_testSlave_writedata; end 2: begin LED2 <= avs_testSlave_writedata; end 3: begin LED3 <= avs_testSlave_writedata; end endcase end end always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset) begin //read if (reset_testSlave_reset == 1) begin avs_testSlave_readdata_ <= 0; end else if(avs_testSlave_read) begin case(avs_testSlave_address) 0: begin avs_testSlave_readdata_ <= LED0; end 1: begin avs_testSlave_readdata_ <= LED1; end 2: begin avs_testSlave_readdata_ <= LED2; end 3: begin avs_testSlave_readdata_ <= LED3; end endcase end end endmodule Nios C code: while(1) { if(alt_timestamp() > 50000000) { printf("* %u \n", alt_timestamp()); printf("* %u \n", counter); counter++; alt_timestamp_start(); if(counter %2 == 0) { testValue = 0x0A; IOWR(TESTSLAVE_0_BASE, 0, testValue); printf("\n write0 %u \n", testValue); testValue = 0x0B; IOWR(TESTSLAVE_0_BASE, 1, testValue); printf("\n write1 %u \n", testValue); testValue = 0x0C; IOWR(TESTSLAVE_0_BASE, 2, testValue); printf("\n write2 %u \n", testValue); testValue = 0x0D; IOWR(TESTSLAVE_0_BASE, 3, testValue); printf("\n write3 %u \n", testValue); } else { ledRegValue0 = IORD(TESTSLAVE_0_BASE, 0); printf("\n read led0 %u \n", (ledRegValue0)); ledRegValue1 = IORD(TESTSLAVE_0_BASE, 1); printf("\n read led1 %u \n", (ledRegValue1)); ledRegValue2 = IORD(TESTSLAVE_0_BASE, 2); printf("\n read led2 %u \n", (ledRegValue2)); ledRegValue3 = IORD(TESTSLAVE_0_BASE, 3); printf("\n read led3 %u \n", (ledRegValue3)); } } } http://www.alteraforum.com/forum/attachment.php?attachmentid=11459&stc=1Link Copied
14 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello,
Few points from my side : (1) Offsets which are provided as arguments in IOWR/IORD functions are byte offsets. (2) Data width for your component (width for read data and write data) is 32 bits. I request you to read description of 'address' from Table 3-1: Avalon-MM Signal Roles, Avalon Specification. Also read description about 'addressUnits' parameter from that specification. Thus, for your code, register -> byte offset (to be used in iowr/iord) -> avalon slave offset(to be used in verilog file) LED0 -> 0x0 -> 0x0 LED0 -> 0x4 -> 0x1 LED0 -> 0x8 -> 0x2 LED0 -> 0xC -> 0x3 In short, if you wish to write to LED2, you should use following : IOWR(TESTSLAVE_0_BASE, 0x8, testValue); Similarly for LED3, IOWR(TESTSLAVE_0_BASE, 0xC, testValue); Cheers, Bhaumik- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Bhaumik is correct only if you have set the addressing as byte, your current addressing is correct if your tcl file specifies word addressing.
The issue is you are not generating a the wait signal correctly for your read data implementation. Since you do not generate wait at all it will be connected as a 0 and therefor data must be ready in the same clock as the read command is issued. Since your data is registered you must COMBINATIONALLY generate a wait=1 for the clock that the read is issued and then deassert wait the next clock.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Bhaumik,
thanks for replying. I did the following changes : testValue = 0x0A; IOWR(TESTSLAVE_0_BASE, 0x00, testValue); printf("\n write0 %u \n", testValue); testValue = 0x0B; IOWR(TESTSLAVE_0_BASE, 0x04, testValue); printf("\n write1 %u \n", testValue); testValue = 0x0C; IOWR(TESTSLAVE_0_BASE, 0x08, testValue); printf("\n write2 %u \n", testValue); testValue = 0x0D; IOWR(TESTSLAVE_0_BASE, 0x0C, testValue); printf("\n write3 %u \n", testValue); and ledRegValue0 = IORD(TESTSLAVE_0_BASE, 0x00); printf("\n read led0 %u \n", (ledRegValue0)); ledRegValue1 = IORD(TESTSLAVE_0_BASE, 0x04); printf("\n read led1 %u \n", (ledRegValue1)); ledRegValue2 = IORD(TESTSLAVE_0_BASE, 0x08); printf("\n read led2 %u \n", (ledRegValue2)); ledRegValue3 = IORD(TESTSLAVE_0_BASE, 0x0C); printf("\n read led3 %u \n", (ledRegValue3)); and the NIOS II console is printing: read led0 10 read led1 10 read led2 10 read led3 10 So, still not working. To be honest I did this attempt before posting this issue and I knew the result... Any other idea? Thanks, Dario- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Necare,
this totaly makes sense and can explain why the reading is shifted by one. Also I'm trying to read continuosly just one register and it works fine after the first cycle. Do you have any idea about the reason why the other component locations are filled with 0x0D000000? (please refer to the previous screenshot) Thanks, Dario- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
The first D is likely because your code ran and thus loaded the value of LED3 into the register before the dump.
The value of LED3 is in all other locations because your code doesn't update the read data register for any other addresses. If your case statement was sized to the lower 2 bits it would cycle between all 4 values or you could put a "default:" case to use for all other addresses. You could prove this by reading a valid address(ie 9404) once then continuously reading invalid addresses and get the value you expected at that address for all of them (ie 0x0B)- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi guys,
thank you very much for your help! The component is working fine now. I referred also to Avalon Interface specification page 3-12. I'm attaaching a copy of the working verilog code, just in case somebody need it :) Cheers // testSlave.v `timescale 1 ps / 1 ps module testSlave ( input [7:0] avs_testSlave_address, // testslave.address input avs_testSlave_read, // .read output [31:0] avs_testSlave_readdata, // .readdata input avs_testSlave_write, // .write input [31:0] avs_testSlave_writedata, // .writedata output avs_testSlave_waitrequest, // .waitrequest input clock_testSlave_clk, // clock_testSlave.clk input reset_testSlave_reset // reset_testSlave.reset ); reg [31:0] LED0,LED1,LED2,LED3; reg [31:0] avs_testSlave_readdata_reg; reg waitRequest; assign avs_testSlave_readdata = avs_testSlave_readdata_reg; assign avs_testSlave_waitrequest = avs_testSlave_read & waitRequest; always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset) begin //write if(reset_testSlave_reset == 1) //if(!reset_testSlave_reset) begin LED0 <= 0; LED1 <= 0; LED2 <= 0; LED3 <= 0; end else if(avs_testSlave_write) begin case(avs_testSlave_address) 0: begin LED0 <= avs_testSlave_writedata; end 1: begin LED1 <= avs_testSlave_writedata; end 2: begin LED2 <= avs_testSlave_writedata; end 3: begin LED3 <= avs_testSlave_writedata; end endcase end end always @(posedge clock_testSlave_clk or posedge reset_testSlave_reset) begin //read if (reset_testSlave_reset == 1) begin avs_testSlave_readdata_reg <= 0; waitRequest <= 1; end else if(avs_testSlave_read == 1) begin waitRequest <= 0; case(avs_testSlave_address) 0: begin avs_testSlave_readdata_reg <= LED0; end 1: begin avs_testSlave_readdata_reg <= LED1; end 2: begin avs_testSlave_readdata_reg <= LED2; end 3: begin avs_testSlave_readdata_reg <= LED3; end default: begin avs_testSlave_readdata_reg <= 0; end endcase end else if(avs_testSlave_read == 0) begin waitRequest <= 1; end end endmodule- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Dario,
Thank you for posting your Verilog code here. If you do not mind, I request you to post here HW_TCL file for that component as well. Both Verilog file and HW_TCL file together would make it much easier for somebody else to take reference from that. Cheers, Bhaumik- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi, Thanks for the above, very helpful.
But I am still having trouble outputting data from a bidirectional PIO. I am working with a DE0-Nano-SoC, in C in Linux, and have created 2 output only PIOs, which work fine. I also have a bidirectional data PIO that can read readonly registers in my firmware, but if I write data to read/write registers in my firmware, and then read it back, it is always 0. Tracing with SignalTap shows no data being output from the PIO on write. Below is the crucial code, I am hoping someone can see where I am going wrong. Is it the address calculation for the Data Direction register ? This is for the Data register (which works for the output only PIOs) : h2p_lw_pio_d_addr=virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE ) & ( unsigned long)( HW_REGS_MASK ) ); Is this right for the Data Direction register ? h2p_lw_pio_d_dirn = virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE + 1 ) & ( unsigned long)( HW_REGS_MASK ) ); https://alteraforum.com/forum/attachment.php?attachmentid=14661&stc=1 I am setting this as : Write : Set Data (8 bit) : Data = strtol(argv[4], &strptr, 10); // Data to write *(uint32_t *)h2p_lw_pio_d_addr = Data; Output it : *(uint32_t *)h2p_lw_pio_d_dirn = 0xff ; // All PIO Data bits set to output (write) Set Input : *(uint32_t *)h2p_lw_pio_d_dirn = 0x00 ; // All PIO Data bits set to input (read) Read Data : SkelData_read = *(uint32_t *)h2p_lw_pio_d_addr; Thanks, Beau Webber- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Try it like this:
h2p_lw_pio_d_dirn = virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE + 4 ) & ( unsigned long)( HW_REGS_MASK ) ); The gpio_swporta_ddr (data direction) register offset is 0x4, not 0x1, according to cv_5_hps_trm.pdf manual.- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- Quote Start --- Try it like this: h2p_lw_pio_d_dirn = virtual_base + ( ( unsigned long )( ALT_LWFPGASLVS_OFST + PIO_D_BASE + 4 ) & ( unsigned long)( HW_REGS_MASK ) ); The gpio_swporta_ddr (data direction) register offset is 0x4, not 0x1, according to cv_5_hps_trm.pdf manual. --- Quote End --- Yes indeed you are quite correct, that works fine, thank you very much. I can now read and write the registers in my firmware. I understand the 4 vs 1 is a matter of byte vs word addressing. I now have 4 of the "instruments" from my Cyclone II firmware installed in the DE0-Nano-SoC fabric, and under test. Sorry to be a pain, but can you give me a link to the cv_5_hps_trm.pdf manual ? I have searched the Altera site and not yet found it. .
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Is it a Cyclone IV device on the DE0-Nano board?
I used the Cyclone V manual since that's what I have available in my board (DE10-Nano). The Cyclone V HPS Technical Reference manual is here: https://www.altera.com/documentation/sfo1410143707420.html Page 22-4, GPIO Module Address Map. Try here to search for the corresponding Cyclone IV manual: https://www.altera.com/products/fpga/cyclone-series/cyclone-iv/support.html- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Oh thanks indeed.
I am using the DE0-Nano-SoC board, which has a Cyclone V : Programmable Logic IC Development Tools Cyclone V SE 5CSEMA4U23C6N + 800MHz Dual-core ARM Cortex-A9 processor http://www.terasic.com.tw/cgi-bin/page/archive.pl?language=english&categoryno=205&no=941 https://www.mouser.co.uk/new/terasic-technologies/terasic-atlas-soc-kit/ Except for the point that you have helped me over I have found it a very easy and flexible system to work with. The two rows of GPIO connectors map well to similar double rows of connectors on my Cyclone II modules, and is allowing me to port hardware as well as the firmware.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page