In embedded system development, keyboard is often used to realize human-computer interaction. This article introduces a method to directly use ARM's I/O port to expand the matrix keyboard. At the same time, taking the TQ2440 development board as an example, the hardware circuit connection and the corresponding Linux driver design method are explained in detail.
1 Introduction
ARM microprocessors have been widely used in industrial control, consumer electronics, communication systems and other fields. Matrix keyboard is a commonly used keyboard form, which designs the keys into M rows and N columns, so that a total of M+N signal lines are required, but M×N keys can be driven, which greatly saves I/O resources. This article introduces a method of using the GPIO port of the TQ2440 development board to expand a 5×4 matrix keyboard, and rearranges all the keys into the form of a handheld terminal keyboard for easy operation.
2. Hardware Design
This design expands a matrix keyboard with 5 rows and 4 columns, as shown in Figure 1. The row lines ROW1-ROW5 are connected to the interrupt pins EINT8, EINT9, EINT11, EINT13, and EINT14 of the S3C2440 [1]. These interrupt pins are connected to 10kΩ pull-up resistors to pull the interrupt pin level high to ensure that the interrupt will not be triggered when the key is idle. The column lines COL1-COL4 are connected to the ordinary I/O ports GPF3, GPF4, GPG7, and GPG10 of the S3C2440. The issue that needs to be noted here is: Make sure that the interrupts used by the row lines are not used by other Linux devices, otherwise it will cause the initialization of this driver or other drivers to fail.
Considering the commonness and convenience of the keys of handheld terminal devices, only the first 18 keys of the matrix keyboard are taken and they are rearranged as shown in Figure 2. The Ent key has dual functions, namely confirmation function (short press) and power on/off function (long press), which will be implemented in the driver.
3. Linux driver design for matrix keyboard
3.1 Keyboard driver overview
The driver is the interface between the operating system kernel and the hardware device. The device driver shields the application from the hardware details, allowing the application to operate the hardware device like operating an ordinary file [2]. The driver does not have a main function. It uses a module initialization function as its entry point, and it stops running after completing the initialization and waits for system calls.
The driver is part of the Linux kernel, so the Linux expression should be used in programming. First, define the column I/O port as an array: col_table[] = {S3C2410_GPF3, S3C2410_GPF4, ...}, and define the row I/O port as a structure:
button_irqs [] ={ {IRQ_EINT8,S3C2410_GPG0,S3C2410_GPG0_EINT8, 0,“R1″},
{IRQ_EINT9,S3C2410_GPG1,S3C2410_GPG1_EINT9, 1,”R2″},
…}.//interrupt number (irq), pin (pin), pin setting, serial number, name
The matrix keyboard is registered to the system as a Linux character device. We first register the matrix keyboard device to the system, including the device number, device name and file_operations structure; the member functions of the file_operations structure are the main content of the character device driver design. These functions will actually be called when the application performs Linux open(), write(), read(), close() and other system calls [3]. The user has no write operation on the keyboard, and the member functions of its file_operations structure are open(), read(), close(), and poll().
The interrupt registration and row and column initialization are implemented when the keyboard is opened (i.e. in the open() function). The interrupt registration includes: interrupt number, interrupt entry program, interrupt mode, interrupt name and code. The key statement is: request_irq (button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_FALLING, button_irqs[i].name, (void*)&button_irqs[i]). IRQ_TYPE_EDGE_FALLING means falling edge trigger. Then perform row and column initialization: set the row line as interrupt and enable pull-up. In Linux, its expression is:
s3c2410_gpio_cfgpin(button_irqs[i].
pin, S3C2410_GPIO_SFN2); //Set the i-th row pin to interrupt
s3c2410_gpio_pullup(button_irqs[i].
pin, 1); //Pull up the pin in row i
Set the column line to output and set it to low level. The statements are expressed in the same way. Due to space limitations, they are not listed here one by one.
The read() function is used to read data from the device. This function allows the program to enter sleep mode when no key is pressed. The key code is:
static DECLARE_WAIT_QUEUE_HEAD(button_waitq); //Generate a waiting queue head queue named button_waitq
static volatile int ev_press = 0; //Set to 1 to indicate a key is pressed
When ev_press is 0, execute the statement: wait_event_interruptible (button_waitq, ev_press), and the program will enter sleep mode. When ev_press is 1, copy the data from kernel space to user space. The key statement is:
copy_to_user(buff, (const void *) key_values, min(sizeof(key_values), count)); //buff is a pointer to user space, key_values is a pointer to kernel space, and the last parameter is the number of bytes to copy from kernel space to user space. We take the minimum value between the actual size and the size specified by the user. Returns zero if the data is copied successfully; returns the number of bytes of data that were not copied successfully if an error occurs.
The close() function closes the matrix keyboard device and releases the registered interrupt. The key statement is: free_irq (button_irqs[i].irq, (void *) &button_irqs[i]).
The Poll() function implements polling. If there is no key data, the Linux poll_wait function is called to wait; if there is key data, the select function will return immediately.
3.2 Interrupt processing and keyboard scanning program
The name of the interrupt processing function is buttons_interrupt registered above. The specific program flow is shown in Figure 3. When a key is pressed, the row and column where the key is located is turned on. The low level of the column pulls down the level of the row, thereby triggering an interrupt. Then, enter the interrupt processing function. Due to the problem of key jitter, it is unreliable to determine that a key is pressed based on the triggering of an interrupt alone, so a timer is used to delay 10ms before entering the keyboard scanning function.
The keyboard scanning program of this design adopts the method of determining the row first and then the column, and finally performs certain operations on the rows and columns to obtain the key value. First determine the row: scan row by row to determine whether there is a row pin at a low level. If so, save the row value (row). Continue to determine the column: set the low level column by column. When the column is pressed, the row will be low again, thereby determining the column (column). Then perform operations on the rows and columns: k=row*4+column, then each key of the matrix keyboard corresponds to the key number 0-19. After the keyboard layout is in the form shown in Figure 2, we only take the first 18 keys of the matrix keyboard (key numbers 0-17), and save the key value as k+1. For the Ent key, the length of time it is pressed distinguishes whether it is a confirmation function or a power on/off function. The pressing time is less than 0.5 seconds for the confirmation function, and the pressing time is greater than 1.6 seconds for the power on/off function. The time between 0.5 seconds and 1.6 seconds is considered an invalid operation. The timing method is:
If the line is still at a low level and the integer cnt is less than 1700: delay 1ms, cnt++; the pressing time is obtained according to the cnt value.
The power on/off function is saved as key number 18, key value 19.
4. Driver Testing
The test program belongs to the upper-level application program, and the keyboard operation can be realized by directly calling the interface provided by the keyboard driver. We call the open() function to open the matrix keyboard device, and then call the read() function to read the keyboard data and save it to the array defined by ourselves, and finally use the printf() function to display the test results.
This function was applied to my project, and the accuracy and response time of keyboard input met the design requirements.
5. Summary
This article introduces a method to expand the matrix keyboard directly from the ARM I/O port. It does not require the addition of other interface components, the design is fast and practical, and the driver is implemented under the Linux system, providing a solution for expanding the handheld terminal keyboard for ARM embedded devices.
Previous article:U-Boot transplantation for embedded systems based on S3C2410A
Next article:Several implementation methods of print function in ARM
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- [AutoChips AC7801x motor demo board review] + Different PWM configurations for motor control
- Senior FPGA engineers tell beginners...
- In just three steps, we will teach you how to quickly use a multimeter to determine the polarity and type of a transistor!
- Today's Live Broadcast: ON Semiconductor's Advanced Image Sensor Solutions for the Internet of Things
- Finalists - 100 evaluation boards of Toshiba's smallest photorelay TLP3547 to be awarded
- [Experience] Namisoft reviews the measurement methods of motor torque
- Submission of the work "Mijia Control 16-way Relay Switch Based on GigaDevice GD32"
- Recruiting electronic, mechanical and communications engineers! ! ! ! ! ! ! ! ! ! !
- About the uboot compilation problem of am335x
- TLC7524 interface circuit program.pdf