\documentclass{article}
\input{6111-preamble}
\usepackage{graphicx,epsfig,verbatim,lscape}


\begin{document}
%\lab{2}{Dan Ports}{2003/10/07}{drkp@mit.edu}
\title{A Traffic Light Controller}
\author{Dan Ports}
\maketitle
%\begin{center}\LARGE{A Traffic Light Controller}\end{center}
\tableofcontents
\newpage
\listoffigures
\listoftables
\newpage
\section{Overview}
This device controls the two red/yellow/green traffic signals at an intersection, based on programmable timing parameters and two sensors. One street is designated as the main street and the other as the side street. A signal input is provided for a traffic sensor that allows the side street's green light interval, normally shorter than that of the main street, to be extended. A walk request button is provided, which allows the intersection to display a walk signal for an interval after the main street light turns red. This walk signal is indicated by activating the red and yellow lights on both street lights.

\section{Operation}
The user can operate this controller via two mode switches (F$_1$ and F$_0$), a GO button which executes the command indicated by F$_1$ and F$_0$, and a RESET button that returns the controller to its default idle state. Possible commands and the corresponding settings for the F switches are listed in Table~\ref{commandtable}.
\begin{table}[bhp]
\caption{Commands}
\label{commandtable}
\begin{center}
\begin{tabular}{|c c | c |}
\hline
F$_1$ & F$_0$ & Command \\
\hline
0 & 0 & Read Memory Location \\
0 & 1 & Write Memory Location \\
1 & 0 & Run Traffic Lights \\
1 & 1 & Blink Traffic Lights \\
\hline
\end{tabular}
\end{center}
\end{table}

To read a timing parameter from memory, the controller must be placed in Read Memory Location mode by setting the mode switches appropriately and pressing GO. The location can then specified using the two address switches, A$_1$ and A$_0$, and the output will be displayed on a hex LED. To write to a memory location, the A switches are used to specify the location, and the new value is entered using the four C switches. After selecting the write command and pressing GO, the new value is written to memory and read back on the hex LED for verification. For a list of memory locations, see Table~\ref{memorytable}.

\begin{table}[bthp]
\caption{Memory locations}
\label{memorytable}
\begin{center}
\begin{tabular}{|c c | c | c |}
\hline
A$_1$ & A$_0$ & Name & Nominal value \\
\hline
0 & 0 & TYEL & 3 \\
0 & 1 & TBASE & 6 \\
1 & 0 & TEXT & 6 \\
1 & 1 & TBLINK & 1 \\
\hline
\end{tabular}
\end{center}
\end{table}

When the Run Traffic Lights command is entered on the $F$ switches, and the GO button is pressed, the green light on the main street and red light on the side street turn on. After TBASE + TEXT seconds have elapsed, the main light switches to yellow for TYEL seconds. Afterwards, if the walk button has been pressed, both lights will display a walk signal (red and yellow both on) for TEXT seconds. If the walk button has not been pressed, or after the walk interval is completed, the main light turns red and the side light turns green for TBASE seconds. If the sensor is active at the end of this interval, the side green interval will be extended for another TBASE seconds. Afterwards, the side light turns yellow for TYEL seconds. Then the side light turns red and the main light turns green, and the cycle repeats.

If the Blink Traffic Lights command is selected and the GO button is pressed, the red light on the side street and the yellow light on the main street blink repeatedly, turning on for TBLINK seconds then off for another TBLINK seconds.

\section{Design}
\subsection{Overview}
The design of this traffic light controller is represented by the block diagram shown in Figure~\ref{blockdiagram}. All synchronous components operate on a 1.8432 MHz clock signal provided by a crystal oscillator. The system is controlled by a finite state machine (FSM) that keeps track of the current state of the system and generates the appropriate traffic light outputs. The FSM is controlled by the user through the switches, which are conditioned by passing through the Synchronizer, Level to Pulse, and Latch modules. These ensure that all input signals are synchronized to the system clock, that push-button inputs are only active for one clock cycle per button-press, and that the walk request signal is stored until it can be serviced. Timing parameters are stored in a 6264 static RAM (SRAM) module. The FSM controls the SRAM, selecting addresses and the read or write mode as appropriate. A Divider module converts the high-frequency clock signal into a once-per-second ``long clock'' signal. The Timer module uses this long clock and the timing parameters read from SRAM to measure the appropriate time interval, then signal the FSM.

\begin{center}
\begin{landscape}
\begin{figure}[bpht]
\caption{System block diagram}
\label{blockdiagram}
\begin{center}
\includegraphics[scale=.5]{new-logicdiagram}
\end{center}
\end{figure}
\end{landscape}
\end{center}

All components except for the SRAM and clock are implemented using an Altera FLEX 10K10 FPGA, as depicted in the wiring diagram in Figure~\ref{wiringdiagram}. The VHDL files used to program the FPGA are attached in the appendix. The clock is a 1.8432 MHz crystal oscillator, and the SRAM module is a MCM6264C 8K x 8 bit static RAM. Inputs are provided using debounced switches for the F, L, C, and SENSOR inputs, and debounced push-buttons for the GO, RESET, and WALKREQUEST signals. The data (D) on the SRAM input/output bus are displayed on a hex LED, and the traffic signals are displayed on a set of six LEDs. In addition, an 8-pin DIP connector is provided for controlling an external traffic light, with pinout listed in Table~\ref{dippinout}.

\begin{table}[bhtp]
\caption{Traffic signal light connections}
\label{dippinout}
\begin{center}
\begin{tabular}{|c|c|}
\hline
Pin number & Signal \\
\hline
1 & +5V \\
2 & Main Street Green \\
3 & Main Street Yellow \\
4 & Main Street Red \\
5 & Side Street Green \\
6 & Side Street Yellow \\
7 & Side Street Red \\
8 & Ground \\
\hline
\end{tabular}
\end{center}
\end{table}


\begin{center}
\begin{landscape}
\begin{figure}[pbht]
\caption{Hardware wiring diagram}
\label{wiringdiagram}
\begin{center}
\includegraphics[scale=.5]{new-wiringdiagram}
\end{center}
\end{figure}
\end{landscape}
\end{center}

\subsection{Clock}
Nearly all components in this system operate on the rising edge of a global clock signal. Because the standard 10 MHz NuBus clock signal was too fast to operate the SRAM chip with acceptable access time, an external 1.8432 MHz crystal oscillator was used to generate the clock signal.

\subsection{FSM}
The synchronous finite state machine used in this system has twelve possible states. These states, their outputs, and the transitions between them are shown in the state diagram in Figure~\ref{statediagram}. All outputs not listed in a state's bubble in the diagram are set to their default value (0 for active high signals and 1 for active high signals).

\begin{figure}[pb]
\caption{State diagram for FSM}
\label{statediagram}
\begin{center}
\epsfig{file=states.xfig.eps}
\end{center}
\end{figure}

Internally, the FSM operates by maintaining signals that keep track of the current state and the next state. 
The FSM is defined by three processes that operate concurrently. 
One process determines the next state signal asynchronously as a function of the current state and the inputs.
 Another process determines the outputs as a function of the current state. Because the outputs depend only on the current state of the FSM, the FSM is a Moore machine. 

The third process handles state transitions. 
State transitions can only occur on a rising edge of the clock. Normally, the transitions also require that the EXPIRED signal from the timer is high; however, if the RESET or GOSYNC signals are high, or the current state is IDLE, READ, or WRITE, the state transition happens the next rising edge of the clock. This logic ensures that, regardless of the current state, pressing the RESET button always immediately returns the system to the IDLE state and pressing the GO button immediately moves the FSM to either the READ, WRITE, MAING1, or BLINKON states, depending on the current values of F$_1$ and F$_0$. This process also generates the STARTTIMER signal. This signal is high for one clock period after a state transition, except for transitions into the IDLE, READ, or WRITE stage.

The system starts up in the IDLE state. All traffic light outputs are disabled. The FSM can be returned to this state at any time by pressing the RESET button.

To read a value, the user sets F$=00$ and presses GO. This moves the system to the READ state. In this state the FSM's RAM address output line A matches the location input set on the L switches. The value output by the RAM will be displayed on the hex LED connected to the RAM I/O lines. The FSM stays in the READ state until the RESET or GO button is pressed. The L inputs are not latched, so changing the L switches while the FSM is in READ mode allows a different address location to be read.

 To read a value, the user sets F$=01$ and presses GO. This moves the FSM to the WRITE state. As in the READ state, the FSM's RAM address output line $A$ matches the location input set on the L switches. The $\overline{\mathrm{WE}}$ write enable signal is set low to instruct the SRAM to write. After one clock cycle has elapsed, the FSM moves into the READ state to read back the value it has written to the SRAM and allow the user to verify that it is correct.

The RESETTIMER and LATCHRESET signals are set high during the IDLE, READ, and WRITE states. This ensures that the timer is not counting, and that any walk request signals received while in these states will be discarded.


Setting F$=10$ and pressing GO puts the FSM in the MAING1 state, beginning the traffic light operation. In this state, the main street is green and the side street is red; A$=01$, so this state is held for TBASE seconds. Then the FSM moves to the MAING2 state, which holds the same traffic light outputs for another TEXT seconds (A$=10$). When the timer expires, the next state is MAINY, in which the main light is yellow and the side street is red. The timer is set for TYEL seconds (A$=01$). If WREQLATCH is high when the timer expires, the next state is WALK; otherwise, the WALK state is skipped and the FSM moves directly to the SIDEG state. In the WALK state, the red and yellow lights on both streets are on, A is set to $10$ to set the timer for TEXT seconds, and the LATCHRESET signal is set in order to clear the latched walk signal. After the WALK state completes, or if it is skipped, the next state is SIDEG, in which the side light is green and the main light is red. When the timer expires after TBASE (A$=01$) seconds, the next state is SIDEEXT if SENSSYNC is high, or SIDEY otherwise. In the SIDEEXT state, all outputs are the same as in SIDEG; this holds the side light green for another TBASE seconds. Afterwards, the FSM moves to the SIDEY state, in which the side light is yellow and the main light is red. A is set to $00$ to hold this state for TYEL seconds; when the timer expires, the FSM moves back to the MAING1 state, and repeats the cycle.


When the user sets F$=11$ and presses GO, the FSM begins a blink sequence with the BLINKON state. The yellow light on the main street and red light on the side street are turned on. The timer is set for TBLINK seconds (A$=11$). When the timer expires, the FSM moves to the BLINKOFF state, in which all lights are off. In this state, A is also set to $11$. When the timer expires, the FSM moves back to BLINKON. In this way, a loop is created in which the red and yellow lights are blink on for TBLINK seconds and off for TBLINK seconds.

\begin{figure}[pbht]
\caption{Timing diagram for FSM --- IDLE, READ, WRITE, and BLINK modes}
\label{fsmtiming1}
\begin{center}
\includegraphics[scale=.5]{fsm-timing-1}
\end{center}
\end{figure}

\begin{figure}[pbht]
\caption{Timing diagram for FSM --- RUN mode}
\label{fsmtiming2}
\begin{center}
\includegraphics[scale=.45]{fsm-timing-2}
\end{center}
\end{figure}

\subsection{Synchronizer}
The input signals to the system are asynchronous with respect to the clock. A synchronizer is used to generate a SENSSYNC signal, which is a synchronized version of the SENSOR input. The synchonized output is guaranteed not to change except on rising edges of the clock.

The implementation of the synchronizer is simply a D flip-flop, as in Figure~\ref{syncschematic}.
\begin{figure}[bthp]
\caption{Synchronizer logic diagram}
\label{syncschematic}
\begin{center}
%\epsfig{file=6111-lab2-sync.ps,bbllx=323,bblly=381,bburx=440,bbury=440}
%\includegraphics[bb=223 281 540 540,clip=true]{6111-lab2-sync}
\includegraphics[scale=.5]{6111-lab2-sync.eps}
\end{center}
\end{figure}

\begin{figure}[bthp]
\caption{Synchronizer timing diagram}
\label{synctiming}
\begin{center}
\includegraphics[scale=.5]{sync-timing}
\end{center}
\end{figure}

\subsection{Level to Pulse}
In addition to being asynchronous, the signals connected to push buttons (GO and RESET) will be high for many clock cycles (since one clock cycle at this frequency is about 500 nanoseconds, and it certainly is not possible to press a button this quickly). The level-to-pulse module compensates for this, generating a pulse one clock cycle in width when the input level changes from low to high.

The implementation of the Level to Pulse module uses three D flip-flops in sequence and an AND gate (Figure~\ref{l2plogic}. The first flip-flop synchronizes the input to prevent metastability issues. The next two flip-flops are used to generate a pulse. By taking the AND of the second flip-flop's non-inverting output and third's inverting output, we ensure that the output can only be high for one clock cycle: when the high input signal has propagated to the second flip-flop but not the third. This generates a pulse.

Two identical Level to Pulse modules are used in this device, each synchronizing one input signal, as shown in Figure~\ref{blockdiagram}.

\begin{figure}[bthp]
\caption{Level to Pulse logic diagram}
\label{l2plogic}
\begin{center}
\includegraphics[scale=.5]{6111-lab2-pulse.eps}
\end{center}
\end{figure}

\begin{figure}[bthp]
\caption{Level to Pulse timing diagram}
\label{pulsetiming}
\begin{center}
\includegraphics[scale=.5]{pulse-timing}
\end{center}
\end{figure}


\subsection{Latch}
The latch module is used to keep track of whether the walk request button has been pressed. This is a SR latch, which sets its output value high when the SET signal (connected to the push-button) goes high, and sets its output low when the RESET signal (connected to the FSM) goes high. if both the SET and RST signals are asserted at the same time, the output is low. An implementation is shown in Figure~\ref{latchlogic}.

\begin{figure}[bthp]
\caption{Latch logic diagram}
\label{latchlogic}
\begin{center}
\includegraphics[scale=.5]{6111-lab2-latch.eps}
\end{center}
\end{figure}

\begin{figure}[bthp]
\caption{Latch timing diagram}
\label{latchtiming}
\begin{center}
\includegraphics[scale=.5]{latch-timing}
\end{center}
\end{figure}

\subsection{SRAM}
The memory used in this system is on a MCM6264C SRAM chip external to the FPGA. Only the two lowest-order address bits on the chip are used; these two are connected to the FSM's A$_0$ and A$_1$ outputs, and the other address lines on the 6264 are all tied to ground. The IO$_1$ through IO$_4$ lines of the SRAM are connected to the D$_0$ through D$_3$ lines of the FPGA, as well as to a hex LED for displaying their value. All other IO lines are left unconnected

The chip's mode is controlled by its $\overline{\mathrm{WE}}$ write enable and $\overline{\mathrm{CS_1}}$ chip select inputs. The CS$_2$ chip select and $\overline{\mathrm{OE}}$ output enable lines are permanently set to their active states (high and low respectively). The $\overline{\mathrm{WE}}$ input is connected to the FSM's $\overline{\mathrm{WE}}$ output, and the $\overline{\mathrm{CS_1}}$ input is connected to the clock. By connecting the active low chip select input to the clock, we ensure that the SRAM chip is only active during the low half of the clock cycle. Since the FSM outputs only change in response to the rising edge of the clock, this allows the FSM outputs time to stabilize before the RAM processes them. Thus glitches on the write-enable or address lines will not cause memory locations to be undesirably overwritten.

\subsection{Divider}
The purpose of the divider is to generate a 1 Hz ``long clock'' signal from the 1.8432 MHz clock signal. The output of the divider is a signal that is high for one pulse of the system clock, once per second. This is done by maintaining a counter that is incremented each clock pulse. (A 24-bit counter was used because this module was originally designed to work with a 10 MHz clock; a 21-bit counter would in fact have been adequate for this purpose.) When the counter reaches 1,843,199, the output is set high. On the next clock pulse (when the counter is 1,843,200), the counter is reset to zero and the output is set low again.

The divider also has a reset signal that allows the counter to be reset to zero. This is connected to the FSM's STARTTIMER signal. By resetting the divider whenever the timer starts counting, we ensure that the timer does not receive its first LONGCLK pulse too early.
\begin{figure}[bthp]
\caption{Divider timing diagram (ratio changed from 1,843,200:1 to 10:1)}
\label{dividertiming}
\begin{center}
\includegraphics[scale=.5]{divider-timing}
\end{center}
\end{figure}

\subsection{Timer}
The timer uses the output of the divider to measure a time interval specified by the data bus. The timer maintains an internal 4-bit counter. When the timer's START input is asserted on a rising edge of the clock, the buffer is initialized to the contents of the data bus. Thereafter, whenever the LONGCLK signal is high on a rising edge of the clock, the counter is decremented by 1. When the clock is zero, the timer generates a one clock cycle long pulse on the EXPIRED output signal, and stops counting. A RESET input is provided; if this input is high on a rising edge of the clock, the timer stops counting. This ensures that the timer is not counting when the FSM is not expecting input from the timer.
\begin{figure}[bthp]
\caption{Timer timing diagram}
\label{timertiming}
\begin{center}
\includegraphics[scale=.5]{timer-timing}
\end{center}
\end{figure}


\subsection{Tristate Buffer}
The tristate buffer module used in this input takes one input and an enable signal, and generates one output. The output is equal to the input when the enable signal is high, and in a tri-state (high-impedance) state when the enable signal is low. In this design, four identical tristate buffers are used to connect the C$_i$ inputs from the switches to the D$_i$ data bus lines. The enable signal to each of these tristate buffers is the logical NOR of the write-enable and clock signals. Thus, the C switches only control the data bus when the write-enable signal is low (active) and the clock is also low. Since the SRAM module is in write mode for this combination of signals, this ensures that no contention can occur on the data bus.

\begin{figure}[bthp]
\caption{Tristate buffer timing diagram}
\label{tribuffertiming}
\begin{center}
\includegraphics[scale=.5]{tribuffer-timing}
\end{center}
\end{figure}

\section{Testing}
All modules of the system were tested first in simulation using MAX+PLUS II software, then in hardware once the FPGA was programmed. 

To test the synchronizer, level to pulse unit, latch, and tri-state buffer, waveforms were generated that tested all possible combinations of inputs and outputs. After the simulation was run, all outputs were verified to be correct. 

To simplify testing the divider, it was modified slightly so that it generated a pulse every 10 cycles of the clock rather than every 1,843,200 (as in Figure~\ref{dividertiming}). This made the behavior easier to visualize and validate in simulation. A clock signal was applied to the input, and the output and state of the internal counter were verified. The reset signal was also tested.

The timer was tested in simulation using a waveform that tested the normal operation of the counter for several different values of D as well as operating the RESET input. The output of the counter was correct.

The FSM was tested in simulation using a waveform that tested the possible states and transitions. The FSM was first reset, then placed in each of the READ, WRITE, and BLINK modes using the GOSYNC and F signals (see Figure~\ref{fsmtiming1}). The correct outputs and internal state variables were observed for each state. Next, the traffic light operation of the FSM was tested by placing it in traffic light mode (as in Figure~\ref{fsmtiming2}). The inputs from the RAM and timer were simulated. By using both values of the SENSSYNC and WREQLATCH signals, all possible states and all possible state transitions were verified. Correct outputs were verified.

After simulation testing was completed, the FPGA was programmed and tested in hardware. For testing purposes, an interface was provided for several intermediate signals to be were connected to hex LEDs: the FSM's state variable, the counter's count variable, and the RAM address lines. The RAM was programmed with the nominal values for each timing parameter. As in simulation, the controller was operated in READ, WRITE, BLINK, and RUN modes, and all possible states and transitions were observed. The debugging outputs (state, count, and address lines) all had the correct outputs, and the traffic signal outputs were correct.

All testing was completed successfully.

\section{Conclusion}
A traffic light controller meeting the desired specifications can be built using a synchronous finite state machine implemented using a FPGA. The controller was successfully implemented and tested.
\appendix
\newpage
\section{Appendix: VHDL Source}
\subsection{top.vhd}
\verbatiminput{top.vhd}
\newpage
\subsection{divider.vhd}
\verbatiminput{divider.vhd}
\newpage
\subsection{fsm.vhd}
\verbatiminput{fsm.vhd}
\newpage
\subsection{leveltopulse.vhd}
\verbatiminput{leveltopulse.vhd}
\newpage
\subsection{synchronizer.vhd}
\verbatiminput{synchronizer.vhd}
\newpage
\subsection{timer.vhd}
\verbatiminput{timer.vhd}
\newpage
\subsection{tribuffer.vhd}
\verbatiminput{tribuffer.vhd}
\newpage
\subsection{wrlatch.vhd}
\verbatiminput{wrlatch.vhd}

\end{document}
