Files
alim_STM32/USBPD/usbpd_dpm_core.c
2025-05-14 10:54:37 +02:00

464 lines
13 KiB
C

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file usbpd_dpm_core.c
* @author MCD Application Team
* @brief USBPD dpm core file
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
#define __USBPD_DPM_CORE_C
/* Includes ------------------------------------------------------------------*/
#include "usbpd_core.h"
#include "usbpd_trace.h"
#include "usbpd_dpm_core.h"
#include "usbpd_dpm_conf.h"
#include "usbpd_dpm_user.h"
#if defined(USE_STM32_UTILITY_OS)
#include "utilities_conf.h"
#endif /* USE_STM32_UTILITY_OS */
/* Generic STM32 prototypes */
extern uint32_t HAL_GetTick(void);
/* Private function prototypes -----------------------------------------------*/
/* !FREERTOS */
void USBPD_CAD_Task(void);
#if defined(USE_STM32_UTILITY_OS)
void TimerCADfunction(void *);
#endif /* USE_STM32_UTILITY_OS */
void USBPD_PE_Task_P0(void);
void USBPD_PE_Task_P1(void);
#if defined(USE_STM32_UTILITY_OS)
void TimerPE0function(void *pArg);
void TimerPE1function(void *pArg);
#endif /* USE_STM32_UTILITY_OS */
void USBPD_TaskUser(void);
/* Private typedef -----------------------------------------------------------*/
/* !_RTOS */
#if defined(USE_STM32_UTILITY_OS)
UTIL_TIMER_Object_t TimerCAD;
UTIL_TIMER_Object_t TimerPE0, TimerPE1;
#endif /* USE_STM32_UTILITY_OS */
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
#define CHECK_PE_FUNCTION_CALL(_function_) _retr = _function_; \
if(USBPD_OK != _retr) {return _retr;}
#define CHECK_CAD_FUNCTION_CALL(_function_) if(USBPD_CAD_OK != _function_) {return USBPD_ERROR;}
#if defined(_DEBUG_TRACE)
#define DPM_CORE_DEBUG_TRACE(_PORTNUM_, __MESSAGE__) USBPD_TRACE_Add(USBPD_TRACE_DEBUG, _PORTNUM_, 0u, (uint8_t *)(__MESSAGE__), sizeof(__MESSAGE__) - 1u);
#else
#define DPM_CORE_DEBUG_TRACE(_PORTNUM_, __MESSAGE__)
#endif /* _DEBUG_TRACE */
/* Private variables ---------------------------------------------------------*/
#if !defined(USE_STM32_UTILITY_OS)
#define OFFSET_CAD 1U
static uint32_t DPM_Sleep_time[USBPD_PORT_COUNT + OFFSET_CAD];
static uint32_t DPM_Sleep_start[USBPD_PORT_COUNT + OFFSET_CAD];
#endif /* !USE_STM32_UTILITY_OS */
USBPD_ParamsTypeDef DPM_Params[USBPD_PORT_COUNT];
/* Private function prototypes -----------------------------------------------*/
static void USBPD_PE_TaskWakeUp(uint8_t PortNum);
static void DPM_ManageAttachedState(uint8_t PortNum, USBPD_CAD_EVENT State, CCxPin_TypeDef Cc);
void USBPD_DPM_CADCallback(uint8_t PortNum, USBPD_CAD_EVENT State, CCxPin_TypeDef Cc);
static void USBPD_DPM_CADTaskWakeUp(void);
/**
* @brief Initialize the core stack (port power role, PWR_IF, CAD and PE Init procedures)
* @retval USBPD status
*/
USBPD_StatusTypeDef USBPD_DPM_InitCore(void)
{
/* variable to get dynamique memory allocated by usbpd stack */
uint32_t stack_dynamemsize;
USBPD_StatusTypeDef _retr = USBPD_OK;
static const USBPD_PE_Callbacks dpmCallbacks =
{
USBPD_DPM_SetupNewPower,
USBPD_DPM_HardReset,
NULL,
USBPD_DPM_Notification,
USBPD_DPM_ExtendedMessageReceived,
USBPD_DPM_GetDataInfo,
USBPD_DPM_SetDataInfo,
USBPD_DPM_EvaluateRequest,
NULL,
NULL,
USBPD_PE_TaskWakeUp,
#if defined(_VCONN_SUPPORT)
USBPD_DPM_EvaluateVconnSwap,
USBPD_DPM_PE_VconnPwr,
#else
NULL,
NULL,
#endif /* _VCONN_SUPPORT */
USBPD_DPM_EnterErrorRecovery,
USBPD_DPM_EvaluateDataRoleSwap,
USBPD_DPM_IsPowerReady
};
static const USBPD_CAD_Callbacks CAD_cbs =
{
USBPD_DPM_CADCallback,
USBPD_DPM_CADTaskWakeUp
};
/* Check the lib selected */
if (USBPD_TRUE != USBPD_PE_CheckLIB(_LIB_ID))
{
return USBPD_ERROR;
}
/* to get how much memory are dynamically allocated by the stack
the memory return is corresponding to 2 ports so if the application
managed only one port divide the value return by 2 */
stack_dynamemsize = USBPD_PE_GetMemoryConsumption();
/* done to avoid warning */
(void)stack_dynamemsize;
for (uint8_t _port_index = 0; _port_index < USBPD_PORT_COUNT; ++_port_index)
{
/* Variable to be sure that DPM is correctly initialized */
DPM_Params[_port_index].DPM_Initialized = USBPD_FALSE;
/* check the stack settings */
DPM_Params[_port_index].PE_SpecRevision = DPM_Settings[_port_index].PE_SpecRevision;
DPM_Params[_port_index].PE_PowerRole = DPM_Settings[_port_index].PE_DefaultRole;
DPM_Params[_port_index].PE_SwapOngoing = USBPD_FALSE;
DPM_Params[_port_index].ActiveCCIs = CCNONE;
DPM_Params[_port_index].VconnCCIs = CCNONE;
DPM_Params[_port_index].VconnStatus = USBPD_FALSE;
/* CAD SET UP : Port 0 */
CHECK_CAD_FUNCTION_CALL(USBPD_CAD_Init(_port_index, (USBPD_CAD_Callbacks *)&CAD_cbs,
(USBPD_SettingsTypeDef *)&DPM_Settings[_port_index], &DPM_Params[_port_index]));
/* PE SET UP : Port 0 */
CHECK_PE_FUNCTION_CALL(USBPD_PE_Init(_port_index, (USBPD_SettingsTypeDef *)&DPM_Settings[_port_index],
&DPM_Params[_port_index], &dpmCallbacks));
/* DPM is correctly initialized */
DPM_Params[_port_index].DPM_Initialized = USBPD_TRUE;
/* Enable CAD on Port 0 */
USBPD_CAD_PortEnable(_port_index, USBPD_CAD_ENABLE);
}
#if defined(USE_STM32_UTILITY_OS)
/* initialise timer server */
UTIL_TIMER_Init();
/* initialize the sequencer */
UTIL_SEQ_Init();
#endif /* USE_STM32_UTILITY_OS */
return _retr;
}
/**
* @brief Initialize the OS parts (task, queue,... )
* @retval USBPD status
*/
USBPD_StatusTypeDef USBPD_DPM_InitOS(void)
{
return USBPD_OK;
}
/**
* @brief Initialize the OS parts (port power role, PWR_IF, CAD and PE Init procedures)
* @retval None
*/
#if defined(USE_STM32_UTILITY_OS)
/**
* @brief Task for CAD processing
* @retval None
*/
void USBPD_CAD_Task(void)
{
UTIL_TIMER_Stop(&TimerCAD);
uint32_t _timing = USBPD_CAD_Process();
UTIL_TIMER_SetPeriod(&TimerCAD, _timing);
UTIL_TIMER_Start(&TimerCAD);
}
/**
* @brief timer function to wakeup CAD Task
* @param pArg Pointer on an argument
* @retval None
*/
void TimerCADfunction(void *pArg)
{
UTIL_SEQ_SetTask(TASK_CAD, 0);
}
#if !defined(USBPDCORE_LIB_NO_PD)
/**
* @brief timer function to wakeup PE_0 Task
* @param pArg Pointer on an argument
* @retval None
*/
void TimerPE0function(void *pArg)
{
UTIL_SEQ_SetTask(TASK_PE_0, 0);
}
/**
* @brief timer function to wakeup PE_1 Task
* @param pArg Pointer on an argument
* @retval None
*/
void TimerPE1function(void *pArg)
{
UTIL_SEQ_SetTask(TASK_PE_1, 0);
}
/**
* @brief Task for PE_0 processing
* @retval None
*/
void USBPD_PE_Task_P0(void)
{
UTIL_TIMER_Stop(&TimerPE0);
uint32_t _timing =
USBPD_PE_StateMachine_SRC(USBPD_PORT_0);
if (_timing != 0xFFFFFFFF)
{
UTIL_TIMER_SetPeriod(&TimerPE0, _timing);
UTIL_TIMER_Start(&TimerPE0);
}
}
/**
* @brief Task for PE_1 processing
* @retval None
*/
void USBPD_PE_Task_P1(void)
{
UTIL_TIMER_Stop(&TimerPE1);
uint32_t _timing =
USBPD_PE_StateMachine_SRC(USBPD_PORT_1);
if (_timing != 0xFFFFFFFF)
{
UTIL_TIMER_SetPeriod(&TimerPE1, _timing);
UTIL_TIMER_Start(&TimerPE1);
}
}
#endif /* !USBPDCORE_LIB_NO_PD */
/**
* @brief Task for DPM_USER processing
* @retval None
*/
void USBPD_TaskUser(void)
{
USBPD_DPM_UserExecute(NULL);
}
#endif /* USE_STM32_UTILITY_OS */
void USBPD_DPM_Run(void)
{
#if defined(USE_STM32_UTILITY_OS)
UTIL_SEQ_RegTask(TASK_CAD, 0, USBPD_CAD_Task);
UTIL_SEQ_SetTask(TASK_CAD, 0);
UTIL_TIMER_Create(&TimerCAD, 10, UTIL_TIMER_ONESHOT, TimerCADfunction, NULL);
UTIL_SEQ_RegTask(TASK_PE_0, 0, USBPD_PE_Task_P0);
UTIL_SEQ_PauseTask(TASK_PE_0);
UTIL_TIMER_Create(&TimerPE0, 10, UTIL_TIMER_ONESHOT, TimerPE0function, NULL);
#if USBPD_PORT_COUNT == 2
UTIL_SEQ_RegTask(TASK_PE_1, 0, USBPD_PE_Task_P1);
UTIL_SEQ_PauseTask(TASK_PE_1);
UTIL_TIMER_Create(&TimerPE1, 10, UTIL_TIMER_ONESHOT, TimerPE1function, NULL);
#endif /* USBPD_PORT_COUNT == 2 */
/* !USBPDCORE_LIB_NO_PD */
UTIL_SEQ_RegTask(TASK_USER, 0, USBPD_TaskUser);
UTIL_SEQ_SetTask(TASK_USER, 0);
do
{
UTIL_SEQ_Run(~0);
} while (1u == 1u);
#else /* !USE_STM32_UTILITY_OS */
do
{
if ((HAL_GetTick() - DPM_Sleep_start[USBPD_PORT_COUNT]) >= DPM_Sleep_time[USBPD_PORT_COUNT])
{
DPM_Sleep_time[USBPD_PORT_COUNT] = USBPD_CAD_Process();
DPM_Sleep_start[USBPD_PORT_COUNT] = HAL_GetTick();
}
uint32_t port = 0;
for (port = 0; port < USBPD_PORT_COUNT; port++)
{
if ((HAL_GetTick() - DPM_Sleep_start[port]) >= DPM_Sleep_time[port])
{
DPM_Sleep_time[port] =
USBPD_PE_StateMachine_SRC(port);
DPM_Sleep_start[port] = HAL_GetTick();
}
}
USBPD_DPM_UserExecute(NULL);
} while (1u == 1u);
#endif /* USE_STM32_UTILITY_OS */
}
/**
* @brief Initialize DPM (port power role, PWR_IF, CAD and PE Init procedures)
* @retval USBPD status
*/
void USBPD_DPM_TimerCounter(void)
{
/* Call PE/PRL timers functions only if DPM is initialized */
if (USBPD_TRUE == DPM_Params[USBPD_PORT_0].DPM_Initialized)
{
USBPD_DPM_UserTimerCounter(USBPD_PORT_0);
USBPD_PE_TimerCounter(USBPD_PORT_0);
USBPD_PRL_TimerCounter(USBPD_PORT_0);
}
#if USBPD_PORT_COUNT==2
if (USBPD_TRUE == DPM_Params[USBPD_PORT_1].DPM_Initialized)
{
USBPD_DPM_UserTimerCounter(USBPD_PORT_1);
USBPD_PE_TimerCounter(USBPD_PORT_1);
USBPD_PRL_TimerCounter(USBPD_PORT_1);
}
#endif /* USBPD_PORT_COUNT == 2 */
}
/**
* @brief WakeUp PE task
* @param PortNum port number
* @retval None
*/
static void USBPD_PE_TaskWakeUp(uint8_t PortNum)
{
#if defined(USE_STM32_UTILITY_OS)
UTIL_SEQ_SetTask(PortNum == 0 ? TASK_PE_0 : TASK_PE_1, 0);
#else
DPM_Sleep_time[PortNum] = 0;
#endif /* USE_STM32_UTILITY_OS */
}
/**
* @brief WakeUp CAD task
* @retval None
*/
static void USBPD_DPM_CADTaskWakeUp(void)
{
#if defined(USE_STM32_UTILITY_OS)
UTIL_SEQ_SetTask(TASK_CAD, 0);
#else
DPM_Sleep_time[USBPD_PORT_COUNT] = 0;
#endif /* USE_STM32_UTILITY_OS */
}
/**
* @brief CallBack reporting events on a specified port from CAD layer.
* @param PortNum The handle of the port
* @param State CAD state
* @param Cc The Communication Channel for the USBPD communication
* @retval None
*/
void USBPD_DPM_CADCallback(uint8_t PortNum, USBPD_CAD_EVENT State, CCxPin_TypeDef Cc)
{
switch (State)
{
case USBPD_CAD_EVENT_ATTEMC :
{
#ifdef _VCONN_SUPPORT
DPM_Params[PortNum].VconnStatus = USBPD_TRUE;
#endif /* _VCONN_SUPPORT */
DPM_ManageAttachedState(PortNum, State, Cc);
#ifdef _VCONN_SUPPORT
DPM_CORE_DEBUG_TRACE(PortNum, "Note: VconnStatus=TRUE");
#endif /* _VCONN_SUPPORT */
break;
}
case USBPD_CAD_EVENT_ATTACHED :
DPM_ManageAttachedState(PortNum, State, Cc);
break;
case USBPD_CAD_EVENT_DETACHED :
case USBPD_CAD_EVENT_EMC :
{
/* The ufp is detached */
(void)USBPD_PE_IsCableConnected(PortNum, 0);
/* Terminate PE task */
#if defined(USE_STM32_UTILITY_OS)
UTIL_SEQ_PauseTask(PortNum == 0 ? TASK_PE_0 : TASK_PE_1);
#else
DPM_Sleep_time[PortNum] = 0xFFFFFFFFU;
#endif /* USE_STM32_UTILITY_OS */
DPM_Params[PortNum].PE_SwapOngoing = USBPD_FALSE;
DPM_Params[PortNum].ActiveCCIs = CCNONE;
DPM_Params[PortNum].PE_Power = USBPD_POWER_NO;
USBPD_DPM_UserCableDetection(PortNum, State);
#ifdef _VCONN_SUPPORT
DPM_Params[PortNum].VconnCCIs = CCNONE;
DPM_Params[PortNum].VconnStatus = USBPD_FALSE;
DPM_CORE_DEBUG_TRACE(PortNum, "Note: VconnStatus=FALSE");
#endif /* _VCONN_SUPPORT */
break;
}
default :
/* nothing to do */
break;
}
}
static void DPM_ManageAttachedState(uint8_t PortNum, USBPD_CAD_EVENT State, CCxPin_TypeDef Cc)
{
#ifdef _VCONN_SUPPORT
if (CC1 == Cc)
{
DPM_Params[PortNum].VconnCCIs = CC2;
}
if (CC2 == Cc)
{
DPM_Params[PortNum].VconnCCIs = CC1;
}
#endif /* _VCONN_SUPPORT */
DPM_Params[PortNum].ActiveCCIs = Cc;
(void)USBPD_PE_IsCableConnected(PortNum, 1);
USBPD_DPM_UserCableDetection(PortNum, State);
#if defined(USE_STM32_UTILITY_OS)
/* Resume the task */
UTIL_SEQ_ResumeTask(PortNum == 0 ? TASK_PE_0 : TASK_PE_1);
/* Enable task execution */
UTIL_SEQ_SetTask(PortNum == 0 ? TASK_PE_0 : TASK_PE_1, 0);
#else
DPM_Sleep_time[PortNum] = 0U;
#endif /* USE_STM32_UTILITY_OS */
}