Mecanum car with 4 motors - ada

I am trying to rotate a mecanum car 360 degrees to right. The car uses 4 motors along with L298N driver. Every other direction works fine, only when I try to rotate the car 360 degrees it rotates opposite side. LEFT is left side wheels; RIGHT is right side wheels. Here is the code:
with MicroBit.IOs;
with MicroBit;
with movement;
procedure Main is
Speed : constant MicroBit.IOs.Analog_Value := 1023; --between 0 and 1023
Forward : constant Boolean := True; -- forward is true, backward is false
begin
-- We set the frequency by setting the period (remember f=1/t).
MicroBit.IOs.Set_Analog_Period_Us(20000); -- 50 Hz = 1/50 = 0.02s = 20 ms = 20000us
--LEFT
--front
MicroBit.IOs.Set(6, Forward); --IN1
MicroBit.IOs.Set(7, not Forward); --IN2
--back
MicroBit.IOs.Set(2, Forward); --IN3
MicroBit.IOs.Set(3, not Forward); --IN4
--RIGHT
--front
MicroBit.IOs.Set(12, not Forward); --IN1
MicroBit.IOs.Set(13, Forward); --IN2
--back
MicroBit.IOs.Set(14, not Forward); --IN3
MicroBit.IOs.Set(15, Forward); --IN4
MicroBit.IOs.Write (0, Speed); --left speed control ENA ENB
MicroBit.IOs.Write (1, Speed); --right speed control ENA ENB
loop
null;
end loop;
end Main;
I tried to do it with procedure at first, but it did not work. I tried to do it on main to find the issue did not work. The weird part is that when I make the car go front it works just fine; when I try to make one side of the car go opposite direction for some weird reason the control suddenly happens opposite way.

It's hard to help without the actual hardware to test on, but googling datasheets and tutorials for L298N suggests the max value for speed may be 255, not 1023. Could this be related to your issue?
Anyway, I would declare some types and helper procedures, and move the magic numbers out of the control logic. Something like this:
(disclaimer: It haven't compiled or tested any of this...)
type Wheel_Pins is
record
Pin1 : Microbit.IOs.Pin_ID; -- IN1 / IN3
Pin2 : Microbit.IOs.Pin_ID; -- IN2 / IN4
end record;
type Sides is (Left, Right);
type Ends is (Front, Back);
type Spin_Direction is (Off, Backward, Forward);
subtype Wheel_Speed is MicroBit.IOs.Analog_Value range 0..255;
procedure Spin_Wheel( Wheel : Wheel_Pins; Direction : Spin_Direction) is
function Low return Boolean renames False;
function High return Boolean renames True;
begin
case Direction is
when Off =>
Microbit.IOs.Set(Wheel.Pin1, Low);
Microbit.IOs.Set(Wheel.Pin2, Low);
when Backward =>
Microbit.IOs.Set(Wheel.Pin1, Low);
Microbit.IOs.Set(Wheel.Pin2, High);
when Forward =>
Microbit.IOs.Set(Wheel.Pin1, High);
Microbit.IOs.Set(Wheel.Pin2, Low);
end case;
end Spin_Wheel;
procedure Set_Speed(Speed : Wheel_Speed; Vehicle_Side : Sides) is
To_Analog_Value : constant array(Sides'Range) --'
of Microbit.IOs.Pin_ID := (Left => 0, Right => 1);
begin
MicroBit.IOs.Write (To_Analog_Value(Vehicle_Side), Speed);
end Set_Speed;
procedure Stop_All_Wheels is
begin
for Wheel of Wheels'Range loop
Spin_Wheel(Wheel, Off);
end loop;
end Stop_All_Wheels;
The pin numbers could then be "hidden" like this:
Wheels : constant array(Ends, Sides) of Wheel_Pins :=
(Front => (Left => Wheel_Pins' --'
(Pin1 => 6,
Pin2 => 7),
Right => Wheel_Pins' --'
(Pin1 => 12,
Pin2 => 13)),
Back => (Left => Wheel_Pins' --'
(Pin1 => 2,
Pin2 => 3),
Right => Wheel_Pins' --'
(Pin1 => 14,
Pin2 => 15)));
I would then test each wheel individually, before combinations of wheels, to make sure the code works as expected:
Stop_All_Wheels;
Set_Speed(Left, 60);
Set_Speed(Right, 60);
-- test all wheels, both forward, backward and off,
-- in the following order: front-left, front-right, rear-left, rear-right
for Vehicle_Side in Wheel'Range(2) loop
for Vehicle_End in Wheels'Range(1) loop
for Direction in reverse Spin_Direction'Range loop
Spin_Wheel(Wheels(Vehicle_End, Vehicle_Side), Direction);
delay 2.0;
end loop;
end loop;
end loop;
-- test two wheels at a time:
for Direction in reverse Spin_Direction'Range loop
for Vehicle_End in Wheels'Range loop
Spin_Wheel(Wheels(Vehicle_End, Left), Direction);
end loop;
delay 2.0;
end loop;
-- test rotation clockwise
Spin_Wheel(Wheels(Front, Left), Forward);
Spin_Wheel(Wheels(Back, Left), Forward);
Spin_Wheel(Wheels(Front, Right), Backward);
Spin_Wheel(Wheels(Back, Right), Backward);
delay 2.0;
Stop_All_Wheels;
-- test rotation counter-clockwise
Spin_Wheel(Wheels(Front, Left), Backward);
Spin_Wheel(Wheels(Back, Left), Backward);
Spin_Wheel(Wheels(Front, Right), Forward);
Spin_Wheel(Wheels(Back, Right), Forward);
delay 2.0;
Stop_All_Wheels;
-- test speed settings
for Wheel of Wheels'Range loop
Spin_Wheel(Wheel, Forward);
end loop;
Speed_Up: for Speed in Wheel_Speed'Range loop
Set_Speed(Left, Speed);
Set_Speed(Right, Speed);
delay 0.01;
end loop Speed_Up;
delay 1.0;
Speed_Down: for Speed in reverse Wheel_Speed'Range loop
Set_Speed(Left, Speed);
Set_Speed(Right, Speed);
end loop Speed_Down;

Related

Drawing Bowling Pins (pyramid) with Recursion in Ada

I know this is pushing the good will of the community by presenting my least elaborate work expecting someone to come and save me but I simply have no choice with nothing to lose. I've gone through packets, files, types, flags and boxes the last few weeks but I haven't covered much of recursion. Especially not drawing with recursion. My exam is in roughly one week and I hope this is ample time to repeat and learn simple recursion tricks like that of drawing bowling pins or other patterns:
I I I I I
I I I I
I I I
I I
I
n = 5
The problem I have with recursion is that I don't quite get it. How are you supposed to approach a problem like drawing pins like this using recursion?
The closest I've come is
I I I
I I
I
n = 3
and that's using
THIS CODE NOW WORKS
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure pyramidchaser is
subtype X_Type is Integer range 0..30;
X: X_Type;
Indent : Integer := 0;
procedure Numbergrabber (X : out Integer) is
begin
Put("Enter a number: ");
Get(X);
Skip_Line;
end Numbergrabber;
procedure PrintSpaces(I : in Integer) is
begin
if I in X_Type then
Put(" ");
else
return;
end if;
PrintSpaces(I - 1);
end Printspaces;
procedure PrintPins(i, n: in Integer) is
begin
if i >= n then
return;
end if;
Put('I');
Put(' ');
PrintPins(i + 1, n);
end Printpins;
function Pins (X, Indent: in Integer) return Integer is
Printed : Integer;
begin
Printed:= 0;
if X > 0 then
PrintSpaces(Indent);
PrintPins(0, X);
New_Line;
Printed := X + Pins(X - 1, Indent + 1);
end if;
return Printed;
end Pins;
Bowlingpins : Integer;
begin
Numbergrabber(X);
Bowlingpins:= Pins(X, Indent);
end pyramidchaser;
but with that I throw in a sum I dont really need just to kick off the recursive part which I dont really know why I do except it seems to be needed to be there. I experimented with code from a completely different assignment, thats why it looks the way it does. I know mod 2 will grant me too many new lines but at least it was an approach to finding heights to the pyramid. I understand the real approach is something similar to N+1 as with each step of the growing pyramid a new line is needed, but I dont know how to implement it.
I don't expect anyone to present a complete code but I hope somebody can clue me in on how to think on the way towards finding a solution.
I can still pass the exam without knowing recursion as its typically 2 assignments where one is and one isnt recursion and you need to pass one or the other, but given that I have some time I thought Id give it a chance.
As always, immensely thankful for anyone fighting the good fight!
Seeing this post gathered some attention Id like to expand the pyramid to one a little more complex:
THE PYRAMID PROBLEM 2
hope someone looks at it. I didnt expect so many good answers, I thought why not throw all I have out there.
Level 1
|=|
Level 2
|===|
||=||
|===|
Level 3
|=====|
||===||
|||=|||
||===||
|=====|
it needs to be figured out recursively. so some way it has to build both upwards and downwards from the center.
To clarify Im studying for an exam and surely so are many others whom would be thankful for code to sink their teeth in. Maybe theres an easy way to apply what Tama built in terms of bowling pin lines in pyramid walls?
Bowling pins:
Printing ----I---- is just: (I'm going to use dashes instead of spaces throughout for readability)
Put_Line (4 * "-" & "I" & 4 * "-");
And printing the whole bowling triangle could be:
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
procedure Print_Bowling_Line (Dashes : Natural; Pins : Positive) is
Middle : constant String := (if Pins = 1 then "I"
else (Pins - 1) * "I-" & "I");
begin
Put_Line (Dashes * "-" & Middle & Dashes * "-");
end Print_Bowling_Line;
begin
Print_Bowling_Line (0, 5);
Print_Bowling_Line (1, 4);
Print_Bowling_Line (2, 3);
Print_Bowling_Line (3, 2);
Print_Bowling_Line (4, 1);
end Main;
Writing the five repeated lines as a loop is quite obvious. For recursion, there are two ways.
Tail recursion
Tail recursion is the more natural 'ask questions, then shoot' approach; first check the parameter for an end-condition, if not, do some things and finally call self.
procedure Tail_Recurse (Pins : Natural) is
begin
if Pins = 0 then
return;
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
Tail_Recurse (Pins - 1);
end Tail_Recurse;
Head recursion
Head recursion is what mathematicians love; how do you construct a proof for N? Well, assuming you already have a proof for N-1, you just apply X and you're done. Again, we need to check the end condition before we go looking for a proof for N-1, otherwise we would endlessly recurse and get a stack overflow.
procedure Head_Recurse (Pins : Natural) is
begin
if Pins < Total_Pins then
Head_Recurse (Pins + 1); -- assuming N + 1 proof here
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
end Head_Recurse;
For the full code, expand the following snippet:
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
Total_Pins : Natural := 5;
procedure Print_Bowling_Line (Dashes : Natural; Pins : Positive) is
Middle : constant String := (if Pins = 1 then "I"
else (Pins - 1) * "I-" & "I");
begin
Put_Line (Dashes * "-" & Middle & Dashes * "-");
end Print_Bowling_Line;
procedure Tail_Recurse (Pins : Natural) is
begin
if Pins = 0 then
return;
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
Tail_Recurse (Pins - 1);
end Tail_Recurse;
procedure Head_Recurse (Pins : Natural) is
begin
if Pins < Total_Pins then
Head_Recurse (Pins + 1); -- assuming N + 1 proof here
end if;
Print_Bowling_Line (Total_Pins - Pins, Pins);
end Head_Recurse;
begin
Total_Pins := 8;
Head_Recurse (1);
end Main;
For simplicity, I don't pass around the second number, that indicates the stopping condition, but rather set it once before running the whole.
I always find it unfortunate to try to learn a technique by applying it where it makes the code more complicated, rather than less. So I want to show you a problem where recursion really does shine. Write a program that prints a maze with exactly one path between every two points in the maze, using the following depth-first-search pseudo code:
start by 'visiting' any field (2,2 in this example)
(recursion starts with this:)
while there are any neighbours that are unvisited,
pick one at random and
connect the current field to that field and
run this procedure for the new field
As you can see in the animation below, this should meander randomly until it gets 'stuck' in the bottom left, after which it backtracks to a node that still has an unvisited neighbour. Finally, when everything is filled, all the function calls that are still active will return because for each node there will be no neighbours left to connect to.
You can use the skeleton code in the snippet below. The answer should only modify the Depth_First_Make_Maze procedure. It need be no longer than 15 lines, calling Get_Unvisited_Neighbours, Is_Empty on the result, Get_Random_Neighbour and Connect (and itself, of course).
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers; use Ada.Containers;
with Ada.Containers.Vectors;
with Ada.Numerics.Discrete_Random;
procedure Main is
N : Positive := 11; -- should be X*2 + 1 for some X >= 1
type Cell_Status is (Filled, Empty);
Maze : array (1 .. N, 1 .. N) of Cell_Status := (others => (others => Filled));
procedure Print_Maze is
begin
for Y in 1 .. N loop
for X in 1 .. N loop
declare
C : String := (case Maze (X, Y) is
--when Filled => "X", -- for legibility,
when Filled => "█", -- unicode block 0x2588 for fun
when Empty => " ");
begin
Put (C);
end;
end loop;
Put_Line ("");
end loop;
end Print_Maze;
type Cell_Address is record
X : Positive;
Y : Positive;
end record;
procedure Empty (Address : Cell_Address) is
begin
Maze (Address.X, Address.Y) := Empty;
end Empty;
procedure Connect (Address1 : Cell_Address; Address2 : Cell_Address) is
Middle_X : Positive := (Address1.X + Address2.X) / 2;
Middle_Y : Positive := (Address1.Y + Address2.Y) / 2;
begin
Empty (Address1);
Empty (Address2);
Empty ((Middle_X, Middle_Y));
end Connect;
function Cell_At (Address : Cell_Address) return Cell_Status is (Maze (Address.X, Address.Y));
function Left (Address : Cell_Address) return Cell_Address is (Address.X - 2, Address.Y);
function Right (Address : Cell_Address) return Cell_Address is (Address.X + 2, Address.Y);
function Up (Address : Cell_Address) return Cell_Address is (Address.X, Address.Y - 2);
function Down (Address : Cell_Address) return Cell_Address is (Address.X, Address.Y + 2);
type Neighbour_Count is new Integer range 0 .. 4;
package Neighbours_Package is new Ada.Containers.Vectors (Index_Type => Natural, Element_Type => Cell_Address);
use Neighbours_Package;
function Get_Unvisited_Neighbours (Address : Cell_Address) return Neighbours_Package.Vector is
NeighbourList : Neighbours_Package.Vector;
begin
NeighbourList.Reserve_Capacity (4);
if Address.X >= 4 then
declare
L : Cell_Address := Left (Address);
begin
if Cell_At (L) = Filled then
NeighbourList.Append (L);
end if;
end;
end if;
if Address.Y >= 4 then
declare
U : Cell_Address := Up (Address);
begin
if Cell_At (U) = Filled then
NeighbourList.Append (U);
end if;
end;
end if;
if Address.X <= (N - 3) then
declare
R : Cell_Address := Right (Address);
begin
if Cell_At (R) = Filled then
NeighbourList.Append (R);
end if;
end;
end if;
if Address.Y <= (N - 3) then
declare
D : Cell_Address := Down (Address);
begin
if Cell_At (D) = Filled then
NeighbourList.Append (D);
end if;
end;
end if;
return NeighbourList;
end Get_Unvisited_Neighbours;
package Rnd is new Ada.Numerics.Discrete_Random (Natural);
Gen : Rnd.Generator;
function Get_Random_Neighbour (List : Neighbours_Package.Vector) return Cell_Address is
Random : Natural := Rnd.Random (Gen);
begin
if Is_Empty (List) then
raise Program_Error with "Cannot select any item from an empty list";
end if;
declare
Index : Natural := Random mod Natural (List.Length);
begin
return List (Index);
end;
end Get_Random_Neighbour;
procedure Depth_First_Make_Maze (Address : Cell_Address) is
begin
null;
end Depth_First_Make_Maze;
begin
Rnd.Reset (Gen);
Maze (1, 2) := Empty; -- entrance
Maze (N, N - 1) := Empty; -- exit
Depth_First_Make_Maze ((2, 2));
Print_Maze;
end Main;
To see the answer, expand the following snippet.
procedure Depth_First_Make_Maze (Address : Cell_Address) is
begin
loop
declare
Neighbours : Neighbours_Package.Vector := Get_Unvisited_Neighbours (Address);
begin
exit when Is_Empty (Neighbours);
declare
Next_Node : Cell_Address := Get_Random_Neighbour (Neighbours);
begin
Connect (Address, Next_Node);
Depth_First_Make_Maze (Next_Node);
end;
end;
end loop;
end Depth_First_Make_Maze;
Converting recursion to loop
Consider how a function call works; we take the actual parameters and put them on the call stack along with the function's address. When the function completes, we take those values off the stack again and put back the return value.
We can convert a recursive function by replacing the implicit callstack containing the parameters with an explicit stack. I.e. instead of:
procedure Foo (I : Integer) is
begin
Foo (I + 1);
end Foo;
We would put I onto the stack, and as long as there are values on the stack, peek at the top value and do the body of the Foo procedure using that value. When there is a call to Foo within that body, push the value you would call the procedure with instead, and restart the loop so that we immediately start processing the new value. If there is no call to self in this case, we discard the top value on the stack.
Restructuring a recursive procedure in this way will give you an insight into how it works, especially since pushing on to the stack is now separated from 'calling' that function since you explicitly take an item from the stack and do something with it.
You will need a stack implementation, here is one that is suitable:
Bounded_Stack.ads
generic
max_stack_size : Natural;
type Element_Type is private;
package Bounded_Stack is
type Stack is private;
function Create return Stack;
procedure Push (Onto : in out Stack; Item : Element_Type);
function Pop (From : in out Stack) return Element_Type;
function Top (From : in out Stack) return Element_Type;
procedure Discard (From : in out Stack);
function Is_Empty (S : in Stack) return Boolean;
Stack_Empty_Error : exception;
Stack_Full_Error : exception;
private
type Element_List is array (1 .. max_stack_size) of Element_Type;
type Stack is
record
list : Element_List;
top_index : Natural := 0;
end record;
end Bounded_Stack;
Bounded_Stack.adb
package body Bounded_Stack is
function Create return Stack is
begin
return (top_index => 0, list => <>);
end Create;
procedure Push (Onto : in out Stack; Item : Element_Type) is
begin
if Onto.top_index = max_stack_size then
raise Stack_Full_Error;
end if;
Onto.top_index := Onto.top_index + 1;
Onto.list (Onto.top_index) := Item;
end Push;
function Pop (From : in out Stack) return Element_Type is
Top_Value : Element_Type := Top (From);
begin
From.top_index := From.top_index - 1;
return Top_Value;
end Pop;
function Top (From : in out Stack) return Element_Type is
begin
if From.top_index = 0 then
raise Stack_Empty_Error;
end if;
return From.list (From.top_index);
end Top;
procedure Discard (From : in out Stack) is
begin
if From.top_index = 0 then
raise Stack_Empty_Error;
end if;
From.top_index := From.top_index - 1;
end Discard;
function Is_Empty (S : in Stack) return Boolean is (S.top_index = 0);
end Bounded_Stack;
It can be instantiated with a maximum stack size of Width*Height, since the worst case scenario is when you happen to choose a non-forking path that visits each cell once:
N_As_Cell_Size : Natural := (N - 1) / 2;
package Cell_Stack is new Bounded_Stack(max_stack_size => N_As_Cell_Size * N_As_Cell_Size, Element_Type => Cell_Address);
Take your answer to the previous assignment, and rewrite it without recursion, using the stack above instead.
To see the answer, expand the following snippet.
procedure Depth_First_Make_Maze (Address : Cell_Address) is
Stack : Cell_Stack.Stack := Cell_Stack.Create;
use Cell_Stack;
begin
Push (Stack, Address);
loop
exit when Is_Empty (Stack);
declare
-- this shadows the parameter, which we shouldn't refer to directly anyway
Address : Cell_Address := Top (Stack);
Neighbours : Neighbours_Package.Vector := Get_Unvisited_Neighbours (Address);
begin
if Is_Empty (Neighbours) then
Discard (Stack); -- equivalent to returning from the function in the recursive version
else
declare
Next_Cell : Cell_Address := Get_Random_Neighbour (Neighbours);
begin
Connect (Address, Next_Cell);
Push (Stack, Next_Cell); -- equivalent to calling self in the recursive version
end;
end if;
end;
end loop;
end Depth_First_Make_Maze;
You’re going to print as many lines as there are pins. Each line has an indentation consisting of a number of spaces and a number of pins, each printed as "I " (OK,there's an extra space at the end of the line, but no one's going to see that).
Start off with no leading spaces and the number of pins you were asked to print.
The next line needs one more leading space and one fewer pin (unless, of course, that would mean printing no pins, in which case we're done).
I don't program in Ada (it looks like a strange Pascal to me), but there is an obvious algorithmic problem in your Pins function.
Basically, if you want to print a pyramid whose base is N down to the very bottom where base is 1, you would need to do something like this (sorry for crude pascalization of the code).
procedure PrintPins(i, n: Integer)
begin
if i >= n then return;
Ada.Text_IO.Put('I'); // Print pin
Ada.Text_IO.Put(' '); // Print space
PrintPins(i + 1, n); // Next iteration
end;
function Pins(x, indent: Integer): Integer
printed: Integer;
begin
printed := 0;
if x > 0 then
PrintSpaces(indent); // Print indentation pretty much using the same artificial approach as by printing pins
PrintPins(0, x);
(*Print new line here*)
(*Now go down the next level and print another
row*)
printed := x + Pins(x - 1, indent + 1);
end;
return printed;
end
P.S. You don't need a specific function to count the number of printed pins here. It's just a Gauss sequence sum of the range 1..N, which is given by N(N + 1)/2
A variation of this program is to use both head recursion and tail recursion in the same procedure.
The output of such a program is
Enter the number of rows in the pyramid: 5
I I I I I
I I I I
I I I
I I
I
I
I I
I I I
I I I I
I I I I I
N = 5
Tail recursion produces the upper triangle and head recursion produces the lower triangle.
The way you develop a recursive algorithm is to pretend that you already have a subprogram that does what you want, except for the first bit, and you know, or can figure out, how to do the first bit. Then your algorithm is
Do the first bit
Call the subprogram to do the rest on what remains,
taking into account the effect of the first bit, if necessary
The trick is that "Call the subprogram to do the rest" is a recursive call to the subprogram you're creating.
It's always possible that the subprogram may be called when there's nothing to do, so you have to take that into account:
if Ending Condition then
Do any final actions
return [expression];
end if;
Do the first bit
Call the subprogram to do the rest
And you're done. By repreatedly doing the first bit until the ending condition is True, you end up doing the whole thing.
As an example, the function Get_Line in Ada.Text_IO may be implemented (this is not how it is usually implemented) by thinking, "I know how to get the first Character of the line. If I have a function to return the rest of the line, then I can return the first Character concatenated with the function result." So:
function Get_Line return String is
C : Character;
begin
Get (Item => C);
return C & Get_Line;
end Get_Line;
But what if we're already at the end of a line, so there's no line to get?
function Get_Line return String is
C : Character;
begin
if End_Of_Line then
Skip_Line;
return "";
end if;
Get (Item => C);
return C & Get_Line;
end Get_Line;
For your problem the first bit is printing a row with an indent and a number of pins, and the ending condition is when there are no more rows to print.
For your pyramid problem, this tail recursion scheme doesn't work. You need to do "middle recursion":
if Level = 1 then
Print the line for Level
return
end if
Print the top line for Level
Recurse for Level - 1
Print the bottom line for Level

How to correctly increment the rate at which segments of a display illuminate via button press

I am programming a xilinx basys 3 board in behavioral VHDL. I am illuminating the individual segments of the 4x seven segment display to make it looks as though the display has two rotating "wheels". My overall project consists of many components such as a decoder, mux, debouncer, counter, clock divider for display refresh rate, etc. All of which have been cleared by my prof.
I am currently working on the component that takes in a 250 Hz clk and an up and down button. The up and down buttons will allow for the incrementation of a counter that is mapped to 11 different prescalar values. These values will then vary a clock divider max step accordingly.
Currently my reset button works. However the up and down buttons just pause the rotation of the segments instead of increasing the rate at which they rotate. I believe this component is the issue but I cannot find out where, within the three processes.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;
entity wheelClkDiv is
Port ( btnUp, btnDown, clk, reset : in STD_LOGIC;
--up/down/rst buttons and 250Hz clk initialized as inputs
clkout : out STD_LOGIC
-- newly divided clock initialized as output
);
end wheelClkDiv;
architecture Behavioral of wheelClkDiv is
signal count : STD_LOGIC_VECTOR(19 downto 0) := x"00000"; --20 bit count value for clk divider
signal temp : STD_LOGIC := '0'; --temp store value for clk divider
signal countDiv : STD_LOGIC_VECTOR(19 downto 0) := x"00000"; --value given to choose prescalar
signal btn_counter : STD_LOGIC_VECTOR(3 downto 0) := "0110"; --button press counter
begin
buttonChoose : process(btnUp, btnDown, reset)
begin
if(btnUp = '1') then
btn_counter <= btn_counter + 1; --add one to count if up button pushed
elsif(btnDown = '1') then
btn_counter <= btn_counter - 1; --subtract one from count if down button pushed
elsif(reset = '1') then
btn_counter <="0110"; --set back to middle speed if reset is pushed
end if;
end process;
setDivideCase : process(btn_counter)
begin
case btn_counter is --case statement to choose prescalar based on btn_counter value
when "0000" =>
countDiv <= b"00000000000110010000"; --3.2s cycle
when "0001" =>
countDiv <= b"00000000000100101100"; --2.4s cycle
when "0010" =>
countDiv <= b"00000000000011001000"; --1.6s cycle
when "0011" =>
countDiv <= b"00000000000010010110"; --1.2s cycle
when "0100" =>
countDiv <= b"00000000000001100100"; --0.8s cycle
when "0101" =>
countDiv <= b"00000000000001001011"; --0.6s cycle
when "0110" =>
countDiv <= b"00000000000000110010"; --0.4s cycle
when "0111" =>
countDiv <= b"00000000000000100110"; --0.3s cycle
when "1000" =>
countDiv <= b"00000000000000011001"; --0.2s cycle
when "1001" =>
countDiv <= b"00000000000000010011"; --0.15s cycle
when "1010" =>
countDiv <= b"00000000000000001101"; --0.1s cycle
when others =>
countDiv <= b"00000000000000001101";--not correct
end case;
end process;
wheelDivider : process(clk, reset)
begin
if(reset = '1') then --reset clock count if reset pushed
count <= x"00000";
temp <= '0';
elsif(rising_edge(clk)) then
if(count = countDiv) then --set clk counter value to prescalar
count <= x"00000";
temp <= not temp;
else
count <= count + 1; --keep incrementing clk count until it matches PS
temp <= temp;
end if;
end if;
end process;
clkout <= temp; --give temp value to output clk
end Behavioral;
First thing I see is that you ignore the fact the count signal is constantly counting.
When you hit reset, your count is back at `x"00000", this is the only reason it works.
But when you hit up/down button, you change the countDiv value from e.g.
countDiv <= b"00000000000000110010"; --0.4s cycle
to
countDiv <= b"00000000000000011001"; --0.2s cycle
but what if, in the moment of button click, the count is b"00000000000000100000" ?
The count = countDiv condition did not caught before, and not it will never catch. The count will start to count infinitely, and any further changes of countDiv won't change that fact (maybe will if you hit other button fast enough and expect of reset button of course). The clkout will stop at current value and display will freeze, until of course count overflows.
Of course the easiest resolution would be changing count = countDiv to count >= countDiv, but such comparison is resources consuming, so it is not good way to design fpgas. You should reset count value to zero every time you chage countDiv, or even better, count down to zero, starting at countDiv. Then temporary overflowing current countDiv should not be a problem. You have plenty of possibilities.
For example:
wheelDivider : process(clk, reset)
begin
if(reset = '1') then --reset clock count if reset pushed
count <= b"00000000000001001011";
temp <= '0';
elsif(rising_edge(clk)) then
if(count = x"00000") then --set clk counter value to zero
count <= countDiv;
temp <= not temp;
else
count <= count - 1; --keep decrementing count until zero
temp <= temp;
end if;
end if;
end process;
I am not sure if this is the only problem for now. Hope it is.

VHDL clock generator with different speeds using button

I am new to VHDL and currently working on a clock generator that generates two different clock speeds.
Everything is working, except the switch between the slow and fast speed_status.
There seems to be a problem with the "speed button" because sometimes I have to press it more than once to change the current set speed. The "reset button" is always working as expected. Is there something wrong with my VHDL Code or do I need to add some sort of software debouncing? If so, why is the reset button working?
And could you give me some advice which parts of my clock generator I could improve (code/logic)?
entity clk_gen is
Port ( clk_in : in STD_LOGIC;
clk_btn_in : in STD_LOGIC_VECTOR (3 DOWNTO 0);
clk_out : out STD_LOGIC);
end clk_gen;
architecture Behavioral of clk_gen is
signal temp : STD_LOGIC := '0';
begin
clock: process(clk_in,clk_btn_in)
variable counter : integer range 0 to 49999999 := 0;
constant freq_cnt_slow : integer := 49999999;
constant freq_cnt_fast : integer := 4999999;
type speed is (slow, fast);
variable speed_status : speed := slow;
begin
if rising_edge(clk_in) then
-- RESET BUTTON PRESSED
if (clk_btn_in = "1000") then
temp <= '0';
counter := 0;
speed_status := slow;
-- SPEED BUTTON
elsif (clk_btn_in = "0100") then
if (speed_status = fast) then
speed_status:= slow;
elsif (speed_status = slow) then
speed_status := fast;
end if;
end if;
if ((counter = freq_cnt_fast) and (speed_status = fast)) then
temp <= NOT(temp);
counter := 0;
elsif ((counter = freq_cnt_slow) and (speed_status = slow)) then
temp <= NOT(temp);
counter := 0;
else
counter := counter + 1;
end if;
end if;
end process clock;
clk_out <= temp;
end Behavioral;
I use Xilinx ISE 13.4 and the XC5VLX110T based on Xilinx Virtex 5.
It looks like your speed mode will toggle any time the button is in the 'pressed' state. Unless you can guarantee that your button is only 'pressed' for one clock period, the state is likely to toggle many times, making the state after you pressed the button essentially random (depending on the exact timing of the button press).
Firstly, you need a debouncing circuit on the button. This can be implemented externally, or within the FPGA. I will not go into switch debouncing in detail here, but you can easily find information on this elsewhere. Secondly, you need to convert the button into a synchronous signal, that is, one that has a fixed relationship to your clock. An example synchroniser for your example would be:
signal button_reg1 : std_logic_vector(3 downto 0) := (others => '0');
signal button_reg2 : std_logic_vector(3 downto 0) := (others => '0');
...
process (clk_in)
begin
if (rising_edge(clk_in)) then
button_reg2 <= button_reg1;
button_reg1 <= clk_btn_in;
end if;
end process;
button_reg2 will then have a fixed relationship to the clock.
Without this, you could violate the setup/hold constraints on the speed_status register. Lastly, you need to convert the pressing of the button into a pulse that is one clock period in length. Example:
signal speed_button_reg : std_logic := '0';
signal speed_button_pressed : std_logic := '0';
...
process (clk_in)
begin
if (rising_edge(clk_in)) then
speed_button_reg <= button_reg2(2);
if (speed_button_reg = '0' and button_reg2(2) = '1') then
-- The button has just been pressed (gone from low to high)
-- Do things here, or set another signal e.g.
speed_button_pressed <= '1';
else
speed_button_pressed <= '0';
end if;
end if;
end process;

VHDL counter/timer

I'm a VHDL newbie and I'm struggling with the following idea. I think I still misunderstand the idea of counters and timers in VHDL. I will explain it with a simple blinking LED diode. (BTW I'm learning on Spartan-3E FPGA kit.) So here is my code (I'm not using reset yet)
entity top_level is
Port( clk : in STD_LOGIC;
led1 : out STD_LOGIC);
end top_level;
architecture Behavioral of top_level is
signal timer : STD_LOGIC_VECTOR(25 downto 0) := "00000000000000000000000000";
signal reset: boolean:= false;
begin
process (clk)
begin
led1 <= '1';
if clk='1' and clk'event then
if reset <= true then
timer <= (others => '0');
end if;
timer <= timer + 1;
end if;
if timer <= "11100100111000011100000000" then
led1 <= '0';
end if;
end process;
end Behavioral;
The oscillator frequency is 50 MHz so one period is 20 ns. If I want to blink with a LED for 1.2 second (which makes 60 000 000 cycles) I need to create a 26 bit vector. So I created a process which is triggered by clk change.
WHAT I THINK IT SHOULD DO:
the first line of code is a logic 1 assignment to led1. So the led1 should light until the counter won't count 60 000 000 cycles. When counter counts 60 000 000 cycles, the led logic state should switch to 0 which means no light. As the maximum value of 26 bit number is 67 108 863, the LED should light for 60 000 000 cycles and be turned off for the remaining 7 108 863 cycles. Isn't that right ?
WHAT IT DOES:My impression is, that it's kinda reversed. The LED is off for the most of the time (67 108 063 cycles) and lights for 7 108 863 cycles. Why is this happening ? I don't really get it.
Additional question: How can I achieve to run this process only once/twice/...? E.g. I want to blink with my LED 3 times and then turn it off. Because as far as I know after reaching maximum 26 bit number, the time vector will start counting from the beginning (from 0). And so on, endlessly.
First of all, you should divide your design in several parts, which can be entities or several processes. I'll use processes or some one-liner. You can also extract the presented functions into a separate package.
part 1: generate a 0.833 Hz signal from 50 MHz system clock
part 2: control whether the led is on or off
part 3: count the on cycles and disable the led after 3
Part 1
I would suggest to use the type UNSIGNED for a counter, so the '+' operator is defined for this type.
I named it timer_us so it's easy to see that this signal is an unsigned.
Additionally, you can use (others => '0') in declarations, too.
signal reset : STD_LOGIC := '0'; -- disabled reset; TODO move this signal to port
signal timer_us : UNSIGNED(25 downto 0) := (others => '0');
signal timer_tick : STD_LOGIC;
process(clk)
begin
if rising_edge(clk) then
if (reset = '1') then
timer_us <= (others => '0');
else
timer_us <= timer_us + 1;
end if;
end if;
end process;
timer_tick <= '1' when (timer_us = to_unsigned(60 * 1000 * 1000), timer_us'length) else '0';
The last line describes a ternary operator (like z = a ? x : y in C). So the tick signal is '1' if the timer reaches 60,000,000. But there is a fault: Your counter starts at 0 so 60,000,000 cycles are already reached at max - 1.
Some improvements for a more generic counter template:
in most cases it's necessary to reset the counter independently from the main reset -> timer_rst
define a constant for the maximal counter value -> TIMER_MAX
automatically calculate the counter value depending on the maximal counter value -> log2ceil
implement a function to convert boolean expressions to STD_LOGIC -> to_sl
because timer is of type unsigned, you can use a direct comparison with an integer value
Here the extended counter code:
signal reset : STD_LOGIC := '0'; -- disabled reset; TODO move this signal to port
function log2ceil(arg : positive) return natural is
variable tmp : positive := 1;
variable log : natural := 0;
begin
if arg = 1 then return 0; end if;
while arg > tmp loop
tmp := tmp * 2;
log := log + 1;
end loop;
return log;
end function;
function to_sl(condition : BOOLEAN) return STD_LOGIC is
begin
if condition then
return '1';
else
return '0';
end if;
end function;
constant TIMER_MAX : POSITIVE := 60 * 1000 * 1000 - 1;
constant TIMER_BITS : POSITIVE := log2ceil(TIMER_MAX);
signal timer_rst : STD_LOGIC;
signal timer_us : UNSIGNED(TIMER_BITS - 1 downto 0) := (others => '0');
signal timer_tick : STD_LOGIC;
timer_rst <= reset or timer_tick;
process(clk)
begin
if rising_edge(clk) then
if (timer_rst = '1') then
timer <= (others => '0');
else
timer <= timer + 1;
end if;
end if;
end process;
timer_tick <= to_sl(timer = TIMER_MAX - 1));
If you have fun in coding function, you can also invent a function which converts a time (the period for the 0.833 Hz signal) into a cycle count at a given frequency of 50 MHz ;)
Part 2
A blinking LED is a simple T-FF:
signal blink : STD_LOGIC := '0'; -- blink will be mapped to a FF, so initialize it
process(clk)
begin
if rising_edge(clk) then
if (timer_tick = '1') then
blink <= not blink;
end if;
end if;
end process;
LED <= blink;
Or as an one-liner (no need for a process block):
blink <= blink xor timer_tick when rising_edge(clk);
LED <= blink;
Part 3
So now you have all the tools to build counters. You can implement a second counter to count from 0 to 2. if 2 is reached you can set a control signal counter2_ctrl which is then feed back to the blink process to stop this process from toggling.
Here the extended one-liner:
blink_enable <= not counter2_ctrl;
blink <= blink xor (timer_tick and blink_enable) when rising_edge(clk);
To your question
The inverse LED output can be caused by low-active circuits on your test board.

Multiple buttons

How to change this code to get it working with several (2, 3 or 4) buttons?
signal lastButtonState : std_logic := '0';
process(clk)
begin
if(rising_edge(clk)) then
if(buttonState = '1' and lastButtonState = '0') then --assuming active-high
--Rising edge - do some work...
end if;
lastButtonState <= buttonState;
end if;
end process;
I would like to get several buttons work and do some work on press 'state'. This part of code works for 1 button only.
Thanks
The std_logic_vector type can be used for multiple buttons. Code may look
like:
constant BUTTONS : positive := 4; -- Number of buttons
subtype buttons_t is std_logic_vector(1 to BUTTONS); -- Type for buttons
signal buttonsState : buttons_t; -- Input from buttons (remember to debounce)
signal lastButtonsState : buttons_t := (others => '0'); -- Last state
... -- End of declarations, and start of concurrent code (processes etc.)
process (clk)
variable buttonsRise_v : buttons_t; -- Support variable to make writing easier
begin
if rising_edge(clk) then
buttonsRise_v := buttonsState and (not lastButtonsState); -- Make '1' for each button going 0 to 1
if buttonsRise_v(1) = '1' then -- Detect button 1 going 0 to 1
-- Do some work...
end if;
-- More code reacting on buttons...
lastButtonsState <= buttonsState;
end if;
end process;

Resources