cancel
Showing results for 
Search instead for 
Did you mean: 

TCPP03 / X-NUCLEO-DRP1M1: Thread Safety and I2C Contention in FreeRTOS

mhd0425
Associate II

Hello, I am developing a project using the TCPP03 (X-NUCLEO-DRP1M1) and the ST USB-PD stack on an STM32G0 with FreeRTOS.

I am concerned about the thread safety of the FLGn interrupt handling. In the standard BSP examples, the EXTI interrupt calls BSP_USBPD_PWR_EventCallback().

  1. I2C Contention: Since BSP_USBPD_PWR_EventCallback() performs blocking I2C reads (ReadFlagRegister), what prevents the PE_Task or CAD_Task from attempting an I2C transaction at the same time?
  2. ISR Safety: In an RTOS environment, is it considered safe to perform blocking I2C calls inside the FLGn ISR, given the risk of HAL_BUSY or kernel priority issues?
  3. Best Practice: Does ST recommend a Deferred Interrupt pattern (e.g., using USBPD_DPM_CADTaskWakeUp) to move the I2C diagnostic logic out of the ISR and into a thread context?
2 REPLIES 2
Saket_Om
ST Employee

Hello @mhd0425 


@mhd0425 wrote:

I am concerned about the thread safety of the FLGn interrupt handling. In the standard BSP examples, the EXTI interrupt calls BSP_USBPD_PWR_EventCallback().


Which BSP example ?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

Hi Saket_Om,
X-CUBE-TCPP 4.2.0 downloaded from ST or GitHub. I followed this guide:
https://wiki.st.com/stm32mcu/wiki/STM32StepByStep:Getting_started_with_USB-Power_Delivery_Dual_Role

When a fault occurs, EXTI IRQ Handler is triggered. 

// File: TCPP/App/app_tcpp.c:60
void TCPP0203_PORT0_FLG_EXTI_IRQHANDLER(void)
{
  BSP_USBPD_PWR_EventCallback(USBPD_PWR_TYPE_C_PORT_1);
  TCPP0203_PORT0_FLG_EXTI_CLEAR_FLAG();
}


The IRQ handler calls the BSP layer EventCallback.

// File: Drivers/BSP/X-NUCLEO-DRP1M1/drp1m1_usbpd_pwr.c:1400
void BSP_USBPD_PWR_EventCallback(uint32_t PortNum)
{
  // ...
  case USBPD_PWR_HW_CONFIG_TYPE_TCPP03:
      PWR_TCPP0203_EventCallback(PortNum); // Calls the internal event handler
      break;
}


The internal event callback function immediately performs a register read over I2C to determine the cause of the interrupt.

// File: Drivers/BSP/X-NUCLEO-DRP1M1/drp1m1_usbpd_pwr.c:1897
static void PWR_TCPP0203_EventCallback(uint32_t PortNum)
{
  uint8_t flg_reg;
  // ...
  /* Read Flags register (FLGn) via I2C */
  if (USBPD_PWR_PortCompDrv[PortNum]->ReadFlagRegister(&USBPD_PWR_PortCompObj[PortNum], &flg_reg) == TCPP0203_OK)
  {
    // ... Logic to handle faults (may also call WriteCtrlRegister which is another I2C write)
  }
}


The ReadFlagRegister function maps to the component driver:

// File: Drivers/BSP/Components/tcpp0203/tcpp0203.c:762
int32_t TCPP0203_ReadFlagRegister(TCPP0203_Object_t *pObj, uint8_t *pFlagRegister)
{
  return tcpp0203_read_reg(&pObj->Ctx, TCPP0203_FLAG_REG, pFlagRegister, 1);
}


The driver calls the BSP layer:

// File: Drivers/BSP/X-NUCLEO-DRP1M1/drp1m1_bus.c:377
int32_t BSP_I2C_ReadReg(uint16_t DevAddr, uint16_t Reg, uint8_t *pData, uint16_t Length)
{
  // Final HAL I2C Call
  if (HAL_I2C_Mem_Read(&TCPP0X_HANDLE_I2C, DevAddr, (uint16_t)Reg, I2C_MEMADD_SIZE_8BIT, pData, Length, 0x1000) == HAL_OK)
  {
    return BSP_ERROR_NONE;
  }
  // ...
}