Implementation of Keyboard Learner with Spartan 3EDK

FPGA Implementation of Keyboard Learner

Overall rating

The main objective of the KBL project is to provide it’s users an easy and straight-forward way to learn, practice and improve the use of the keyboard in typewriting. The proposed solution for reaching this objective is a clean application, with no unnecessary artwork and with a few options for customizing the user-experience.

The keyword of the project is random. The system generates and displays random character codes, with a very small possibility of the code being an actual word. This forces the user to keep his eyes on the screen, and not at the keyboard. If the system would use intelligible words, the user would just read them and switch his eyes to the keyboard to type them. The effect of using this system is that users will start typing faster, and with fewer spelling errors, eventually without even looking to the keys.

Tool required

  • Software: Xilinx ISE 11.1i
  • Language: VHDL
  • Hardware: 1.Spartan3 EDK FPGA kit
    2.VGA Monitor
    3.PS/2 Keyboard

Block Diagram



The Keyboard Learner gets its user inputs from the PS/2 keyboard. Each input characters must be compared with a generated character, and the score modified accordingly, and displayed. From this single sentence, some of the main components of the design can be easily identified: a random character generator, a keyboard input reader, a comparator, a score updater and a display unit. Also, code sequences must be memorized and the custom settings for the timer and the length of the sequence must be handled. Most of the components are based on registers and counters and use comparators, multiplexers and demultiplexers. Figure 3.1 shows the top level block diagram, with all the components used in the design and the links between them.

Functional Description

This section describes the flow of events that can take place while using the KBL system.

The Menu Screen

The system starts in the Menu Screen – the state signal is set to logical ‘0’. This screen displays on two different lines the labels for the timer (T) and level (L) settings together with their default values. The third line contains the GO label, used to start the application. The first line, corresponding to the timer setting is highlighted (yellow). The system waits for user input.

The user can change the timer value, or switch the selected item to the next line, from where he/she can change the level value, or step to the third line and start the application. A minimum of 3 keys must be pressed in order to get to the Application Screen. These 3 keystrokes are used in the background to generate the first random character sequence and store it, each character in its corresponding register. Therefore, the default level value must be less then or equal to 3, so that all the characters are generated.

The units used during the Menu Screen are: KB_UNIT, MENU, VGA_CTRL, COLORIZER and NUM_CNTR, and, unnoticeably for the user, the RANDOMIZER, CRST and REG_PIPE.

The Application Screen

When in Application Screen, the screen contains the generated character code in the centre and the user score in the upper right corner. Initially the score is null (000). The system waits for the user to type the code displayed.

As each character is typed in, it is compared to the one in the code. If they match, the score is incremented. If not, the score is decremented (if it is still positive). The colours of the typed characters changes with regard to the past comparison results. A green character signifies a correct match, while a red one means that character was mistyped.

If the user has set a non-null timer value, then the ready-for-display registers are cleared after the specified amount of time and the code disappears from screen, the application becoming a memory test.

All the units are functional when the system is in Application Screen.:

  • The KB_UNIT reads the user input;
  • The NUM_CNTR iterates the character sequence;
  • The RANDOMIZER generates a new character code at each key stroke;
  • The REG_PIPE stores the codes, moves them into the pipe and outputs them to the COUNTER or the COLORIZER;
  • The COUNTER compares the generated and the read character code and computes the score and sends it to the COLORIZER;
  • The COLORIZER computes the colour channels value for each character
  • The VGA_CTRL selects the current character, character line and pixel, and generates the synchronization signals;
  • The HIDER clears generated code from the screen if the time limit has been reached;
  • The MENU identifies the ESC (escape) keystroke, and send the system back in Menu Screen.

Source Code


library IEEE;





-- The KBL top module

entity learner is

             Port (  mclk    : in std_logic;               -- master clock

                        kd, kc   : in std_logic;               -- keyboard input: keyboard data, keyboard clock

                        rst        : in std_logic;               -- master reset

                        hs         : out std_logic;            -- horizontal synchronization output

                        vs         : out std_logic;            -- verical synchronization output

                        red, grn, blu : out std_logic    -- colour channels output


end learner;


architecture Behavioral of learner is


component randomizer is                                -- generates the character sequence

    Port ( clk : in  STD_LOGIC;                                      -- master clock

           rst : in  STD_LOGIC;                                        -- asyncronous reset

           oe : in  STD_LOGIC;                                          -- asyncronous output enable

           ascig : out  STD_LOGIC_VECTOR (5 downto 0));         -- generated character code

end component;


component kb_unit is                         -- component that reads the user input

    Port ( clk : in  STD_LOGIC;           -- master clock

           rst : in  STD_LOGIC;             -- master reset

           kc : in  STD_LOGIC;             -- keyboard clock

           kd : in  STD_LOGIC;              -- keyboard data

           kbexec : in  STD_LOGIC;      -- keyboard execution enable

           scancode : out  STD_LOGIC_VECTOR (7 downto 0);-- scan code of the pressed key

           ascii : out  STD_LOGIC_VECTOR (5 downto 0);           -- character code corresponding to the scan code

           numclk : out  STD_LOGIC);                  -- number clock - a positive impulse at each keystroke

end component kb_unit;


component num_cntr is                               -- counts the keystrokes => current index in the sequence

    Port ( numclk : in  STD_LOGIC;                               -- number clock

           crst : in  STD_LOGIC;                                        -- counter reset

           level : in  STD_LOGIC_VECTOR (2 downto 0); -- length of character sequence

           num : out  STD_LOGIC_VECTOR (2 downto 0));-- current index in the sequence

end component num_cntr;


component vgactrl is             -- goes through the screen pixels and enables display

    Port ( clk : in std_logic;                                           -- master clock input

            kbexec : out std_logic;                                    -- keyboard execution enable

           hs : out std_logic;                                             -- horizontal synchronization signal

           vs : out std_logic;                                             -- vertical synchronization signal

           text : out std_logic;                                          -- text display enable

           pixel : out std_logic_vector(2 downto 0);        -- pixel selector

           line : out std_logic_vector(2 downto 0);          -- line selector

 col : out std_logic_vector(6 downto 0);         -- current column

 row : out std_logic_vector(5 downto 0));      -- current row

end component;


component counter is       -- counts the user points

    Port ( ascig : in std_logic_vector(5 downto 0);       -- generated character code to be compared

ascik : in std_logic_vector(5 downto 0);         -- read from keyboard character code to be compared

            clk, rst, ce : in std_logic;                                 -- clock (numclk), master reset and chip enable

           ascip : out std_logic_vector(17 downto 0);     -- character codes for the 3 digits of the score

                                      ok : out std_logic);                -- comparison result

end component;


component reg_pipe is                     -- stores and transmits character codes

    Port ( ascig : in  STD_LOGIC_VECTOR (5 downto 0);         -- generated character code

           ascii : in  STD_LOGIC_VECTOR (5 downto 0);             -- typed character code

                                      rst : in STD_LOGIC;                           -- master reset

                                      crst : in std_logic;                              -- counter reset

           num : in  STD_LOGIC_VECTOR(2 downto 0);              -- current index in the sequence

           numclk : in  STD_LOGIC;                                              -- number clock

           level : in  STD_LOGIC_VECTOR(2 downto 0);              -- length of character sequence

           hide : in  STD_LOGIC;                                                   -- hide command

ok : in std_logic;                                                          -- comparison result

           cascig : out  STD_LOGIC_VECTOR (5 downto 0);        -- comparison register output

           rascig : out  STD_LOGIC_VECTOR (23 downto 0);       -- ready-for-display registers output

           kasci : out  STD_LOGIC_VECTOR (23 downto 0);        -- keyboard registers output

            status : out std_logic_vector(3 downto 0));                -- comparisons history status register output

end component reg_pipe;


component hider is                                           -- clears the generated sequence from the screen

    Port ( mclk : in  STD_LOGIC;                                   -- master clock

           crst : in  STD_LOGIC;                                        -- counter reset

           state : in  STD_LOGIC;                                      -- current state(screen)

           num : in  STD_LOGIC_VECTOR (2 downto 0); -- current index in the sequence

           level : in  STD_LOGIC_VECTOR (2 downto 0); -- length of the character sequence

            timer : in STD_LOGIC_VECTOR (1 downto 0);            -- timer value

           hide : out  STD_LOGIC);                                               -- hide command

end component hider;


component menu is                                           -- handles the user settings menu screen

    Port ( clk : in  STD_LOGIC;                                                  -- clock (number clock)

                                      rst : in STD_LOGIC;                                                                                                   -- reset

           scancode : in  STD_LOGIC_VECTOR (7 downto 0);      -- scan code of the pressed key

           level : out  STD_LOGIC_VECTOR (2 downto 0);           -- length of the character sequence

           timer : out  STD_LOGIC_VECTOR (1 downto 0);         -- timer value

           state : out  STD_LOGIC;                                                           -- current state (screen)

           start : out  STD_LOGIC;                                                            -- start application signal

            selmenu : out std_logic_vector(1 downto 0));            -- selected menu item

end component;


component colorizer is                                                                    -- computes the output and the color channels for each character

            Port ( num : in std_logic_vector(2 downto 0);                        -- current index in the sequence

                                     row : in std_logic_vector(5 downto 0);          -- current row

                                     col : in std_logic_vector(6 downto 0);           -- current column

                                     status : in std_logic_vector(3 downto 0);      -- comparisons history status

                                     text : in std_logic;                                          -- text display enable

                                     pixel : in std_logic_vector(2 downto 0);        -- selected pixel

                                     line : in std_logic_vector(2 downto 0);          -- selected line

                                     state : in std_logic;                                         -- current state (screen)

                                     selmenu : in std_logic_vector(1 downto 0);  -- selected menu item

                                     level : in  STD_LOGIC_VECTOR (2 downto 0);-- length of the character sequence

          timer : in  STD_LOGIC_VECTOR (1 downto 0);             -- timer value


                                     rascig : in std_logic_vector(23 downto 0);    -- ready-for-display character codes

                                     kasci : in std_logic_vector(23 downto 0);      -- keyboard-read character codes

                                     ascip : in std_logic_vector(17 downto 0);      -- user score character codes


                                     red, grn, blu : out std_logic);                         -- colour channels

end component;


signal col : std_logic_vector(6 downto 0) := "0000000";        -- current column

signal row : std_logic_vector(5 downto 0) := "000000";        -- current row


signal ascii : std_logic_vector(5 downto 0) := "000000";       -- user input character code

signal ascig : std_logic_vector(5 downto 0) := "000000";      -- generated character code


signal cascig : std_logic_vector(5 downto 0) := "000000";-- generated character code selected for comparison


signal rascig : std_logic_vector(23 downto 0);           -- ready-for-display character codes

signal kasci : std_logic_vector(23 downto 0);            -- keyboard-read character codes

signal ascip : std_logic_vector(17 downto 0) := "011011011011011011";    -- user score character codes


signal scancode : std_logic_vector(7 downto 0) := "00000000";       -- scan code of the pressed key

signal kbexec : std_logic := '0';                                                           -- keyboard execution enable

--signal sseg : std_logic_vector(6 downto 0) := "0000000";   -- for debug


signal text : std_logic := '0';                                                                -- text display enable

signal line : std_logic_vector(2 downto 0) := "000";              -- selected character line

signal pixel : std_logic_vector(2 downto 0) := "000";             -- selected pixel in line


signal numclk : std_logic := '0';                                              -- number clock

signal num : std_logic_vector(2 downto 0) := "000";             -- current index in the sequence (number of keystrokes)


signal level : std_logic_vector(2 downto 0) := "100";             -- length of character sequence

signal timer : std_logic_vector(1 downto 0) := "00";             -- timer value

signal hide : std_logic := '0';                                                   -- hide command

signal selmenu : std_logic_vector(1 downto 0) := "00";         -- selected menu item


signal state : std_logic := '0';                                                  -- current state (screen)

signal crst : std_logic := '0';                                                    -- counter reset

signal start : std_logic := '0';                                                   -- start application signal


signal ok  : std_logic := '0';                                                     -- comparison result

signal status : std_logic_vector(3 downto 0) := "0000";         -- comparisons history



            -- component instantiation

            random0 : randomizer port map(

                        clk => mclk,

                        rst => rst,

                        oe => numclk,                         -- output enable on keystroke

                        ascig => ascig);


            reg_pipe0 : reg_pipe port map(

                        ascig => ascig,

                        ascii => ascii,

                        rst => rst,

                        crst => crst,

                        num => num,

                        numclk => numclk,

                        level => level,

                        hide => hide,

                        ok => ok,

                        cascig => cascig,

                        rascig => rascig,

                        kasci => kasci,

                        status => status);


            kbunit0 : kb_unit port map(

                        clk => mclk,

      rst => rst,

                        kc => kc,

                        kd => kd,

                        kbexec => kbexec,

                        scancode => scancode,

                        ascii => ascii,

                        numclk => numclk);


            num_cntr0 : num_cntr port map(

                        numclk => numclk,

      crst => crst,

      level => level,

      num => num);


            pcount0: counter port map(

                        ascig => cascig,

                        ascik => ascii,

                        clk => numclk,                      -- compares inputs and modifies at each keystroke

                        rst => crst,

                        ce => state,

                        ascip => ascip,

                        ok => ok);


            vgactrl0: vgactrl port map(

                        clk => mclk,

                        kbexec => kbexec,

                        hs => hs,

                        vs => vs,

                        text => text,

                        pixel => pixel,

                        line  => line,

                        col => col,

                        row => row);


            menu0 : menu port map(

                        clk => numclk,

                        rst => rst,

                        scancode => scancode,-- sensitive to menu operations keystrokes: SPACE, ENTER, ESC

                        level => level,

                        timer => timer,

                        state => state,

                        start => start,

                        selmenu => selmenu);


            hider0 : hider port map(

                        mclk => mclk,

                        crst => crst,

                        state => state,

                        num => num,

                        level => level,

                        timer => timer,

                        hide => hide);


            color0: colorizer port map(

                        num => num,

                        row => row,

                        col => col,

                        status => status,

                        text => text,

                        pixel => pixel,

                        line => line,

                        state => state,

                        selmenu => selmenu,

                        level => level,

                        timer => timer,


                        rascig => rascig,

                        kasci => kasci,

                        ascip => ascip,


                        red => red,

                        grn => grn,

                        blu => blu);


            -- counters reset

            crst <= rst or start;     -- reset on global reset or when state changes from menu screen to application screen


end Behavioral;



Typewriting skills are an important asset for anyone in the modern society. There are many tools and systems (hardware and software) for learning, developing and improving this ability. The Keyboard Learner is one of them. It achieves its goal of being a self-educational tool by its simplicity and ease of use at a low cost.

The additional option of using a limited display time period makes out of KBL not only an educational tool, but also a memory game, fun for children in growing phase, when developing attention and memory capability is very important.

The project uses a hierarchical and modular design, which has the advantage of being easy to follow and understand. It is event oriented, so it can be easily translated into natural language. The reusability of independent units is not one of the project’s strong points. This is caused by the high dependency between components and can be seen as a drawback. On the other hand, the components are designed to be dedicated to the specific role that they have within the Keyboard Learner.

Join the World's Largest Technical Community

we respect your privacy.