外设接口与驱动
本文档介绍 AC632N(AC63 系列 MCU)BSP 层提供的外设接口与驱动体系,涵盖 GPIO、引脚复用(CrossBar)、ADC、硬件/软件 IIC、MCPWM、脉冲计数、按键、唤醒、充电检测等驱动的接口约定、寄存器操作模型与典型使用流程。
Purpose and Scope
本页面向 sdk/bsp/AC632N/ 目录下的外设驱动层,说明:
- GPIO 驱动:引脚编号体系、方向/上下拉/数字模拟功能控制、输出驱动能力配置。
- CrossBar 引脚复用:通过
JL_IMAP/JL_OMAP寄存器把外设信号(UART、SPI、IIC、定时器捕获、PWM 故障引脚等)路由到任意 IO。 - ADC 驱动:通道定义、异步中断采样与同步轮询采样两种模式、AD 值到电压的换算。
- IIC 驱动:硬件 IIC(寄存器级主从模式)与软件模拟 IIC 两套实现。
- 其他外设:MCPWM、脉冲计数(PL-CNT)、按键驱动、端口唤醒、充电检测、调试串口等 BSP 模块的定位与归属。
不涉及的内容:时钟/电源管理(见时钟与电源相关页面)、Flash 存储、蓝牙协议栈、音频编解码等由 sdk/apps 与其他 BSP 模块承载的能力。本文聚焦"如何把芯片引脚与片内外设用起来"这一层。
Overview
AC632N 是杰理科技 AC63 系列低功耗 MCU,其 BSP(Board Support Package)位于 sdk/bsp/AC632N/,其中:
include/asm/存放驱动头文件(gpio.h、adc_api.h、iic_hw.h、iic_soft.h、charge.h、hwi.h、io_imap.h、io_omap.h等);src/存放驱动实现(gpio.c、adc.c、iic_hw.c、iic_soft.c、mcpwm.c、plcnt.c、key_driver.c、port_wkup.c、charge.c、debug_uart.c等)。
外设驱动的设计遵循"寄存器封装 + 句柄式 API"的经典 BSP 模式:
- 引脚抽象:所有外设共用同一套
IO_PORTx_xx编号,例如IO_PORTA_00表示 A 组第 0 脚,编号本身即端口基址的偏移,gpio2reg()可将其换算成struct gpio_reg *寄存器视图。 - 功能复用:IO 既是普通 GPIO,也是外设信号的载体,通过 CrossBar 的输入功能表(
enum PFI_TABLE)与输出映射寄存器(io_omap.h中的FO_*索引)实现任意 IO 到任意外设的灵活路由。 - 同步/异步双模式:如 ADC 同时提供
adc_get_value()(死等)与adc_get_value_by_isr()(中断回调)两种采样方式,兼顾简单性与实时性。 - 主从模式统一:硬件 IIC 通过
struct hw_iic_config配置端口/波特率/角色,主机与从机行为由 CON0 寄存器位控制宏区分。
关键概念:
struct gpio_reg:一组端口的 9 个控制寄存器(out/in/dir/die/pu/pd/hd0/hd/dieh)。enum PFI_TABLE:CrossBar 可输入外设信号索引(如PFI_UART0_RX、PFI_IIC_SCL)。AD_CH_*/ADC_PMU_CH_*:ADC 模拟输入通道与 PMU 内部通道(VBAT、LDO5V、温度等)。hw_iic_dev:硬件 IIC 句柄(const int),配合hw_iic_cfg[]平台配置表使用。
Architecture
flowchart TD
subgraph sg_App["应用层 sdk/apps"]
Main["main.c / board_demo.c"]
end
subgraph sg_BSP_API["BSP 外设 API 层 include/asm"]
GPIO_H["gpio.h<br/>GPIO + CrossBar"]
ADC_H["adc_api.h"]
IIC_HW_H["iic_hw.h"]
IIC_SOFT_H["iic_soft.h"]
MISC_H["charge.h / hwi.h / clock.h ..."]
end
subgraph sg_BSP_SRC["BSP 驱动实现层 src"]
GPIO_C["gpio.c"]
ADC_C["adc.c"]
IIC_HW_C["iic_hw.c"]
IIC_SOFT_C["iic_soft.c"]
OTHER_C["mcpwm.c / plcnt.c / key_driver.c<br/>port_wkup.c / charge.c / debug_uart.c"]
end
subgraph sg_HW["硬件层"]
REGS["寄存器视图<br/>struct gpio_reg / JL_IMAP / JL_OMAP / JL_IIC / JL_ADC"]
PINS["芯片引脚 A/B/D/P + USB + P33"]
end
Main --> GPIO_H
Main --> ADC_H
Main --> IIC_HW_H
Main --> IIC_SOFT_H
GPIO_H --> GPIO_C
ADC_H --> ADC_C
IIC_HW_H --> IIC_HW_C
IIC_SOFT_H --> IIC_SOFT_C
MISC_H --> OTHER_C
GPIO_C --> REGS
ADC_C --> REGS
IIC_HW_C --> REGS
OTHER_C --> REGS
REGS --> PINS
各层职责:
- 应用层(
sdk/apps/main.c、board_demo.c)通过头文件暴露的 API 使用外设,不直接触碰寄存器。 - API 层以头文件形式定义接口契约:引脚宏、枚举、结构体与函数原型,是驱动唯一的"公共表面"。
- 实现层把 API 翻译成对
struct gpio_reg、JL_IMAP、JL_OMAP、JL_IIC、JL_ADC等寄存器结构的读写,完成位操作。 - 硬件层由
AC632N.h/csfr.h定义寄存器布局,最终作用到芯片引脚(A/B/D/P 四组普通 IO + USB 复用 IO + P33 电源检测 IO)。
该分层让应用代码与具体寄存器解耦:更换引脚只需改宏/配置表,无需改动业务逻辑。
主要外设驱动详解
GPIO 驱动
引脚编号体系
gpio.h 以 IO_GROUP_NUM 16 为每组端口容量,用线性编号统一表达所有引脚:
#define IO_GROUP_NUM 16
#define IO_PORTA_00 (IO_GROUP_NUM * 0 + 0)
#define IO_PORTA_09 (IO_GROUP_NUM * 0 + 9)
#define IO_PORTB_00 (IO_GROUP_NUM * 1 + 0)
#define IO_PORTB_09 (IO_GROUP_NUM * 1 + 9)
#define IO_PORTD_00 (IO_GROUP_NUM * 2 + 0)
#define IO_PORTP_00 (IO_GROUP_NUM * 3 + 0)
#define IO_MAX_NUM (IO_PORTP_00 + 1)
Source: gpio.h
编号设计意图:IO_PORTx_yy = 组号*16 + 组内序号,因此"引脚序号"与"端口基址偏移"天然对应,gpio2reg() 只需按编号定位到 GPIOA/GPIOB/GPIOD/GPIOP 之一,即可返回 struct gpio_reg *。普通 IO 之外,USB 与电源检测引脚被编码在 IO_MAX_NUM 之后的扩展区:
#define IO_PORT_DP (IO_MAX_NUM + 0)
#define IO_PORT_DM (IO_MAX_NUM + 1)
#define IO_PORT_DP1 (IO_MAX_NUM + 2)
#define IO_PORT_DM1 (IO_MAX_NUM + 3)
#define IO_CHGFL_DET (IO_MAX_NUM + 4)
#define IO_VBGOK_DET (IO_MAX_NUM + 5)
#define IO_VBTCH_DET (IO_MAX_NUM + 6)
#define IO_LDOIN_DET (IO_MAX_NUM + 7)
#define IO_PORT_MAX (IO_LDOIN_DET + 1)
Source: gpio.h
寄存器视图
每个端口组对应一个 struct gpio_reg,它直接映射硬件寄存器布局:
struct gpio_reg {
volatile unsigned int out;
volatile unsigned int in;
volatile unsigned int dir;
volatile unsigned int die;
volatile unsigned int pu;
volatile unsigned int pd;
volatile unsigned int hd0;
volatile unsigned int hd;
volatile unsigned int dieh;
};
Source: gpio.h
out:输出电平寄存器;in:输入电平寄存器。dir:方向(0 输出 / 1 输入,见enum gpio_direction)。die/dieh:数字功能使能。作为 ADC 等模拟输入时必须把die置 0(数字缓冲关闭)。pu/pd:上拉/下拉(10K,输入模式有效)。hd0/hd:输出内阻与电流增强控制(输出模式有效),用于驱动能力调整。
核心 API 一览
| 函数 | 作用 | 关键约定 |
|---|---|---|
struct gpio_reg *gpio2reg(u32 gpio) | 引脚序号 → 端口寄存器 | 返回 JL_PORTA 等基址 |
int gpio_set_direction(u32 gpio, u32 value) | 设置方向 | 1 输入 / 0 输出;非 0 返回失败 |
int gpio_direction_input(u32 gpio) | 直接设为输入 | 便捷封装 |
int gpio_direction_output(u32 gpio, u32 value) | 设为输出并同时置电平 | 避免先配方向再写电平的毛刺 |
int gpio_read(u32 gpio) / gpio_read_input_value() | 读输入电平 | 输入模式下有效 |
int gpio_write(u32 gpio, u32 value) / gpio_set_output_value() | 写输出电平 | 输出模式下有效 |
int gpio_set_pull_up(u32 gpio, u32 value) | 上拉 10K | 输入模式有效 |
int gpio_set_pull_down(u32 gpio, u32 value) | 下拉 10K | 输入模式有效 |
int gpio_set_hd0(u32 gpio, u32 value) | 关闭内阻增强输出 | 输出模式有效 |
int gpio_set_hd(u32 gpio, u32 value) | 增大输出电流 | 输出模式有效 |
int gpio_set_die(u32 gpio, u32 value) | 数字/模拟功能切换 | ADC 输入需 die=0 |
int gpio_set_dieh(u32 gpio, u32 value) | 另一组数字/模拟切换 | 与 die 模拟通路不同 |
u32 get_gpio(const char *p) | 解析 "PA00" 字符串 | "PB01" → 17 |
void usb_iomode(u32 enable) / usb1_iomode() | USB 引脚复用为普通 IO | 使能后 DP/DM 变 GPIO |
设计意图:gpio_direction_output(gpio, value) 把"方向+初值"合成一个原子操作,避免按键/指示灯等场景下输出瞬间出现错误电平;get_gpio() 支持用字符串配置引脚,便于板级配置表(如 board_demo.c)以文本形式描述管脚用途。
CrossBar 引脚复用(BR30 Crossbar API)
CrossBar 是 AC632N 外设路由的核心:IO 既是 GPIO,又能承载 UART/SPI/IIC/定时器捕获/PWM 等片内外设信号,路由关系通过 JL_IMAP(输入映射)与 JL_OMAP(输出映射)寄存器配置。
输入侧信号索引定义在 enum PFI_TABLE 中,覆盖了绝大多数外设输入:
enum PFI_TABLE {
PFI_GP_ICH0 = ((u32)(&(JL_IMAP->FI_GP_ICH0))),
PFI_TMR0_CIN = ((u32)(&(JL_IMAP->FI_TMR0_CIN))),
PFI_TMR0_CAP = ((u32)(&(JL_IMAP->FI_TMR0_CAP))),
PFI_SPI0_CLK = ((u32)(&(JL_IMAP->FI_SPI0_CLK))),
PFI_SPI1_DA3 = ((u32)(&(JL_IMAP->FI_SPI1_DA3))),
PFI_MCPWM_TMR0_CLKI = ((u32)(&(JL_IMAP->FI_MCPWM_TMR0_CLKI))),
PFI_MCPWM_FPIN_A = ((u32)(&(JL_IMAP->FI_MCPWM_FPIN_A))),
PFI_IIC_SCL = ((u32)(&(JL_IMAP->FI_IIC_SCL))),
PFI_IIC_SDA = ((u32)(&(JL_IMAP->FI_IIC_SDA))),
PFI_UART0_RX = ((u32)(&(JL_IMAP->FI_UART0_RX))),
PFI_UART1_RX = ((u32)(&(JL_IMAP->FI_UART1_RX))),
PFI_UART1_CTS = ((u32)(&(JL_IMAP->FI_UART1_CTS))),
PFI_UART2_RX = ((u32)(&(JL_IMAP->FI_UART2_RX))),
PFI_RDEC0_DAT0 = ((u32)(&(JL_IMAP->FI_RDEC0_DAT0))),
PFI_CHAIN_IN0 = ((u32)(&(JL_IMAP->FI_CHAIN_IN0))),
PFI_TOTAL = ((u32)(&(JL_IMAP->FI_TOTAL))),
};
Source: gpio.h
枚举值直接取 JL_IMAP 寄存器地址,因此 gpio_set_fun_input_port(gpio, pfun) 内部只需把对应寄存器写成目标 IO 序号。输出侧由 gpio_set_fun_output_port() 完成,功能索引(如 FO_UART0_TX)定义在 io_omap.h。四个关键 API:
| 函数 | 作用 |
|---|---|
int gpio_set_fun_output_port(u32 gpio, u32 fun_index, u8 dir_ctl, u8 data_ctl) | 把外设输出信号(fun_index)路由到指定 IO;dir_ctl/data_ctl 常设为 1,表示方向与电平由外设接管 |
int gpio_disable_fun_output_port(u32 gpio) | 释放 IO 的外设输出控制,恢复普通 IO |
int gpio_set_fun_input_port(u32 gpio, enum PFI_TABLE pfun) | 把外设输入信号(如 PFI_UART0_RX)接到指定 IO |
int gpio_disable_fun_input_port(enum PFI_TABLE pfun) | 释放某外设输入的 IO 占用 |
头文件给出了标准使用顺序(UART0 TX 输出到 IO_PORTA_05):
// gpio_direction_output(IO_PORTA_05, 1); //设置IO为输出状态
// gpio_set_fun_output_port(IO_PORTA_05, FO_UART0_TX, 1, 1); //将UART0的Tx信号输出到IO_PORTA_05口
Source: gpio.h
输入方向(UART0 RX 从 IO_PORTA_05 输入)的约定是:先 gpio_set_die(pin, 1) 使能数字输入,再 gpio_set_pull_up(pin, 1) 上拉,然后 gpio_direction_input(),最后 gpio_set_fun_input_port(IO_PORTA_05, PFI_UART0_RX)。这个顺序保证在信号接驳前引脚已经是稳定的数字输入态,避免误触发。
ADC 驱动
adc_api.h 定义了完整的 ADC 通道体系:14 个模拟输入通道(PA1/PA3/PA5/PA7/PA8/PA9、PB1/PB4/PB6、DP/DM/DP1/DM1、PMU)加上 PMU 内部通道(VBG 基准、SYSVDD、VBAT 1/4 分压、LDO5V 1/4 分压、DIE 温度等):
#define AD_CH_PA1 (0x0)
#define AD_CH_PA8 (0x4)
#define AD_CH_PB1 (0x7)
#define AD_CH_PMU (0xd)
#define ADC_PMU_CH_VBG (0x0<<16) //MVBG
#define ADC_PMU_CH_VBAT (0x5<<16) //1/4vbat
#define ADC_PMU_CH_LDO5V (0x6<<16) //1/4 LDO5V
#define ADC_PMU_CH_DTEMP (0x3<<16)
#define AD_CH_PMU_VBG (AD_CH_PMU | ADC_PMU_CH_VBG)
#define AD_CH_VBAT (AD_CH_PMU | ADC_PMU_CH_VBAT)
#define AD_CH_LDO5V (AD_CH_PMU | ADC_PMU_CH_LDO5V)
#define AD_CH_LDOREF AD_CH_PMU_VBG
Source: adc_api.h
通道号编码技巧:低 16 位放物理通道,高 16 位放 PMU 子通道,通过 AD_CH_PMU | ADC_PMU_CH_xxx 组合出内部通道。AD_CH_LDOREF 即内部 VBG 基准,是电压换算的参考值来源。
核心 API:
| 函数 | 模式 | 说明 |
|---|---|---|
void adc_init(void) | — | ADC 模块初始化 |
u32 adc_get_value(u32 ch) | 同步 | 死等转换结束返回 AD 值,简单但阻塞 |
void adc_get_value_by_isr(u32 ch, void (*cbfun)(u8, u16)) | 异步 | 使能采样后立即返回,转换完成中断里执行回调 |
u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val) | — | 用 VBG 基准 AD 值换算通道电压(mV) |
u32 adc_get_voltage(u32 ch) | 同步 | 一步获取通道电压(mV),内部完成基准采样+换算 |
void adc_test(void) | — | SDK 参考示例 |
设计意图:同步模式适合初始化自检、低频轮询;异步中断模式适合电源监测等需要"采完就走、不阻塞主循环"的场景,回调签名 void(*)(u8, u16) 携带通道号与 16 位 AD 值。电压换算不依赖固定满量程,而是实时采样 AD_CH_LDOREF 基准再按比例计算,从而抵消 VDD 波动对采样精度的干扰。
IIC 驱动
AC632N 同时提供两套 IIC 实现:硬件 IIC(iic_hw.h / iic_hw.c,占用片内 IIC 外设)与软件模拟 IIC(iic_soft.h / iic_soft.c,GPIO 位翻转模拟时序)。
硬件 IIC
iic_hw.h 是典型的寄存器宏封装头:全部时序控制以宏方式映射到 CON0/BAUD/BUF/ADR/CNT 寄存器位,分为公共、主机、从机三组:
#define iic_enable(reg) (reg->CON0 |= BIT(0))
#define iic_kick_start(reg) (reg->CON0 |= BIT(1))
#define iic_isel_filter(reg) (reg->CON0 |= BIT(3))
#define iic_dir_in(reg) (reg->CON0 |= BIT(4))
#define iic_int_enable(reg) (reg->CON0 |= BIT(8))
#define iic_is_pnding(reg) ((reg->CON0 & BIT(31)))
#define iic_force_nack(reg) (reg->CON0 |= BIT(11))
#define iic_restart(reg) (reg->CON0 |= BIT(13)) //没有stop, 发start
#define iic_host_mode(reg) (reg->CON0 &= ~BIT(2))
#define iic_host_send_stop(reg) (reg->CON0 |= BIT(5))
#define iic_host_is_stop_pending(reg) ((reg->CON0 & BIT(29)))
#define iic_host_send_is_ack(reg) ((reg->CON0 & BIT(30)))
#define iic_host_dma_send_enable(reg) (reg->CON0 |= BIT(17))
#define iic_slave_mode(reg) (reg->CON0 |= BIT(2))
#define iic_slave_dma_enable(reg) (reg->CON0 |= BIT(15))
#define iic_slave_dma_buf(reg) (reg->ADR)
#define iic_slave_dma_buf_depth(reg)(reg->CNT)
#define iic_slave_scl_pull_down_enble(reg) (reg->CON0 |= BIT(12))
#define iic_slave_is_required_send(reg) (reg->CON0 & BIT(28))
#define iic_slave_send_is_end(reg) (reg->CON0 & BIT(27))
Source: iic_hw.h
位定义的设计要点:方向位(BIT4)、中断位(BIT8)、主从模式位(BIT2)共用同一个 CON0 寄存器,因此宏按位操作而非常量赋值——避免并发配置时互相覆盖;iic_kick_start/iic_host_read_kick_start 是"启动"位,写 1 即触发一次总线动作,完成状态通过 iic_is_pnding/iic_host_is_stop_pending/iic_host_send_is_ack 查询。
句柄与配置表:hw_iic_dev 是 const int 句柄,索引平台配置表 hw_iic_cfg[],每个条目描述端口、波特率与角色:
typedef const int hw_iic_dev;
enum {IIC_MASTER, IIC_SLAVE};
struct hw_iic_config {
u8 port[2];
u32 baudrate;
u8 hdrive;
u8 io_filter;
u8 io_pu;
u8 role;
};
extern const struct hw_iic_config hw_iic_cfg[];
Source: iic_hw.h
API 分为生命周期(hw_iic_init / hw_iic_uninit / hw_iic_suspend / hw_iic_resume)、总线控制(hw_iic_start / hw_iic_stop)、单字节收发(hw_iic_tx_byte / hw_iic_rx_byte)与批量收发(hw_iic_read_buf / hw_iic_write_buf)以及 hw_iic_set_baud。约定:tx_byte 返回 1 表示收到 ACK;批量接口返回实际长度,< 0 表示失败。suspend/resume 与 uninit/init 的区别在于:前者保留配置、仅停用外设(低功耗挂起场景),后者彻底释放资源。
软件模拟 IIC
iic_soft.h / iic_soft.c 提供不依赖片内外设的 GPIO 位操作 IIC,适用于引脚数量紧张或硬件 IIC 已被占用的场景。其接口形态与硬件版对等(初始化、起始/停止、读写字节/缓冲),实现上通过 gpio_set_direction / gpio_write / gpio_read 在 SCL/SDA 上逐位翻转时序。选择建议:总线速率要求高、或需要 DMA/多从机仲裁时用硬件 IIC;只是低速挂接 EEPROM/传感器时,软件 IIC 可节省片内外设资源(BSP 中 iic_eeprom_test.c 即典型应用场景)。
其他 BSP 外设模块
src/ 下还有若干面向产品功能的外设驱动,均遵循"头文件声明 + 配置表 + 回调"的同一风格:
| 模块 | 源文件 | 职责 |
|---|---|---|
| MCPWM | mcpwm.c | 多通道 PWM,支持 4 组定时器时钟输入与 A/B/C/D 故障引脚(见 PFI_MCPWM_*),用于电机/背光等驱动 |
| 脉冲计数 | plcnt.c | 脉冲计数/编码器计数,输入可来自 PFI_GP_ICHx 或 PFI_RDECx_DATx |
| 按键驱动 | key_driver.c | 矩阵/AD 按键扫描、去抖与事件上报 |
| 端口唤醒 | port_wkup.c | 低功耗模式下 IO 电平变化唤醒,复用 gpio_set_pull_up 等配置 |
| 充电检测 | charge.c | 充电状态监测,依赖扩展 IO IO_CHGFL_DET / IO_VBGOK_DET / IO_VBTCH_DET / IO_LDOIN_DET |
| 调试串口 | debug_uart.c | 早期打印与调试通道,通常独占一路 UART(PFI_UARTx_RX 输入侧) |
| 硬件中断 | hwi.c | 中断控制器封装,供驱动注册 ISR(ADC 异步回调即挂在此机制上) |
注:以上模块的接口细节未在本次文档采集中逐一定位,具体函数签名请以对应头文件为准;本文档侧重共享的引脚/寄存器/复用机制。
Core Flow
CrossBar 外设复用配置流程
flowchart TD
Start([配置外设复用]) --> Die["gpio_set_die(pin, 1)<br/>使能数字功能"]
Die --> Dir{"输入 or 输出?"}
Dir -->|"输入 (如 UART RX)"| Pull["gpio_set_pull_up(pin, 1)<br/>上拉稳定电平"]
Pull --> In["gpio_direction_input(pin)"]
In --> MapIn["gpio_set_fun_input_port(pin, PFI_UART0_RX)"]
Dir -->|"输出 (如 UART TX)"| Out["gpio_direction_output(pin, 1)<br/>设为输出"]
Out --> MapOut["gpio_set_fun_output_port(pin, FO_UART0_TX, 1, 1)"]
MapIn --> Done([外设信号生效])
MapOut --> Done
ADC 异步采样时序
sequenceDiagram
participant App as 应用
participant ADC as ADC 驱动 (adc.c)
participant HWI as 中断控制器 (hwi.c)
participant REG as ADC 寄存器
App->>ADC: adc_init()
ADC->>REG: 初始化时钟/通道选择
App->>ADC: adc_get_value_by_isr(ch, cbfun)
ADC->>REG: 使能通道并启动转换
ADC-->>App: 立即返回(不死等)
REG->>HWI: 转换完成触发中断
HWI->>ADC: 进入 ISR
ADC->>App: cbfun(ch, adc_val) 回调
App->>ADC: adc_value_to_voltage(adc_vbg, adc_val)
App->>App: 得到 mV 电压值
流程要点:异步模式下调用方在 adc_get_value_by_isr 返回后即可继续主循环,转换结果经中断回调送达,适合周期性电源监测;同步模式 adc_get_value 则是同一驱动的简化路径——使能、轮询 pending 位、返回 AD 值,用阻塞换代码简洁。
Usage Examples
GPIO:LED 输出 + 按键输入(典型板级用法)
// 设置 PA1 为输出并输出高电平(点亮 LED)
gpio_direction_output(IO_PORTA_01, 1);
// 设置 PA3 为输入并开启上拉(按键按下拉低)
gpio_direction_input(IO_PORTA_03);
gpio_set_pull_up(IO_PORTA_03, 1);
// 读取按键电平
int key_level = gpio_read(IO_PORTA_03);
Source: gpio.h(API 行为定义)
ADC:同步采电压
u32 vbat_mv = adc_get_voltage(AD_CH_VBAT); // 电池电压(mV,内部已做 1/4 分压补偿前的换算)
u32 temp_mv = adc_get_voltage(AD_CH_DTEMP); // 芯片温度对应电压
Source: adc_api.h(
adc_get_voltage契约)
IIC:硬件 IIC 向 EEPROM 写读一字节
hw_iic_dev iic = 0; // 句柄,索引 hw_iic_cfg[0]
hw_iic_init(iic); // 按配置表初始化
hw_iic_start(iic); // 产生起始条件
hw_iic_tx_byte(iic, (dev_addr << 1) | 0); // 发送设备地址+写位,返回 1 表示 ACK
hw_iic_tx_byte(iic, reg_addr); // 发送寄存器地址
hw_iic_tx_byte(iic, data); // 写数据
hw_iic_stop(iic); // 产生停止条件
u8 ack = hw_iic_tx_byte(iic, byte); // 单字节发送可获取应答状态
u8 rx = hw_iic_rx_byte(iic, 1); // 读 1 字节并回 ACK
Source: iic_hw.h(收发接口契约)
Configuration Options
| 配置项 | 类型 | 默认/取值范围 | 说明 |
|---|---|---|---|
IO_GROUP_NUM | 宏 | 16 | 每组端口引脚容量,决定 IO_PORTx_yy 线性编号步长 |
enum gpio_direction | 枚举 | GPIO_OUT=0 / GPIO_IN=1 | 方向语义,与 gpio_set_direction 的 value 对应 |
enum gpio_op_mode | 枚举 | GPIO_SET/AND/OR/XOR | 多引脚批量位操作模式(GPIO_SET=1 起) |
hw_iic_cfg[].port[2] | u8[2] | 平台配置表定义 | 硬件 IIC 的 SCL/SDA 引脚编号 |
hw_iic_cfg[].baudrate | u32 | 配置表定义 | IIC 总线波特率 |
hw_iic_cfg[].role | u8 | IIC_MASTER / IIC_SLAVE | 主/从角色,决定 CON0 BIT2 置位方式 |
hw_iic_cfg[].hdrive / .io_filter / .io_pu | u8 | 0/1 | 驱动能力、输入滤波(iic_isel_filter)、上拉开关 |
AD_CH_* | 宏 | 0x0~0xd | ADC 物理通道编号(低 16 位) |
ADC_PMU_CH_* | 宏 | 0x0<<16~0xe<<16 | PMU 内部通道(高 16 位),与 AD_CH_PMU 组合使用 |
hw_iic_dev | const int | 0(IIC_HW_NUM=1) | IIC 句柄,本芯片仅 1 路硬件 IIC |
配置哲学:BSP 不把外设参数散落在业务代码里,而是收敛到 hw_iic_cfg[] 这类平台配置表(定义于 src/ 实现中),应用层只传句柄。改板卡只需改配置表,不动调用代码。
API Reference
GPIO
int gpio_set_direction(u32 gpio, u32 value)
- 参数:
gpio引脚宏(如IO_PORTA_00);value1=输入,0=输出。 - 返回:0 成功,非 0 失败(越界引脚)。
- 别名封装:
gpio_direction_input(gpio)、gpio_direction_output(gpio, value)。
int gpio_read(u32 gpio) / int gpio_read_input_value(u32 gpio)
- 参数:
gpio引脚宏。 - 返回:输入电平值;仅在输入模式下有效。
int gpio_write(u32 gpio, u32 value) / int gpio_set_output_value(u32 gpio, u32 value)
- 参数:
gpio引脚宏;value1 输出高,0 输出低。 - 返回:0 成功,非 0 失败;仅在输出模式下有效。
int gpio_set_pull_up(u32 gpio, u32 value) / gpio_set_pull_down(u32 gpio, u32 value)
- 参数:
gpio;value1 使能 10K 上/下拉。 - 返回:0 成功,非 0 失败;输入模式下才有效。
int gpio_set_die(u32 gpio, u32 value)
- 参数:
gpio;value1=数字功能,0=模拟功能(ADC 输入场景)。 - 返回:0 成功,非 0 失败。
u32 get_gpio(const char *p)
- 参数:引脚字符串,如
"PA00"、"PB01"。 - 返回:引脚线性序号(
"PB01"→ 17)。
int gpio_set_fun_output_port(u32 gpio, u32 fun_index, u8 dir_ctl, u8 data_ctl)
- 参数:
gpio目标 IO;fun_index输出功能索引(见io_omap.h的FO_*);dir_ctl/data_ctl置 1 表示方向/电平由外设接管。 - 返回:0 正确;
-EINVAL传参出错。 - 前置:IO 需先配置为输出(
gpio_direction_output)。
int gpio_set_fun_input_port(u32 gpio, enum PFI_TABLE pfun)
- 参数:
gpio目标 IO;pfun输入功能索引(见enum PFI_TABLE,如PFI_UART0_RX)。 - 返回:0 正确;
-EINVAL传参出错。 - 前置:IO 需先配置为数字输入(
gpio_set_die(pin,1)+gpio_direction_input)。
ADC
u32 adc_get_value(u32 ch)
- 参数:
ch通道宏(AD_CH_PA1、AD_CH_VBAT等)。 - 返回:当前通道 AD 值;同步死等模式,转换完成才返回。
void adc_get_value_by_isr(u32 ch, void (*cbfun)(u8, u16))
- 参数:
ch通道号;cbfun中断回调,形参为(通道号, 16 位 AD 值)。 - 返回:无;使能采样后立即返回,转换结束在中断上下文执行回调。
u32 adc_value_to_voltage(u32 adc_vbg, u32 adc_ch_val)
- 参数:
adc_vbg基准通道(AD_CH_LDOREF)AD 值;adc_ch_val目标通道 AD 值。 - 返回:目标通道电压,单位 mV。
u32 adc_get_voltage(u32 ch)
- 参数:
ch通道宏。 - 返回:通道电压(mV),内部自动完成基准采样与换算。
硬件 IIC
int hw_iic_init(hw_iic_dev iic)
- 参数:
iic句柄(索引hw_iic_cfg[])。 - 返回:0 成功,< 0 失败。
u8 hw_iic_tx_byte(hw_iic_dev iic, u8 byte)
- 参数:
iic句柄;byte待发字节。 - 返回:1 收到 ACK,0 未收到 ACK。
u8 hw_iic_rx_byte(hw_iic_dev iic, u8 ack)
- 参数:
iic句柄;ack1=收后回 ACK,0=不回 ACK。 - 返回:接收到的字节。
int hw_iic_read_buf(hw_iic_dev iic, void *buf, int len) / hw_iic_write_buf(hw_iic_dev iic, const void *buf, int len)
- 参数:
iic句柄;buf缓冲区;len期望长度。 - 返回:实际收发长度;< 0 表示失败。
int hw_iic_set_baud(hw_iic_dev iic, u32 baud)
- 参数:
iic句柄;baud目标波特率。 - 返回:0 成功,< 0 失败。
Failure Modes, Edge Cases & Concurrency
- 引脚参数越界:GPIO 系列函数对
gpio >= IO_PORT_MAX或非法端口组返回非 0 失败;gpio_set_fun_output_port/gpio_set_fun_input_port以-EINVAL区分传参错误。应用应先get_gpio()或宏常量校验,避免把 USB/P33 扩展 IO 直接当作普通 IO 配置。 - 数字/模拟功能误配:ADC 输入通道若未
gpio_set_die(pin, 0),数字缓冲仍使能,模拟采样会被数字通路干扰甚至损坏信号完整性——这是外设复用时最常见的"能采到值但不准"问题。 - IIC 无应答:
hw_iic_tx_byte返回 0 表示从机未 ACK(地址错误、器件不在线、总线被拉死)。上拉电阻(io_pu)与波特率(baudrate)配置不当会导致 NACK 或数据错位。 - IIC 主从模式互斥:
IIC_HW_NUM = 1表明芯片仅一路硬件 IIC,主机与从机角色互斥;同时需要两路 IIC 总线时必须启用软件 IIC 作为第二路。 - 中断回调上下文:
adc_get_value_by_isr的回调在中断上下文执行,回调内禁止阻塞等待(如死等另一路 ADC、打印长日志),应只做标记/置标志/搬数据。 - 并发访问:寄存器宏均为位操作(
|=/&=),对同一 CON0 的不同位并发配置不会互相覆盖;但应用层对同一外设的两次事务(如两次hw_iic_write_buf)需自行保证串行化,BSP 不提供互斥锁。 - CrossBar 占用冲突:同一外设信号只能路由到一个 IO(输入侧),同一 IO 也只能承载一个输出功能;重复
gpio_set_fun_input_port会覆盖旧映射,释放时须配对调用gpio_disable_fun_*_port。
Performance & Operational Considerations
- 同步 ADC 采样阻塞时长:
adc_get_value死等转换,高频调用会拖慢主循环;周期性电源监测建议改用adc_get_value_by_isr+ 中断回调。 - IIC 批量收发:优先用
hw_iic_read_buf/hw_iic_write_buf代替逐字节tx_byte循环,减少总线起停开销;主机批量读时可配合iic_host_receive_continue_byte连续收字节。 - GPIO 驱动能力:长走线/大负载场景用
gpio_set_hd(gpio, 1)增大输出电流、gpio_set_hd0(gpio, 1)关闭内阻增强输出,降低压降与边沿劣化。 - 低功耗挂起:进入低功耗前对 IIC 等外设调用
suspend而非uninit,恢复时resume可保留配置,减少重初始化开销;USB 引脚复用为普通 IO 需先usb_iomode(1)。 - 调试串口独占:
debug_uart.c通常独占一路 UART,量产固件可关闭以释放PFI_UARTx_RX/FO_UARTx_TX给业务使用。
Extension Points
- 新增外设实例:扩展
hw_iic_cfg[]配置表条目即可增加硬件 IIC 实例(受IIC_HW_NUM限制);软件 IIC 无数量硬限制,只需分配 SCL/SDA 引脚。 - 自定义引脚字符串解析:
get_gpio()支持"PAxx"文本解析,板级配置(如board_demo.c)可把管脚表写成字符串数组,便于按板卡切换。 - ADC 回调链:
adc_get_value_by_isr的回调机制与hwi.c中断框架解耦,业务可注册自己的通道回调而不侵入驱动。 - CrossBar 功能扩展:
io_imap.h/io_omap.h定义了完整的输入/输出功能表,新外设信号(如 RDEC、CHAIN)可直接通过PFI_*/FO_*枚举路由,无需改动 GPIO 驱动本体。
Tests
BSP 层以参考示例形式提供自测入口:adc_test()(ADC 各通道采样打印)、iic_eeprom_test.c(硬件/软件 IIC 读写 EEPROM 验证)以及 board_demo.c/test.c 中的板级外设演示。这些示例同时充当 API 的"活文档":新板卡 bring-up 时可先跑通 ADC 电压换算与 IIC 读写,再接入业务逻辑。驱动本身的寄存器级行为验证依赖上述示例在目标板上的人工/自动化比对。
Related Links
- GPIO 头文件 — 引脚宏、寄存器结构、CrossBar API 完整定义
- ADC 接口头文件 — 通道定义与采样 API
- 硬件 IIC 头文件 — 寄存器宏与主从模式 API
- BSP 驱动实现目录 — gpio.c / adc.c / iic_hw.c / iic_soft.c / mcpwm.c / plcnt.c / key_driver.c / port_wkup.c / charge.c / debug_uart.c
- IO 输入映射头文件 — CrossBar 输入信号表(
PFI_*) - IO 输出映射头文件 — CrossBar 输出信号表(
FO_*) - 相关目录页:时钟与电源管理、系统启动与中断(
hwi.h/boot.h)、板级配置(board_demo.c)