IT8528E Embedded Controller Firmware Architecture and Code Flow
The ITE IT8528E is a highly integrated embedded controller (EC) used in notebook computer motherboards. Built around an 8032 Twin Turbo 8051 core, it provides host communication, keyboard scanning, serial buses, analog acquisition, timers, GPIO, and power-management functions.
The hardware provides the interfaces, but the firmware determines how they work together. Its initialization routines establish the controller’s operating environment, code banking expands the available firmware space, the main loop coordinates foreground execution, and timer hooks schedule periodic tasks such as power-button detection, battery monitoring, and system-event processing.
This article examines the IT8528E hardware architecture and a representative Keil uVision firmware project, focusing on its directory structure, startup sequence, core and OEM initialization, priority-based service dispatcher, and periodic OEM hooks.
🧠 1. IT8528E Overview and Specifications #
The IT8528E integrates an 8032-compatible Twin Turbo 8051 core with a range of peripheral interfaces for motherboard management. It supports code banking for firmware stored in external SPI Flash and provides the hardware interfaces needed for communication between the EC, host processor, and onboard devices.
Core specifications #
| Feature | Specification |
|---|---|
| CPU core | 8032 Twin Turbo 8051 |
| Instruction cycle | One machine cycle per instruction cycle, as specified in the source material |
| Maximum operating frequency | 10 MHz |
| Code space | Code banking with support for up to 4 MB of SPI Flash |
| Host bus | LPC 1.1 with Serial IRQ |
| SMBus | Four-channel Host/Slave interface, up to 400 kHz |
| GPIO | Ports A–J with multifunction pin multiplexing |
| PWM | 8 channels |
| ADC | 12 channels, 10-bit resolution |
| DAC | 4 channels, 8-bit resolution |
| Package | TQFP-128 |
The controller’s peripherals can be grouped into six functional categories: host-side interfaces, serial communication buses, analog interfaces, timing and control units, human-machine interfaces, and general-purpose I/O and power management.
Together, these modules support firmware functions such as keyboard scanning, smart-battery communication, hardware monitoring, fan-speed control, event processing, and motherboard power sequencing.
For broader context on how embedded controller firmware fits into the platform’s startup environment, see UEFI BIOS Architecture and Boot Flow.
🔌 2. Internal Architecture and Peripheral Modules #
2.1 Host-side bridging interfaces #
The host-facing interfaces allow the EC to exchange data with the CPU, BIOS, and supported platform components.
LPC bus
The Low Pin Count (LPC) bus provides the traditional host interface used by the CPU and BIOS to access supported controller registers and Super I/O functions. The supplied material also identifies the I-Bus arbiter as part of this interface architecture.
EC2I bridge
The EC2I bridge allows the EC core to access selected host-side registers, including registers associated with PNPCFG and SWUC. The supplied description identifies register-access coordination, lock protection, and bus arbitration as part of its role.
PECI interface
The Platform Environment Control Interface (PECI) provides access to CPU platform telemetry, including CPU core temperature information where supported. In the firmware project, PECI-related logic is associated with routines such as Init_PECI() and PECI_PowerCtrlCenter().
2.2 Serial communication buses #
The IT8528E includes several serial interfaces for communication with external devices.
| Interface | Main purpose |
|---|---|
| SMBus | Communication with smart batteries, power-management ICs, hardware-monitoring sensors, and EEPROMs |
| SSPI | Serial SPI communication, including access to external Flash |
| UART | Debug output and communication with supported external modules |
| CEC | Consumer Electronics Control for compatible HDMI-connected devices |
SMBus is particularly important for battery-management and monitoring functions. The supplied firmware includes core-level SMBus support and OEM routines for configuring channels and coordinating transactions.
SPI-related initialization includes functions such as GPIO_HSPI_INIT() and ChangeSPIFlashReadMode(), depending on the selected configuration.
2.3 Analog interfaces: ADC and DAC #
The analog interfaces allow firmware to acquire sensor signals and produce analog outputs.
ADC — Analog-to-Digital Converter
The controller provides 12 ADC channels with 10-bit resolution according to the supplied specifications. ADC inputs can be used for voltage monitoring and temperature sensing through NTC thermistors.
The firmware examples include two dynamic scanning functions:
ScanADCDyChannel1();
ScanADCDyChannel2();These calls are associated with 10 ms OEM timer hooks. The first call is commented out in the supplied Event A example, while the second is conditionally compiled in Event B.
DAC — Digital-to-Analog Converter
The controller provides four DAC channels with 8-bit resolution. These channels support analog-output functions where required by the board design and firmware configuration.
2.4 Timers, PWM, watchdog, and counters #
The controller’s timing and control modules support periodic execution, signal generation, watchdog operations, and pulse measurement.
- PWM: Provides pulse-width modulation for applications such as fan-speed regulation and LED brightness control.
- TMR: General-purpose 8-bit timers for timing and pulse-related operations.
- ETWD: External timer and watchdog functionality used for monitoring and system recovery.
- GCTRL: General counter functionality, including pulse counting for fan tachometer measurements.
Fan control commonly combines a PWM output with tachometer feedback. The firmware can use the counter and timer functions to measure fan activity and apply the relevant OEM control policy.
2.5 Human-machine and legacy interfaces #
The IT8528E includes interfaces for keyboard input, pointing devices, infrared reception, and legacy peripheral functions.
| Module | Description |
|---|---|
| KBS | Internal keyboard-matrix scanning |
| PS/2-compatible interface | External keyboard and mouse support |
| Parallel port | Traditional parallel-port functionality |
| CIR | Consumer infrared reception |
The KBS hardware supports matrix scanning, while PS/2-related functions handle compatible external devices and their communication paths.
The project separates these responsibilities across modules such as CORE_SCAN.C, CORE_PS2.C, CORE_XLT.C, and corresponding OEM modules.
2.6 GPIO, interrupts, and power management #
These modules connect firmware logic to physical board signals and system-state transitions.
- EGPC: Configurable GPIO for buttons, LEDs, and other control signals.
- ECPM: EC clock and power management, including clock control and low-power functionality.
- INT: Interrupt handling and reporting.
- WUC: Wake-up source management.
- BRAM: Battery-backed SRAM for retaining supported data across power loss.
GPIO pins may support multiple functions. Their effective role therefore depends on pin multiplexing, register configuration, and the motherboard’s electrical design.
Peripheral summary #
| Category | Interfaces and modules | Typical use |
|---|---|---|
| Host bridge | LPC, EC2I, PECI | Host communication and CPU telemetry |
| Serial buses | SMBus, SSPI, UART, CEC | Battery access, Flash communication, debugging, peripheral control |
| Analog interface | ADC, DAC | Voltage and temperature acquisition, analog output |
| Timer and control | PWM, TMR, ETWD, GCTRL | Fan control, timing, watchdog, pulse counting |
| Human-machine interface | KBS, PS/2, CIR, parallel port | Keyboard, mouse, infrared, legacy peripherals |
| Basic I/O and power | GPIO, INT, ECPM, WUC, BRAM | Buttons, LEDs, interrupts, wake-up, power management, retained data |
🗂️ 3. Firmware Project Architecture #
The firmware project is compiled using Keil uVision and separates common controller functionality from motherboard-specific implementations.
The source structure can be understood as three conceptual layers:
- CORE layer: Shared firmware services, including host communication, timers, GPIO, SMBus, memory management, and service scheduling.
- OEM layer: Motherboard-specific configuration and behavior, including power sequencing, battery management, fan control, LEDs, and OEM event processing.
- CHIP layer: Chip-specific configuration, startup support, and low-level initialization.
The supplied directory tree primarily exposes CORE and OEM directories, while chip-specific support is represented by files such as CORE_CHIPREGS.C and STARTUP.A51.
3.1 Directory structure #
The following tree summarizes the project organization shown in the source material.
KB01_EC/
└── KB01EC/ # Keil main project
├── CORE_COMMON/ # Resident core layer
│ ├── CORE_ACPI.C # ACPI EC interface
│ ├── CORE_ASM.C # Assembly helper functions
│ ├── CORE_BITADDR.C # Bit-addressable operations
│ ├── CORE_GPIO.C # GPIO control and initialization
│ ├── CORE_HOSTIF.C # Host interface
│ ├── CORE_INIT.C # Core initialization
│ ├── CORE_IRQ.C # Interrupt vectors and dispatch
│ ├── CORE_MAIN.C # Main loop and service scheduler
│ ├── CORE_Memory.C # Memory management
│ ├── CORE_PORT6064.C # KBC ports 60/64
│ ├── CORE_SMBUS.C # SMBus protocol support
│ ├── CORE_TIMERS.C # Timer management
│ ├── CORE_CHIPREGS.C # Chip register definitions
│ ├── CORE_ITEString.C # String utilities
│ ├── UART.C # Debug serial port
│ ├── L51_BANK.A51 # Bank-switching assembly
│ └── STARTUP.A51 # 8051 startup code
├── CORE_BANK0/ # Switchable core bank 0
│ ├── CORE_FLASH.C # SPI Flash read/write
│ ├── CORE_PS2.C # PS/2 handling
│ ├── CORE_SCAN.C # Keyboard-matrix scanning
│ └── CORE_XLT.C # Scan-code translation tables
├── CORE_BANK1/ # Additional core bank
└── OEM/ # OEM customization
└── Example/
├── OEM_BANK0/
│ ├── OEM_6064.C
│ ├── OEM_ACPI.C
│ ├── OEM_ADC.C
│ ├── OEM_BATTERY.C # Battery management
│ ├── OEM_CIR.C
│ ├── OEM_DEBUG.C
│ ├── OEM_ECD.C
│ ├── OEM_EVENT.C
│ ├── OEM_FAN.C
│ ├── OEM_FLASH.C
│ ├── OEM_GPIO.C # GPIO configuration
│ ├── OEM_HOSTIF.C
│ ├── OEM_HSPL.C
│ ├── OEM_INIT.C
│ ├── OEM_IRQ.C
│ ├── OEM_LCD.C
│ ├── OEM_LED.C
│ ├── OEM_LPC.C
│ ├── OEM_MAILBOX.C
│ ├── OEM_MAIN.C # OEM timer hooks
│ ├── OEM_MEMORY.C
│ ├── OEM_MMB.C
│ ├── OEM_PECI.C
│ ├── OEM_PM3.C
│ ├── OEM_PORT6064.C
│ ├── OEM_POWER.C # Power-sequencing logic
│ ├── OEM_PS2.C
│ ├── OEM_SCANTABS.C
│ ├── OEM_SMBUS.C
│ ├── OEM_SPI.C
│ ├── OEM_TIMER.C
│ └── OEM_VER.C
├── OEM_BANK1/
├── OEM_BANK2/
├── OEM_BANK3/
└── INCLUDE/
├── CORE_INCLUDE.H
└── OEM_INCLUDE.HThe project directories separate shared infrastructure from functions specific to a motherboard.
| Directory or file | Responsibility |
|---|---|
CORE_COMMON |
Resident shared code, including main-loop scheduling and core services |
CORE_BANK0 |
Banked core functionality such as Flash access, PS/2 handling, and keyboard scanning |
CORE_BANK1 |
Additional banked core code |
OEM_BANK0–OEM_BANK3 |
Board-specific functionality distributed across OEM banks |
INCLUDE |
Shared header files for CORE and OEM interfaces |
STARTUP.A51 |
Startup and low-level execution setup |
L51_BANK.A51 |
Assembly support for code-bank switching |
For example, CORE_SMBUS.C is the starting point for examining shared SMBus services, while OEM_BATTERY.C contains motherboard-specific battery logic in this project. Similarly, CORE_SCAN.C and OEM_SCANTABS.C are relevant when tracing keyboard scanning and scan-code configuration.
3.2 Code banking and memory layout #
The standard 8051 code-address space is limited to 64 KB. The IT8528 firmware architecture uses code banking to address a larger external SPI Flash image, with support described in the source material for up to 4 MB.
The project divides the EC code-address space into two regions.
| Region | Address range | Size | Role |
|---|---|---|---|
| COMMON | 0x0000–0x7FFF |
32 KB | Resident code, including main(), interrupt routines, and core scheduling |
| BANK | 0x8000–0xFFFF |
32 KB | Switchable window used for banked functions |
The COMMON area remains resident, while the banked region maps the selected code bank into the upper portion of the code-address space.
This arrangement allows firmware modules to be distributed across multiple banks without requiring the entire firmware image to be visible simultaneously.
Bank-switching mechanism #
The source identifies L51_BANK.A51 as the assembly component responsible for bank switching. Its described mechanism uses the BANKSEL register to select a bank and transfers control using a long jump (LJMP).
The supplied material gives 0x2002 as an example address for BANKSEL.
// Conceptual example from the supplied firmware description.
// Initialize the code-banking state.
ResetBANKDATA();
// Calls to banked functions use the project's
// compiler, linker, and assembly bank-switching support.
// The switching mechanism selects the required bank
// through the configured BANKSEL register.
Before a banked function is invoked, the firmware’s generated call sequence and assembly support arrange for the relevant bank to be selected. The exact behavior depends on the compiler and linker configuration as well as the implementation in L51_BANK.A51.
ResetBANKDATA() is called during startup to initialize the bank-switching state to Bank 0. This gives the firmware a known starting point before executing subsequent code.
🚀 4. Main Loop and Initialization Flow #
The main execution flow starts in main(). The function establishes the initial CPU and banking state, selects an initialization path, configures keyboard scan pins, and enters the continuous polling loop.
The initialization path depends on the return value of Hook_ECReturnMainFuncKeepCondition().
4.1 The main() function
#
The following code preserves the startup branches and main-loop structure shown in the supplied source.
void main(void)
{
DisableAllInterrupt();
SP = 0xC0;
ResetBANKDATA();
// Branch 1: Exiting Follow Mode or EC Scratch ROM
if(Hook_ECReturnMainFuncKeepCondition() == 0x33)
{
CLEAR_MASK(FBCFG, SSMC);
_nop_();
MPRECF = 0x01;
_nop_(); MPRECF = 0x01;
_nop_(); MPRECF = 0x01;
_nop_(); MPRECF = 0x01;
_nop_(); _nop_();
WinFlashMark = 0x00;
Hook_ECExitFollowMode();
Init_Timers();
EnableModuleInterrupt();
}
// Branch 2: Normal cold reset
else
{
Core_Initialization();
Oem_Initialization();
InitEnableInterrupt();
#ifdef UART_Debug
Init_UART();
printf("\n***************************************");
printf("\nEC Init OK !!!");
printf("\n***************************************\n");
#endif
}
KSOLGCTRL |= 0x07;
KSOLGOEN &= 0xF8;
while(1)
{
if(OEM_SkipMainServiceFunc() == Normal_MainService)
{
main_service();
EnableModuleInterrupt();
_nop_();
_nop_();
_nop_();
_nop_();
}
#if TouchPad_only
#else
if(PS2CheckPendingISR() == 0x00)
{
ScanAUXDeviceStep();
}
#endif
DebugUart();
#ifdef SMBusServiceCenterFunc
if((Service == 0x00) && (Service1 == 0x00)
&& (CheckSMBusNeedService() == SMBus_ClearService))
#else
if((Service == 0x00) && (Service1 == 0x00))
#endif
{
PCON = 1;
}
}
}Startup stages #
1. Establish the initial execution state #
The function begins by disabling all interrupts, setting the stack pointer to 0xC0, and calling ResetBANKDATA().
These operations establish the initial execution environment before the firmware enters either initialization path.
2. Evaluate the startup pathway #
The condition
Hook_ECReturnMainFuncKeepCondition() == 0x33selects the Follow Mode / EC Scratch ROM exit path when it evaluates to true.
In that path, the code clears the SSMC bit in FBCFG, performs repeated writes to MPRECF, clears WinFlashMark, invokes Hook_ECExitFollowMode(), initializes timers, and enables module interrupts.
The repeated MPRECF writes and intervening _nop_() instructions are part of the supplied low-level sequence.
If the condition does not match 0x33, the function follows the normal cold-reset path.
3. Perform normal initialization #
The normal startup path executes the following functions in order:
Core_Initialization();
Oem_Initialization();
InitEnableInterrupt();The CORE layer establishes shared controller functionality. The OEM layer then applies board-specific configuration, after which the configured interrupt environment is initialized and enabled.
If UART_Debug is defined, the firmware initializes UART and prints an initialization message.
4. Configure keyboard scan pins #
After either startup path, the following register operations execute:
KSOLGCTRL |= 0x07;
KSOLGOEN &= 0xF8;These operations set the lower three bits in KSOLGCTRL and clear the lower three bits in KSOLGOEN, following the register conventions used by this firmware.
5. Enter the main polling loop #
The infinite loop repeatedly performs four kinds of work:
- Calls
OEM_SkipMainServiceFunc()to determine whether the standard service scheduler should run. - Calls
main_service()and re-enables module interrupts when the normal scheduling path is selected. - Processes PS/2 auxiliary-device scanning when
TouchPad_onlyis not enabled and no PS/2 ISR is pending. - Calls
DebugUart()and checks whether the service flags and any required SMBus work have cleared.
When no relevant service work remains, the firmware writes PCON = 1 to enter the 8051 Idle mode. An interrupt can wake the controller and allow the main loop to resume.
The resulting execution pattern is:
Hardware or host event → pending service state → foreground processing → idle when no eligible work remains.
4.2 Core initialization: Core_Initialization()
#
Core_Initialization() initializes shared EC functions before the firmware enters the OEM initialization stage.
void Core_Initialization(void)
{
Init_Kbd(); // Keyboard module initialization
Core_InitSio(); // SIO/Super I/O initialization
cold_reset(); // Cold-reset processing
common_reset(); // Common peripheral reset
Init_Mouse(); // Mouse and touchpad variables
Init_Timers(); // Timer initialization
Core_Init_Regs(); // Core register initialization
Core_Init_SMBus(); // SMBus initialization
#if !TouchPad_only
// Delay auxiliary-device scanning
// SetPS2SkipScanTime(60);
#endif
}The function is organized around a sequence of shared initialization operations.
| Function | Purpose |
|---|---|
Init_Kbd() |
Initializes the keyboard module and KBS-related functionality |
Core_InitSio() |
Initializes shared SIO/Super I/O functionality |
cold_reset() |
Executes the project’s cold-reset processing |
common_reset() |
Performs common peripheral reset operations |
Init_Mouse() |
Initializes mouse and touchpad variables |
Init_Timers() |
Prepares timer functionality |
Core_Init_Regs() |
Loads core register settings, including core_reg_init_table |
Core_Init_SMBus() |
Initializes shared SMBus functionality |
The ordering establishes input and communication functionality before later foreground processing depends on those services.
The source includes a commented call to SetPS2SkipScanTime(60), described as a delay for auxiliary-device scanning. Because the call is commented out in the supplied code, it is not executed by this snippet.
4.3 OEM initialization: Oem_Initialization()
#
After shared core initialization, Oem_Initialization() configures platform-specific functionality. Its conditional blocks enable selected features according to the project’s compile-time definitions.
void Oem_Initialization(void)
{
// Init_GPIO();
// InitSio();
#ifdef HSPI
GPIO_HSPI_INIT();
#endif
#ifdef SPIReadMode
ChangeSPIFlashReadMode(SPIReadMode);
#endif
#ifdef HSRSMode
ChangeHSRSMode(HSRSMode);
#endif
#ifdef PLLFrequency
ChangePLLFrequency(PLLFrequency);
#endif
#ifdef PECI_Support
Init_PECI();
#endif
Init_Regs();
#ifdef SMBusChannel4Support
InitSMBusChannel4();
#endif
Init_SMBus_Regs();
// #ifdef ADCFuncSupport
// Init_ADC();
// #endif
#if CIRFuncSupport
Init_CIR();
#endif
Init_Cache();
Init_PS2Port();
#ifdef SysMemory2ECRam
InitSysMemory2ECRam();
#endif
InitSMBus();
ResetSCIEvent();
Init_OEMVariable();
// Check the extended keyboard-matrix configuration
if(ExtendScanPin == 0x02)
{
if(ExternMatrixGPO)
{
ExtendScanPin++;
}
}
}Initialization phases #
1. Clock and Flash configuration
The first conditional blocks configure selected SPI, reset, and clock features.
GPIO_HSPI_INIT()configures pins for the high-speed SPI implementation.ChangeSPIFlashReadMode()applies the configured Flash read mode.ChangeHSRSMode()configures the selected high-speed reset mode.ChangePLLFrequency()applies the specified EC clock configuration.
These calls are conditional on the relevant compile-time definitions.
2. Peripheral initialization
Init_PECI() initializes PECI functionality when PECI_Support is enabled.
InitSMBusChannel4() initializes the fourth SMBus channel when SMBusChannel4Support is enabled. The subsequent calls Init_SMBus_Regs() and InitSMBus() configure additional SMBus state and functionality.
Init_CIR() initializes the consumer infrared receiver when CIRFuncSupport is enabled. Init_PS2Port() initializes the PS/2-related interface.
The Init_ADC() call appears inside a commented-out block in the supplied code. It is not an active initialization call in this example.
3. Register, cache, and variable setup
Init_Regs() applies OEM register configuration, while Init_Cache() initializes the project’s cache functionality.
InitSysMemory2ECRam() is called when SysMemory2ECRam is enabled. The routine is associated with mapping system memory into EC RAM.
ResetSCIEvent() resets the firmware’s SCI-event state, and Init_OEMVariable() initializes OEM-specific variables.
4. Extended keyboard-matrix configuration
The last conditional checks ExtendScanPin and ExternMatrixGPO. If ExtendScanPin equals 0x02 and ExternMatrixGPO is active, ExtendScanPin is incremented.
The supplied description associates this logic with extending the keyboard matrix through additional scan lines, including KSO16 and KSO17.
Initialization function mapping #
| Function or setting | Purpose | Related module |
|---|---|---|
GPIO_HSPI_INIT() |
Configure high-speed SPI pins | SSPI / GPIO |
ChangeSPIFlashReadMode() |
Configure SPI Flash read mode | SSPI |
ChangeHSRSMode() |
Configure high-speed reset behavior | Reset configuration |
ChangePLLFrequency() |
Configure the EC clock | ECPM |
Init_PECI() |
Initialize PECI telemetry | PECI |
InitSMBusChannel4() |
Initialize the fourth SMBus channel | SMBus |
Init_SMBus_Regs() |
Configure SMBus registers | SMBus |
Init_CIR() |
Initialize infrared reception | CIR |
Init_PS2Port() |
Initialize PS/2 functionality | PS/2 |
InitSysMemory2ECRam() |
Configure system-memory mapping | EC RAM |
ResetSCIEvent() |
Reset SCI-event state | ACPI event handling |
ExtendScanPin handling |
Configure extended keyboard scanning | KBS / GPIO |
Compile-time configuration switches #
| Macro or setting | Effect |
|---|---|
HSPI |
Enables high-speed SPI pin initialization |
SPIReadMode |
Selects the configured Flash read mode |
HSRSMode |
Enables high-speed reset configuration |
PLLFrequency |
Selects the EC clock configuration |
PECI_Support |
Enables PECI initialization |
SMBusChannel4Support |
Enables initialization of SMBus channel 4 |
ADCFuncSupport |
Controls ADC-related functionality where referenced by active code |
CIRFuncSupport |
Enables CIR initialization |
SysMemory2ECRam |
Enables the system-memory-to-EC-RAM mapping path |
ExtendScanPin |
Participates in keyboard-matrix extension configuration |
When tracing initialization behavior, both the function body and the active preprocessor definitions must be examined. A function can appear in the source while its call is disabled by comments or compile-time conditions.
4.4 The main_service() priority polling engine
#
main_service() is the central foreground service dispatcher in the supplied firmware. It checks pending service flags in a fixed sequence, clears a flag when its handler is selected, runs the handler, and then restarts the scan from the top.
When SMBusServiceCenterFunc is defined, the loop condition also checks for outstanding SMBus work.
void main_service(void)
{
#ifdef SMBusServiceCenterFunc
while((Service != 0x00) || (Service1 != 0x00)
|| (CheckSMBusNeedService() == SMBus_NeedService))
#else
while((Service != 0x00) || (Service1 != 0x00))
#endif
{
// 1. Host command/data service
if(F_Service_PCI)
{
F_Service_PCI = 0;
service_pci1();
continue;
}
// 2. Service unlock
if(F_Service_UNLOCK)
{
F_Service_UNLOCK = 0;
service_unlock();
continue;
}
// 3. Send byte from KBC
if(F_Service_SEND)
{
F_Service_SEND = 0;
service_send();
continue;
}
// 4. Send data to PS/2 peripheral
if(F_Service_Send_PS2)
{
F_Service_Send_PS2 = 0;
service_PS2_data();
continue;
}
// 5. Process incoming PS/2 data
if(F_Service_PS2)
{
F_Service_PS2 = 0;
service_ps2();
continue;
}
// 6. Process SMBus service
#ifdef SMBusServiceCenterFunc
ServiceSMBus();
#endif
// 7. One-millisecond service
if(F_Service_MS_1)
{
F_Service_MS_1 = 0;
service_1mS();
continue;
}
// 8. Secondary host command/data service
if(F_Service_PCI2)
{
F_Service_PCI2 = 0;
service_pci2();
continue;
}
// 9. Keyboard scanner service
if(F_Service_KEY)
{
F_Service_KEY = 0;
service_scan();
continue;
}
// OEM high-priority hook
Hook_main_service_H();
// 10. Low-level event
if(F_Service_Low_LV)
{
F_Service_Low_LV = 0;
service_Low_LVEvent();
continue;
}
// 11. Third host command/data service
if(F_Service_PCI3)
{
F_Service_PCI3 = 0;
service_pci3();
continue;
}
// 12. CIR interrupt service
if(F_Service_CIR)
{
F_Service_CIR = 0;
service_cir();
continue;
}
// 13. Fourth host command/data service
if(F_Service_PCI4)
{
F_Service_PCI4 = 0;
service_pci4();
continue;
}
// 14–17. OEM service slots
if(F_Service_OEM_1)
{
F_Service_OEM_1 = 0;
service_OEM_1();
continue;
}
if(F_Service_OEM_2)
{
F_Service_OEM_2 = 0;
service_OEM_2();
continue;
}
if(F_Service_OEM_3)
{
F_Service_OEM_3 = 0;
service_OEM_3();
continue;
}
if(F_Service_OEM_4)
{
F_Service_OEM_4 = 0;
service_OEM_4();
continue;
}
// OEM low-priority hook
Hook_main_service_L();
}
}Dispatcher execution model #
Entry condition
The dispatcher continues while Service or Service1 is nonzero. When SMBusServiceCenterFunc is enabled, the condition also considers whether SMBus needs service.
Flag polling and handler execution
The service flags are evaluated sequentially. When a flag is set, the dispatcher clears it and calls the corresponding handler.
Each selected handler is followed by continue, which returns execution to the start of the loop. The next scan therefore begins again with the highest-positioned service condition.
This structure gives earlier checks precedence when multiple services are pending. The source describes the design as flag polling with priority preemption; operationally, the shown loop is a priority-ordered polling dispatcher, and its response time also depends on handler execution and event-arrival timing.
SMBus processing
When SMBusServiceCenterFunc is enabled, ServiceSMBus() runs within the dispatch loop. The outer loop condition checks whether SMBus work remains, keeping that activity part of the foreground service process.
OEM extension points
Two hook functions provide OEM insertion points:
Hook_main_service_H()is called after keyboard scanning is checked and before low-level event processing.Hook_main_service_L()runs after the listed OEM service slots have been checked.
The four OEM service flags, F_Service_OEM_1 through F_Service_OEM_4, provide additional locations for custom service handlers.
This arrangement lets OEM code extend the shared scheduler while retaining the standard service order.
Service priority reference #
| Priority | Service flag | Handler | Description |
|---|---|---|---|
| 1 | F_Service_PCI |
service_pci1() |
Primary host command/data service, including KBC traffic |
| 2 | F_Service_UNLOCK |
service_unlock() |
Auxiliary-device unlock and host IRQ handling |
| 3 | F_Service_SEND |
service_send() |
Sends data to the host through the KBC path |
| 4 | F_Service_Send_PS2 |
service_PS2_data() |
Sends data to PS/2 peripherals |
| 5 | F_Service_PS2 |
service_ps2() |
Processes incoming PS/2 data |
| 6 | — | ServiceSMBus() |
SMBus processing, when enabled |
| 7 | F_Service_MS_1 |
service_1mS() |
One-millisecond service |
| 8 | F_Service_PCI2 |
service_pci2() |
Secondary host command/data service |
| 9 | F_Service_KEY |
service_scan() |
Keyboard-matrix scanning |
| — | — | Hook_main_service_H() |
OEM high-priority hook |
| 10 | F_Service_Low_LV |
service_Low_LVEvent() |
Low-level event processing |
| 11 | F_Service_PCI3 |
service_pci3() |
Third host command/data service |
| 12 | F_Service_CIR |
service_cir() |
Consumer infrared processing |
| 13 | F_Service_PCI4 |
service_pci4() |
Fourth host command/data service |
| 14 | F_Service_OEM_1 |
service_OEM_1() |
OEM service slot 1 |
| 15 | F_Service_OEM_2 |
service_OEM_2() |
OEM service slot 2 |
| 16 | F_Service_OEM_3 |
service_OEM_3() |
OEM service slot 3 |
| 17 | F_Service_OEM_4 |
service_OEM_4() |
OEM service slot 4 |
| — | — | Hook_main_service_L() |
OEM low-priority hook |
The table follows the order in the supplied main_service() function. It describes foreground dispatch order rather than the hardware interrupt controller’s priority configuration.
⏱️ 5. OEM Timer Hook Architecture #
The firmware separates timer management from platform-specific processing. The core timer implementation is identified as CORE_TIMERS.C, while OEM hook functions provide scheduled entry points for application logic.
The supplied material describes timer intervals of 1 ms, 5 ms, 10 ms, 50 ms, 100 ms, 500 ms, 1 second, and 1 minute, along with OEM-customized intervals.
Shorter intervals are used for tasks requiring frequent evaluation, while longer intervals provide additional scheduling levels for work that does not require the same frequency.
5.1 Hook_Timer1msEvent() — one-millisecond hook
#
void Hook_Timer1msEvent(IBYTE EventId)
{
#if MailBoxRWECram
HandleMailBox();
#endif
EventManager(EventId);
Oem_SysPowerContrl();
SMBusCenter();
ACPILED_ON();
}The 1 ms hook combines mailbox handling, event processing, power control, SMBus coordination, and LED-related activity.
Mailbox handling
When MailBoxRWECram is enabled, HandleMailBox() processes the associated mailbox functionality.
Event processing
EventManager(EventId) receives the event identifier for the current invocation.
In the supplied description, the event ID cycles through values 0–9, with each 1 ms tick polling one-tenth of the physical events. Under that arrangement, the complete event set is checked over a nominal 10 ms cycle.
Power sequencing
Oem_SysPowerContrl() executes the OEM system power-control logic. Its placement in this hook allows the power-control state machine to be evaluated on the 1 ms schedule.
SMBus coordination
SMBusCenter() coordinates SMBus activity, including smart-battery polling and charger-related operations described in the source material.
LED updates
ACPILED_ON() performs the associated LED update logic.
5.2 Hook_Timer5msEvent() — five-millisecond hook
#
void Hook_Timer5msEvent(void)
{
#ifdef PECI_Support
PECI_PowerCtrlCenter();
#endif
#ifdef PMC3_Support
SystemIsS0
{
PECI_SendBufferData();
}
#endif
#if ACPI_QEventPending
Get_PendingECQEvent();
#endif
}The 5 ms hook focuses on PECI-related processing and pending ACPI query events.
PECI power-control processing
When PECI_Support is defined, PECI_PowerCtrlCenter() handles the corresponding PECI control workflow. The supplied description associates this processing with CPU telemetry for thermal policy and fan-control decisions.
Conditional PECI buffer transmission
When PMC3_Support is defined, the code invokes PECI_SendBufferData() within the SystemIsS0 condition.
The supplied code expresses SystemIsS0 as a condition surrounding the buffer-send operation. Its exact macro or statement implementation resides elsewhere in the project.
ACPI query-event processing
When ACPI_QEventPending is enabled, Get_PendingECQEvent() retrieves pending EC query events. The supplied description associates this with reporting query-event information to the host through the SCI mechanism.
5.3 Hook_Timer10msEventA() — ten-millisecond Event A
#
void Hook_Timer10msEventA(void)
{
#if ADCFuncSupport
// ScanADCDyChannel1();
#endif
#if BAT1FuncSupport
if(BT1_STATUS1 & bat_in)
{
if(BAT1_CtrlStep == BATCHECK)
ChkBatt();
}
if(BT1_STATUS1 & bat_in)
{
PollingBAT1Data();
}
#endif
#ifdef ECPowerDownModeSupport
ECPowerDownModeManager();
#endif
}Event A primarily handles smart-battery processing and EC power-down management. An ADC scanning call is present but commented out.
Battery-presence check
When BAT1FuncSupport is enabled, the function checks whether BT1_STATUS1 contains the bat_in flag.
Battery identification
If the battery is present and BAT1_CtrlStep equals BATCHECK, the firmware calls ChkBatt().
The supplied description associates this step with retrieving battery identification information, including manufacturer information and design capacity.
Battery telemetry polling
PollingBAT1Data() is called when the battery-presence condition is true. The described polling process obtains dynamic battery information such as voltage, current, and relative state of charge (RSOC).
The source describes this work as being distributed across successive 10 ms intervals to avoid overloading SMBus processing.
EC power-down management
When ECPowerDownModeSupport is enabled, ECPowerDownModeManager() evaluates the configured EC power-down logic.
The ADC call remains commented out in the provided example, so it is not executed by this function as shown.
5.4 Hook_Timer10msEventB() — ten-millisecond Event B
#
void Hook_Timer10msEventB(void)
{
CheckSBPowerButton();
#if ADCFuncSupport
ScanADCDyChannel2();
#endif
}Event B complements Event A by handling power-button checking and a second ADC scanning path.
Power-button processing
CheckSBPowerButton() monitors the system power-button state. The supplied description associates the routine with button-transition detection and hardware debounce handling before the resulting state change is handled by Oem_SysPowerContrl().
The source also references an approximately 200 ms PWRBTN# pulse assertion requirement. The specific timing behavior belongs to the platform implementation.
Secondary ADC scan
When ADCFuncSupport is enabled, ScanADCDyChannel2() performs the secondary dynamic ADC scan. Dividing ADC work between Event A and Event B distributes the acquisition tasks across separate timer hooks.
5.5 Timer hierarchy summary #
| Timer interval | Main task described in the source | Related hook or implementation |
|---|---|---|
| 1 ms | Event polling, power-control evaluation, SMBus coordination, LED updates | Hook_Timer1msEvent() |
| 5 ms | PECI control, conditional buffer transmission, ACPI query-event processing | Hook_Timer5msEvent() |
| 10 ms, Event A | Battery identification, battery-data polling, EC power-down management, optional ADC scan | Hook_Timer10msEventA() |
| 10 ms, Event B | Power-button checking and optional secondary ADC scan | Hook_Timer10msEventB() |
| 50 ms | Additional periodic work in the timer hierarchy | OEM-defined hook |
| 100 ms | Additional periodic work in the timer hierarchy | OEM-defined hook |
| 500 ms | Additional periodic work in the timer hierarchy | OEM-defined hook |
| 1 second | Longer-interval periodic work | OEM-defined hook |
| 1 minute | Long-interval maintenance or monitoring work | OEM-defined hook |
| OEM-defined intervals | Application-specific periodic processing | Project-specific implementation |
The timer hierarchy provides multiple scheduling frequencies for different types of work. Power control and event detection use shorter intervals, while tasks such as thermal averaging, fan-speed smoothing, and LED fading can be assigned to longer intervals where the implementation requires them.
🔧 6. Practical Firmware Debugging #
Understanding the boundaries between CORE, OEM, and hardware functionality makes it easier to identify where a failure originates.
6.1 Trace initialization in execution order #
When a peripheral or board function is unavailable, start with the initialization sequence.
- Confirm which branch of
main()executes. - Check whether
Core_Initialization()completes. - Determine which OEM initialization calls are enabled by the build configuration.
- Inspect the relevant register setup and GPIO multiplexing.
- Verify that the associated interrupt or foreground service can run.
Pay particular attention to preprocessor definitions and commented-out calls. Their presence in the source does not mean the associated functionality is active in the compiled firmware.
6.2 Trace events through the service dispatcher #
For host communication, keyboard scanning, SMBus work, or other delayed operations, follow the entire processing path:
Event source → pending flag or state → main_service() → service handler → resulting hardware or host action.
This makes it possible to distinguish an event that never becomes pending from a handler that is delayed or does not produce the expected result.
6.3 Inspect code-bank placement and switching #
For faults involving functions in different banks, examine:
- The code-bank assignment of the affected function.
- The bank-switching support in
L51_BANK.A51. - The configured
BANKSELregister. - The generated call and return sequences.
- The compiler and linker configuration.
- The initialization performed by
ResetBANKDATA().
The directory structure indicates where modules are organized, but the actual placement of individual functions depends on the firmware build configuration.
6.4 Review timer scheduling and peripheral workloads #
When periodic processing is delayed, inspect the execution time and scheduling behavior of the relevant handlers.
Useful areas to examine include service-flag management, SMBus transaction progress, ADC scanning, power-state transitions, and the work performed by OEM hooks.
Because the dispatcher checks flags in order and restarts the scan after processing a selected service, the amount of time spent in a handler can influence when other services receive attention.
✅ 7. Conclusion #
The IT8528E firmware architecture combines integrated EC peripherals with a layered software design. The CORE layer supplies shared initialization, interfaces, timers, and service scheduling, while the OEM layer configures and implements motherboard-specific behavior.
Code banking expands the available firmware space beyond the conventional 8051 code-address window. The main() function establishes the startup state and chooses the initialization path; Core_Initialization() prepares common services; Oem_Initialization() configures platform-specific functionality; and main_service() dispatches pending foreground work according to its defined order.
The OEM timer hooks add periodic processing for event management, power sequencing, PECI, battery monitoring, power-button detection, ADC scanning, and other platform tasks.
Taken together, these components provide the foundation for understanding how the supplied EC firmware initializes the controller, coordinates peripherals, schedules foreground services, and manages recurring system tasks.