Laboratory 8 and Homework 8
Using FSMs and Shift Registers in Designing a Parallel-to-Serial and a Serial-to-Parallel Convertor


Laboratory 8

Serial data transmission is commonly used when the distance between devices is relatively great, more than a few meters, rendering impractical the faster but more expensive multiple connections required for parallel communications. Nearly all PCs have a serial port for connection to modems, mouse, and keyboard devices, as does the UP1. Inside the PC where distance is small, most devices such as the CPU, memory, and IO ports communicate with each other over multiple, parallel connections. However, when using serial communications between devices, as with other computers or the keyboard, the parallel data must be converted to serial form for output; for input the data must be converted from serial to parallel form.

The following laboratory explains the concepts behind standard serial communications used between computer systems and presents the design for an implementation of a serial-to-parallel convertor based upon those standards. The homework assignment is to complete the design and implement a parallel-to-serial convertor. The combined serial-to-parallel and parallel-to-serial convertor components will provide full serial communications between the UP1 and a standard computer system that will be used in this and later laboratories.


Serial Communications Basics

Before going into the details of the serial-to-parallel convertor design, some definitions are needed: The following diagrams the signal when the binary code for character 'S' is transmitted using RS-232C standards.
                                            Data Bit
                                0   1   2   3   4   5   6   7
       12                  ___         _______     ___     ___
Volts -12 ________________|   |_______|       |___|   |___|   |__________________
             0   0   0   0  1   0   0   1   1   0   1   0   1   0   0   0   0
           |   Idle bits  | B |   Data 'S' ASCII code         | E |Idle bits|
           |______________|   |_______________________________|   |_________|
                                time-->
          B = Start bit (opposite of idle bit).                                                   E = Stop bit (same as idle bit).

FSM for a Serial-to-Parallel Convertor

Before any communications can be successful several parameters must be agreed upon by the serial sender and receiver:
  1. baud rate - both must use the same baud rate for sending and receiving serial bits.
  2. data bits - how many.
  3. parity - whether to use parity and if so whether even or odd.
  4. stop bits - how many.
The SP (serial-to-parallel convertor) task can be relatively simple:
  1. wait for the beginning of the start bit,
  2. wait long enough for the middle of the start bit,
  3. wait long enough for the middle of the data bit 0 to arrive then read data bit 0 into the buffer,
  4. wait long enough for the middle of the data bit 1 to arrive then read data bit 1 into the buffer,
  5. wait long enough for the middle of the data bit 2 to arrive then read data bit 2 into the buffer,
  6. wait long enough for the middle of the data bit 3 to arrive then read data bit 3 into the buffer,
  7. wait long enough for the middle of the data bit 4 to arrive then read data bit 4 into the buffer,
  8. wait long enough for the middle of the data bit 5 to arrive then read data bit 5 into the buffer,
  9. wait long enough for the middle of the data bit 6 to arrive then read data bit 6 into the buffer,
  10. wait long enough for the middle of the data bit 7 to arrive then read data bit 7 into the buffer,
  11. wait long enough for the middle of the stop bit to arrive then signal that data has been received,
  12. wait for the stop bit, then go to 1.
One question is how fast should the SP operate, at what clock rate should it move from one state to the next? If the agreed upon baud rate used is 100 then obviously it must operate at at least 100 Hz. since bits will arrive at the rate of 100 per second. One complicating factor is that the start bit may arrive at any time, asynchronous to the serial-to-parallel convertor state clock. Another is that as the bits arrive, one should read the bit very near its middle to improve the chance of correctly reading the value. If it were read near the edge of two bits, one might easily be somewhat early or late, misreading one bit for another. As the diagram illustrates, at time A the read may give either 0 or 1 while at time B, in the middle of the bit, one is nearly certain to read the bit correctly. That is the notion of wait long enough for middle of data bit in the algorithm above, to improve the odds of reading the data bit correctly, the read wait long enough for the middle of the data bit.

The start bit serves to synchronize the receiver with the sender bits. If the bit rate is 1, then 1 bit arrives every second. The middle of the first data bit then arrives 1.5 seconds after the beginning of the start bit. The middle of the next bit arrives 1 second after that, etc. as the diagram below illustrates. The start bit, B, should be detected near the rising edge in order to synchronize the remaining bits. This requires that the FSM clock must be somewhat faster than the baud rate, a clock of 16 times the baud rate usually provides sufficient detection accuracy of the start bit. The remaining bits are then read after waiting some fixed amount of time, long enough to pass from the middle of one bit to the middle of the next.

With a baud rate of 1 a serial-to-parallel FSM clock rate of 16 Hz. is reasonable. To read the first bit requires a wait of 1.5 seconds or 24 clock cycles (8 to the middle of the start bit then 16 to the middle of the first data bit). The remaining reads at the middle of each bit are then separated by 1 second or 16 clock cycles. It is important to note that speeding up the baud rate does not change the number of clock cycles separating each read, it remains 16 clock cycles whether at 1 bit per second or 4800 bits per second. For a bit rate of 1 bit per second a 16 Hz. clock is needed while for a bit rate of 4800 bits per second a 16*4800 Hz. clock is needed for the FSM.

Putting these ideas together produces a more detailed list of tasks for the SP:

  1. Set data Ready to FALSE. Go to 1 until serial input (start bit)  is TRUE,
  2. Count to 8 for the middle of the start bit,
  3. Count to 16 then read data bit 0 into the buffer,
  4. Count to 16 then read data bit 1 into the buffer,
  5. Count to 16 then read data bit 2 into the buffer,
  6. Count to 16 then read data bit 3 into the buffer,
  7. Count to 16 then read data bit 4 into the buffer,
  8. Count to 16 then read data bit 5 into the buffer,
  9. Count to 16 then read data bit 6 into the buffer,
  10. Count to 16 then read data bit 7 into the buffer,
  11. Count to 16 for the stop bit. Set data Ready to TRUE.
  12. Go to 1.
The state description of the sequential system is:
 
Input:    SerialIn(t) element of {0,1} 
Output: ParallelOut(t) element of {00000000..11111111}, dataReady(t) element of {0,1} 
State:    s(t) element of {S0,S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11} 
Initial:    s(0)=S0 
Present |       Next         | Output
s(t)    |  Input SerialIn(t) | Parallel(t) dataReady(t)
        |      0      1      |                         
 S0     |     S0     S1      | xxxxxxxx       0
 S1     |     S2     S2      | xxxxxxxx       0
 S2     |     S3     S3      | xxxxxxx0       0
 S3     |     S4     S4      | xxxxxx10       0
 S4     |     S5     S5      | xxxxx210       0
 S5     |     S6     S6      | xxxx3210       0
 S6     |     S7     S7      | xxx43210       0
 S7     |     S8     S8      | xx543210       0
 S8     |     S9     S9      | x6543210       0
 S9     |     S10    S10     | 76543210       0
 S10    |     S11    S11     | 76543210       1
 S11    |     S0     S11     | 76543210       1

The SerialIn is the serial input from the receiver, the Parallel is the 8 bits of parallel data for output. dataReady output signals when a full 8 bits of serial data has been received and the parallel data is ready.

Serial Input Component Implementation

The following implements the serial input component serI design given above.
 
-- Serial input component. 8 data bits, 1 stop bit, NO parity 

ENTITY serI IS 
        PORT(                        clk : IN BIT;                                                          -- Baud rate*16 
                                    SerialIn : IN BIT;                                                          -- Serial input stream 
                               ParallelOut : OUT BIT_VECTOR(7 DOWNTO 0);          -- Parallel data output 
                               dataReady : OUT BIT);                                                     -- Parallel data ready 
END serI; 

ARCHITECTURE behavioral OF serI IS 

       TYPE STATE_TYPE IS (S0, S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11); 
        SIGNAL presentS, nextS : STATE_TYPE; 
        SIGNAL CountOut, StartBit, StopBit, SIn, TRUE, FALSE : BIT; 

 BEGIN 

     TRUE <= '1';  FALSE <= '0'; 

PROCESS (clk)                           -- Change nextS on rising clock edge 
    VARIABLE Count : INTEGER RANGE 0 to 16 := 0; 
  BEGIN 
     IF clk'EVENT AND clk = '1' THEN 

          Count := Count + 1;           -- Count number of clock cycles 
           IF Count = 16 THEN 
               CountOut <= TRUE; 
               Count := 0; 
           ELSE 
               CountOut <= FALSE; 
           END IF; 

           SIn <= SerialIn;                 -- Synchronize serial input 

          CASE presentS IS 
                  WHEN S0 =>  IF StartBit    = TRUE THEN nextS <= S1; ELSE nextS <= S0; END IF; 
                                          Count := 0; 
                  WHEN S1 =>  IF Count       = 8        THEN Count := 0; nextS <= S2; ELSE nextS <= S1; END IF; 
                  WHEN S2 =>  IF CountOut = TRUE THEN nextS <= S3;  ELSE nextS <= S2;  END IF; 
                  WHEN S3 =>  IF CountOut = TRUE THEN nextS <= S4;  ELSE nextS <= S3;  END IF; 
                  WHEN S4 =>  IF CountOut = TRUE THEN nextS <= S5;  ELSE nextS <= S4;  END IF; 
                  WHEN S5 =>  IF CountOut = TRUE THEN nextS <= S6;  ELSE nextS <= S5;  END IF; 
                  WHEN S6 =>  IF CountOut = TRUE THEN nextS <= S7;  ELSE nextS <= S6;  END IF; 
                  WHEN S7 =>  IF CountOut = TRUE THEN nextS <= S8;  ELSE nextS <= S7;  END IF; 
                  WHEN S8 =>  IF CountOut = TRUE THEN nextS <= S9;  ELSE nextS <= S8;  END IF; 
                  WHEN S9 =>  IF CountOut = TRUE THEN nextS <=S10; ELSE nextS <= S9;  END IF; 
                  WHEN S10=> IF CountOut = TRUE THEN nextS <=S11; ELSE nextS <= S10; END IF; 
                  WHEN S11=> IF StopBit    =  TRUE THEN nextS <= S0; ELSE nextS <= S11; END IF; 
            END CASE; 
     END IF; 
  END PROCESS; 

PROCESS (nextS, StartBit) 
  BEGIN 
       presentS <= nextS; 
       CASE presentS IS 
                  WHEN S0 =>  StartBit              <= SIn;                    dataReady <= FALSE; 
                  WHEN S1 =>  StartBit              <= FALSE; 
                  WHEN S2 =>  ParallelOut(0)    <= NOT SIn; 
                  WHEN S3 =>  ParallelOut(1)    <= NOT SIn; 
                  WHEN S4 =>  ParallelOut(2)    <= NOT SIn; 
                  WHEN S5 =>  ParallelOut(3)    <= NOT SIn; 
                  WHEN S6 =>  ParallelOut(4)    <= NOT SIn; 
                  WHEN S7 =>  ParallelOut(5)    <= NOT SIn; 
                  WHEN S8 =>  ParallelOut(6)    <= NOT SIn; 
                  WHEN S9 =>  ParallelOut(7)    <= NOT SIn; 
                  WHEN S10=>  StopBit             <= FALSE;                dataReady <= TRUE; 
                  WHEN S11 => StopBit             <= NOT SIn; 
      END CASE; 
 END PROCESS; 
END behavioral;

Serial Input Component Test

The following tests the serial input component above by inputting a character from the serial input line and displaying the ASCII code on the two 7-segment LEDs. The serial input is provided by a Windows 95 terminal program named HyperTerminal. Testing instructions follow this program.
 
-- Test serial input component by outputting to LED of UP1 

ENTITY serITest IS 
     PORT(      systemCLK : IN BIT;      -- Pin 91 
                             SerialIn : IN BIT;      -- Pin 31 
        a1,b1,c1,d1,e1,f1,g1  : OUT BIT;  -- a1-e1, a2-e2 LED pins 
        a2,b2,c2,d2,e2,f2,g2  : OUT BIT); 
END serITest; 

ARCHITECTURE structural OF serITest IS 

   COMPONENT segment7 
           PORT(              x : IN BIT_VECTOR(3 DOWNTO 0); 
                   a,b,c,d,e,f,g  : OUT BIT); 
   END COMPONENT; 

   COMPONENT slowCLK 
          GENERIC( FREQUENCY : INTEGER RANGE 0 TO 12587500 := 12587500); 
           PORT(   clockIN    : IN BIT;    clockOUT : OUT BIT); 
    END COMPONENT; 

    COMPONENT serI 
       PORT(          clk : IN BIT; 
                     SerialIn : IN BIT; 
                ParallelOut : OUT BIT_VECTOR(7 DOWNTO 0); 
                 dataReady : OUT BIT);                             -- Pulses high to signal serial input data ready 
    END COMPONENT; 

    SIGNAL data : BIT_VECTOR(7 DOWNTO 0); 
    SIGNAL dataAvailable : BIT; 
    SIGNAL BAUD16 : BIT; 

BEGIN 
  U0: slowCLK  GENERIC MAP (4800*16) PORT MAP(systemCLK, Baud16); -- Baud rate*16 
  U2: serI           PORT MAP(Baud16, SerialIn, data, dataAvailable); 
  U3: segment7  PORT MAP(data(7 DOWNTO 4), a1,b1,c1,d1,e1,f1,g1); 
  U4: segment7  PORT MAP(data(3 DOWNTO 0), a2,b2,c2,d2,e2,f2,g2); 
END structural; 
 

  1. Connect the serial cable, it should have a round mini-DIN connector, to the UP1 (the cable ends should be labeled UP1 and PC).
  2. Copy and compile the serI.vhd and serITest.vhd components to the directory containing your 7 segment and the slowCLK FLEX component.
  3. Use the Assign, Pin/Location/Chip menu. Click the  button and select the EPF10K20RC240-4 FPGA device, click OK to complete the device assignment. Assign the device for the serI.vhd and serITest.vhd components.
  4. Assign the serITest interface pins as in the figure below.
  5. Recompile the serI.vhd and serITest.vhd components.

 
 
Necessary Pin Definitions for serITest component
 
systemClk - 91          
SerialIn  - 31
a1 - 6
b1 - 7
c1 - 8
d1 - 9
e1 - 11
f1 - 12
g1 - 13
a2 - 17
b2 - 18
c2 - 19
d2 - 20
e2 - 21
f2 - 23
g2 - 24
 
Pin Assignments for serITest Component on FLEX FPGA

Homework 8

Assignment .
  1. Implement a parallel-to-serial convertor VHDL FSM.
  2. Test using the serIO component given below and the HyperTerminal program.

Turn In

  1. Cover Page - Your name, date, and Homework 8. Staple all pages together.
  2. Demonstrate results to instructor.
  3. State transition table for the architecture.
  4. VHDL listing of the parallel-to-serial component.

Design

The serial-to-parallel (SP) and parallel-to-serial (PS) components are the reverse of the other. The SP receives serial data and converts to parallel (serI component), the PS converts parallel to serial data (serO component). The inputs to PS are 8 bits of Parallel data and a signal that new data is available to convert. The outputs are the serial output and a signal to indicate that data sent. The design of the parallel-to-serial component can be listed as the series of steps required:

  1. Go to 1 until new data input is TRUE while outputting idle (0=low voltage) to the serial output.
  2. Set data sent to FALSE.
  3. Output a start bit (1=high voltage).
  4. Output the inverted bit 0 of the parallel data. Remember that the data sent in order of 0, 1, ...
  5. Output the inverted bit 1 of the parallel data.
  6. Output the inverted bit 2 of the parallel data.
  7. Output the inverted bit 3 of the parallel data.
  8. Output the inverted bit 4 of the parallel data.
  9. Output the inverted bit 5 of the parallel data.
  10. Output the inverted bit 6 of the parallel data
  11. Output the inverted bit 7 of the parallel data.
  12. Set data sent to TRUE. Output a stop bit (0=low voltage).
  13. Go to 1.

Implementation

Points of note:

Testing

There are two testing components. The first sends a character 'A' or ASCII code 01000001 binary until the pushbutton is pressed. The second echos whatever character is typed on the terminal program.
 

  • serOTest.vhd - The component uses your serO component to output a character to the serial port. Because the pushbutton is 1 when not pressed, the character 'A' is output continously until the pushbutton is pressed. Compile the following component and assign the pins to:
  • serOTest.vhd 
    -- Serial output via mouse connector of Altera UP1 when PB pressed 

    ENTITY serOTest IS 
     PORT(      systemCLK : IN BIT; 
                                    PB : IN BIT; 
                           SerialOut : OUT BIT); 
    END serOTest; 

    ARCHITECTURE structural OF serOTest IS 

        COMPONENT debounce 
          PORT (  systemCLK, bounce : IN  BIT ; 
                                       debounced : OUT BIT); 
        END COMPONENT; 

       COMPONENT slowCLK 
          GENERIC( FREQUENCY : INTEGER RANGE 0 TO 12587500 := 12587500); 
          PORT(   clockIN    : IN BIT;    clockOUT : OUT BIT); 
        END COMPONENT; 

        COMPONENT serO 
                PORT(          clk : IN BIT; 
                                  SOut : OUT BIT; 
                           ParallelIN : IN BIT_VECTOR(7 DOWNTO 0); 
                          newDATA : IN BIT;                       -- Set to '1' when new output data to be sent 
                              dataSent : OUT BIT);                  -- Pulses high to signal output data sent 
        END COMPONENT; 

        SIGNAL  data : BIT_VECTOR(7 DOWNTO 0); 
        SIGNAL dataAvailable, dataSent : BIT; 
        SIGNAL BAUD16, Baud : BIT; 

    BEGIN 
            data <= "01000001";                                                                                      -- Capital letter A 
      U0: slowCLK  GENERIC MAP (4800*16) PORT MAP(systemCLK, Baud16); -- Baud rate*16 
      U1: slowCLK  GENERIC MAP (4800) PORT MAP(systemCLK, Baud);           -- Baud rate 
      U2: debounce PORT MAP(systemCLK, PB, dataAvailable);                                -- Debounce PB input 
      U3: serO   PORT MAP(Baud, SerialOut, data, dataAvailable, dataSent); 
    END structural;


    Test Component serIO - The testing procedure for the second test component generally follows that of the laboratory with the few exceptions given below. The primary difference is that instead of displaying the character ASCII code on the LEDs, the character is echoed back using your parallel-to-serial component. The serial-to-parallel serI component inputs the character which is then output immediately by your parallel-to-serial serO component, creating an echo of the character typed. The main points of note are:

    -- Echo serial input/output via mouse/keyboard connection on Altera UP1 

    ENTITY serIO IS 
         PORT(      systemCLK : IN BIT; 
                                 SerialIn : IN BIT; 
                              SerialOut : OUT BIT); 
    END serIO; 

    ARCHITECTURE structural OF serIO IS 

       COMPONENT slowCLK 
                  GENERIC( FREQUENCY : INTEGER RANGE 0 TO 12587500 := 12587500); 
                  PORT(   clockIN    : IN BIT;    clockOUT : OUT BIT); 
        END COMPONENT; 

        COMPONENT serI 
                   PORT(          clk : IN BIT; 
                                 SerialIn : IN BIT; 
                            ParallelOut : OUT BIT_VECTOR(7 DOWNTO 0); 
                             dataReady : OUT BIT);         -- Pulses high to signal serial input data ready 
        END COMPONENT; 

        COMPONENT serO 
               PORT(        clk : IN BIT; 
                               SOut : OUT BIT; 
                        ParallelIN : IN BIT_VECTOR(7 DOWNTO 0); 
                       newDATA : IN BIT;              -- Set to '1' when new output data to be sent 
                           dataSent : OUT BIT);         -- Pulses high to signal output data sent 
        END COMPONENT; 

         SIGNAL data : BIT_VECTOR(7 DOWNTO 0); 
         SIGNAL dataAvailable, dataSent : BIT; 
         SIGNAL BAUD16, Baud : BIT; 

    BEGIN 
      U0: slowCLK  GENERIC MAP (4800*16) PORT MAP(systemCLK, Baud16); -- Baud rate*16 
      U1: slowCLK  GENERIC MAP (4800) PORT MAP(systemCLK, Baud);           -- Baud rate 
      U2: serI           PORT MAP(Baud16, SerialIn,    data, dataAvailable); 
      U3: serO         PORT MAP(Baud,     SerialOut,  data, dataAvailable, dataSent); 
    END structural;

    Debugging


    Document last modified: