In this lab, you will take the Verilog concepts you have been learning and apply them to new subsystems in the car. Specifically, you will learn how to use the bumper switches to send stimulus to your Verilog modules, and how to control the motors of the car through a Verilog module. You will also learn how to distribute your Verilog code across multiple modules to make it more compartmentalize-able and easier to read.
Bumper SwitchesBefore we learn how to run, let’s learn how to stop, yeah? The bumper switches are located on the front end of your car, 3 of them each. Each signal passes through a resistor on the PCB to pull the signal. The digital signals come in on their own pins on the WebFPGA. When the bumpstop is unpressed, it outputs high; When it is pressed, it outputs low. See the pin mapping below for the correct bumper switch pin mapping for the PCB, and how they correspond physically to the actual car:
// @MAP_IO bump0 6
// @MAP_IO bump1 7
// @MAP_IO bump2 8
// @MAP_IO bump3 9
// @MAP_IO bump4 10
// @MAP_IO bump5 11
By setting these as input wires, we can use them to control digital signals. See below for a basic example:
// @MAP_IO bump0 6
// @MAP_IO bump1 7
// @MAP_IO bump2 8
// @MAP_IO bump3 9
// @MAP_IO bump4 10
// @MAP_IO bump5 11
// @MAP_IO motorL_pwm 0
// @MAP_IO motorL_dir 1
// @MAP_IO motorL_en 2
// @MAP_IO motorL_encdr 12
// @MAP_IO motorR_pwm 3
// @MAP_IO motorR_dir 4
// @MAP_IO motorR_en 5
// @MAP_IO motorR_encdr 14
module fpga_top(
input wire bump5,
output wire WF_LED,
output wire motorL_pwm,
output wire motorL_dir,
output wire motorL_en,
output wire motorR_pwm,
output wire motorR_dir,
output wire motorR_en
);
assign motorL_pwm = 0;
assign motorL_dir = 0;
assign motorL_en = 0;
assign motorR_pwm = 0;
assign motorR_dir = 0;
assign motorR_en = 0;
assign WF_LED = bump5;
endmodule
This basic code ties the bump switch to the LED on the WebFPGA. Try it out on your own system; when you press bump switch 5, the WebFPGA should turn on. Build off of this, can you create verilog modules that:
- Assign each switch to as many unique LEDs on the WebFPGA/RSLK (Don’t forget, the RSLK and WebFPGA LEDs have different turn on requirements)?
- Make the switches on the left turn on the LEDs on the left, and do the same for the right?
As you may have noticed in past code snippets, we’ve been including the motor GPIO pin mapping in the inputs and outputs. This is to ensure the motors don’t fire accidentally while you're testing unrelated code. Now, we’re going to start actually using those pin inputs. Real quick, let’s review the pin mapping that makes the motors NOT MOVE and nothing else:
// @MAP_IO motorL_pwm 0
// @MAP_IO motorL_dir 1
// @MAP_IO motorL_en 2
// @MAP_IO motorL_encdr 12
// @MAP_IO motorR_pwm 3
// @MAP_IO motorR_dir 4
// @MAP_IO motorR_en 5
// @MAP_IO motorR_encdr 14
module fpga_top(
output wire motorL_pwm,
output wire motorL_dir,
output wire motorL_en,
output wire motorR_pwm,
output wire motorR_dir,
output wire motorR_en
);
assign motorL_pwm = 0;
assign motorL_dir = 0;
assign motorL_en = 0;
assign motorR_pwm = 0;
assign motorR_dir = 0;
assign motorR_en = 0;
endmodule
Each motor has 3 signals that control it. There is motorL/R_en, which enables power to either motor when it is high, there is motorL/R_pwm, which actually makes the motor turn when it is high, and there is motorL/R_dir, which moves the wheel forward if it is low, or backwards if it is high.
VERY IMPORTANT: Setting PWM to high will make the given wheel turn at FULL SPEED in the direction set by the motor direction.
Make sure you have code in place to stop the wheels from turning (which we will go over shortly), or if you don’t and really want to try out making the car move, either hold it in your hands (keeping loose hair and clothes away from the spinning wheels) so you can turn it off easily, or be prepared to quickly pick the car up before you have any rapid unplanned disassembly from collisions/falls.
A quick aside: it’s not advisable to have the car’s wheels spinning at full speed, both for nuanced control and general motor health. We’ll do it for this portion of the lab, but in the next section we will talk about how to make the motors move more slowly.
Below is a code snippet to make the car spin in place at full speed for half a second, and then stops it by turning off all the motors. It uses timers, a concept you’re familiar with from Lab 3. Keep in mind, the car motors fire backwards briefly during start-up while the FPGA initializes. See if you can figure out, physically, why the car is spinning in place.
// @MAP_IO motorL_pwm 0
// @MAP_IO motorL_dir 1
// @MAP_IO motorL_en 2
// @MAP_IO motorR_pwm 3
// @MAP_IO motorR_dir 4
// @MAP_IO motorR_en 5
module fpga_top(
input WF_CLK,
output reg motorL_pwm,
output reg motorL_dir,
output reg motorL_en,
output reg motorR_pwm,
output reg motorR_dir,
output reg motorR_en
);
reg [31:0] counter;
always@(posedge WF_CLK)begin
if(counter <= 8000000)begin
motorL_pwm <= 1;
motorL_dir <= 0;
motorL_en <= 1;
motorR_pwm <= 1;
motorR_dir <= 1;
motorR_en <= 1;
counter <= counter + 1;
end
else
begin
motorL_pwm <= 0;
motorL_dir <= 0;
motorL_en <= 0;
motorR_pwm <= 0;
motorR_dir <= 0;
motorR_en <= 0;
counter <= counter;
end
end
endmodule
The car shooting backwards before immediately spinning around isn’t exactly optimal behavior. Here’s a problem for you.
- Can you create a simple state machine to make the car wait for the button to be pressed before doing the spin? That way, you can safely hold the car, turn it on, and wait for the wheels to stop spinning before setting it down and pressing the button. You may want to add another state delay after the button is pressed so you can get your hands clear before the spin begins. Hint: You can use button presses to trigger timers to start ticking up/down as well as deciding for a state to advance to a different state.
You may have noticed that the bit we assign to actually make the motor move is called PWM. PWM stands for pulse width modulation, which for us, refers to turning the motors on and off intermittently. Let’s say, for example, we turned the motors on and off, alternating every rising clock edge. Instead of being on for every rising clock edge, the motors are now only on for half of them. As a result, they are turning approximately 50 percent slower. See the code snippet below for an example. When flashed and synthesized, it will cause the motors to move forward at 50 percent speed.
// @MAP_IO motorL_pwm 0
// @MAP_IO motorL_dir 1
// @MAP_IO motorL_en 2
// @MAP_IO motorR_pwm 3
// @MAP_IO motorR_dir 4
// @MAP_IO motorR_en 5
module fpga_top(
input WF_CLK,
output reg motorL_pwm,
output reg motorL_dir,
output reg motorL_en,
output reg motorR_pwm,
output reg motorR_dir,
output reg motorR_en
);
reg [31:0] counter;
always@(posedge WF_CLK)begin
motorL_pwm <= ~motorL_pwm;
motorL_dir <= 0;
motorL_en <= 1;
motorR_pwm <= ~motorR_pwm;
motorR_dir <= 0;
motorR_en <= 1;
end
endmodule
The above module implements PWM in a very simple manner, taking advantage of the fact that our clock is only high for 50 percent of the time and syncing the motor signal to it. But what if we wanted the motor to be high 75 percent of the time? Or 25 percent of the time? This implementation is a bit more complicated, but we are going to provide you a module for it. We will detail it’s design and usage in the rest of this section before setting you loose in using it to implement a more complex set of motor movements. From here on out, any verilog for the RSLK that you write should use the motor module as a sub module of fpga_top. This makes it easier to encapsulate and read your designs, as well as giving you experience using multi-module verilog programs, as you will find more complex designs and subsystems will require them. Now, on to the motor module. Take a look at it below, read the comments, and see if you can understand how it works before moving on to the detailed explanation.
module pwm (
input wire clk,
input enable,
input[15:0] timeon,
output reg PWM
);
reg [15:0] timerPWM;
always @(posedge clk)
begin
if (enable)
begin
timerPWM <= timerPWM + 1'b1;
if (timerPWM == 16'd16000)
begin
timerPWM <= 0;
PWM <= 1'b1;
end
else if (timerPWM > timeon)
PWM <= 1'b0;
end
else
begin
timerPWM <=0;
PWM <= 0;
end
end
endmodule
The module above takes in the clock (to synchronize it’s elements with), a drive signal (that turns on the internal logic of the module), and a 7 bit long value called “speed”. The speed value you add should correspond to 100/x, where x is the percentage of speed you want to achieve. Note that values that don’t divide cleanly will be rounded down by Verilog. If you wanted 50 percent speed, you would set speed to 100/50, or 2, and if you wanted 20 percent speed, you would set speed to 100/20, or 5. You still have to enable the power signal, set the direction signal and the speed, and hook up the PWM output of the module to the motorL/R_pwm output of your top level module, but our submodule will handle the rest.
To use this module, simply paste it after the endmodule statement for your fpga_top module, then instantiate it as you would an and or xor gate level primitive module. From here, you can control it’s input signals like any other in your main state machine.
Here’s a problem for you. Can you make Verilog code, using the motor module, and your experience with state machines, to do the following:.
- Upon power up, wait in an idle state until the FPGA button is pressed.
- After the button is pressed, wait five seconds.
- Move forward at 25 percent power for two seconds, then stop for one second
- Move backwards at 50 percent power for one second, then stop for one second
- Turn in place at 75 percent power for 3 seconds, stop completely, and turn on all LEDs on the RSLK and WebFPGA.
- If at any point during the state machine, the any bumper switches are pressed, the car stops dead and aborts the sequence
It’s possible your car won’t move in a straight line when moving forwards and backwards, and that’s OK; this is due to slight imperfections or damages in the motors, wheels, and axles. We will implement subsystems to account for this and allow for precise turns and movements at a later date.
ConclusionCongratulations! With the completion of this lab, you now know how to control the speed and direction of your car’s motors. The lines of code you write on your computer can now move matter in the physical world; this is no small feat. You have the knowledge you need to wield this power safely and effectively. Soon, you will learn to move your car precisely, and even give it a mind of its own when it moves in the form of a control system that responds to digital inputs from external sensors. All future labs will use car movement, so make sure you get comfortable with adjusting speeds for straightaways and turns for your car.
Comments