IMX6ULL Key Driver Development: Implementation from Polling to Interrupt
I. Pre-class Review: Foundation for Embedded Low-level Development
Before developing the key driver, preliminary core work laid the critical groundwork for this practice: using C language to directly manipulate GPIO registers to light up LEDs, and porting the NXP SDK package to achieve register-level driver implementation for the buzzer (Beep). Simultaneously, the project was restructured by modifying the Makefile to adapt compilation rules and writing a linker script to define the storage locations of program segments in RAM. These efforts solidified the core capabilities of embedded low-level development—register operation logic, project construction processes, and the fundamental approach to peripheral drivers—clearing foundational obstacles for key driver development.
II. Hardware Basis of Key Driver: Understanding Input Characteristics
The essence of driver development is “adhering to hardware logic.” The first step in key driver development requires a thorough understanding of core hardware rules:
III. Polling Method: Basic Implementation and Core Defects of Key Driver
3.1 Core Principle of Polling Driver
Polling is the most basic method for detecting input from embedded peripherals. The core logic is “after initializing the GPIO, the main loop continuously reads the pin level status.” The principle of its core steps is broken down as follows:
- GPIO Multiplexing Configuration (IOMUXC): IMX6ULL pins are multifunctional. The target pin (e.g., UART1_CTS_B) must be configured to ALT5 (corresponding to GPIO1_IO18) via IOMUXC (I/O Multiplexing Controller). The essence of IOMUXC is a “pin function routing switch.” Only with correct configuration can the pin switch from UART to GPIO functionality, which is the prerequisite for driver-hardware interaction.
- Electrical Characteristic Configuration: For input-type keys, pin electrical parameters must be adapted to ensure stable voltage levels:
- Pull-up configuration (PUS=11, PUE=1, PKE=1): When the button is disconnected, a 22K pull-up resistor pulls the pin to a high level, avoiding level jitter due to floating.
- Input adaptation configuration (HYS=0, ODE=0, DSE=000): In input mode, output drive capability (DSE) is disabled, open-drain is disabled, and slew rate is set to slow, further ensuring input level stability.
- Speed configuration (SPEED=10): Matches the 100MHz bus speed, balancing response efficiency and level stability.
- GPIO Direction and Clock Configuration: Configure GPIO1_IO18 as input mode (clear the corresponding bit in the GDIR register). Simultaneously, enable the clock gating for GPIO1 in the CCM (Clock Controller Module)—IMX6ULL peripherals must have their clocks enabled to function, as clocks are the “power source” for peripheral operation.
- Runtime Detection: Read the pin level via the GPIO_DR register, judging the button state based on the logic “high level = disconnected, low level = pressed.”
3.2 Fatal Defects of Polling Method
The core issue with polling is that “real-time performance depends on the main loop frequency.” When the main loop handles complex, time-consuming tasks (e.g., simulating industrial scenarios with delay(0x7FFFFF)), the window for detecting button level changes may be skipped, leading to “missed detection.” This defect is entirely unacceptable in high-real-time scenarios—such as car brake buttons, where missed detection can directly cause safety accidents. This is the core reason for introducing the interrupt method.
IV. Interrupt Method: Key Driver Implementation for Real-time Scenarios
4.1 Core Nature of Interrupts
Interrupts are a core feature of CPUs, essentially meaning “the CPU responds to urgent peripheral requests, processes them, and then returns to the original task.” The complete interrupt response process requires understanding the core significance of each step:
4.2 IMX6ULL Interrupt Architecture Analysis
The IMX6ULL is based on the Cortex-A7 core, and interrupt management relies on two core components, which are the underlying guarantees for normal interrupt driver operation:
(1) GIC (Generic Interrupt Controller)
The GIC is the “bridge” connecting peripheral interrupts to the CPU, with its core structure divided into two parts:
- Distributor: Manages all interrupt sources, classifying them by type:
- SGI (Software Generated Interrupt): Dedicated to multi-core communication, triggered via the GICD_SGIR register.
- PPI (Private Peripheral Interrupt): Unique to each CPU core, only the corresponding core responds.
- SPI (Shared Peripheral Interrupt): Interrupts 32–1019 are peripheral interrupts, which are the core type for GPIO key interrupts (IMX6ULL GPIO interrupts all belong to SPI).
- CPU Interface: Each CPU core has an interface responsible for receiving interrupt requests from the distributor and passing them to the core for processing.
(2) CP15 Coprocessor
The Cortex-A7’s CP15 coprocessor handles system-level control and is the core of interrupt configuration:
- Core functions: System control configuration, MMU/Cache management, interrupt vector table configuration, etc.
- Key interrupt-related registers:
- SCTLR (System Control Register): Controls the interrupt vector table address (V-bit) and instruction cache enable (I-bit), forming the foundational configuration for interrupt response.
- VBAR (Vector Base Address Register): Configures the physical base address of the interrupt vector table, ensuring the CPU can accurately locate the interrupt service function entry.
- CBAR (Configuration Base Address Register): Stores the physical base address of GIC registers, serving as the prerequisite for CPU-GIC communication.
4.3 Core Advantages of the Interrupt Method
The interrupt method completely resolves the missed detection issue of polling: when a button event is triggered, the CPU immediately interrupts the current task and responds, without relying on the main loop’s detection frequency. Even if the main loop handles complex, time-consuming tasks, button events can be accurately captured, fully meeting the requirements of high-real-time scenarios such as car brakes or industrial emergency stops.
V. Project Optimization: Low-coupling Design and Open-Closed Principle
Embedded driver development must not only achieve functionality but also ensure project maintainability and scalability, adhering to the OCP (Open-Closed Principle)—closed for modification, open for extension:
VI. Summary
This key driver development started from hardware principles, first implementing a basic polling driver and analyzing its real-time defects, then delving into the core principles of interrupts and the IMX6ULL interrupt architecture to achieve a high-real-time interrupt driver. Finally, project-level optimization was completed through module encapsulation. This process reflects the core logic of embedded development: first understand the hardware and underlying principles, then implement functionality, and finally optimize the project architecture.



