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++
12590 Discussions

Programming NIOSII interfaced with custom component, using Avalon MM Interface

Altera_Forum
Honored Contributor II
3,703 Views

Hello Everyone, 

 

I am trying to interface NIOS II with a custom component using Avalon MM Inferface where NIOS acts as Master. 

During the C coding, how do i get access to the function to send/receive data through the Avalon MM interface ? 

Can i get direct access to the ports dedicated for the interface ? and Do i need to follow some particular protocol while C coding for the interface ?
0 Kudos
23 Replies
Altera_Forum
Honored Contributor II
1,432 Views

You'll want to use the IOWR(),IORD() functions to access Avalon-MM registers in your peripheral (assuming that you're trying to read/write registers). See the software handbook (http://www.altera.com/literature/hb/nios2/n2sw_nii5v2.pdf), page 9-4 in particular. Or you can use the direct functions (ex IORD_32DIRECT()).

0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Thanks.. that helped. 

Other than this i have a very basic confusion. In my project, i want to transfer 128 16-bit values to the custom component (slave) and this values will be used by component to evaluate the final output and that output will again be sent back to NIOS (master).  

So should i just write IOWR_32DIRECT() 128 times as below: 

IOWR_32DIRECT(BASE, OFFSET0, DATA0);IOWR_32DIRECT(BASE, OFFSET0, DATA1); 

IOWR_32DIRECT(BASE, OFFSET0, DATA2); 

IOWR_32DIRECT(BASE, OFFSET0, DATA127); 

 

And then read the final output register as: 

 

IORD_32DIRECT(BASE, OFFSET1); 

 

If this is correct, does the nios II automatically sends the data sequentially ? Then how does the custom component gets to know when the new data arrives ?? And how NIOS will know when to read the final output register. 

 

Thanks for your time & effort, 

Anuj
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Your custom component uses 16 bit Avalon data bus or 32 bit Avalon data bus.If it is using 16 bit Avalon data bus then you should write IOWR_16DIRECT instead of IOWR_32DIRECT and same way for IORD function also. 

Other then that your C code is correct. 

 

Whenever you use IOWR function,Avalon Master generate Avalon write request and provide address of Slave Component Register on Avalon address bus line and provides data on Avalon data bus.Avalon Slave component uses this write request and address information to update its registers.Same way for IORD function,Avalon Master generates read request and address of the Slave component register.In this case slave component provides data on Avalon data bus.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

OK.. I got it. Thanks. 

 

Now when i am compiling my system in Quartus it gives warning as "Warning (20028): Parallel compilation is not licensed and has been disabled" and also says ".sdc file not found". 

 

Please guide
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

If you wanted to burst the data to be a little more efficient, you could DMA the data over. Or, I THINK if you have a data cache, you could move data as pointers and that might burst (i.e. don't use the IOWR/RD macros that bypass the cache), but I'm not sure, I've never done that - just read about it on this forum before. If a few wasted clock cycles don't matter, then you could just do a bunch of IORD/WR ops. 

 

I'm guessing you're using Quartus Web Edition? It doesn't support parallel compilation.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Do you mean to include a DMA block in between Master & Slave ?? 

 

As per the forum discussions, it suggests to optimize the code to avoid parallel computing. But i cannot understand which part of my design is creating this issue and what should i optimize? Is this the data bus width i.e. 16 bit that i am sending in parallel?? 

 

And i did not use Avalon Bridge in the interface.. Is it recommended? I saw in the online lectures that it is necessary but i compiled my code without that too.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

A DMA core could be used for efficient burst transfer between memory locations. See the embedded IP user's guide (http://www.altera.com/literature/ug/ug_embedded_ip.pdf), chapters 25 & 26 for the SGDMA and DMA cores. There's also the modular SGDMA (mSGMDA) available on the wiki (http://www.alterawiki.com/wiki/modular_sgdma), but I don't have any experience with it. 

 

The warning (20028) just means that Quartus II won't use multiple cores to synthesize/fit your design. I.e. it may take a little longer to build the image. The standard edition of Quartus II does support it - but I honestly do see a huge improvement, it still uses 1 core on my quad core xeon for the most part. 

 

When you say "Avalon Bridge", are you referring to the pipelined bridge? You can use those to break up your bus if you have a lot of components and you're having trouble meeting timing. If you just have a few peripherals, and a reasonable clock speed, you probably don't have to bother with it.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

I have one more question... 

 

I made a new component in Qsys to implement my custom design. And from there i got the base address allocated to that component that will be used during the communication through the avalon MM interface (in NIOS). But I got one more option to implement the custom component.. 

 

I created the design in Qsys w/o custom component. Got that design imported in quartus and manually instantiated the HDL file of custom component in the TOP Level file generated by Qsys. I was successful in compiling the code.  

"But how to get the base address allocated to my custom block in this case ?? I need that address while coding in NIOS."
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

 

--- Quote Start ---  

 

 

"But how to get the base address allocated to my custom block in this case ?? I need that address while coding in NIOS." 

--- Quote End ---  

 

 

I don't think so you can access your custom component which is not having Avalon Interface using NIOS. Would you please tell what do you want to do with your custom component?
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Hi,  

I succeeded in implementing the system on board. My custom component is a 128 tap FIR filter which is to be started by NIOS and stimuli is also provided by nios. I made the custom component in Qsys and implemented the system. 

Now i am able to write the c code successfully on the NIOS without any tool errors. 

 

But, i am not able to communicate properly. Below is my code: 

 

int var =1234; 

IOWR(20496,0,11); 

 

printf("%d\n",var); //prints 1234 

 

var = IORD(20496,0); 

 

printf("%d\n",var); // prints 0 

 

When I am reading the same address and offset, it gives 0.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Your c code looks correct. I think there should be some problem in your custom component register interface logic. 

Would you provide that logic? 

 

Or You can verify using NIOS II Modelsim.You can also use signal tap and check whether data is written into your custom component register or not.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Hi, the code look like: 

 

always @(posedge csi_clk or posedge rsi_reset_n) begin // To read 

if (rsi_reset_n) begin 

 

end else if (avs_s0_read) begin 

avs_s0_readdata = START; 

end else begin 

avs_s0_readdata = 0;  

end 

end  

 

always @(posedge csi_clk or posedge rsi_reset_n) begin // To write 

if (rsi_reset_n) begin 

START <= 0; 

DATA <= 0; 

end else if (avs_s0_write) begin 

case (avs_s0_address) 

2'b00 : begin// 

START <= avs_s0_writedata; 

end 

2'b01 : begin 

DATA <= avs_s0_writedata; 

end 

default : begin 

DATA <= 0; 

end 

endcase 

end 

end 

 

In my C ode, i am trying to write START register (as posted previously) and read back START register. 

Please suggest. I need to come out of this issue soon
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

 

--- Quote Start ---  

Hi, the code look like: 

 

always @(posedge csi_clk or posedge rsi_reset_n) begin // To read 

if (rsi_reset_n) begin 

 

end else if (avs_s0_read) begin 

avs_s0_readdata = START; 

end else begin 

avs_s0_readdata = 0;  

end 

end  

 

--- Quote End ---  

 

 

Its look like your code is correct. Still you can replace above code with this one 

 

always @(posedge csi_clk or posedge rsi_reset_n)  

begin // To read 

if (rsi_reset_n) 

begin 

avs_s0_readdata <= 0; 

end 

else  

begin  

case(avs_s0_address) 

2'b00 : avs_s0_readdata <= START; 

default : avs_s0_readdata <= 0; 

endcase 

end 

end 

 

Apart from this what is the read and write latency of your Avalon interface.You can find it in your .tcl file.If write latency is zero then your write logic is correct and if your read latency is 1 then your read logic is correct. 

 

I have one doubt regarding reset.Is it active high or low? From the name of reset it looks like it is active low and you have used it as a active high. You can also find this from your .tcl file. 

 

Also make practice to use non blocking statement for sequential logic. 

 

Regards, 

 

Krupesh
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Hi, 

 

I am able to communicate with the custom component successfully. 

Now my final task is to calculate the no of clock cycles consumed by the custom component during the execution. 

 

I also included Signal Tap II in my design. But i don't know how to use that to calculate no of clock cycles. 

 

Please help.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

You can use performance counter or interval timer provided by the Altera or  

You can implement one counter inside your custom component and add one register to read its value.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

I used performance counter, but not able to see anything on the console. Not even the stuff which I was getting before adding the performance counter. 

I followed the steps below: 

 

1. Added Performance counter in Qsys Design. 

2. Added Timer. 

3. Used: 

PERF_RESET(); 

PERF_START_MEASURING(); 

PERF_BEGIN(); 

 

// Here is the code block to be tested. 

// I want to know the cycles consumed during this block. 

 

PERF_END(); 

PERF_STOP_MEASURING(); 

perf_print_formatted_report(); 

 

Please help if i am missing anything in the process.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

I have used performance counter long time ago.Its look like that you are doing the same thing. Here is my code 

 

PERF_RESET(PERFORMANCE_COUNTER_0_BASE); 

PERF_START_MEASURING(PERFORMANCE_COUNTER_0_BASE); 

PERF_BEGIN(PERFORMANCE_COUNTER_0_BASE,1); 

 

// Here is the code block to be tested. 

// I want to know the cycles consumed during this block. 

 

PERF_END(PERFORMANCE_COUNTER_0_BASE,1); 

 

int cycles = IORD(PERFORMANCE_COUNTER_0_BASE,4); //Read the value of counter.Note that offset is set to 4. 

 

If it is not working then your should design counter in your custom component and read it using avalon interface for the quick solution.
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Thanks a lot zoomkrupesh, cronus10. 

 

With all your help and guidance, I successfully implemented and tested my project. 

 

Regards, 

Anuj Agrawal
0 Kudos
Altera_Forum
Honored Contributor II
1,432 Views

Hi Anuj, 

 

Would you please share how did you find the solution? So that it will be helpful to other users as well. 

 

Thanks, 

 

Krupesh
0 Kudos
Altera_Forum
Honored Contributor II
1,329 Views

For performance evaluation, I used the below template: 

 

PERF_RESET(PERFORMANCE_COUNTER_0_BASE); 

PERF_START_MEASURING(PERFORMANCE_COUNTER_0_BASE); 

PERF_BEGIN(PERFORMANCE_COUNTER_0_BASE,1); 

 

// Here is the code block to be tested. 

// I wanted to know the cycles consumed during this block. 

 

PERF_END(PERFORMANCE_COUNTER_0_BASE,1); 

PERF_STOP_MEASURING(PERFORMANCE_COUNTER_0_BASE); 

long time; 

time = perf_get_section_time(PERFORMANCE_COUNTER_0_BASE, 1); 

printf("\n\nTotal cycles consumed in FIR calculation = %ld cycles\n", time); 

 

This returns the no of clock cycles consumed. And by knowing the oscillator frequency, we can calcuate the total time consumed in the block. 

 

Thanks, 

Anuj
0 Kudos
Reply