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

How to implement very basic custom QSys component

Altera_Forum
Honored Contributor II
2,330 Views

I know this question has to have been posted and answered, but I can't find it in a way I can understand and solve my problem. 

 

My effort is very basic and I'm new to the QSys way of FPGAs. Basically, I'm attempting to flash the LEDs of a De0 Nano from 'C'. 

 

I've divided the 8 LEDs into 3. 

 

Led7 is a VHDL heartbeat 

Led6..4 is a software controlled LED set via the standard altera Qsys PIO. 

Led3..0 a software controlled LED set via a custom avalon slave VHDL Qsys module 

 

Every thing compiles and programs fine. 

 

Led7, the heartbeat, is working fine. 

Led6..4 is working fine. 

Led3..0, my custom Qsys component, is not working. 

 

What have I done wrong? What am I missing? 

 

 

I've added the following VHDL component. 

 

ENTITY LGLed IS 

PORT( 

clk : in std_logic; 

reset_n : in std_logic; 

write : in std_logic; 

writedata : in std_logic_vector(7 downto 0); 

 

 

leds : out std_logic_vector(3 downto 0) 

 ); 

END LGLed; 

 

 

-- Architecture Body 

 

 

ARCHITECTURE synth OF LGLed IS 

signal myleds : std_logic_vector(3 downto 0); 

 

 

BEGIN 

process(clk, reset_n) 

begin 

if(reset_n = '0')then 

myleds <= to_stdlogicvector(x"0"); 

else 

if ((write = '1') and rising_edge(clk))then 

myleds <= writedata(3 downto 0); 

end if; 

end if; 

leds <= myleds; 

end process; 

end synth; 

 

 

 

My C code is as follows: 

# include <stdio.h># include "sys/alt_stdio.h"# include "alt_types.h"# include "system.h"# include "altera_avalon_pio_regs.h" 

 

# define LEDDELAY 125000 

 

 

 

 

int main() 

{ int n1; 

int cnt=0; 

unsigned char *my_register = (unsigned char*)alt_remap_uncached((void*)LGLED_BASE,sizeof(alt_8)); 

 

 

printf("Hello from Nios II!!!!\n"); 

 

 

while(1) { 

for (n1=0; n1 < LEDDELAY; n1++) {} 

IOWR_ALTERA_AVALON_PIO_DATA(PIO_LED_GREEN_BASE, (cnt) & 0xF); 

// IOWR_ALTERA_AVALON_PIO_DATA(LGLED_BASE, (cnt) & 0xF); 

*my_register = (cnt) & 0xF; 

 

 

cnt++; 

 

 

return 0; 

}
0 Kudos
11 Replies
Altera_Forum
Honored Contributor II
1,269 Views

Try declaring my_register as a alt_u32. 

Your custom component doesn't care of addr nor byte enable signals. Since Avalon is a 32bit bus, I guess the 8bit access could possibly write inconsistent data because Nios actually generates 4 8bit writes to complete the 32bit word.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

 

--- Quote Start ---  

Try declaring my_register as a alt_u32. 

Your custom component doesn't care of addr nor byte enable signals. Since Avalon is a 32bit bus, I guess the 8bit access could possibly write inconsistent data because Nios actually generates 4 8bit writes to complete the 32bit word. 

--- Quote End ---  

 

 

Ok...I tried the alt_u32 as follows: 

alt_u32 *my_register = (unsigned char*)alt_remap_uncached((void*)LGLED_BASE,sizeof(alt_8)); 

 

and as 

alt_u32 *my_register = (unsigned char*)alt_remap_uncached((void*)LGLED_BASE,sizeof(alt_u32)); 

 

Neither made a difference.  

 

Why would the 8bit access possibly write inconsistent data. Even (in most cases I've seen) when a 32bit bus does 4 writes for a byte, typically the whole byte is applied across the entire bus thus writing the same byte value from each lane 4 times (maybe not the same for avalon\nios). Additionally, doesn't the avalon support 8bit access even on a 32bit bus? I thought the docs say it does and it support automatic bus sizing. 

 

Just for clarity. 

I did try (just to make sure my vhld was compiled in) tying two of the LEDs to the reset and the write. The reset shows inactive as I would expect and the write I'm sure I can't see because of the speed. 

 

 

 

In any case, the suggested solution made no changes. It appears like the write never occurs. To test this, I implemented a latch on the write and routed it to one of the Leds. It doesn't occur. The Vhdl code never sees the write signal. Because of this, I dropped in a counter and check that the clock was there, and it is. So it just the write that is not happening as I would expect.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

You could post a .zip of your _hw.tcl and .vhd file together and someone might check it. 

 

But assuming there isn't some basic error like incorrect connections, "write never happens" could simply be because the software never did it. e.g. writing to the wrong address, or optimizer removing the statements in question. Similar to the use of u32, another easy change is to use the IOWR() macro from <io.h> instead of your straight pointer handling.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

I didn't use a tcl, only a vhdl and the component editor with the analyze file and then proceeded from there; however, Cris72 did get me thinking about the bus and byte lanes. I converted the vhdl to 32bit bus and it works fine now. So I guess the question now is, why don't I get the write when I use an 8bit bus. 

 

Edit...... 

 

I did a bit more trial and error and found that I can do 32/16/8 bit bus as long as the Qsys address is on a 32bit boundary. With any other boundary, I don't ever get the 'write'. I know how to use byte lanes for an 8 bit periph, but it does no good if I don't get a 'write'. 

 

So what do I need to do get the 'write' if my periph is not on a 32bit boundary?
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

 

--- Quote Start ---  

 

So what do I need to do get the 'write' if my periph is not on a 32bit boundary? 

--- Quote End ---  

 

Did you try using IOWR_8DIRECT instead of pointers or IOWR ?
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

 

--- Quote Start ---  

Did you try using IOWR_8DIRECT instead of pointers or IOWR ? 

--- Quote End ---  

 

 

 

Like in the commented code above, I did try IOWR_ALTERA_AVALON_PIO_DATA when I got it working, but it failed in a working environment (I totally don't understand that). 

 

But I have not tried IOWR_8DIRECT. I will today.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

I tried the following with the following success, or lack there of. (I changed the name just in case you see the difference) 

 

alt_u8 *my_register = (unsigned char*)alt_remap_uncached((void*)DE0NANOLEDS_BASE,sizeof(alt_u8)); 

 

IOWR_ALTERA_AVALON_PIO_DATA(DE0NANOLEDS_BASE, (cnt) & 0xF); 

IOWR_8DIRECT(DE0NANOLEDS_BASE, 0, (cnt) & 0xF); 

*my_register = ((cnt) & 0xF); 

 

With address on a 32bit boundary 

IOWR_ALTERA_AVALON_PIO_DATA(DE0NANOLEDS_BASE, (cnt) & 0xF); <-- The write does not occur 

IOWR_8DIRECT(DE0NANOLEDS_BASE, 0, (cnt) & 0xF); <-- The write does occur 

*my_register = ((cnt) & 0xF); <-- The write does occur 

 

With address on a 8bit boundary =># define DE0NANOLEDS_BASE 0x40018e9 

None of the accesses generate a write. 

 

I can do any 8/16/32bit accesses to any byte, or bytes, within the word all day long as long as the base address is 32bit aligned. If the address is 8/16 bit aligned, but not 32bit alligned, then I cannot do any accesses. 

 

Is there a setting somewhere that forces that all address must be 32bit aligned?
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

 

--- Quote Start ---  

 

I can do any 8/16/32bit accesses to any byte, or bytes, within the word all day long as long as the base address is 32bit aligned. If the address is 8/16 bit aligned, but not 32bit alligned, then I cannot do any accesses. 

 

Is there a setting somewhere that forces that all address must be 32bit aligned? 

--- Quote End ---  

 

 

I did some experimenting and the problem is not with your software or component. 

 

What I found was if you connect your component on a bus in parallel with wider components, it looks like the automatically generated Qsys adaptation modules are applying 32-bit alignment and your 8-bit writes to non-32-bit-aligned addresses are getting "lost" (specifically, altera_merlin_master_agent.sv). The issue might be straightforward like the address alignment depends on the bus width of the master (32-bit master -> 32-bit alignment, 64-bit master -> 64-bit alignment, ...). 

 

The only arrangement that I found that would work is to insert a Clock Crossing bridge with 8-bit data bus width between the wider bus and the narrower 8-bit components.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

Ahhhh...Ok... Atleast I'm not losing my mind. I was thinking it was my inexperience with Qsys and the avalon interface. Many thanks. Atleast I now have an understanding as to what is going on and how to fix it. 

 

Again. Thanks for the time and effort in researching this for me.
0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

For those who see the same problem, I finally got it working. Here is the code. I'm not exactly sure why these differences make the difference, but it works now and gives me a foundation to go further for what I need.

0 Kudos
Altera_Forum
Honored Contributor II
1,269 Views

Hello, 

I am looking for interfacing a custom component with Arm processor. I have very little knowledge of Altera software tools. Could you please share document or link for learning custom component interface and use in bare metal or Linux environment? Could you please share how you learnt interfacing your custom peripheral slave? 

Thank you.
0 Kudos
Reply