Structured Digital Design EEN 316 Section 48 Final Project Morse Code Translator Cynthia Rodriguez Nemanja Stojanovic Michael Hall Jia Xu, TA University of Miami 5 December 2013 Abstract The Morse Code Translator project is a design that takes inputs of the form “.” and “-”, or dots and dashes, that correspond to the Morse Alphabet and decodes them into a human readable symbol, displaying the result on the Seven Segment Display. The design contains 4 stages: - Top level Morse Code unit - Control unit that specifies the state machine for decoding Morse code - A sequence builder unit - An LED Decoder unit This project was our third choice for the final project for the class, we had had 2 other ideas prior. Our first idea was a piano decoder that would use a PS/2 keyboard to take inputs and output a specific sound according to the key that was pressed. After researching and testing, we came to the conclusion that using Audio Codecs in VHDL and ModelSim too advanced for us at the current time. Our second idea was to use keyboard input again to input a letter or Arabic number in Morse Code and the output would be the decoded code displayed on the seven segment. This idea had to be discarded due to the fact that the Altera DE2 board has old-fashioned PS/2 ports that communicate with the keyboard, and we weren’t able to find a PS/2 keyboard that would work. Finally, we arrived at our final project which would be like the previous idea except without any external I/O devices, that is, all I/O operations would be done on the DE2 board itself. The Morse Code Translator was completed successfully, although we had some synchronization issues that would not give us the desired output when we implemented the code on a physical device. 1 Table of Contents Introduction ............................................................................................................................... 3 Objectives .................................................................................................................................... 4 Requirements and Equipment ............................................................................................. 4 Design and Implementation ................................................................................................. 5 Specifications ....................................................................................................................................... 7 Design Synthesis ................................................................................................................................. 7 VHDL Code ................................................................................................................................... 8 Results and Simulations ...................................................................................................... 12 Synthesis ................................................................................................................................... 14 Conclusion ................................................................................................................................ 14 Works Cited ............................................................................................................................. 14 2 Introduction The Morse Code Translator project is a design that takes Morse Code as dots and dashes as inputs and decodes it into a symbols we are used to displaying the output on the Seven Segment Display. The design contains 4 stages: - Top level Morse Code unit - Control unit that controls the state machine for decoding Morse code - A sequence builder unit - A LED Decoder unit Background: The Morse Code is a method of transmitting text information as series of on-off tones, lights, or clicks that can be directly understood by a skilled listener or observer. The Morse code alphabet has some variations, but the one we will be using will be the official International Morse Code, provided below: Morse Code Alphabet 3 In order to accomplish this design, we implemented a top level module that connects the following three components: - Sequence Builder - Input Controller/Morse Decoder - Led Decoder/Display The top level module will have 4 input signals that will be input as switches: 1) Start – resets the registers and seven segment 2) Dash – input a dash 3) Dot – input a dot 4) Finish – output the result to the seven-segment LEDs The state machine will use and combine these signals into a value that represents raw Morse code. The 4 states for doing its tasks are: 1) Start – reset 2) Gather – pick up the sequence of dots and dashes 3) No Action – used when neither switch is on 4) Done – output the final result to the seven-segments Objectives The objective of this project was to design a fully functional translator for Morse Code that will accepts “dash” and “dot” inputs, decode this series of characters, and display all the corresponding letters of the English alphabet (A – Z) as well as all of the decimal digits of the Arab numerals (0 – 9) according to those inputs. Requirements and Equipment Equipment/SW used: Hardware: Altera DE2 FPGA Board Software: ModelSim 4 Quartus Design and Implementation Phase 1: Determining the components we will need The first phase of our project involved the conceptual design of the project. We based the design of our components on the main operations needed for this project to be successful. These operations are the following: - Reading user input signal - Storing user input and storing it into some sort of standard form - Decoding this standard form into Seven Segment outputs Phase 2: Building the components The first component built was the Sequence Builder unit that takes 4 single-bit inputs and produces the Morse instruction 4-bit sequence. The 4 inputs are: - Start signal to determine when the user wants to begin inputting the Morse code - Dash and Dot signals that determine the bit sequence that will represent the Morse instruction - Finish signal that will determine when the user has finished inputting data This component was very simple but it was fully efficient in formatting user input into a structure that we can use. Next, we designed the Input Controller. This component contains the state machine, both data flow and control portions, that reacts to the user input sequence coming from the Sequence Builder and stores it into a standardized form that will be decoded for Seven Segment Display. Since no Morse code instruction in our Data range (A – Z, 0 – 9) requires more than 5 bits, we decided to make the standardized size of our instruction be 5 bits. The state machine will have 4 states: - Start 5 o This state initializes user input and the needed control and storage signals to be used during the instruction building process and also serves as the Clear/Restart state of the whole process. - Done o This state determines the end of user input and the beginning of raw Morse code (a single letter) decoding process for the Seven Segment Display. - Gather o This state represents the process of gathering Morse code inputs (“dots” and “dashes”) and building the 5bit raw Morse code instruction that will be decoded and sent to the Seven Segment display in the Done state. The building process of the instruction is done by using a 5-bit shift register to store the input value each time a user sends a dot (0) or a dash (1). This state also keeps track of the number of bits used since the size of our Morse code instructions can be from 1bit to 5 bits. - No Action o This state represents the IDLE state of the state machine when we are not receiving any input from the user and takes care of internal signal control needed for state machine to function and so that no data gets corrupted or lost. Next component was the Seven Segment decoder. This decoder’s purpose was to receive the raw Morse code instruction from the Input Controller after the user has finished inputting data and decode this instruction into an appropriate symbol to be shown on the Seven Segment display. This component also receives the Count signal from the Input Controller that it uses to determine the number of bits that need to be decoded. Phase 3: Connecting the components This phase involved connecting the three components explained above from a Top-level component. This component was the Morse Top unit that takes the initial four 1-bit user input signals (start, dash, dot, finish) from the physical input and outputs the 7-bit Seven 6 Segment data to the physical Seven Segment on the board. This component is in charge of connecting all of the inner components as well as directly interacting with the user both from the input and the output side. Phase 4: Physical I/O This phase caused us the most problems. The simulations we performed in ModelSim gave accurate and correct results but we had unexpected glitches that were causing the data output to behave very chaotically. It took as a fairly long time to decipher what is the best way to approach this issue. We decided to make the whole project synchronized to the same clock, as well as add the No Action state to the Input Controller to take care of any possible data losses. After a few hours of debugging, we have successfully managed to display the letters C – A – T based on user input of dots and dashes. Specifications There were no specifications for this project. Design Synthesis 7 State Machine of Input Controller: START GATHER NOACTION DONE VHDL Code --Sequence Builder -----------------------------------------------------------------------------------------------------------library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_unsigned.all; entity input_build is port(clk, start, dash, dot, finish : in std_logic; input_sequence : out std_logic_vector(3 downto 0)); end input_build; architecture build of input_build is signal temp_seq: std_logic_vector(3 downto 0); begin bld: process(clk)--process(start, dash, dot, finish) begin if(clk'event and clk='1') then temp_seq(3) <= start; temp_seq(2) <= dash; temp_seq(1) <= dot; temp_seq(0) <= finish; end if; end process bld; 8 input_sequence <= temp_seq; end build; -------------------------------------------------------------------------------------------------------------Input Controller -----------------------------------------------------------------------------------------------------------library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_unsigned.all; --Sequence Determinator entity inputctrl_top is port ( clk : in std_logic; input_seq : in std_logic_vector(3 downto 0); bit_count: out std_logic_vector(2 downto 0); letter: out std_logic_vector(4 downto 0)); end inputctrl_top; architecture seqdet of inputctrl_top is type state_type is (start, gather, noaction, done); signal state: state_type; signal shift_reg: std_logic_vector(4 downto 0); signal count: std_logic_vector(2 downto 0); signal raw_morse: std_logic_vector(4 downto 0); signal input_received: std_logic; signal sequence_started: std_logic; begin --state machine for reading morse code --input sequence is 4 bits in the MSB order: start dash dot end --assign: process(input_seq) assign: process(clk) --Control Portion-----------------------------------------begin if(clk'event and clk='1') then --the start button is pressed (1xxx) if (input_seq(3)='1') then state <= start; -- the finish button is pressed (xxx1) elsif (input_seq(0)='1') then state <= done; --dot or dash is pressed (x11x) elsif (input_seq(1)='1' or input_seq(2)='1') then state <= gather; --no input is received (0000) else state <= noaction; end if; end if; --Execution Portion---------------------------------------if(clk'event and clk='1') then case state is -- start/clr state when start => raw_morse <= "10101"; shift_reg <= "00000"; count <= "000"; input_received <= '0'; sequence_started <= '1'; --will keep on gathering until finish button is pushed when gather => --if input not received and the sequence started if(input_received = '0' and sequence_started = '1') then --gather a dash and increment a counter if (input_seq = "0100") then shift_reg <= (shift_reg(3 downto 0) & '1'); count <= (count + 1); --gather a dot and increment the counter --1 means dash 9 elsif (input_seq = "0010") then shift_reg <= (shift_reg(3 downto 0) & '0'); --0 means dot count <= (count + 1); else --if input is neither a dot nor a dash, do not change anything shift_reg(4 downto 0) <= shift_reg(4 downto 0); count(2 downto 0) <= count(2 downto 0); end if; input_received <= '1'; --set input received signal end if; --end input received if --no action state when noaction => shift_reg(4 downto 0) <= shift_reg(4 downto 0); count(2 downto 0) <= count(2 downto 0); raw_morse <= "10101"; input_received <= '0'; --reset input received signal --finish/display state when done => sequence_started <= '0'; case count is when "001" => if (shift_reg = 1) then raw_morse <= "00001"; --T --1 elsif (shift_reg = 0) then raw_morse <= "00000"; --E --0 . end if; when"010"=> if (shift_reg = 2) then raw_morse <= "00010"; --N --10 -. elsif (shift_reg = 3) then raw_morse <= "00011"; --M --11 -elsif (shift_reg = 0) then raw_morse <= "00000"; --I --00 .. elsif (shift_reg = 1) then raw_morse <= "00001"; --A --01 .end if; when "011" => if (shift_reg = 3) then raw_morse <= "00011"; --W --011 .-elsif (shift_reg = 1) then raw_morse <= "00001"; --U --001 ..elsif (shift_reg = 2) then raw_morse <= "00010"; --R --010 .-. elsif (shift_reg = 0) then raw_morse <= "00000"; --S --000 ... elsif (shift_reg = 5) then raw_morse <= "00101"; --K --101 -.elsif (shift_reg = 7) then raw_morse <= "00111"; --O --111 --elsif (shift_reg = 6) then raw_morse <= "00110"; --G --110 --. elsif (shift_reg = 4) then raw_morse <= "00100"; --D --100 -.. end if; when "100" => if (shift_reg = 7) then raw_morse <= "00111"; --J --0111 .--elsif (shift_reg = 10)then raw_morse <= "01010"; --C --1010 -.-. elsif (shift_reg = 13)then raw_morse <= "01101"; --Q --1101 --.elsif (shift_reg = 0) then raw_morse <= "00000"; --H --0000 .... elsif (shift_reg = 8) then raw_morse <= "01000"; --B --1000 -... elsif (shift_reg = 11)then raw_morse <= "01011"; --Y --1011 -.-elsif (shift_reg = 9) then raw_morse <= "01001"; --X --1001 -..elsif (shift_reg = 2) then raw_morse <= "00010"; --F --0010 ..-. elsif (shift_reg = 1) then raw_morse <= "00001"; --V --0001 ...elsif (shift_reg = 6) then raw_morse <= "00110"; --P --0110 .--. elsif (shift_reg = 4) then raw_morse <= "00100"; --L --0100 .-.. elsif (shift_reg = 12)then raw_morse <= "01100"; --Z --1100 --.. end if; when "101" => if (shift_reg = 31) then raw_morse <= "11111"; --0 --11111 ----elsif (shift_reg = 15) then raw_morse <= "01111"; --1 --01111 .---elsif (shift_reg = 7) then raw_morse <= "00111"; --2 --00111 ..--elsif (shift_reg = 3) then raw_morse <= "00011"; --3 --00011 ...-elsif (shift_reg = 1) then raw_morse <= "00001"; --4 --00001 ....elsif (shift_reg = 0) then raw_morse <= "00000"; --5 --00000 ..... elsif (shift_reg = 16) then raw_morse <= "10000"; --6 --10000 -.... elsif (shift_reg = 24) then raw_morse <= "11000"; --7 --11000 --... elsif (shift_reg = 28) then raw_morse <= "11100"; --8 --11100 ---.. elsif (shift_reg = 30) then raw_morse <= "11110"; --9 --11110 ----. end if; when others => raw_morse <= "10101"; --this value shuts off the SEVSEG end case;--end the count case statement end case;--end the state case statement end if;--end the clk if statement end process assign; letter <= raw_morse; --send the morse sequence to the SEVSEG decoder 10 bit_count <= count; end seqdet; --send the number of bits to SEVSEG to be used for decoding -------------------------------------------------------------------------------------------------------------Seven Segment Decoder -----------------------------------------------------------------------------------------------------------library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_unsigned.all; entity seven_seg is port (clk: in std_logic; count: in std_logic_vector(2 downto 0); letter: in std_logic_vector (4 downto 0); led: out std_logic_vector(6 downto 0)); end seven_seg; architecture led_arch of seven_seg is --signal led: std_logic_vector(6 downto 0); begin --inputs are in binary Translation: process(count, letter, clk) begin if(clk'event and clk='1') then case count is when "001" => if (letter = 1) then led <= "1110000"; --t elsif (letter = 0) then led <= "0110000"; --E end if; when "010" => if (letter = 2) then led <= "1101010"; --n elsif (letter = 3) then led <= "0001001"; --M looks like a big little n elsif (letter = 0) then led <= "1101111"; --i elsif (letter = 1) then led <= "0001000"; --A end if; when "011" => if (letter = 3) then led <= "0110110";--W three horizontal bars elsif (letter = 1) then led <= "1100011";--u little u elsif (letter = 2) then led <= "1111010";--r elsif (letter = 0) then led <= "0100100";--S, a 5 elsif (letter = 5) then led <= "1011000";--k looks like a flipped 4 elsif (letter = 7) then led <= "1100010";--o elsif (letter = 6) then led <= "0000100";--g elsif (letter = 4) then led <= "1000010";--d end if; when "100" => if (letter = 7) then led <= "1000111"; --J 1110001 elsif (letter = 10)then led <= "1110010"; --c elsif (letter = 13)then led <= "0001100"; --q elsif (letter = 0) then led <= "1001000"; --H elsif (letter = 8) then led <= "1100000"; --b elsif (letter = 11)then led <= "1000100"; --y elsif (letter = 9) then led <= "1011010"; --X bge light up elsif (letter = 2) then led <= "0111000"; --F elsif (letter = 1) then led <= "1000001"; --V like a big U elsif (letter = 6) then led <= "0011000"; --p elsif (letter = 4) then led <= "1110001"; --L elsif (letter = 12)then led <= "0010010"; --Z a 2 end if; when "101" => if (letter = 31)then led <= "0000001"; --0 elsif (letter = 15)then led <= "1001111"; --1 elsif (letter = 7) then led <= "0010010"; --2 elsif (letter = 3) then led <= "0000110"; --3 elsif (letter = 1) then led <= "1001100"; --4 elsif (letter = 0) then led <= "0100100"; --5 elsif (letter = 16)then led <= "0100000"; --6 elsif (letter = 24)then led <= "0001111"; --7 elsif (letter = 28)then led <= "0000000"; --8 elsif (letter = 30)then led <= "0000100"; --9 11 end if; when others => led <= "1111111"; --all off end case; --led_out <= led; end if; end process Translation; end led_arch; -------------------------------------------------------------------------------------------------------------Morse Top Level Unit -----------------------------------------------------------------------------------------------------------library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_unsigned.all; entity Morse_top is port(start, dash, dot, finish, clk: in std_logic; sev_seg: out std_logic_vector(6 downto 0)); end entity; architecture morse of Morse_top is component seven_seg is port (clk: in std_logic; count: in std_logic_vector (2 downto 0); letter: in std_logic_vector (4 downto 0); led: out std_logic_vector(6 downto 0)); end component; component inputctrl_top is port ( clk : in std_logic; input_seq : in std_logic_vector(3 downto 0); bit_count: out std_logic_vector(2 downto 0); letter: out std_logic_vector(4 downto 0)); end component; component input_build is port(clk, start, dash, dot, finish : in std_logic; input_sequence : out std_logic_vector(3 downto 0)); end component; signal counter : std_logic_vector(2 downto 0); signal letter : std_logic_vector(4 downto 0); signal temp_start, temp_dash, temp_dot, temp_f: std_logic; signal input_seq : std_logic_vector(3 downto 0); begin temp_start <= start; temp_dash <= dash; temp_dot <= dot; temp_f <= finish; SEQUENCE: input_build port map(clk, temp_start, temp_dash, temp_dot, temp_f, input_seq); INPUT: inputctrl_top port map(clk, input_seq, counter, letter); SEVSEG: seven_seg port map(clk, counter, letter , sev_seg); end architecture; ------------------------------------------------------------------------------------------------------------ Results and Simulations ModelSim Simulation of inputting Morse Code for the letter ‘T’. The code is “–” (dash) 12 The output should be: 1110000 As can be seen from the screen shot above, the output for the seven segments when the Morse Code for ‘T’ was input into the system was 1110000. However, note that the output took a few clock cycles after the ‘finish’ switch was turned on to appear. This was reflected in the physical implementation on the code where you had to wait a while between turning switches on and off. If you changed switches too quickly, the output would not display correctly or nothing would be displayed at all. Seven-Segment Decoder: The above screen shot shows the decoded output to the seven-segment LEDs when the Morse Code encoded in binary for ‘D’ (dash-dot-dot is 00100 in binary) and ‘M’ (dash – dash is 00011 in binary) as well as the number of dots and dashes it’s composed of (count = 3 for D and count = 2 for M) was input. The outputs were correct. 13 Synthesis Our simulation went through the process of simulating user input and observing the outcomes in the project after each input. The user enters the sequence for the letter or number they want then flips the ‘finish’ switch on (make finish = ‘1’) to indicate that they are finished inputting their sequence. When they want to input a new sequence they flip the ‘start’ switch on (make start = ‘1’) and this will reset the interior registers and seven-segment LEDs. We also had all-zero inputs between each individual input to simulate the releasing of the switch, as a user would do in a real-life demonstration. Conclusion Our design takes an input of dashes and dots provided by the user. The leftmost switch on the DE2 board initializes the input sequence, and the dashes and dots are accepted by the second and third switches. The fourth switch is flipped when the user is finished inputting the code. The associated letter or number is displayed on the 7-segment display. When loading our design on the DE2 board, we need to use the JTAG method. This does not allow the code to be stored on the board for future use. We need to load the design onto the board everytime the board becomes reset. Our design is limited because it needs to be synced to at 4 clock cycles, which was a problem with our original design. This leads to the realization that the processes we wrote takes more than one clock cycle to preform, which our original design was designed for. Works Cited Morse Code Table - http://www.bbc.co.uk/schools/gcsebitesize/science/images/gatewaysci_09.gif 14