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.
- 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.
- 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 bit?
- 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.
- 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; 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; // 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
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:
This is a good starting point for creating a custom component that will work in Platform Designer:
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!