1. 简介 #
集成电路总线 (I²C) 是一种广泛使用的低速、双线通信协议,专为集成电路之间的通信而设计。在嵌入式系统中,通常通过 I²C 连接传感器、EEPROM、ADC 和其他外设。
VxWorks 7引入了一个现代、可扩展和模块化的驱动程序框架,该框架基于 VxBus 构建,支持动态驱动程序注册、设备树集成和电源管理。对于 BSP(板级支持包)开发人员来说,了解如何创建健壮的 I²C 设备驱动程序对于支持定制硬件平台上各种 I²C 连接的外设至关重要。
本文面向已经熟悉 BSP 架构、内存映射和设备树的经验丰富的 VxWorks BSP 开发人员。它旨在演示如何开发 I²C 主控制器驱动程序,以及使用 VxWorks 7 驱动程序模型的基本 I²C 外设驱动程序示例。
我们将使用一个通用的内存映射 I²C 主控制器作为参考,以说明关键概念并提供可供构建的实际代码片段。
2. VxWorks 7 I2C 驱动程序架构 #
2.1 VxBus 概述 #
VxBus 是 VxWorks 的设备驱动程序框架,它抽象了硬件细节,并提供了一种模块化、分层的方式来管理驱动程序和设备。它支持通过设备树自动进行设备匹配,并管理生命周期回调,例如 probe、attach 和 detach。
对于 I²C,VxBus 区分两种类型的驱动程序:
-
I²C 控制器驱动程序(主/总线驱动程序): 直接与硬件(I²C 控制器)接口。注册为总线并实现
vxbI2cDevXfer()
API。 -
I²C 外设驱动程序(客户端/从设备驱动程序): 使用控制器驱动程序公开的 API 与 I²C 总线上 的设备通信。
2.2 关键组件和接口 #
vxbI2cLib.h
: I²C 消息传递和控制器 APIVXB_I2C_BUS_METHODS
: I²C 总线驱动程序的方法表vxbFdtLib.h
: 设备树解析实用程序
2.3 典型调用流程 #
- 启动时解析设备树
- 控制器驱动程序被探测 (probed) 和连接 (attached)
- 使用
vxbI2cBusDevRegister()
注册总线 - 外设驱动程序使用
vxbI2cDevXfer()
进行通信
3. 示例 I²C 控制器:通用 I²C 主机 #
3.1 控制器寄存器布局 #
寄存器 | 偏移量 | 描述 |
---|---|---|
CTRL |
0x00 | 控制寄存器 |
STATUS |
0x04 | 状态寄存器 |
DATA |
0x08 | 数据寄存器 |
CLK_DIV |
0x0C | 时钟分频寄存器 |
3.2 寄存器位定义 #
#define I2C_CTRL_START (1 << 0)
#define I2C_CTRL_STOP (1 << 1)
#define I2C_CTRL_READ (1 << 2)
#define I2C_CTRL_WRITE (1 << 3)
#define I2C_STATUS_BUSY (1 << 0)
#define I2C_STATUS_ACK (1 << 1)
#define I2C_REG_CTRL 0x00
#define I2C_REG_STATUS 0x04
#define I2C_REG_DATA 0x08
#define I2C_REG_CLK_DIV 0x0C
4. 编写 I²C 控制器驱动程序 #
4.1 寄存器访问辅助函数 #
#define I2C_READ_REG(base, offset) (*(volatile UINT32 *)((UINT8 *)(base) + (offset)))
#define I2C_WRITE_REG(base, offset, v) (*(volatile UINT32 *)((UINT8 *)(base) + (offset)) = (v))
4.2 数据结构 #
typedef struct i2cGenDrvCtrl
{
VXB_DEV_ID dev;
void *regBase;
VXB_RESOURCE *pRes;
} I2C_GEN_DRV_CTRL;
LOCAL VXB_DRV_METHOD i2cGenDrvMethods[] =
{
{ VXB_DEVMETHOD_CALL(vxbDevProbe), i2cDrvProbe },
{ VXB_DEVMETHOD_CALL(vxbDevAttach), i2cDrvAttach },
{ 0, NULL }
};
4.3 探测 (Probe) 和连接 (Attach) #
LOCAL STATUS i2cDrvProbe(VXB_DEV_ID pDev)
{
return vxbFdtDevMatch(pDev, NULL);
}
LOCAL STATUS i2cDrvAttach(VXB_DEV_ID pDev)
{
I2C_GEN_DRV_CTRL *pDrvCtrl;
void *regBase;
pDrvCtrl = (I2C_GEN_DRV_CTRL *) vxbMemAlloc(sizeof(I2C_GEN_DRV_CTRL));
if (pDrvCtrl == NULL) return ERROR;
pDrvCtrl->dev = pDev;
regBase = (void *)vxFdtRegGet(pDev, 0);
if (regBase == NULL)
{
vxbMemFree(pDrvCtrl);
return ERROR;
}
pDrvCtrl->regBase = regBase;
vxbDevSoftcSet(pDev, pDrvCtrl);
return vxbI2cBusDevRegister(pDev);
}
4.4 实现 vxbI2cDevXfer()
#
LOCAL STATUS i2cDevXfer(VXB_DEV_ID dev, VXB_I2C_MSG *msgs, int num)
{
I2C_GEN_DRV_CTRL *pDrvCtrl = vxbDevSoftcGet(dev);
void *base = pDrvCtrl->regBase;
for (int i = 0; i < num; i++)
{
VXB_I2C_MSG *msg = &msgs[i];
for (int j = 0; j < msg->len; j++)
{
I2C_WRITE_REG(base, I2C_REG_DATA, msg->buf[j]);
UINT32 ctrl = (msg->flags & VXB_I2C_M_RD) ? I2C_CTRL_READ : I2C_CTRL_WRITE;
if (j == 0) ctrl |= I2C_CTRL_START;
if (j == msg->len - 1) ctrl |= I2C_CTRL_STOP;
I2C_WRITE_REG(base, I2C_REG_CTRL, ctrl);
while (I2C_READ_REG(base, I2C_REG_STATUS) & I2C_STATUS_BUSY);
if (!(I2C_READ_REG(base, I2C_REG_STATUS) & I2C_STATUS_ACK))
return ERROR;
if (msg->flags & VXB_I2C_M_RD)
msg->buf[j] = I2C_READ_REG(base, I2C_REG_DATA);
}
}
return OK;
}
LOCAL VXB_I2C_BUS_METHODS i2cBusMethods =
{
.i2cDevXfer = i2cDevXfer,
.i2cDevXferTimeout = NULL
};
5. 设备树集成 #
5.1 示例设备树片段 #
i2c@4000f000 {
compatible = "generic,i2c-master";
reg = <0x4000f000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
status = "okay";
eeprom@50 {
compatible = "atmel,24c32";
reg = <0x50>;
};
};
6. 编写一个示例 I²C 外设驱动程序:EEPROM #
6.1 连接 (Attach) 例程 #
LOCAL STATUS eepromAttach(VXB_DEV_ID pDev)
{
VXB_I2C_MSG msg[2];
UINT8 addr = 0x00;
UINT8 data;
msg[0].addr = 0x50;
msg[0].flags = 0;
msg[0].buf = &addr;
msg[0].len = 1;
msg[1].addr = 0x50;
msg[1].flags = VXB_I2C_M_RD;
msg[1].buf = &data;
msg[1].len = 1;
if (vxbI2cDevXfer(pDev, msg, 2) == OK)
printf("EEPROM read success: 0x%02x\n", data);
else
printf("EEPROM read failed\n");
return OK;
}
7. 测试和调试 #
-
常用命令:
i2cShow
: 显示已注册的 I²C 总线和设备vxbDevShow
: 显示所有 VxBus 设备
-
调试技巧:
- 验证设备树兼容性字符串
- 检查 ACK 和 STOP 条件
- 使用逻辑分析仪进行信号追踪
8. 结论 #
在本文中,我们介绍了为 VxWorks 7 设计通用 I²C 设备驱动程序的过程,涵盖了:
- VxBus 和 I²C 驱动程序结构
- 寄存器级 I²C 控制器驱动程序实现
- 设备树绑定
- 外围设备通信
- 测试和调试
这个基本框架可以通过以下方式进行扩展:
- 支持重复启动 (Repeated START)
- 集成中断/DMA
- 支持多总线
- 复杂的外部设备驱动程序(例如,传感器、编解码器)
Happy hacking with VxWorks! 🔧🛠️