Typing Tutor

Design Documentation

Courtney Adams Jonathan Corretjer

December 16, 2016 USU 3710 Contents

1 Introduction 2

2 Scope 2

3 Design Overview 2 3.1 Requirements ...... 2 3.2 Dependencies ...... 2 3.3 Theory of Operation ...... 3

4 Design Details 5 4.1 Hardware Design ...... 5 4.2 Software Design ...... 5 4.2.1 LCD Keyboard Display ...... 5 4.2.2 Key Stroke Input ...... 7 4.2.3 Menu Layout ...... 8 4.2.4 Level and Test Design ...... 9 4.2.5 Correctness Logic ...... 11 4.2.6 Buzzer Implementation ...... 11 4.2.7 Calculations ...... 12

5 Testing 12 5.0.1 SSI Output to LCD ...... 12 5.0.2 Keyboard Data Input ...... 13 5.0.3 Buzzer Frequency ...... 14 5.0.4 Buzzer Length ...... 15 5.0.5 Trial Testing ...... 15 5.0.6 Calculations ...... 16

6 Conclusion 16

7 Appendix 18 7.1 Code...... 18 7.1.1 LCD.h ...... 19 7.1.2 LCD.c ...... 20 7.1.3 main.c ...... 22 7.1.4 TypingLib.h ...... 24 7.1.5 TypingMenu.h ...... 27 7.1.6 TypingMenu.c ...... 28 7.1.7 Keys.h ...... 31

1 7.1.8 Keys.c ...... 32 7.1.9 Speaker.h ...... 37 7.1.10 Speaker.c ...... 38

2 1 Introduction

The goal of the Tutor is to enable users to practice and develop their typing skills using an interactive interface that encourages improvement. Composed of various levels, the Typing Tutor provides a challenging medium for both beginners and experienced, alike. At any time during the tutoring process, users can take a typing test to measure their progress in speed and accuracy. The Typing Tutor is implemented on the Tiva TM C series TM4C123GH6PM Microcontroller and includes the ability to monitor key stroke inputs from a PS/2 keyboard and display the correct key input on an LCD screen as an additional aid to users. The Typing Tutor also includes a buzzer that indicates when an incorrect key has been inputted by the user.

2 Scope

This document describes the hardware and software design of the Typing Tutor project. It includes the requirements, dependencies, design, implementation, and testing of the project. The complete code is located in the Appendix at the end.

3 Design Overview

3.1 Requirements

The following is a list of requirements for the Typing Tutor:

1. Monitor key stroke input 2. Verify correctness of input 3. Display a small keyboard to an LCD screen that highlights the next key 4. Implement a feedback buzzer to indicate incorrect input 5. Transmit a menu interface to a terminal emulator for the user to interact with 6. Provide levels of varying difficulty that target specific sets of keys 7. Generate a random variety of words and phrases in each level to properly test the user’s reaction speed 8. Calculate the user’s accuracy after every level 9. Provide a typing test that calculates the typing speed and accuracy of the user

3.2 Dependencies

The following is a list of hardware dependencies for the Typing Tutor:

• A 5 volt DC power supply • A 3.3 volt DC power supply • 16 MHz crystal oscillator • ER-TFTM032 LCD Touchscreen • MCP4724 DAC • Analog Test Board (Speaker) • PS/2 keyboard

3 3.3 Theory of Operation

At startup, the menu interface will be transmitted to the terminal emulator and a blank keyboard will display on the LCD screen. The user will be able to navigate the menu screen using the arrow keys and select the level they want to begin. There will be 6 total levels, with each level targeting a specific set of keys, and a typing speed test that measures the user’s words per minute (WPM) rate. Figure 1 shows a software diagram of the program levels and what each level will consist of. Refer to Figures 2 and 3 for the initial designs of the menu screen and LCD .

Figure 1: Software Diagram of Program

Figure 2: Design of Menu Screen

4 Figure 3: LCD Keyboard Layout

A level will begin by prompting the user to practice typing single letters of the target key-set. Then, it will generate words that consist of mostly the target key-set for the user to type out. Finally, it will concatenate a random sample of those words to form sentences for the user to type. After the user finishes the level, the terminal will display the user’s accuracy based on the number of errors he or she made throughout the level. Figure 4 is the design of the terminal interface for a example level.

Figure 4: Design of Example Level

The typing test will randomly choose one of three possible paragraph-length passages and display it for the user to type. Once finished, the program will calculate the words per minute (WPM) rate of the user as well as display his or her accuracy. At the completion of a level or test, the interface will return to the starting menu, but the accuracy and WPM rate of the finished level/test will remain displayed to the user until he or she begins another level/test. During the course of a level or test, the keyboard inputs of the user will be monitored by the software to verify correctness. The small keyboard displayed on the LCD keyboard will highlight the level’s target keys grey and the next key green as an additional aid to the user. If the user types the wrong key, the buzzer will generate a brief audio tone to indicate error to the user. Additionally, the incorrect key that the user pressed will be highlighted red on the LCD keyboard.

Figure 5: Example Keyboard Layout

5 4 Design Details

4.1 Hardware Design

Each required component of the project is connected to pins on the TM4C123GH6PM microcontroller as shown in Table 1, and the peripherals used for the design of this project are shown in Table 2.

Table 1: Pins

µC pin Function A2 SSI0 CLK A3 SSI0 FFS A4 SSI0 RX A5 SSI0 TX B0 LCD instruction control B2 I2C0 SCL B3 I2C0 SDA D0 PS/2 CLK D1 PS/2 Data

Table 2: Peripherals

Peripheral Use UART0 Transmit to terminal emulator SSI0 Transmit to LCD I2C0 Transmit to DAC Systick Random generator 16/32-bit Timer0 Buzzer length 16/32-bit Timer1 Buzzer frequency 16/32-bit Timer2 Test timer

Figure 6 shows a hardware schematic of how the components connect together and to the microcontroller.

4.2 Software Design

The software aspect of the design is accomplished in a series of steps centered around these six re- quirements of the project: displaying the LCD keyboard, displaying the menu, monitoring keyboard input, verifying correctness of the input, implementing the buzzer, and calculating typing speed and accuracy. The details of the steps taken to meet these requirements will be discussed in detail in this section. Initialization and configuration of the necessary peripherals will also be discussed.

4.2.1 LCD Keyboard Display

SSI Configuration SSI0 is used as the peripheral to communicate with the ER-TFTM032 LCD screen. The TM4C123GH6PM microcontroller is configured as the master device, and SSI as the slave. The SSI clock source is set as the 16 MHz System clock and the SSI is configured with a Freescale SPI frame format and 8-bit data.

Drawing the Keyboard: The method used to draw the keyboard is as follows:

6 Figure 6: Hardware Schematic

1. Color the entire screen black 2. Store the coordinates of every key into four parallel arrays (left, right, top, and bottom bounds)

3. At startup, draw a white box at the location of every key’s coordinates 4. Whenever a key needs to update its color, find the key’s index in the parallel arrays to obtain its coordinates and re-draw the box with the new color

Dimensions: The coordinates for each of the keys are calculated by measuring the dimensions of the keyboard on the LCD screen, which are determined by the following method: Given that the LCD screen has dimensions of 320x240 pixels, and that there should be a 10 pixel buffer on each side of the keyboard, that gives the keyboard a length of 300 pixels. The top row of of the keyboard has 14 keys, with the backspace key twice as long as the rest, which results in 15 total equal-spaced boxes needed for the top row. This means that each box is 300/5 = 20 pixels long. Assuming the boxes are square, and that there are 5 rows of keys, this means that the keyboard has a width of 20 · 5 = 100 pixels. So the dimensions of the keyboard are 300x100 pixels. Assuming that the top-right corner of the LCD is the point of origin on the LCD coordinate system, the corner coordinates of the keyboard are calculated accordingly. Figure 7 is a visual of how the keyboard dimensions map to the LCD coordinate system. To draw the individual boxes, the coordinates for the left, right, top, and bottom sides of each key are recorded in four respective parallel arrays stored in the TypingLib.h header file. Figure 8 is a photo taken of the resulting keyboard printed to the LCD screen.

7 Figure 7: Dimensions of Keyboard

Figure 8: Drawing of Keyboard on LCD Screen

4.2.2 Key Stroke Input

When a key is pressed on the keyboard, the PS/2 clock line is brought low, and a one-byte key code for the key is transmitted serially through the PS/2 data line, bit by bit. In order to monitor this keyboard input, an interrupt is configured to key-log the data transmitted from the keyboard, and then the key code is converted to an ascii code. Once the key is released, the keyboard transmits a two more bytes: 0xF0 followed by the key code again. To filter out the repeated data and unnecessary bytes, these two bytes are usually ignored.

Interrupt Configuration: The program software captures the data transmitted from the keyboard by configuring pin PD0 (con- nected to the keyboard Clock port) to trigger an interrupt at the event of a negative edge. When this interrupt triggers, the bit being transmitted by the keyboard Data port (connected to pin PD1) is stored and shifted. For every bit transmitted by the keyboard, this interrupt is triggered until it is done. The software knows when the key code byte has been completely transmitted by checking the value of a counter that increments every time a data bit gets stored.

Converting to Ascii: Once the program has stored the key code byte, it runs a routine to search for the key code in a parallel array of key codes. If the code is found, the corresponding key index is returned, and the program uses this

8 index to identify the equivalent Ascii code for the key using another parallel array. The key index is also used to find other important information about the key, such as its LCD coordinates. If the code is not found in the parallel array of key codes, a default index of 58 is returned (58 is one more than the last index value of the parallel arrays). The software is designed to handle this case as though the keyboard data is garbage, and ignore it.

Transmitting to UART0 : Once the program has obtained the Ascii code for the key just pressed, it transmits the code to the terminal emulator for immediate feedback for the user. UART0 is the peripheral used to transmit to the terminal emulator, and it is configured to transmit through the USB connection of the microcontroller and its baud rate is set to a standard 9600 baud.

4.2.3 Menu Layout

Before printing the menu, the program begins by clearing about 15 lines of the terminal and then return- ing the curser back to the beginning. This ensures that whatever menu is left over from previous execution is sufficiently cleared before it starts again. The main purpose for including this feature is to add conve- nience during testing, because otherwise the terminal emulator would need to be restarted every time the microcontroller gets reset in order to clear the previous data. The method for clearing a line is to transmit several spaces, carriage return the curser to the beginning of the line, backspace to move to the previous line, and carriage return the curser again. This routine can be repeated as necessary to clear a certain number of lines, however, since the baud rate of UART0 is not extremely fast, clearing more than 15 lines can take a few seconds.

Writing the Menu: The menu is written by first transmitting a welcome phrase to the terminal emulator, then the Level Op- tions, and finally, the Level Description. Figure 9 shows the menu interface displayed in PuTTY at program start-up.

Figure 9: Menu Interface in PuTTY

9 The user can then use the arrow keys on the keyboard to navigate through the levels and view the descriptions of each. The method used to implement this feature is to run an input loop, in which the program waits for input from the keyboard, and if the input is an arrow key it re-prints the Level Options with the arrow brackets shifted and the Level Description changed accordingly. If the input of the keyboard is the enter key, then the program proceeds with the level selected. Otherwise, the keyboard input is ignored.

4.2.4 Level and Test Design

Level Interface: A level proceeds underneath the menu interface, so that the user can still view the Level Description and target key-set of the level. The level begins by prompting the user to typing single letters of the target key- set, and then single words composed of mostly the target-key set, and then sentences composed of a random string of those words. Figure 10 shows an example execution of Level 1 during the sentence phase. The number of letters, words, and sentences to generate for the user to type are determined by the parameters that are hard-coded into the program as constants. These values can easily be changed in the code, but not through the interface. The words are generated by randomly choosing from a library of words assigned to each level. Naturally, the words are stored as character strings in an array, and the Systick timer of the microcontroller is used to generate a random value for the index of the array. A sentence is generated by concatenating a sequence of randomly generated words. Each letter, word, or sentence that gets generated is then run through the Interface, where the user’s typing is monitored by the software.

Figure 10: Example Level in PuTTY

The steps for running the Interface for a single phrase are as follows:

1. Highlight the target keys grey on the LCD screen

2. Print the phrase for the user to type in the terminal 3. Print a new line to move the curser down and change its position to underneath the first character

10 4. For every character in the phrase: (a) Highlight the next key green on the LCD screen (b) Print a ˆ underneath the next character in the terminal (c) Print a new line to move the curser underneath the ˆ (d) Wait for keyboard input (e) If incorrect input: i. Unhighlight the previous incorrect key on the LCD screen (if there was one) ii. Highlight the new incorrect key red on the LCD screen iii. Sound the buzzer iv. Increment the error count v. Wait for another input (f) If correct input: i. Print the character ii. Unhighlight the green key on the LCD screen and any previous incorrect key iii. Carriage return and backspace the curser up to the ˆ and delete it

These steps are repeated for all letters, words, and sentences of the level until complete.

Test Interface: The Typing Test has a similar procedure to the levels, except that there is only one phrase that the user types, and it is a paragraph-long passage. Since a paragraph cannot fit on a single line of the interface, the passage is instead printed all at once, and the curser follows along with the user’s typing over the characters of the passage, instead of beneath them. Figure 11 shows an example of the beginning of a test, with the curser positioned at the start of the passage.

Figure 11: Example Test in PuTTY

11 The Test is run by first randomly selecting a passage for the user to type by using the Systick Random Generator. There are currently three passages programmed into the software, but more could easily be added. Timer2 is the peripheral used to time the number of seconds it takes the user to finish the test. To accomplish this, Timer2 is configured in periodic mode to run for one second and trigger an interrupt when it reaches 0. Its interrupt handler then increments a counter to update test timer. When a passage is chosen and the test is ready to begin, Timer2 is enabled to start the test timer and the passage is sent to the Interface where the software monitors the user’s typing and records the number of errors he or she make. Upon return, the timer is disabled and the test timer is used to calculate the user’s WPM rate.

4.2.5 Correctness Logic

A few measures are taken in the Interface to verify whether the user’s input is correct. First, it verifies that the key code inputted from the keyboard is consistent with the next character of the phrase by identifying the key code’s index in the key code parallel array and verifying that it matches the index of the next character in the Ascii code array. Second, it monitors the status of the shift keys, and whether they are pressed or not, in order to verify correct capitalization of the character. To do this, the software checks the keyboard input for either the left or right shift keys, and if pressed, marks a flag indicating that shift is being pressed. Then, it checks the keyboard input for the value of 0xF0, which indicates that a key has been released. If the following key code is the shift key, then the shift flag is reset, since the shift key is no longer being held. This flag can then be used to verify that the user is holding shift when typing a capital letter.

4.2.6 Buzzer Implementation

I2C Configuration: I2C0 is the peripheral used to output a sine-wave to the MCP4724 DAC. The Tiva C microcontroller is configured as the master device and the I2C0 clock source is set for 1 Mbps (“Fast mode”). When trans- mitting to I2C0, the address of the DAC with an appended write bit at the end (0b11000100 = 0xC4) is outputted first, and then the data.

Interrupts and Timers: Timer0 is the peripheral used as the length of the buzzer and Timer1 is used to generate the audio tone by outputting a voltage to the 12-bit DAC according to a 40 entry sine table. Timer0 is configured in one-shot mode to run for 0.25 seconds, triggering an interrupt when it finishes counting. Timer1 is configured in periodic mode to run for the length of time required to output a frequency of 150 Hz. Calculations of the necessary load value for Timer1 to achieve this frequency are described below. Upon pressing the wrong key, the program sets a buzzer flag to true and enables Timer0 to start count- ing. With the buzzer flag turn on, I2C0 begins outputting entries from the sine table to the DAC in Timer1 intervals. Once Timer0 expires, its interrupt resets the buzzer flag to stop I2C0 from transmitting, stopping the buzzer. This procedure ensures a brief audio sound for the length of 0.25 seconds.

Frequency Calculation: 1 1 For a frequency of 150 Hz, the period of the sine-wave must be T = freq = 150Hz = 6.67 ms. Using a T 6.67 ms sine table of 40 entries means that the DAC needs to be updated every 40 = 40 = 166.7µs. Thus, the load value is (166.7µs)(System clock frequency)−1 = (166.7µs)(16 MHz) − 1 = 2666 =0xA6A.

12 4.2.7 Calculations

Accuracy: Accuracy is calculated for both levels and tests by summing together the total number of errors made by the user during the Interface stage and dividing them by the total number of characters typed by the user. This total is obtained by summing the lengths of each phrase passed to the Interface. Figure 12 shows an example of an accuracy calculation after completing the first level.

Figure 12: Example of Accuracy Output

WPM : The words per minute rate for the test is calculated by using the test timer implemented with Timer2. After returning from the Interface and stopping the timer, the program calculates the WPM rate by convert- ing the timer length from seconds to minutes and then dividing the number of words in the passage (which is stored in an array) by this value. Figure 13 shows an example of both an accuracy and WPM calculation after completing a test.

5 Testing

A number of tests were carried out to ensure proper function of both the hardware and software aspects of this project. Tools and equipment such as a Logic Analyzer and Oscilloscope were used to verify results and various screenshots were recorded and are displayed in the figures below.

5.0.1 SSI Output to LCD

When testing the output of the SSI to the LCD, the Logic Analyzer was used to verify that the correct data was being transmitted. Figure 14 is a screenshot that displays the Master outputting a value of 0xF800 through the SSI, also known as the code for the color red, which the program was attempting to transmit at the time. This test verifies that the SSI is initialized correctly and that the LCD is working properly.

13 Figure 13: Example of WPM Rate Output

Figure 14: Master Outputting Code for Red Through SSI

5.0.2 Keyboard Data Input

When testing the input of the keyboard data, the Logic Analyzer was used to verify that the correct key code data was being transmitted from the keyboard. Figure 15 is a screenshot that displays the keyboard data and clock signals when pressing the c key. The data bits being transmitted in the screenshot translate to the hex value, 0x21, with is the correct key code value for the c key. This test verifies that the PS/2

14 keyboard is working properly and the results of this test were used in the method of capturing the keyboard data.

Figure 15: Keyboard Data and Clock Signals

5.0.3 Buzzer Frequency

To test the frequency of the audio tone transmitted to the DAC, the Oscilloscope was used to measure the sine wave. Figure 16 is a screenshot that displays the sine wave generated when the buzzer sounds. The measured value of the frequency shown in the bottom left corner of the screenshot is 149.7 Hz, which is within 0.5% error of the attempted frequency of 150 Hz. This test verifies that the software calculation of the frequency is correct and that the DAC is outputting the sine wave properly.

Figure 16: Frequency of Audio Tone

15 5.0.4 Buzzer Length

To test the length of the audio tone transmitted to the DAC, the Oscilloscope was used to measure the length of the sine wave. Figure 17 is a screenshot that displays the entire sine wave that generates when the buzzer sounds. The cursers lined up on either side of the sine wave in the screenshot show that the length is 250 ms, which is the exact value of the attempted buzzer length. This test verifies that the software implementation of the timer is correct.

Figure 17: Length of Audio Tone

5.0.5 Trial Testing

In addition to testing the hardware and software configurations of the peripherals, other tests were im- plemented to test the function of some of the software features. These tests consist mostly of trial testing: experimenting with the program and running through the levels over and over until a software bug showed up, and then attempting to fix the bug.

Pressing Invalid Keys: This test was performed to ensure that the program was properly filtering out invalid keys and that if the user accidentally presses a key not monitored by the software (i.e., the Home key) or a key monitored by the keyboard but an invalid input nonetheless (i.e., the backspace key), that this does not cause the program to malfunction. To properly test this feature, invalid keys were pressed throughout the duration of program execution, including during the menu, level, and test interfaces.

Holding Down Keys: This test was performed to observe the behavior of the buzzer while holding down a key, which would be registered as a fast succession of errors. This test verified that the buzzer timer was short enough for the user to be able to register each individual buzzer sound even while holding down a key.

Correctness testing:

16 The correctness logic of the software was tested by attempting to type different combinations of keys in an attempt to deceive the program or cause it to malfunction. Combinations included:

• pressing the correct key and an incorrect key at the same time

• not pressing the shift key while typing a capital letter • pressing the shift key while typing a non-capital letter • pressing both shift keys at the same time

• pressing three or four keys at the same time • holding the previous correct key down while pressing the next correct key

The results from this test were used to fine-tune the logic of the Interface to ensure the most valid and fair measurement of correctness.

Test subjects: Several different test subjects were used to test how the program reacts to different typing styles. Re- sults of this test revealed that certain users have the tendency to hold down keys while typing, especially when typing quickly, which once registered to the software as incorrect input. A minor adjustment to the correctness logic was made to correct this bug. The change allows the program to accept simultaneous key inputs if the keys are pressed successively and are both sequentially correct.

5.0.6 Calculations

Some calculations, such as the audio length and frequency, could be verified by the Logic Analyzer and Oscilloscope, but other calculations had to be verified manually. The tests carried out to verify these values are described below.

Accuracy: The accuracy calculation feature was verified by running several trials of levels and tests, counting the number of errors made in each level/test, verifying the length of characters stored for each phrase, and then using a to determine the accuracy. This accuracy value was compared with the software’s accuracy value to ensure consistency.

Test Timer: The test timer was verified by starting a test, setting an external timer (such as a cell phone timer), and verifying that the test timer matched the external timer when complete.

WPM : The WPM rate calculation was verified by running several trials and tests, using a calculator to convert the test timer value to minutes, and then dividing the number of words in the passage by that value. This WPM value was compared to the software’s WPM value to ensure consistency.

6 Conclusion

This document has described the design and testing details of the implementation of the Typing Tutor project. Deliberate planning and execution has resulted in a functional program that meets all requirements

17 and necessary features of the project. Additional logic was even included in the software of the project after trial testing that exceeded the requirements and enhanced the experience of the Typing Tutor. Unfortunately, there are two existing software bugs that, due to time constraints, have not been resolved at this time. One relates to the issue of the keyboard data collection routine being interrupted by timer interrupts. Unfortunately, this issue cannot be solved by setting PD0 interrupt at a higher priority than the timer interrupts because the logic of this routine relies on being able to enter and exit the interrupt handler every time the keyboard clock line goes low, which is for every bit that gets transmitted by the keyboard. If this process of collecting the data bits gets interrupted by another interrupt service routine, data from the keyboard gets lost, and the collected byte becomes incoherent, causing the program to believe the user pressed the wrong key. The other bug is related to this issue, and it’s due to the fact that the program cannot be relied to always receive the transmitted up-stroke key code (0xF0) whenever a key is released. There may be many reasons why this code might not get transmitted or might not get registered by the software, but it causes the program to believe that the user is still pressing a shift key even after releasing it. As a result, the program registers the next key as incorrect because it believes that the user is trying to type a capital letter. However inconvenient, these two bugs occur rarely, and the software is implemented with methods of self-correction when they do appear. As a whole, the Typing Tutor executes its program efficiently and elegantly. Many users have reported improved typing and enjoyment when using the project, which fulfills the most fundamental requirement: providing an enjoyable, challenging interface for users to develop their typing skills.

18 7 Appendix

7.1 Code

7.1.1 LCD.h

19 7.1.2 LCD.c

20 21 7.1.3 main.c

22 23 7.1.4 TypingLib.h

24 25 26 7.1.5 TypingMenu.h

27 7.1.6 TypingMenu.c

28 29 30 7.1.7 Keys.h

31 7.1.8 Keys.c

32 33 34 35 36 7.1.9 Speaker.h

37 7.1.10 Speaker.c

38 39