hobbyiclearner;1523046r said:3. In the 'send' state of the, why has been busy assigned '1' before the first if statement. Since the controller has to wait for atleast in the send state for 50 usec before going back to ready state, in the first if statement, the busy port has been already assigned logic 1.
The code has many extra assignments that are not needed. The important assignments to "busy" are the ones that occur when state is assigned to a different value. These are the transitions of the state machines.
e <= '0';
state <= initialize;
ELSE --initialization complete
clk_count := 0;
[B]busy <= '0';[/B]
state <= ready;
END IF;
WHEN ready =>
IF(lcd_enable = '1') THEN
[B]busy <= '1';[/B] -- should this not come after the 3rd line form this line
rs <= lcd_bus(9);
rw <= lcd_bus(8);
lcd_data <= lcd_bus(7 DOWNTO 0);
clk_count := 0;
state <= send;
for example busy will be '1' on the first cycle of ready.
IF(reset_n = '0') THEN
state <= power_up;
[B]clk_count:=0;[/B]
END IF;
Forum members are not free consultants, we are all volunteers, as such having to work on some random code (perhaps rubbish code) and modify it to do something that we've suggested (that you should implement) is not something you should expect from another forum member. Occasionally you'll find someone with too much time on their hands that might do the work for you, but don't count on it!
I do not know anyone nearby to help me in this matter. Hence I am forced to request at the forum for support.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY lcd_controller_modified IS
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reinitializes lcd
lcd_enable : IN STD_LOGIC; --latches data into lcd controller
lcd_bus : IN STD_LOGIC_VECTOR(9 DOWNTO 0); --data and control signals
busy : OUT STD_LOGIC := '1'; --lcd controller busy/idle feedback
rw, rs, e : OUT STD_LOGIC; --read/write, setup/data, and enable for lcd
lcd_data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); --data signals for lcd
END lcd_controller_modified;
ARCHITECTURE controller OF lcd_controller_modified IS
TYPE CONTROL IS(power_up, initialize, ready, send);
SIGNAL state : CONTROL;
CONSTANT freq : INTEGER := 25; --system clock frequency in MHz
BEGIN
PROCESS(clk, reset_n)
VARIABLE clk_count : INTEGER := 0; --event counter for timing
BEGIN
IF(clk'EVENT and clk = '1') THEN
CASE state IS
--wait 50 ms to ensure Vdd has risen and required LCD wait is met
WHEN power_up =>
busy <= '1';
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(clk_count < (50000 * freq)) THEN --wait 50 ms
clk_count := clk_count + 1;
state <= power_up;
ELSE --power-up complete
clk_count := 0;
rs <= '0';
rw <= '0';
lcd_data <= "00110000";
state <= initialize;
END IF;
--cycle through initialization sequence
WHEN initialize =>
busy <= '1';
clk_count := clk_count + 1;
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(clk_count < (10 * freq)) THEN --function set
lcd_data <= "00111100";
e <= '1';
state <= initialize;
ELSIF(clk_count < (60 * freq)) THEN --wait 50 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (70 * freq)) THEN --display on/off --control
lcd_data <= "00001100";
e <= '1';
state <= initialize;
ELSIF(clk_count < (120 * freq)) THEN --wait 50 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (130 * freq)) THEN --display clear
lcd_data <= "00000001";
e <= '1';
state <= initialize;
ELSIF(clk_count < (2130 * freq)) THEN --wait 2 ms
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (2140 * freq)) THEN --entry mode set
lcd_data <= "00000110";
e <= '1';
state <= initialize;
ELSIF(clk_count < (2200 * freq)) THEN --wait 60 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSE --initialization complete
clk_count := 0;
busy <= '0';
state <= ready;
END IF;
--wait for the enable signal and then latch in the instruction
WHEN ready =>
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(lcd_enable = '1') THEN
busy <= '1';
rs <= lcd_bus(9);
rw <= lcd_bus(8);
lcd_data <= lcd_bus(7 DOWNTO 0);
clk_count := 0;
state <= send;
ELSE
busy <= '0';
rs <= '0';
rw <= '0';
lcd_data <= "00000000";
clk_count := 0;
state <= ready;
END IF;
--send instruction to lcd
WHEN send =>
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(clk_count < (50 * freq)) THEN --doNt exit for 50us
busy <= '1';
IF(clk_count < freq) THEN --negative enable
e <= '0';
ELSIF(clk_count < (14 * freq)) THEN --+IVE enable 1/2 cycle
e <= '1';
ELSIF(clk_count < (27 * freq)) THEN ---IVE enable half-cycle
e <= '0';
END IF;
clk_count := clk_count + 1;
state <= send;
ELSE
clk_count := 0;
state <= ready;
END IF;
END CASE;
END IF;
END PROCESS;
END controller;
:grin:busy <= '1' assignment and the answer is that it's redundant,
For example, if the state machine is in the "ready" state with "busy = '1'", that would seem a bit odd. But that does happen. When in the send state, if the else statement is reached state will change to ready. busy is not changed. On the next cycle, the state will be ready and busy will remain '1'. There is an implicit assumption that lcd_enable will be '0'. "i'm ready but also busy" seems to mean the signals were not named (or used) correctly.
"i'm ready but also busy" seems to mean the signals were not named (or used) correctly.
--+-----+-------+------+--------------------------+
--| cnt | state | busy | |
--+-----+-------+------+--------------------------+
--| N-2 | send | '1' | <- elsif branch reached |
--| N-1 | send | '1' | <- elsif branch reached |
--| N | send | '1' | <- else branch reached |
--| 0 | ready | '1' | <- busy + ready |
--| 0 | ready | '0' | <- changes 1 cycle later |
--+-----+-------+------+--------------------------+
PROCESS(clk)
VARIABLE clk_count : INTEGER := 0; --event counter for timing
BEGIN
IF(clk'EVENT and clk = '1') THEN
CASE state IS
WHEN power_up =>
busy <= '1'; -- (1) should not be needed, but is needed
IF(clk_count < (50000 * freq)) THEN
clk_count := clk_count + 1; -- post-increment.
state <= power_up; -- (2) not needed.
ELSE
clk_count := 0;
rs <= '0';
rw <= '0';
lcd_data <= "00110000"; -- (3) this should be left out, or should be the same value as line (5)
state <= initialize;
END IF;
WHEN initialize =>
busy <= '1'; -- (4) not needed
clk_count := clk_count + 1; -- pre-increment this time
IF(clk_count < (10 * freq)) THEN
lcd_data <= "00111100"; -- (5) one cycle after setting lcd_data 00110000, it changes to 00111100.
e <= '1';
state <= initialize; -- (6) not needed
ELSIF(clk_count < (60 * freq)) THEN
lcd_data <= "00000000";
e <= '0';
state <= initialize; -- (7) not needed
ELSIF(clk_count < (70 * freq)) THEN
lcd_data <= "00001100";
e <= '1';
state <= initialize; -- (8) not needed
ELSIF(clk_count < (120 * freq)) THEN
lcd_data <= "00000000";
e <= '0';
state <= initialize; -- (9) not needed
ELSIF(clk_count < (130 * freq)) THEN
lcd_data <= "00000001";
e <= '1';
state <= initialize; -- (10) not needed
ELSIF(clk_count < (2130 * freq)) THEN
lcd_data <= "00000000";
e <= '0';
state <= initialize; -- (11) not needed
ELSIF(clk_count < (2140 * freq)) THEN
lcd_data <= "00000110";
e <= '1';
state <= initialize; -- (12) not needed
ELSIF(clk_count < (2200 * freq)) THEN
lcd_data <= "00000000";
e <= '0';
state <= initialize; -- (13) not needed
ELSE
clk_count := 0;
busy <= '0';
state <= ready;
END IF;
WHEN ready =>
IF(lcd_enable = '1') THEN
busy <= '1'; -- (14) busy will be set 1 cycle after entering "ready"
rs <= lcd_bus(9);
rw <= lcd_bus(8);
lcd_data <= lcd_bus(7 DOWNTO 0);
clk_count := 0;
state <= send;
ELSE -- (15) should not be needed.
busy <= '0';
rs <= '0';
rw <= '0';
lcd_data <= "00000000";
clk_count := 0;
state <= ready;
END IF;
WHEN send =>
busy <= '1'; -- (16) not needed
IF(clk_count < (50 * freq)) THEN
busy <= '1'; -- (17) not needed
IF(clk_count < freq) THEN
e <= '0';
ELSIF(clk_count < (14 * freq)) THEN
e <= '1';
ELSIF(clk_count < (27 * freq)) THEN
e <= '0';
END IF;
clk_count := clk_count + 1; -- post increment.
state <= send; -- (18) not needed
ELSE -- (19) busy <= '0' needed.
-- busy will change at the same edge as state,
-- placeing busy = '0' and state = ready
clk_count := 0;
state <= ready;
END IF;
END CASE;
IF(reset_n = '0') THEN
state <= power_up; -- (20) count should be reset, busy should be set. other io should be set.
END IF;
END IF;
END PROCESS;
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY lcd_controller_modified_1 IS
PORT(
clk : IN STD_LOGIC; --system clock
reset_n : IN STD_LOGIC; --active low reinitializes lcd
lcd_enable : IN STD_LOGIC; --latches data into lcd controller
lcd_bus : IN STD_LOGIC_VECTOR(9 DOWNTO 0); --data and control signals
busy : OUT STD_LOGIC := '1'; --lcd controller busy/idle feedback
rw, rs, e : OUT STD_LOGIC; --read/write, setup/data, and enable for lcd
lcd_data : OUT STD_LOGIC_VECTOR(7 DOWNTO 0)); --data signals for lcd
END lcd_controller_modified_1;
ARCHITECTURE controller OF lcd_controller_modified_1 IS
TYPE CONTROL IS(power_up, initialize, ready, send);
SIGNAL state : CONTROL;
CONSTANT freq : INTEGER := 25; --system clock frequency in MHz
BEGIN
PROCESS(clk, reset_n)
VARIABLE clk_count : INTEGER := 0; --event counter for timing
BEGIN
IF(clk'EVENT and clk = '1') THEN
CASE state IS
--wait 50 ms to ensure Vdd has risen and required LCD wait is met
WHEN power_up =>
clk_count := clk_count + 1;
busy <= '1';
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
rs <= '0';
rw <= '0';
ELSIF(clk_count < (50000 * freq)) THEN --wait 50 ms
state <= power_up;
ELSE --power-up complete
clk_count := 0;
rs <= '0';
rw <= '0';
state <= initialize;
END IF;
--cycle through initialization sequence
WHEN initialize =>
busy <= '1';
clk_count := clk_count + 1;
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(clk_count < (10 * freq)) THEN --function set
lcd_data <= "00111100";
e <= '1';
state <= initialize;
ELSIF(clk_count < (60 * freq)) THEN --wait 50 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (70 * freq)) THEN --display on/off control
lcd_data <= "00001100";
e <= '1';
state <= initialize;
ELSIF(clk_count < (120 * freq)) THEN --wait 50 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (130 * freq)) THEN --display clear
lcd_data <= "00000001";
e <= '1';
state <= initialize;
ELSIF(clk_count < (2130 * freq)) THEN --wait 2 ms
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSIF(clk_count < (2140 * freq)) THEN --entry mode set
lcd_data <= "00000110";
e <= '1';
state <= initialize;
ELSIF(clk_count < (2200 * freq)) THEN --wait 60 us
lcd_data <= "00000000";
e <= '0';
state <= initialize;
ELSE --initialization complete
clk_count := 0;
busy <= '1';
state <= ready;
END IF;
--wait for the enable signal and then latch in the instruction
WHEN ready =>
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(lcd_enable = '1') THEN
rs <= lcd_bus(9);
rw <= lcd_bus(8);
lcd_data <= lcd_bus(7 DOWNTO 0);
clk_count := 0;
state <= send;
ELSE
busy <= '0';
rs <= '1';
rw <= '0';
lcd_data <= "00000000";
clk_count := 0;
state <= ready;
END IF;
--send instruction to lcd
WHEN send =>
clk_count := clk_count + 1;
IF (reset_n = '0') then
state <= power_up;
clk_count := 0;
ELSIF(clk_count < (50 * freq)) THEN --dont exit for 50us
busy <= '1';
IF(clk_count < freq) THEN --negative enable
e <= '0';
ELSIF(clk_count < (14 * freq)) THEN --+IVE enable 1/2 cycle
e <= '1';
ELSIF(clk_count < (27 * freq)) THEN ---IVE enable half-cycle
e <= '0';
END IF;
state <= send;
ELSE
clk_count := 0;
busy <= '0';
state <= ready;
END IF;
END CASE;
END IF;
END PROCESS;
END controller;
process (blah) is
begin
X <= X; // a signal remains the same if not changed in a process, even if that is not desired. (eg, non clocked processes infer latches vs erroring if a signal isn't assigned in any code branch.)
Y := Y; // a variable remains the same if not changed within a process. (eg, you can infer registers or combinatorial logic or both with variables. There is no way that could get confusing...)
-- your actual code here.
end process
As a result there is no reason to write the code for: "when the current state is X, on the next cycle set the current state to (the same) X".
It isn't harmful to makes these re-assignments. It just isn't needed.
.
For comment #4, busy is set to '1' for all transitions to this state. It is not set to '0' for any transition from this state. As a result, the assignment is not needed as there would never be a way to reach the state with busy=0. You could add an assertion for busy = '1' instead. This would cause a simulation to show an error if busy /= '1' when in that state.
With this new understanding, you might try adding assert statements to your fsm's. This would help show when you are in a state and a state-related signal doesn't agree. Often it doesn't matter, but such designs are also often sloppy and miss corner cases. They can require much more test time than the 1-5 minutes to add asserts.
Code VHDL - [expand] 1 2 3 4 5 6 7 if (reset = '1') then flag <= '0'; elsif (state = s3) then -- synchronous set flag <= '1'; elsif (state = s17) then -- synchronous clear flag <= '0'; end if;
@hobbyiclearner: There are multiple ways to look at state machines.
In one method, you consider logic as it occurs _within_ a state. (This is best represented with a 2+ process state machine)
In one method, you consider logic as you _transition-to_ a state. (This is best represented with a 1 process state machine)
.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?