Tool/software:
Hi,
I'm using Processor SDK RTOS 09-02-00-05 to develop applications on the SK-TDA4VM. I'm developing a low-level application for MCU1_0 based on pdk_jacinto_09_02_00_30/packages/ti/drv/sciclient/examples/sciserver_testapp. I want to extend the sciserver_testapp with I2C peripherals attached to bus I2C5, pinmuxed to Pin 3 (SDA, AA27) and Pin 5 (SCL, Y26) of the 40-pin RPi header (J3). I am using the PDK I2C driver.
I have successfully configured the pinmuxes and initialized the I2C5 peripheral in blocking mode. In pdk_jacinto_09_02_00_30/packages/ti/drv/i2c/soc/j721e/I2C_soc.c I found that I2C5 base address and interrupt pin numbers are not assigned in i2cInitCfg struct when BUILD_MCU macro is defined, which leads me to believe that I2C5 is not supported on MCU1_0, but if I set the base address manually during I2C initialization, then the peripheral works just fine. See I2C5 initialization code on MCU1_0 in blocking mode below:
I2C_Handle i2c_handle;
void i2c_init(void) {
I2C_HwAttrs i2cCfg;
I2C_socGetInitCfg(5, &i2cCfg);
i2cCfg.baseAddr = CSL_I2C5_CFG_BASE; // manually set base address
i2cCfg.enableIntr = false;
I2C_socSetInitCfg(5, &i2cCfg);
I2C_init();
I2C_Params i2cParams;
I2C_Params_init(&i2cParams);
i2cParams.bitRate = I2C_400kHz;
i2cParams.transferMode = I2C_MODE_BLOCKING;
i2cParams.transferCallbackFxn = NULL;
i2c_handle = I2C_open(5, &i2cParams);
}
Here is a successful I2C transaction with register writes and reads:
I want to achieve the same transaction in callback mode, but I'm running into issues when I try to read registers. From my understanding, I2C5 is not native to MCU domain, so I need to route I2C interrupts with Sciclient. If I initialize I2C5 with the following code, I can successfully write data in callback mode:
void i2c_callback(I2C_Handle i2cHnd, I2C_Transaction * msg, int16_t transferStatus) {
// do nothing for now
}
I2C_Handle i2c_handle;
void i2c_init(void) {
I2C_HwAttrs i2cCfg;
I2C_socGetInitCfg(5, &i2cCfg);
i2cCfg.baseAddr = CSL_I2C5_CFG_BASE;
i2cCfg.enableIntr = true;
i2cCfg.intNum = CSLR_R5FSS0_INTROUTER0_IN_I2C5_POINTRPEND_0;
I2C_socSetInitCfg(5, &i2cCfg);
I2C_init();
I2C_Params i2cParams;
I2C_Params_init(&i2cParams);
i2cParams.bitRate = I2C_400kHz;
i2cParams.transferMode = I2C_MODE_CALLBACK;
i2cParams.transferCallbackFxn = i2c_callback;
i2c_handle = I2C_open(5, &i2cParams);
/* Configure Interrupt routing through SCI Client */
struct tisci_msg_rm_irq_set_req rmIrqReq = {0};
struct tisci_msg_rm_irq_set_resp rmIrqResp = {0};
rmIrqReq.secondary_host = TISCI_MSG_VALUE_RM_UNUSED_SECONDARY_HOST;
rmIrqReq.valid_params |= TISCI_MSG_VALUE_RM_DST_ID_VALID;
rmIrqReq.valid_params |= TISCI_MSG_VALUE_RM_DST_HOST_IRQ_VALID;
rmIrqReq.dst_id = TISCI_DEV_MCU_R5FSS0_CORE0;
rmIrqReq.dst_host_irq = CSLR_R5FSS0_INTROUTER0_IN_I2C5_POINTRPEND_0;
rmIrqReq.src_id = TISCI_DEV_I2C5;
rmIrqReq.src_index = 0;
int32_t retVal = Sciclient_rmIrqSet(&rmIrqReq, &rmIrqResp, SCICLIENT_SERVICE_WAIT_FOREVER);
while (retVal != CSL_PASS);
}
Here is a successful register write in callback mode:
I can confirm with a Blackhawk debugger that i2c_callback is executed when a write transaction is finished. If I configure a simple binary semaphore, then I can do repeated writes as well.
If I want to read the same register in callback mode:
After the register address is transmitted, the transaction halts and SCL gets stuck. I am using PDK I2C_transfer function to initiate transactions. I2C_transfer returns I2C_STS_SUCCESS even when the transaction halts. After an I2C read halts like this, the driver gets stuck in an unknown state and I can no longer initiate any transactions. When the transaction halts, I2C_v1_hwiFxnMaster executes, but i2c_callback does not execute. It seems like the I2C driver is stuck waiting for an event at the end of the transmitted bytes. If I stop I2C_v1_hwiFxnMaster with a debugger breakpoint at the transaction halt point, and then resume program execution with a little delay, then the transaction finishes properly. Is it possible that the transmission end event is masked somehow? Am I missing something with my Sciclient configuration?
I noticed in the PDK I2C driver that if I2C is in callback mode, sequential calls to I2C_transfer will put transactions in an internal queue. If I understand correctly, queued transactions should automatically start when a previous transaction has completed. I didn't check the entire driver, but it seems that the transaction queue is a linked list of pointers to transactions. If I allocate the I2C_transaction structure as a local variable inside a function stack, and the local variable address is queued by the PDK driver, then the driver will use invalid memory addresses if the function stack is popped. Is this situation handled in the driver? Do I need to allocate transactions statically for the internal callback queue to work?
Best regards,
Akos Balogh