Building a special elevator on an FPGA using Verilog

Status
Not open for further replies.

Verilognoob1

Newbie level 3
Joined
Dec 8, 2013
Messages
4
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Visit site
Activity points
56
Hello:

I'm having trouble starting this project which is building a special type of an elevator, I'm planning on using FSM and maybe behavioral, but behavioral will be really hard.. I kind of started building one using the FSM with a topelevel module, controller module, datapath module, and a slowclock module to implement it on the FPGA... I will post the requirements here in addition to my attempt ( my attempt is failing really bad when I try to implement it on FPGA using xilinx, so many error and warnings) any ideas and help editing would be appreciated it ....oh and I'm using Digilent BASYS2 FPGA board, I'm coding this project using Verilog on Modelsim, then flashing the fpga using Xilinx tools...

requirement of this special elevator:

The purpose of the Elevator Control System is to send an elevator to the correct floor to carry Zoompa
Boompa’s, the affectionate name for Billy’s highly-skilled workers, to the two key locations in the
chocolate factory where they make Billy’s famous candies - Floor #1 and Floor #4. Zoompa Boompas
may use slides at their discretion to go to lower floors whenever they wish.

!
There are four floors in the chocolate factory. Zoompa Boompa’s pressing the Floor #1 button will be
taken to Floor #4, the top floor. Zoompa Boompa’s pressing the Floor #4 button will be taken to the
bottom floor. If a Zoompa Boompa presses the Floor #2 or Floor #3 button, then they must go in the
current direction of travel of the elevator, taking them to either Floor #1 or Floor #4. So, unlike a normal
elevator, there is only one button per floor.

!
It takes 2-seconds to travel from one floor to the next. This must be simulated as part of your final
solution.

!
Oh … and one more thing. Billy Zonka has a “prefix code” - a special combination of switches that, if
thrown properly, blast the elevator out of the Chocolate Factory. The Prefix Code for this elevator is
1011. If four special switches (to be defined next) are set in this specific arrangement, then the Elevator
is instantaneously shot into the atmosphere and may only be reset to Floor #1 upon throwing a reset
button.

!
On your BASYS2 board you are to utilize the following buttons, switches, and LEDs:

* SW7 is your Elevator Reset Button. It should remain high when in active use, and toggling it low, then
high, resets the entire elevator control system (including placing the elevator back on Floor #1 if blasted
into space).

* SW3, SW2, SW1, and SW0 contain the Prefix Code Setting. If set to 1011 at any point during normal
operation, then the elevator ejects itself from the building.

* BTN3, BTN2, BTN1, and BTN0 represent the push buttons on Floors #1, #2, #3, and #4 respectively.

* LD3, LD2, LD1, and LD0 represent the four floors, #1 - #4, respectively, and are an indicator of where
the elevator is. So, if the elevator is on Floor #1, and a Zoompa Boompa presses the Floor #4 button,
the LD3 LED should turn off instantly, the LD2 LED should be on for 2-seconds, turn off, then the LD1
button should be on for 2-seconds, etc.

* If the elevator goes to Floor #1 or Floor #4 and has no queued push button requests on any floors,
then it should just remain at rest.

* If the elevator is traveling up, then the 7-segment display digit on the far right of the board should
display a “U”. If the elevator is traveling down, then the 7-segment display should display a “D”. If it is
not traveling at all, it should display a “-“. The other three displays should be off at all times.

* If the elevator is out of the factory due to the Prefix Code being set properly, then LD3, LD2, LD1, and
LD0 should ALL be on, and the 7-segment display should display a “-“.


my attempt:

toplevel
Code:
module toplevel (sevseg, segout, L1, L2, L3, L4, clock_2Hz, f1, f2, f3, f4, a, b, c, d, clock_50MHz, reset, direc, rest);
  
 output wire L1, L2, L3, L4, clock_2Hz, f1, f2, f3, f4, direc, rest;
 input wire a, b, c, d, clock_50MHz, reset;
 //input wire [3:0] prefix;
 output wire [0:6] sevseg, segout;
 
 
 controller I1 (f1, f2, f3, f4, segout, a, b, c, d, clock_2Hz, reset, direc, rest, prefix);
 datapath I2 (L1, L2, L3, L4, sevseg, f1, f2, f3, f4, segout, clock_2Hz, reset);
 slowclock I3 (clock_2Hz, clock_50MHz, reset);
 
 
endmodule

controller
Code:
module controller (f1, f2, f3, f4, segout, a, b, c, d, clock_2Hz, reset, direc, rest, prefix);
  
  output reg f1, f2, f3, f4;
  input wire a, b, c, d, clock_2Hz, reset;
  
  output reg direc, rest;
  
  input wire [3:0] prefix;
  
  output reg [0:6] segout;
  
  reg [2:0] presentState, nextState;											// TO BE DONE STILL: (NOTES TO ME)
																							// ADD PREFIX CODE
																							// NEXT STATE DETERMINATION FOR ALL FLOORS
																							// FIGURE OUT ERROR: Multi-source in Unit <controller> on signal <nextState<3>>; this signal is connected to multiple drivers.
																							// FIGURE OUT ERROR: "toplevel_toplevel.v" line 44: Invalid use of input signal <prefix> as target.
  parameter floor_1 = 2'b00; 
  parameter floor_2 = 2'b01;
  parameter floor_3 = 2'b10;
  parameter floor_4 = 2'b11; 

  
/* SET THE PRESENT STATE EQUAL TO THE NEXT STATE */
always @( posedge clock_2Hz or negedge reset) begin
  if( reset == 0 ) presentState <= floor_1;
  else presentState <= nextState;
  
  end
  
    
/* DETERMINE THE NEXT STATE */													
  always @ (presentState or a or b or c or d) begin
 
 
	if ( a == 1) direc <=1;
	if ( d == 1) direc <=0;
 
   case( presentState )
   floor_1: if( a == 1 ) nextState <= floor_2; else rest = 1;
   floor_2: begin if ( direc == 1) nextState <= floor_3; if (direc == 0) nextState <= floor_1; if( b == 1 && direc == 1) nextState <= floor_4; else if (b == 1 && direc == 0) nextState <= floor_1; end
   floor_3: begin if ( direc == 1) nextState <= floor_4; if (direc == 0) nextState <= floor_2; if( c == 1 && direc == 1) nextState <= floor_4; else if (c == 1 && direc == 0) nextState <= floor_1; end
   floor_4: if( d == 1 ) nextState <= floor_3; else rest = 1;
   default: nextState <= floor_1;
   
   endcase
	
	
   
  end



 
   /* ISSUE COMMANDS TO THE DATAPATH */
  always @ (presentState or a or b or c or d) begin
	
   case( presentState )
   floor_1: begin f1 = 1; f2 = 0; f3 = 0; f4 = 0; end
   floor_2: begin f1 = 0; f2 = 1; f3 = 0; f4 = 0; end
   floor_3: begin f1 = 0; f2 = 0; f3 = 1; f4 = 0; end
   floor_4: begin f1 = 0; f2 = 0; f3 = 0; f4 = 1; end
   default: nextState <= floor_1;
	
   endcase
   
   //if (prefix == 4'b1011) f1 <=1; // this line compiles, but not sure if works overall
   //if (prefix == 4'b1011) presentState <= floor_1 ; // this line compiles 
   //if
	
	end
 
   
 /* TELLS DATAPATH WHAT TO OUTPUT TO THE SEVSEG */
  always @ (presentState or a or b or c or d) begin
 
   if ( direc == 1) segout = 7'b1000001; 
	 if ( direc == 0) segout = 7'b1000010;
	 if ( rest == 1) segout = 7'b1111110;
	 //if ( f1 == 1 &&) segout = 7'b
	   
		 //f1 == 1; f2 == 1; f3 == 1; f4 == 1;
		 //segout = 7'b1111110;
		 
		 end
		 
endmodule

datapath
Code:
module datapath (L1, L2, L3, L4, sevseg, f1, f2, f3, f4, segout, clock_2Hz, reset);
  
  output reg L1, L2, L3, L4; 
  output reg [0:6] sevseg;

  input wire f1, f2, f3, f4, clock_2Hz, reset;
  
  input wire [0:6] segout;
  
always @ (posedge clock_2Hz or negedge reset) begin
  if (reset == 0) begin
  sevseg <= 7'b0000001;
  L1 <=1;
  L2 <=1;
  L3 <=1;
  L4 <=1;
  
  end
  
  else begin
  
 if( f1 ) L1 <= 1;
 if( f2 ) L2 <= 1;
 if( f3 ) L3 <= 1;
 if( f4 ) L4 <= 1;
 sevseg <= segout;
 
 end
    
  
 end
   
endmodule

slowclock
Code:
module slowclock (clock_2Hz, clock_50MHz, reset);
  
input wire reset;
input wire clock_50MHz;
output reg clock_2Hz;
reg [26:0] counter_50M;


// Create a 1Hz clock from the 50MHz oscillator that's on the eval board
always @ (posedge clock_50MHz or negedge reset)
 if (reset == 1'b0) begin
 clock_2Hz <= 0;
 counter_50M <= 0;
 end
 
 else begin
 
 if (counter_50M == 50000000) begin
 counter_50M <= 0;
 clock_2Hz <= ~clock_2Hz;
 
 end else begin
	counter_50M <= counter_50M + 1;
	clock_2Hz <= clock_2Hz;
  end
 
 end
 
endmodule
 

* Did you make a flowchart? That is a helpful aid for conceptualizing your project. Unfortunately they get cluttered as you make revisions, and redrawing them takes up time. So it's up to you.

* You make tests for numerous conditions, and then you perform actions. The orderly way to do this is to set a status flag (or several flags), and wait until you exit a function, then jump to the other function if you need to perform an action.

* Put initial effort towards perfecting the modules which handle normal operation. Later on you can write routines for the unusual conditions.

* Somewhere you will have an idle loop, doing nothing but waiting for a button to be pressed. You'll return to this loop when everything that needs to be done has been done.

* As you run the program, have it display running status of variables. Watch to see if these behave correctly when certain things happen, when you press the buttons, when the elevator is between floors, when it arrives at a floor, etc.

- - - Updated - - -

* A function (or module) is easier to grasp if you can see all of it on one screen.

* This project is complex enough that you will need to eat, live and breathe it for at least a couple days. Just to get a grasp on all the different IF...THEN conditions, it takes a while.
 

Post #2 doesn't seem to understand that you are implementing a Verilog HW design on a BASYS2 board. Oh well.

Based on your RTL HW design...

- You are generating a clock from the output of a register.
This is a bad practice in an FPGA from the standpoint that the access from a register to the clock network is typically a path that is much more difficult to route and may result in much worse clock jitter performance. A better solution is to convert the signal to an enable pulse and run everything off of the 50 MHz clock or use a PLL/DLL/DCM etc to generate a clock. Though in your case with such a low frequency clock jitter is probably not an issue.

-Your generated clock isn't 2 Hz

Code Verilog - [expand]
1
2
3
if (counter_50M == 50000000) begin
 counter_50M <= 0;
 clock_2Hz <= ~clock_2Hz;


This code will result in counting from 0-50000000-0, which is 50000001 counts. This changes the frequency of the "clock". Also you've made a mistake in toggling your clock every time you reach a count of 50 million, that will result in a frequency that approximately 1/2 Hz (You doubled the period of the clock). So you should check for (12500000-1) to toggle at 4 Hz resulting in a 2 Hz output.

- Your multi-source error is due to a typo.

Code Verilog - [expand]
1
2
3
4
5
6
case( presentState )
   floor_1: if( a == 1 ) nextState <= floor_2; else rest = 1;
   floor_2: begin if ( direc == 1) nextState <= floor_3; if (direc == 0) nextState <= floor_1; if( b == 1 && direc == 1) nextState <= floor_4; else if (b == 1 && direc == 0) nextState <= floor_1; end
   floor_3: begin if ( direc == 1) nextState <= floor_4; if (direc == 0) nextState <= floor_2; if( c == 1 && direc == 1) nextState <= floor_4; else if (c == 1 && direc == 0) nextState <= floor_1; end
   floor_4: if( d == 1 ) nextState <= floor_3; else rest = 1;
   default: nextState <= floor_1;



Code Verilog - [expand]
1
2
3
4
5
6
case( presentState )
   floor_1: begin f1 = 1; f2 = 0; f3 = 0; f4 = 0; end
   floor_2: begin f1 = 0; f2 = 1; f3 = 0; f4 = 0; end
   floor_3: begin f1 = 0; f2 = 0; f3 = 1; f4 = 0; end
   floor_4: begin f1 = 0; f2 = 0; f3 = 0; f4 = 1; end
   default: nextState <= floor_1;


Both of these have a default of nextState, which is probably not what you intended. You should code the FSM as a single clocked always block.
The two always block FSM style (clocked state variable and combinatorial transition) can easily result in latches if not properly written.
Try not to string everything together on one line, doing that makes code less readable.

-The error about prefix is due to commenting out the line
//input wire [3:0] prefix;

-Some general observations.
Use 2001 style module declarations.
Your declaration.

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
module controller (f1, f2, f3, f4, segout, a, b, c, d, clock_2Hz, reset, direc, rest, prefix);
  
  output reg f1, f2, f3, f4;
  input wire a, b, c, d, clock_2Hz, reset;
  
  output reg direc, rest;
  
  input wire [3:0] prefix;
  
  output reg [0:6] segout;


Verilog 2001 style declaration.

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
module controller (
  output reg f1, f2, f3, f4,
  output reg [0:6] segout,
  input a, b, c, d, clock_2Hz, reset,
  output reg direc, rest,
  input prefix
);
// better coding practice is to put each port on a separate line...
module controller (
  output reg  f1,                       // now you can add comments for each port :-)
  output reg  f2,
  output reg  f3,
  output reg  f4,
  output reg [0:6]  segout,
  input  a,
  input  b,
  input  c,
  input  d,
  input  clock_2Hz,
  input  reset,
  output reg  direc,
  output reg  rest,
  input  prefix
);



- Use named association instead of order association for instantiated modules. It makes the code both more readable and allows you to add/delete ports without having your synthesis/simulation become a mess due to misconnected signals.

Code Verilog - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
slowclock I3 (clock_2Hz, clock_50MHz, reset);
[syntax]
...becomes this
[syntax=verilog]
  slowclock I3 (
    .clock_2Hz (clock_2Hz),
    .clock_50MHz (clock_50MHz),
    .reset (reset)
  );
[syntax]
 
-Your reset comes in from and external input to the toplevel and is used as an asynchronous reset. This is not a good design practice. You should use either synchronous resets or a asynchronous assert synchronous deassert reset. Definitely don't use a reset that comes directly from a pin unless you know it makes timing on the deassertion.
 
- Your if statements should be rewritten. You should be assigning direc in a single if - else if - else structure not the separate if's you currently have. Same thing with your nextState assignments in the case statement.
 
- It might make more sense to define your f1-f4 as a bus f[1:4] or f[4:1].
 
- instead of..
[syntax=verilog]
  always @ (presentState or a or b or c or d) begin


..use

Code Verilog - [expand]
1
always @ (*) begin


does the same thing but now you won't miss any of the RHS signals (or have extras like you do in this situation)

I'm sure there are more issues, but I'll leave it at this for now.

Regards
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…