行业资讯
📅 2026/9/3 15:26:28
IT557x代码学习及实操(不定时持续更新的半成品)
1 oem_main.c1.1 Hook_Timer1msEvent(1ms心跳)1.1.1 按电源状态选择分支对象S0、1 运行S3 睡眠手动睡眠S5 关机G3 断主电CPU/PCH全速断电上下文在 DRAM断电断电DRAM工作自刷新带电​断电断电主板 MAIN 电开关关关ALWAYS/SUS 电开开​开关拔电/无电池EC(IT5571)跑全量任务跑仅值守唤醒​跑守 SLP_S5/拔插电掉 ALWAYS 才停EC 代码分支Oem_SysPowState_S0_S1Oem_SysPowState_S3Oem_SysPowState_S4_S5Oem_SysPowState_G3if ((SysPowState _SYSTEM_S0) || (SysPowState _SYSTEM_S1)) { Oem_SysPowState_S0_S1(); }跑 S0/S1 的全量业务扫键盘、控风扇、充放电算法、PECI 温度、LED 指示等else if (SysPowState _SYSTEM_S3) { Oem_SysPowState_S3(); }只保最低唤醒LID 开关、电源键、键盘唤醒、Type-C 插拔唤醒。不读 CPU 温度、不控风扇else if ((SysPowState _SYSTEM_S4) || (SysPowState _SYSTEM_S5)) { #if SUPPORT_SW_MIRROR if (IS_MASK_CLEAR(EC_SW_MIRROR, SW_MIRROR_EN)) { Oem_SysPowState_S4_S5(); } #else Oem_SysPowState_S4_S5(); #endif }笔记本电脑已关机但电池还有电EC做最基础的看门狗因为EC管机器的上电功能即就是开机故需要一直低功耗运行else if (IS_MASK_CLEAR(SysPowState, F_PST_BUSY)) { Oem_SysPowState_G3(); }拔适配器没电池或 EC 主动拉死。G3为兜底情况正常流程S0/S3/S4/S5 都被前面拦住1.1.2 System Power Control上电/下电序列if (IS_MASK_SET(SysPowState, F_PST_BUSY)) { Oem_SysPowSequence(); // System Power Control } else { if (EventId 0x01) { /* Divide Timer2msEvent */ SMBusA_ScanCenter(); // Cypress Type-C PD } else { /* Divide Timer2msEvent */ SMBusB_ScanCenter(); // PollSmartCharger,PollSmartBattery } }若是检测到电源为1只跑系统开关的函数因为开机需要时间电源其余模块不一定被拉起了若是为0则持续保持低功耗运行SMBusB​ → 智能充电器 智能电池老式 SMBus 电池协议SMBusA​ → Cypress Type-C PD 控制器CCG 系列EventId奇偶跑什么间隔0,2,4,6,8偶SMBusB_ScanCenter()每 2ms1,3,5,7,9奇SMBusA_ScanCenter()每 2ms2 UART2.1 Init_UART2(串口)void Init_UART2(void) { AUTOCG 0x00; GCR1 0xF3; //SIN1/SOUT1 are enabled. GCR1 | 0x04; GCR6 0x0F; GCR8 0xF3; //0x16F7 GCR8 | 0x04; RSTDMMC 0x1F; RSTC4 BIT2; //Reset UART2 (RUART2) UART2_LCR 0x80; //Bit7: DLAB1 UART2_RBR 0x01; //UART2_IER UART2_DLL (DLAB1) UART2_IER 0x00; //UART2_IER UART2_DLM (DLAB1) // 0x00 0x01 : 115200 Baud Rate UART2_LCR 0x03; UART2_MCR 0x00; UART2_IIR 0xC7; //(W)UART2_IIR UART2_FCR (Use FIFO) UART2_IER 0x01; GPCRH2 ALT; //SOUT1 //GPCRH1 ALT; //SIN1 #if 0 UART2_RBR U; UART2_RBR A; UART2_RBR R; UART2_RBR T; UART2_RBR 2; UART2_RBR ; UART2_RBR O; UART2_RBR K; UART2_RBR ; #endif printf(\n************************************); printf(\nEC PRINTF UART2 OK !!!); printf(\n************************************); } #endif2.1.1 关时钟门控防配置中途乱跑AUTOCG 0x00;AUTOCG Auto Clock Gating 控制寄存器。写 0x00 表示关闭自动门控强制给 UART2 模块供时钟。⚠️ FAE 高频坑如果这里没开时钟后面所有 UART2_xxx xx 都等于写空气示波器上绝对没波形但代码不报错2.1.2 引脚复用 驱动能力配置GCR1 / GCR6 / GCR8GCR1 0xF3; // SIN1/SOUT1 enable GCR1 | 0x04; GCR6 0x0F; GCR8 0xF3; // 0x16F7 GCR8 | 0x04;EC 把 GPIO 复用、上拉、驱动强度、施密特触发等统一塞进几个全局GCRxGlobal Control Register清00xF3 清掉 bit3~20xF3 转成 8 位二进制是1111 0011| 0x04 只把 bit2 置 1​ 0000 0100→ 使能 SIN1(RX)、SOUT1TX注释里的 0x16F7 是客户原厂参考设计的“魔数”别抄数值要抄意图把 TX 脚设成 ALT 合适驱动。这两个寄存器的 Bit2、Bit3确实都涉及 UART2但它们分工不同且 GCR1 还同时管着 UART1。1. GCR1同时控制 UART1 与 UART2Bit 3-2 (UART2 Control / U2CTRL)正是你之前代码GCR1 0xF3; GCR1 | 0x04;操作的位置。写成0b10即 0x04对应手册的10b使能了SIN1/SOUT1/DSR1/RTS1/CTS1/DTR1/DCD1。这里出现了一个手册命名细节GCR1 的 Bit3-2 虽然叫 UART2 控制但描述的引脚却是SIN1/SOUT1通常对应 UART1 的引脚名实际以引脚表为准。Bit 1-0 (UART1 Control / U1CTRL)控制真正的 UART1引脚为SIN0/SOUT0。你之前的代码 0xF3刚好也保留了 Bit1-0 的原值未被清除。2. GCR8也涉及 UART2且有额外含义Bit 3-2 (UART2 Control / U2CTRL)同样控制 UART2。代码GCR8 0xF3; GCR8 | 0x04;设为0b10对应使能SIN1/SOUT1/RTS1/CTS1。Bit 1-0 (UART1 Control / U1CTRL)截图中 GCR8 底部也出现了 UART1 控制位引脚为SIN0/SOUT0等。关键差异Bit4GCR8 的 Bit4 是PWRSW WDT 2 Enable这与电源/看门狗有关说明 GCR8 不仅是引脚复用。3. 为什么两个寄存器都要配置既然都控制 UART2为何代码两处都写功能互补GCR1 的 UART2 模式10b包含完整的流控/调制解调引脚DSR/DTR/DCD而 GCR8 的 UART2 模式10b包含部分流控RTS/CTS。两者配合才能完整开启 UART2 所需功能。历史/兼容性ITE 芯片常有多组复用GCR1 和 GCR8 可能对应不同物理引脚组但都映射到 UART2 功能。代码惯性SDK 初始化模板常把相关 GCR 都刷一遍确保状态一致。GCR6 0x0F; 的本质是独立开启 UART1 与 UART2 的收发引脚且完全契合手册默认值。结合前序讨论GCR1/GCR8 负责整体引脚复用模式GCR6 在这里负责独立使能收发器UART2对应你关注的 SIN1/SOUT1Bit31, Bit21 → 收发全开。UART1对应 SIN0/SOUT0Bit11, Bit01 → 收发全开。值得注意的是手册中 Bit0~3 的默认值Default全都是 1b。因此这行代码虽然写死了 0x0F高4位强制清0但在核心串口使能上它相当于显式确认了默认状态确保 UART2SIN1/SOUT1和 UART1SIN0/SOUT0的收发均处于使能状态。总结GCR1 / GCR8配置 Bit2-3选定 UART2 的复用模式如流控与引脚组映射。GCR6最终拍板单独打开这些引脚的 TXSOUT和 RXSIN通道。2.1.3 硬件复位 UART2 模块RSTDMMC 0x1F; RSTC4 BIT2; // Reset UART2 (RUART2)RSTDMMC释放/控制各模块复位状态机先写解锁序列 0x1F。RSTC4 BIT2拉低 bit2 → UART2 模块硬复位复位完成后硬件自动释放。 为什么先复位再配​ 寄存器上电初值不确定硬复位一次保证 LCR/FCR/IER 都回到 16550 默认态DLAB0无 FIFO配置才可控。**2.1.4波特率设置16550 经典三步开 DLAB → 写 DLL/DLM → 关 DLABUART2_LCR 0x80; // Bit7: DLAB1允许访问波特率除数锁存器 UART2_RBR 0x01; // DLL 低8位 (除数低字节) UART2_IER 0x00; // DLM 高8位 (除数高字节) // 0x00 0x01 : 115200 Baud Rate UART2_LCR 0x03; // DLAB0, 8N1这是UART 最核心的一段记住公式DLAB1时RBR接收缓冲和IER中断使能这两个地址被硬件重定向成DLL除数低字节​ 和DLM除数高字节。DLL0x01, DLM0x00→ 16 位除数 0x0001 1。反推UART_CLK / (1×16) 115200→ 说明这颗 EC 的 UART2 时钟源被配成了1.8432 MHz或 3.6864MHz/2具体看APBCLK/UARTCLK分频。FAE 现场客户换晶振你只改 DLL/DLM 两个值或者调时钟分频宏不用动逻辑。最后UART2_LCR 0x03→ 二进制0000 0011bit1~0 11→8 位数据位bit2 0→1 位停止位bit3 0→ 无奇偶校验即8N1PC 串口助手必须一致否则全乱码。2.1.5 关 Modem 控制 开 FIFOUART2_MCR 0x00; // 无流控 RTS/CTS无环回 UART2_IIR 0xC7; // 写 FCR使能 FIFO清 TX/RX FIFO14字节触发级MCR0不用硬件流控EC 调试口 99% 都是三线 TX/RX/GND。IIR 寄存器在 16550 里是只读的读中断标识但往它地址写实际是写 FCRFIFO Control Register0xC7 1100 0111bit7~6 11 → 触发深度 14 bytes收到 14 字节才中断减 IRQ 负担bit3 1 → DMA 模式部分型号bit2 1 → 清空 TX FIFObit1 1 → 清空 RX FIFObit0 1 → FIFO 使能2.1.6 开接收中断UART2_IER 0x01; // 使能 Receive Data Available 中断之前IER0x00是配波特率时临时借用现在波特率定好了再正式开“收到数据就打断 EC”。注意这里只开了 RX 中断。如果后面要做命令行交互比如进 BIOS setup 敲ESC靠的就是它只打 log 的话其实可以不开但开了也不碍事。2.1.7 引脚切复用 首发 logGPCRH2 ALT; // SOUT1 → 实际硬件 TX 脚 // GPCRH1 ALT; // SIN1 → RX 脚先不用 printf(\nEC PRINTF UART2 OK !!!);GPCRx ALT 就是把 GPIO 切成串口功能。这里只开 TX 脚GPCRH2RX 脚注释掉 → 说明这个 EC 当前只往外吐日志不接命令。#if 0 那段往 RBR 手动塞 UART... 是上古裸机调试法直接写发送保持寄存器不用 printf。现在有 printf 重定向这招退休了但客户老代码里常见你知道它是“手动吐字符”就行2.1.8 总结AUTOCG0 供时钟↓GCR1/GCR6/GCR8 配引脚电气 复用使能↓RSTC4 硬复位 UART2 → 模块归零↓LCR.71 → 写 DLL0x01 / DLM0x00 → 定 115200↓LCR0x03 → 8N1DLAB 关闭↓MCR0 / FCR0xC7 → 无流控 开 FIFO↓IER0x01 → 开接收中断↓GPCRH2ALT → TX 脚浮出波形↓printf → PC 串口助手看到 UART2 OK2.2 相关知识2.2.1 需确定引脚、波特率、电平1.pin对应根据芯片spec可知RXD/TXD分别在5571芯片的108(GPB0)、109(GPB1)pin将串口与芯片对应pin连接2.波特率波特率使用115200, 8N1, 无流控3.电平ITE5571 是 3.3V TTLUSB-TTL 模块跳线切到 3.3V千万别用 5V 挡直接接信号线2.2.2 硬件连线断电接USB-TTL ↔ ITE5571 开发板TTLTX​ → 板子RX2TTLRX​ → 板子TX2TTLGND​ → 板子GND必须共地TTL 的VCC 不接板子自己供电接完先别上电确认 TX/RX 是交叉的、电平是 3.3V。2.2.3 代码层在初始化之后加“会动的东西”你已有 UART2 初始化函数接着做三小块在main()或 EC 上电后的某个任务里调用一次 UART2_Init()确认时钟、波特率除数、FIFO、中断/DMA 模式和你学的函数一致。写一个最朴素的发送函数或调用 SDK 的uart_putc/Uart2Sendvoid uart2_puts(const char *s){ while(*s){ UART2_SEND_BYTE(*s); while(!UART2_TX_EMPTY()); } }在初始化后加uart2_puts(ITE5571 UART2 hello\r\n);再搞个回环/echo收到什么发什么或者按键盘 a 返回 A用来验证 RX 也通。如果 SDK 里有printf重定向到 UART2 的钩子EC 代码里常见putchar/SERIAL_OUTPUTUART2直接重定向printf更省事。2.2.4 PC 端收数据装好 CH340/CP2102 驱动设备管理器看 COM 号Linux 下/dev/ttyUSB0。打开串口工具MobaXterm / PuTTY / SSCOM / minicom 都行设115200-8-N-1-无流控。板子上电或按 Reset应该能看到ITE5571 UART2 hello。没出字先不怀疑代码按下面排错。2.2.5 常见“没输出”排查顺序示波器/逻辑分析仪抓 TX2 脚上电瞬间有无 0/1 跳变 → 有跳变说明 MCU 在发是 PC 端或波特率问题完全死高/死低说明 MUX 没配或 UART 没使能。互换 TX/RX新手最常错。GND 没共地最隐蔽。波特率算错EC 内部时钟源内部 IRC 还是外部晶振和初始化函数里填的 divisor 不匹配。UART2 在 EC 里被 BIOS/Host 域占用需要确认你的固件镜像里 UART2 分配给了 EC 域。2.2.6 跑通后你可以继续做的实验由浅入深串口命令行解析 PC 发来的led on/led off控制开发板 LED用 UART2 把 ADC 采到的电压值定时打印出来改成中断接收做带缓冲的命令行把 UART2 和 UART0EC 调试口对比理解 EC 多路 UART 的时钟域最后再回头读 datasheet 里 UART2 的Line Control / FIFO Control / INT Enable​ 寄存器和你刚才看的初始化函数逐行对上号最小下一步今天就把“初始化 上电打一句 hello”跑通看到字再从 PC 发一个字节让灯翻转。这一关过了UART 在 IT5571 上就算真正入门了。