Finite State Machine - Without Shift Register
Here's what I got. I didn't understand your transition from S18 to S19. It seems to me that the preamble has been detected when it is in S18, therefore no need for an extra detection transition. I've also split your S19 into 3 states, i.e. S18, S19 and S20.

Finite State Machine - With Shift Register
Here is the state diagram for a shift register being used to detect the preamble sequence. S1 waits for a shift register to detect the preamble sequence.

VHDL Implementation of FSM

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity StateMachineChallenge is
generic
(
NUM_STATES: natural := 5;
NUM_OUTPUTS: natural := 6
);
port
(
clock: in std_logic;
reset: in std_logic;
button: in std_logic;
found_preamble: in std_logic;
timer_a_timeout: in std_logic;
timer_b_timeout: in std_logic;
timer_c_timeout: in std_logic;
state: out natural range 0 to NUM_STATES := 0;
outputs: out std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0')
);
end entity;
architecture V1 of StateMachineChallenge is
constant S0: natural range 0 to NUM_STATES := 0;
constant S1: natural range 0 to NUM_STATES := 1;
constant S2: natural range 0 to NUM_STATES := 2;
constant S3: natural range 0 to NUM_STATES := 3;
constant S4: natural range 0 to NUM_STATES := 4;
constant LED_OFF, FIND_PREAMBLE_OFF, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF: std_logic := '0';
constant LED_ON, FIND_PREAMBLE_ON, TIMER_A_ON, TIMER_B_ON, TIMER_C_ON: std_logic := '1';
constant SERVO_POSITION_START: std_logic := '0'; -- 1.0 ms
constant SERVO_POSITION_90DEG: std_logic := '1'; -- 1.5 ms
type TOutputsTable is array(0 to NUM_STATES - 1) of std_logic_vector(NUM_OUTPUTS - 1 downto 0);
constant OUTPUTS_TABLE: TOutputsTable :=
(
-- LED, Find preamble, Servo position, Timer A run, Timer B run, Timer C run
(LED_OFF, FIND_PREAMBLE_OFF, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_ON, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_90DEG, TIMER_A_ON, TIMER_B_OFF, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_90DEG, TIMER_A_OFF, TIMER_B_ON, TIMER_C_OFF),
(LED_ON, FIND_PREAMBLE_OFF, SERVO_POSITION_START, TIMER_A_OFF, TIMER_B_OFF, TIMER_C_ON)
);
signal next_state: natural range 0 to NUM_STATES := S0;
signal next_outputs: std_logic_vector(NUM_OUTPUTS - 1 downto 0) := OUTPUTS_TABLE(S0);
begin
--
-- State register and outputs register.
--
process(clock, reset)
begin
if reset = '1' then
state <= S0;
outputs <= OUTPUTS_TABLE(S0);
elsif rising_edge(clock) then
state <= next_state;
outputs <= next_outputs;
end if;
end process;
--
-- Next state logic
--
process(reset, state, button, found_preamble, timer_a_timeout, timer_b_timeout, timer_c_timeout)
begin
if reset = '1' then
next_state <= S0;
else
case state is
when S0 => -- Reset
if button = '1' then
next_state <= S1;
else
next_state <= S0;
end if;
when S1 => -- Looking for preamble
if found_preamble then
next_state <= S2;
else
next_state <= S1;
end if;
when S2 => -- Moving servo to 90 degrees
if timer_a_timeout then
next_state <= S3;
else
next_state <= S2;
end if;
when S3 => -- Waiting for 10 seconds
if timer_b_timeout then
next_state <= S4;
else
next_state <= S3;
end if;
when S4 => -- Moving servo to start position
if timer_c_timeout then
next_state <= S0;
else
next_state <= S4;
end if;
when others =>
next_state <= S0;
end case;
end if;
end process;
--
-- Next outputs logic
--
process(reset, next_state)
begin
if reset = '1' then
next_outputs <= OUTPUTS_TABLE(S0);
else
next_outputs <= OUTPUTS_TABLE(next_state);
end if;
end process;
end architecture;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity TestBench is
end entity;
architecture V1 of TestBench is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
signal halt_sys_clock: boolean := false;
signal sys_clock: std_logic;
signal reset: std_logic;
signal button: std_logic;
signal found_preamble: std_logic;
signal timer_a_timeout: std_logic;
signal timer_b_timeout: std_logic;
signal timer_c_timeout: std_logic;
constant NUM_STATES: natural := 5;
constant NUM_OUTPUTS: natural := 6;
signal state: natural range 0 to NUM_STATES;
signal outputs: std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0');
signal led: std_logic;
signal find_preamble: std_logic;
signal servo_position: std_logic;
signal timer_a_enable: std_logic;
signal timer_b_enable: std_logic;
signal timer_c_enable: std_logic;
component StateMachineChallenge is
generic
(
NUM_STATES: natural := NUM_STATES;
NUM_OUTPUTS: natural := NUM_OUTPUTS
);
port
(
clock: in std_logic;
reset: in std_logic;
button: in std_logic;
found_preamble: in std_logic;
timer_a_timeout: in std_logic;
timer_b_timeout: in std_logic;
timer_c_timeout: in std_logic;
state: out natural range 0 to NUM_STATES := 0;
outputs: out std_logic_vector(NUM_OUTPUTS - 1 downto 0) := (others => '0')
);
end component;
begin
SysClockGenerator: process
begin
while not halt_sys_clock loop
sys_clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
sys_clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process SysClockGenerator;
ResetProcess: process
begin
reset <= '0';
wait for 1 ns;
reset <= '1';
wait for 10 ns;
reset <= '0';
--wait for 21 ms;
wait for 1 ms;
halt_sys_clock <= true;
wait;
end process ResetProcess;
ButtonPress: process
begin
button <= '0';
wait for 1 us;
button <= '1';
wait for 1 us;
button <= '0';
wait;
end process ButtonPress;
FindPreamble: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and find_preamble = '1' then
count := count + 1;
end if;
if count = 17 * 50 then
found_preamble <= '1';
else
found_preamble <= '0';
end if;
end process FindPreamble;
TimerA: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_a_enable = '1' then
count := count + 1;
end if;
if count = 200 then
timer_a_timeout <= '1';
else
timer_a_timeout <= '0';
end if;
end process TimerA;
TimerB: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_b_enable = '1' then
count := count + 1;
end if;
if count = 1000 then
timer_b_timeout <= '1';
else
timer_b_timeout <= '0';
end if;
end process TimerB;
TimerC: process(sys_clock)
variable count: natural := 0;
begin
if rising_edge(sys_clock) and timer_c_enable = '1' then
count := count + 1;
end if;
if count = 200 then
timer_c_timeout <= '1';
else
timer_c_timeout <= '0';
end if;
end process TimerC;
DUT: StateMachineChallenge
generic map
(
NUM_STATES => NUM_STATES,
NUM_OUTPUTS => NUM_OUTPUTS
)
port map
(
clock => sys_clock,
reset => reset,
button => button,
found_preamble => found_preamble,
timer_a_timeout => timer_a_timeout,
timer_b_timeout => timer_b_timeout,
timer_c_timeout => timer_c_timeout,
state => state,
outputs => outputs
);
(led, find_preamble, servo_position, timer_a_enable, timer_b_enable, timer_c_enable) <= outputs;
end architecture;
Clock Timings

VHDL to Generate Clock Strobes
--
-- Clock Strobe
--
-- Generates a slow clock strobe from a fast clock.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity ClockStrobe is
generic
(
max_count: natural
);
port
(
clock: in std_logic;
clock_strobe: out std_logic
);
end;
architecture V1 of ClockStrobe is
begin
-- Create clock strobe.
process(clock)
variable counter: natural range 0 to max_count := 0;
begin
if rising_edge(clock) then
counter := counter + 1;
if counter = max_count then
clock_strobe <= '1';
counter := 0;
else
clock_strobe <= '0';
end if;
end if;
end process;
end architecture;
--
-- Test Bench
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity TestBench is
end entity;
architecture V1 of TestBench is
constant SYS_CLOCK_FREQ: real := 100000000.0; -- Hz
constant SYS_CLOCK_PERIOD: time := 1.0 sec / SYS_CLOCK_FREQ;
constant MAX_COUNT_2MHz: natural := 50;
constant MAX_COUNT_50Hz: natural := 2000000;
signal stop_clock: boolean := false;
signal clock: std_logic;
signal clock_strobe_2MHz: std_logic;
signal clock_strobe_50Hz: std_logic;
component ClockStrobe is
generic
(
max_count: natural
);
port
(
clock: in std_logic;
clock_strobe: out std_logic
);
end component;
begin
ClockGenerator: process
begin
while not stop_clock loop
clock <= '0';
wait for SYS_CLOCK_PERIOD / 2.0;
clock <= '1';
wait for SYS_CLOCK_PERIOD / 2.0;
end loop;
wait;
end process ClockGenerator;
ClockStrobe2MHz: ClockStrobe
generic map
(
max_count => MAX_COUNT_2MHz
)
port map
(
clock => clock,
clock_strobe => clock_strobe_2MHz
);
ClockStrobe50Hz: ClockStrobe
generic map
(
max_count => MAX_COUNT_50Hz
)
port map
(
clock => clock,
clock_strobe => clock_strobe_50Hz
);
-- Preamble process.
process(clock)
begin
if rising_edge(clock) then
if clock_strobe_2MHz then
-- Process the next preamble bit.
end if;
end if;
end process;
-- Servo process.
process(clock)
begin
if rising_edge(clock) then
if clock_strobe_50Hz then
-- Process the servo.
end if;
end if;
end process;
end architecture;
Simulation
Only shows the 2 MHz strobe.
