工具与软件:
大家好!
我正在开发 I2C 驱动程序以满足客户端的应用要求。 我将 I2C 控制器操作分解成了几个阶段:
i2c_start_writei2c_start_readi2c_writei2c_readi2c_stop
目前、写操作(start_write→write)工作正常。 但是,我遇到了读取操作(start_read→read→stop)的问题。 下面是发生的情况:
问题:
当我执行以下序列时:
start_write > write > start_read > read > stop
在start_read该阶段、函数DL_I2C_startControllerTransferAdvanced自动触发数据读取操作。 这会导致读取数据时钟意外生成。 尽管addr正在发送目标地址()、但读取的数据应该是 不会 在此阶段自动启动。

预期行为:
在start_read该阶段、系统应:
- 生成起始条件。
- 发送目标地址
addr()。 - STOP (停止) 而不启动数据读取。
- 实际读取的数据应在后续
read阶段手动触发。
相关代码片段:
static bool i2c_start_read(void) {
// Wait until I2C controller is idle
if (!retry_until_condition(BUS0_I2C_INST, MAX_RETRIES, 10, is_i2c_idle)) {
uart_printf("%s I2C not idle; retry limit reached before starting read transfer\n", TAG);
return false;
}
// Flush RX FIFO and reset transfer
DL_I2C_flushControllerRXFIFO(BUS0_I2C_INST);
DL_I2C_resetControllerTransfer(BUS0_I2C_INST);
// Set only the START condition, print debug message
#if DEBUG_START
uart_printf("%s Starting I2C read transfer (START only)\n", TAG);
#endif
DL_I2C_startControllerTransferAdvanced(
BUS0_I2C_INST,
addr,
DL_I2C_CONTROLLER_DIRECTION_RX,
0, // Transmission length set to 0
DL_I2C_CONTROLLER_START_ENABLE,
DL_I2C_CONTROLLER_STOP_DISABLE,
DL_I2C_CONTROLLER_ACK_ENABLE
);
// Check for transfer errors
if (DL_I2C_getControllerStatus(BUS0_I2C_INST) & DL_I2C_CONTROLLER_STATUS_ERROR) {
uart_printf("%s Read start transfer error\n", TAG);
return false;
}
return true;
}
其他上下文:
根据 I2C 控制器文档:
- 要启动传输、请将
STARTMCTR寄存器中的位置位以生成启动条件。 一旦控制器检测到总线空闲、就应发送启动条件、后跟目标地址。 - 该
MBLEN域指定要发送的字节数。 将设置MBLEN为0可能会阻止正确发送地址。
我尝试过的:
-
确保
MBLEN设置正确:- 确保该
MBLEN字段至少设置为1以保证发送地址。 BURSTRUN以开始操作。
- 确保该
-
调节
i2c_start_read功能:- 在设置启动条件之前、清空 RX FIFO 并复位传输。
- 已确认在不启动任何数据操作的情况下仅设置 START 条件。
尽管进行了这些更改、但问题仍然存在、在DL_I2C_startControllerTransferAdvancedi2c_start_read该阶段仍会自动触发数据读取、从而导致意外生成读取数据时钟。
正常行为示例:
执行时i2c_start_read、系统应:
- 生成起始条件。
- 发送目标地址
addr()。 - STOP (停止) 而不生成读取数据时钟。
- 手动触发在此
read阶段读取的数据。
有任何建议或解决方案?
我如何修改 I2C 控制器操作、以确保在start_read该阶段仅生成启动条件、而不自动启动数据读取? 是否存在可能缺失的特定寄存器设置或操作顺序?
提前感谢您的帮助!
此致、
蔡奕迅

