0 Introduction
The development of embedded systems has its own special applications and specific functions, and the embedded Linux operating system is favored by the industry because of its open source, wide processor support, and easy portability. AT91RM9200 is a 32-bit RISC microprocessor based on the ARM920T core launched by Atmel for system control and communication fields. It has the characteristics of small size, low power consumption, low cost and high performance, and integrates multiple interfaces such as SPI, serial port, PIO, Ethernet, EBI, USB, MCI, etc.
In Linux system, the application layer cannot directly operate the hardware, and the driver needs to be designed to shield the hardware characteristics downward to achieve communication between the hardware and the user. The system platform is Fedora 8 installed in a virtual machine, the target system uses the Linux 2.6.21.7 kernel, the file system is customized to establish the NFS root file system, the dual network card method is used to build a cross-development environment, and the hyperterminal or minicom is used as the console.
l Device driver design
The framework of the control system is shown in Figure 1. ARM receives external control commands through USART1, and communicates with external devices through the SPI interface and the general PIO port to achieve control. Under Linux, all devices are used in the form of files. Linux has provided SPI drivers, DBGU and UART drivers that support AT91RM9200. As long as some modifications are made to the source code and it is selected when compiling the kernel, it can be used directly. Therefore, the main focus is on the PIO port driver design. The external device uses a .PB29 pin (ie IRQO) as an external interrupt signal to provide to ARM, and some I/O pins are used to control the external device.
Linux devices are divided into three categories: character devices, block devices, and network devices. The system is designed with modular character device drivers. The Linux 2.6 kernel is different from the Linux 2.4 kernel in three main ways:
(1) The kernel API has changed and many new functions have been added;
(2) sysfs is provided to describe the device tree;
(3) The driver module changes from .o to .ko.
1.1 Driver Important Data Structure
The opened device is identified by the file structure inside the kernel, and the kernel uses the file_operations structure to access the driver's functions. The file_operations structure is an array of function pointers defined in . The following mainly introduces several commonly used members:
Among these function pointers, open and release are used to open and close the device, and are functions that each driver must implement. Other functions are implemented according to actual needs. In this project, the implementation method is as follows:
[page]
Another important data structure is the file structure, which mainly includes the following members:
It represents an open file, which only appears in kernel space and is different from the file in user space. It is created during the open operation and then passed to other function pointers of file_operations until close.
The third important data structure is inode, whose members include: dev_ti_rdev and struet cdev*i_cdev, where i_rdev contains the actual device number. The master and slave device numbers can be obtained through the following two macro functions:
After initializing the file_operations structure, the various methods defined in it, such as open, release, write, read, ioctl, etc., must be implemented one by one. The function name is the pointer to each member function when initializing the file_operations structure. When open is called in user space, the open method in kernel space is the corresponding operation, and the same applies to other methods.
1.2 Driver initialization and uninstallation cleanup
Driver loading requires a series of initialization work such as device registration; and when unloading the driver, resources must be released and some cleanup work must be performed so that it does not affect the kernel. Therefore, two functions static int devctl_init() and static void devctl_exit() are defined, and then module_init(devctl_init) and module_exit(devctl_exit) are used to notify the kernel. In order to maintain the open source nature of Linux, the following macro is called to declare:
In the initialization function, the device is first registered. The major device number indicates the corresponding driver, and the minor device number is used by the kernel to correctly determine the device to which the device file refers. The device number can be applied dynamically or statically. Dynamic application uses the following function:
dev is an output-only parameter that holds the first number in the allocation range when the function completes successfully; firstminor is the first minor number requested; count is the total number of consecutive device numbers requested; name is the device name, and a return value less than 0 indicates allocation failure. Then get the major device number through major=MMOR(dev). If registration is unsuccessful or the device needs to be deregistered when the driver is uninstalled, use the following function to implement it (its parameters have the same meaning as above):
For character devices, a cdev structure variable must be defined and initialized using cdev_init(), and then cdev_add() is called to notify the kernel to add a character device. Also, cdev_del() must be used to remove it when uninstalling, otherwise the user may not be able to open the device when using the driver. Not using cdev or not deleting cdev when the module is uninstalled will cause the kernel to be in an unstable state, and the device file may not be opened at the user level. 1.3 I/O port access
In the system control requirements, it is necessary to access the ARM I/O port, including the ordinary I/O port and the PB29 pin multiplexed as IRQO. However, in Linux, the read and write instructions for I/O port 12 and I/0 memory use virtual addresses, so the physical register address must be mapped to the I/O memory before access. There are two ways to implement address mapping, one is to use ioremap to assign a virtual address to the I/O memory area and use iounmap to cancel it, and the other is to use the virtual address that the kernel has defined. Here we mainly introduce the second method. [page]
For AT91RM9200, the following conversion function is used to obtain the virtual address, where the macro AT91_VA_BASE_SYS is the system virtual base address:
The read and write ports can also use special functions for AT91RM9200
int at9 1_set_gpio_value(unsigned pin, int value), and include the header file asm-arm/arch-at91/gpio.h. Generally, the access to the port is to apply for resources when the driver module is initialized and release the resources when it is unloaded. The enabling of the I/O port is implemented in the open method, and the corresponding disabling is implemented in the release method.
1.3 Implementation of ioctl method
Users can send various commands to the kernel through the ioctl method and pass parameters when necessary. A simple example is shown below.
1.4 Interrupt Control Implementation
When the arrival time of the external signal is unpredictable, the polling method will be extremely inefficient and a blocking interrupt is required. That is, when no interrupt signal arrives, the reading process is blocked and put into a sleep state. When an interrupt arrives, the reading process is awakened and the predetermined processing operation is performed.
First, use request_irq() in the open method to install the interrupt handler and release it in the release method. The function prototype is as follows:
Among them: the parameter irq is the interrupt number; handler is the ISR pointer; flags is the option byte mask related to interrupt management; dev_name is the device name; dev_id is the interrupt signal line.
Secondly, ISR is the parameter name used when applying for an interrupt, assuming it is irq0_handler, and the definition prototype is as follows:
[page]
Interrupt blocking is implemented by calling void wake_up_interrupTIble(wait_queue_head_t*queue) internally, and then returning IRQ_HANDLED; in the read method, wait_event_interruptible(queue, condition) is called to wake up the reading process. In this way, when the user program reads the device, if no interrupt arrives, the reading process will enter the sleep state and be awakened by an interrupt.
For the interrupt signal IRQO, since it is multiplexed with PB29, it needs to be configured as peripheral A[4], and the interrupt source type must also be configured. The functions are respectively in #in
2 Compiling and debugging
The driver can be statically compiled into the kernel, or compiled into a module for dynamic loading. In order to facilitate debugging, the dynamic module loading method is adopted. The driver compilation method under the Linux 2.6 kernel is significantly different from that of the Linux 2.4 version. The Makefile it creates only needs to simply write obj-m:=devctl.O (assuming the source file is devctl.c), and then execute the command: make-C/usr/lo-cal/arm/Linux-2.6.21.7 SUBDIRS="MYMPWDmodules". Note that the kernel source file directory varies depending on the system. Then place the generated .ko file in the /home directory of the target system, use insmod to load the module, and use the cat/proc/devices command to view the assigned device number, use mknod to create a device node, and use the rmmod command to uninstall the module.
To facilitate debugging, you can use printk to print information appropriately, and you can also turn on the LED to find problems.
3 Conclusion
Through in-depth research and self-design practice of the driver source code in the relevant Linux 2.6 kernel, and continuous debugging, the method described here has been verified in practice and has been successfully used in the control system of a certain instrument. Linux is profound and its open source characteristics will surely attract more developers to invest in it, allowing it to develop better and be applied to more fields.
Previous article:ARM Linux static mapping analysis
Next article:Design of digital multi-channel voice recorder based on ARM9 processor S3C2410
Recommended ReadingLatest update time:2024-11-17 00:32
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Innolux's intelligent steer-by-wire solution makes cars smarter and safer
- 8051 MCU - Parity Check
- How to efficiently balance the sensitivity of tactile sensing interfaces
- What should I do if the servo motor shakes? What causes the servo motor to shake quickly?
- 【Brushless Motor】Analysis of three-phase BLDC motor and sharing of two popular development boards
- Midea Industrial Technology's subsidiaries Clou Electronics and Hekang New Energy jointly appeared at the Munich Battery Energy Storage Exhibition and Solar Energy Exhibition
- Guoxin Sichen | Application of ferroelectric memory PB85RS2MC in power battery management, with a capacity of 2M
- Analysis of common faults of frequency converter
- In a head-on competition with Qualcomm, what kind of cockpit products has Intel come up with?
- Dalian Rongke's all-vanadium liquid flow battery energy storage equipment industrialization project has entered the sprint stage before production
- Allegro MicroSystems Introduces Advanced Magnetic and Inductive Position Sensing Solutions at Electronica 2024
- Car key in the left hand, liveness detection radar in the right hand, UWB is imperative for cars!
- After a decade of rapid development, domestic CIS has entered the market
- Aegis Dagger Battery + Thor EM-i Super Hybrid, Geely New Energy has thrown out two "king bombs"
- A brief discussion on functional safety - fault, error, and failure
- In the smart car 2.0 cycle, these core industry chains are facing major opportunities!
- The United States and Japan are developing new batteries. CATL faces challenges? How should China's new energy battery industry respond?
- Murata launches high-precision 6-axis inertial sensor for automobiles
- Ford patents pre-charge alarm to help save costs and respond to emergencies
- New real-time microcontroller system from Texas Instruments enables smarter processing in automotive and industrial applications
- Smaller and more reliable 65V GaN technology makes radar more powerful
- DSP28335 eCAP module capture pulse problem
- TI CCS & controlSUITE Troubleshooting Log
- CC1310 Two-wire Serial Bootloader Solution
- Fomu can now run CircuitPython
- Concentration is the essence? Why GaN fast charging has become the new generation of travel magic
- Have you used the DW06D lithium battery charging and discharging protection chip?
- Why is the PLC system more stable than the system with the same function using a single chip microcomputer?
- Raspberry Pi Pico 3D Mouse
- Purgatory Legends-Battle of Music Players