Tool/software:
Hi everyone,
I'm working on an I2C driver to meet a client's application requirements. I've broken down the I2C Controller operations into several phases:
i2c_start_write
i2c_start_read
i2c_write
i2c_read
i2c_stop
Currently, the write operations (start_write
→ write
) are functioning correctly. However, I'm encountering issues with the read operations (start_read
→ read
→ stop
). Here's what's happening:
Issue:
When I execute the following sequence:
start_write > write > start_read > read > stop

During the start_read
phase, the function DL_I2C_startControllerTransferAdvanced
automatically triggers a data read operation. This results in the read data clock being generated unexpectedly. Although the target address (addr
) is being sent out, the data read should not start automatically at this stage.
Expected Behavior:
In the start_read
phase, the system should:
- Generate the START condition.
- Send out the target address (
addr
). - Stop there without initiating the data read.
- The actual data read should be manually triggered in the subsequent
read
phase.
Relevant Code Snippet:
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;
}
Additional Context:
According to the I2C Controller documentation:
- To initiate a transfer, set the
START
bit in theMCTR
register to generate the START condition. The controller should then send the START condition followed by the target address once it detects the bus is free. - The
MBLEN
field specifies the number of bytes to transmit. SettingMBLEN
to0
may prevent the address from being sent correctly.
What I've Tried:
-
Ensuring
MBLEN
is Set Correctly:- Made sure that the
MBLEN
field is set to at least1
to guarantee the address is sent. - Enabled
BURSTRUN
to start the operation.
- Made sure that the
-
Adjusting
i2c_start_read
Function:- Flushed the RX FIFO and reset the transfer before setting the START condition.
- Confirmed that only the START condition is set without initiating any data operations.
Despite these changes, the issue persists where DL_I2C_startControllerTransferAdvanced
still automatically triggers a data read during the i2c_start_read
phase, causing the read data clock to be generated unexpectedly.
Normal Behavior Example:
When executing i2c_start_read
, the system should:
- Generate the START condition.
- Send out the target address (
addr
). - Stop without generating the read data clock.
- Manually trigger the data read in the
read
phase.
Any Suggestions or Solutions?
How can I modify the I2C controller operations to ensure that during the start_read
phase, only the START condition is generated without automatically initiating a data read? Is there a specific register setting or sequence of operations I might be missing?
Thanks in advance for your help!
Best regards,
Eason Tsai