Forum Discussion

TwoBit's avatar
TwoBit
Icon for New Contributor rankNew Contributor
6 years ago

Help learning to write an avalon wrapper for new custom component

I am a beginner learning Quartus. I am trying to write the HDL for a new component to make 2 LEDs blink in a system using a NIOS II processor. I'm trying to learn SystemVerilog rather than verilog. This HDL compiles without errors but is unfinished because I am still learning and and not fully certain how the avalon MM interface actually works. What is written is my understanding so far.

  1. Can someone please shed some light on how the addressing part works? I've been reading through the altera manuals but am starting to get muddled in all the info. I do not understand how to set addresses so that the LSB of writedata will alert my go_flag to make my hardware actually start and be enabled.
  2. Is my state machine correct? To get my module to show that it is in action I can just use the go_flag and the go_Flag_Start relationship to get the writedata[0] bit?
  3. Where can I find learn how to write the c-code for the NIOS II processor? I'm googling and see examples using commands like IOWR and stuff like that but I can't yet find resources for learning that. I know C but not these commands in C.
  4. Any general coding (HDL) tips are welcomed to. I look forward to hearing back. Thank you!

Here's the module and the interface for it that I've written so far:

/* Memory Map
* 
* Write - 0x00
* 
* Read - 0x01
*  
/*
 
 
/******LEDFlash Modules *******/
 
module LEDFlash
 
(
	input logic clock_50, 			//50MHz clock
	input logic reset,			// button 0 							
	input logic enable1,			//switch 0						
	input logic enable100Hz,		// switch 2
	input logic [31:0]goFlag,		// Flag to start the module 
						// (info will come from first bit of writedata[0];
	
	output logic state = 1'b0,		//0.5sec blink LED
	output logic led100Hz = 1'b0,		//100Hz blink LED
	
	// for read state
	output logic readLED = 1'b0		// LED to show when the nios is sending read data
);
 
 
//Counter registers declared:
logic [24:0] counter = 25'b0;			// 0.5sec counter bits start set to 0
logic [18:0] counter100Hz = 19'b0;		// 100Hz counter bits starts at 0 
						// (ctr needs 16 bits at count up to 50,000 cycles in binary)
 
//Counter: count for every 0.5 seconds
always_ff @ (posedge clock_50)			// at every pos clock edge do this: 
	begin 
		counter[24:0] <= counter[24:0] + 25'b1;		// all counter bits = counters + 1
		if (counter[24:0] == 25'd12500000)		// if counter bits = 25,000,000 cycles
			begin
				counter[24:0] <= 25'b0;		// reset counter to zero
			end
	end												
		
		
//State: blink for 0.5 seconds		
always_ff @ (posedge clock_50)						// at every pos clock edge do this:
	begin
		if (enable1 == 1'b1)
			begin
				if (counter[24:0] == 25'd12500000) 	// if counter bits = 25,000,000 AND 
									// enable is ON - blink
					begin
						state <= ~state;	// LED blinks every 25'd500,000 
									//(switch state from what it was previously - 
									// blinks on for 0.5 sec, then off for 0.5 									// sec)						
					end
			end
		else 
			state <= 1'b0;				// else, keep LED off
	end		
	
	
// Not sure this actually works correctly... 
 
//100Hz counter (500,000 cycles)
always_ff @ (posedge clock_50)
	begin 
		counter100Hz[18:0] <= counter100Hz[18:0] + 19'b1;		//start counting 
			if (counter100Hz[18:0] == 19'd500000)			//if 50,000 cycles are reached
				begin
					counter100Hz[18:0] <= 19'b0;		//reset counter100Hz													
				end
	end
	
// 100Hz blink
always_ff @ (posedge clock_50)				// why always_ff? should it be always_combo?
	begin
		if (enable100Hz == 1'b1)
			begin 
				if (counter100Hz[18:0] == 19'd500000)
					begin			
						led100Hz <= ~led100Hz;
					end
			end
		else 
			led100Hz <= 1'b0;
	end
	
endmodule
 
 
 
/************************ The Avalon Interface ****************************/ 
 
module avs_blinking_interface (
 
// Signals between FPGA and NIOS:
	// avs clock and reset
	input logic csi_clk,
	input logic rsi_rst_n,
	
	// avs slave signals: 
	input logic avs_s0_read,			// for a load transmission - reads/loads from master
	input logic avs_s0_write,			// for a store transmission - write to the master
	input logic [3:0] avs_s0_address,		// Why do I need an address?
	input logic [31:0] avs_s0_writedata,		// Comes from C code in NIOS
	output logic [31:0] avs_s0_readdata		// FPGA to NIOS
);		
	
	
	// Internal Logic
	logic [0:0]goFlag_Start = 1'b0;			// FYI: Would automatically be set to a 1 bit register
	
	// Blinking LED Instantiation
	LEDFlash U1 (
		.Clock_50(csi_clk), 
		.reset (rsi_rst_n), 
		.goFlag(goFlag_Start)
	);
	
	// How system should work when it talks through avs:
	always_ff @ (posedge csi_clk) begin
		
		if (!rsi_rst_n) begin				// If I don't press reset button (KEY0)
			
			// If no reset, start in Idle State = nothing happening on FPGA
			goFlag_Start <= 1'b0;			// go_flag_Start keeps anything from happening 								// because it's staying low right?
			
			if (avs_s0_write && avs_s0_address == 0) begin	// if sent a write command: slave is getting 									// data
				goFlag_Start <= avs_s0_writedata[0];	// set the go flag is based on LSB of 									//writedata
				
				// State depends on go flag
				case (goFlag_Start)
					
					1'b0: begin 
						// don't let U1 module activate - Idle state
				              end
							
					1'b1: begin	
						// start U1 module, start blinking - Blink state
								
						goFlag_Start <= 1'b0;	// reset goFlag
								
					      end
							
					default: begin
						//pick a default
						end
				endcase
				
			end
			
			//if read command sent:
			if (avs_s0_read && avs_s0_address == 1) begin
					// send something back...light up an LED?
					// just so I know read is actually working
					
					
			end 
			
		// reset is pressed:
		else		
			goFlag_Start <= 1'b0;			// Stay in idle state, go flag is LOW
		end
	end
 
endmodule

4 Replies

  • sstrell's avatar
    sstrell
    Icon for Super Contributor rankSuper Contributor

    There's a lot going on here. Things I've noticed:

    goFlag isn't doing anything in your LEDFlash. How is it supposed to work there? Is it supposed to be what you call "enable1"?

    Your LEDFlash instantiation is missing a number of the I/O defined in the module (enable1, enable100Hz, goFlag, etc.).

    You don't need an address input unless there is more than 1 addressable location required for reading from or writing to. That does not look to be the case here. You could just use the avs_s0_read, avs_s0_readdata, avs_s0_write, and avs_s0_writedata signals to read from or write to goFlag_Start.

    I don't see why you even need a state machine here. You already created enable signals for the flashing in the LEDFlash module and you're not doing anything more complicated than enabling or disabling the flashing.

    I suggest you take a look at a number of online trainings. Search for "avalon", "platform designer", and "verilog" to find things that may be applicable:

    https://www.intel.com/content/www/us/en/programmable/support/training/catalog.html

    This is a good starting point for creating a custom component that will work in Platform Designer:

    https://www.intel.com/content/www/us/en/programmable/support/training/course/oqsys3000.html

    #iwork4intel

    • TwoBit's avatar
      TwoBit
      Icon for New Contributor rankNew Contributor

      Wow, thank you for so much input! I was given this project to learn Quartus/FPGA stuff. It's really interesting to me but this is a lot to learn. The end goal of the project was to use memory mapping which is why I was trying to use the read/write/readdata/writedata/address parts and I wanted the LSB of writedata to read from/write to the go_Flag_Start. I will look into all the links you suggest and hopefully be back with improvements but I'm sure more questions will arise. Thank you again!