cancel
Showing results for 
Search instead for 
Did you mean: 

UCPD activation crashes STM32U5 MCUs - hardware bug?

TDJ
Lead

Using Nucleo-U575ZI-Q (rev X) board I try to do a PoC - a very simple UCPD source app providing default USB 5V and 0.5A max. With undocumented onboard SB8-10 shorten this probably can be accomplished. I know this board does not provide output current control, but that is OK, it is just a simple UCPD test to check if I am able to control CC lines state and receive line state change events, no BMC communication.
At first, I tried to use CubeMX middleware. Generated application requires two DMA channels, one advanced timer, uses proprietary ST library and crashes MCU so badly that probably no fault handler is even being called.

So I tried to activate UCPD and monitor CC lines with my simple code. As soon as I activate the Rp resistor MCU crashes, debug communication is lost. Sample code below. Please Advise.
Firmware package version: 1.3.0

Update: I got success, but with Nucleo-H563ZI Rev W. Using the same code (w/o trimming) I was able to correctly read SR.TYPEC_VSTATE_CCn, UCPD1_IRQn seems to fire as expected.
Then I tried with another U5 board (B-U585I-IOT02A, Rev X) and the result was consistent with the first one - MCU crash.

The question: what is so different between H5 and U5 MCUs with respect to UCPD?
Or maybe what matters it is MCU revision? I am stacked and clueless.
What is the correct UCPD activation routine for SM32U5 MCU?
No sample code seems to be available, CubeMX uses ST proprietary library.

 

// Precondition: MX_UCPD1_Init() called

#include "stm32u5xx.h"
#include "stm32u5xx_ll_ucpd.h"

#define SET_REG_FIELD(reg, mask, value) reg = ((reg) & ~mask) | (((value) << mask##_Pos) & mask)

// Table 766. UCPD software trim data
#define _3A0_CC1 ((*(uint8_t*)0x0BFA0545) & 0x0f)
#define _3A0_CC2 ((*(uint8_t*)0x0BFA0547) & 0x0f)
#define _1A5_CC1 ((*(uint8_t*)0x0BFA07A7) & 0x0f)
#define _1A5_CC2 ((*(uint8_t*)0x0BFA07A8) & 0x0f)
#define _Rd_CC1 ((*(uint8_t*)0x0BFA0544) & 0x0f)
#define _Rd_CC2 ((*(uint8_t*)0x0BFA0546) & 0x0f)

UCPD_TypeDef* UCPD = UCPD1;

// Note: Writing to CFG1-CFG3 registers is only effective when UCPD is disabled (UCPDEN = 0)
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_PSC_UCPDCLK, 0x01);  // set the ucpd_clk divider to 2 since 6-9 MHz range is recommended (16/2=8MHz)
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_TRANSWIN, 0x09);     // recommended value
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_IFRGAP, 0x0E);       // 15 - USB PD 2.0 nominal value
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_HBITCLKDIV, 0x1A);   // ? or 0x00 bypass

// 74.5.5 UCPD software trimming - required for Rev X
SET_REG_FIELD(UCPD->CFG3, UCPD_CFG3_TRIM_CC1_RP, _3A0_CC1);
SET_REG_FIELD(UCPD->CFG3, UCPD_CFG3_TRIM_CC2_RP, _3A0_CC2);
SET_REG_FIELD(UCPD->CFG3, UCPD_CFG3_TRIM_CC1_RD, _Rd_CC1);
SET_REG_FIELD(UCPD->CFG3, UCPD_CFG3_TRIM_CC2_RD, _Rd_CC2);

LL_UCPD_RxAnalogFilterEnable(UCPD);

LL_UCPD_Enable(UCPD);

// Writing to CR & IMR registers is only effective when the peripheral is enabled (UCPDEN = 1)
LL_UCPD_EnableIT_TypeCEventCC1(UCPD);
LL_UCPD_EnableIT_TypeCEventCC2(UCPD);

LL_UCPD_SetSRCRole(UCPD);
LL_UCPD_SetRpResistor(UCPD, LL_UCPD_RESISTOR_DEFAULT); // this line crashes MCU
LL_UCPD_SetccEnable(UCPD, LL_UCPD_CCENABLE_CC1CC2);

 

1 ACCEPTED SOLUTION

Accepted Solutions
OlivierR
ST Employee

Without update, I'm able to reproduce this issue. Some Ips clocks setup seems missing (DMA??, ADC??).

I made a quick test with my system clock settings in your environment, and now I observe no hang.

I have no time today to go deeper, but here is the wa:

 

DB TCPP01 setup is missing in your latest change, add this:

// Set TCPP01 DB inactive
HAL_GPIO_WritePin(UCPD_DBn_GPIO_Port, UCPD_DBn_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_BLUE_GPIO_Port, LED_BLUE_Pin, GPIO_PIN_SET);

 

Regarding system clocks:

 

void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

 

/** Configure the main internal regulator output voltage

*/

if (HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1) != HAL_OK)

{

Error_Handler();

}

 

/** Initializes the CPU, AHB and APB buses clocks

*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI48|RCC_OSCILLATORTYPE_HSI

|RCC_OSCILLATORTYPE_MSI;

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;

RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;

RCC_OscInitStruct.MSIState = RCC_MSI_ON;

RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;

RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_4;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI;

RCC_OscInitStruct.PLL.PLLMBOOST = RCC_PLLMBOOST_DIV1;

RCC_OscInitStruct.PLL.PLLM = 1;

RCC_OscInitStruct.PLL.PLLN = 80;

RCC_OscInitStruct.PLL.PLLP = 2;

RCC_OscInitStruct.PLL.PLLQ = 2;

RCC_OscInitStruct.PLL.PLLR = 2;

RCC_OscInitStruct.PLL.PLLRGE = RCC_PLLVCIRANGE_0;

RCC_OscInitStruct.PLL.PLLFRACN = 0;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

{

Error_Handler();

}

 

/** Initializes the CPU, AHB and APB buses clocks

*/

RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2

|RCC_CLOCKTYPE_PCLK3;

RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

RCC_ClkInitStruct.APB3CLKDivider = RCC_HCLK_DIV1;

 

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)

{

Error_Handler();

}

}

Have a nice we.

Olivier

View solution in original post

20 REPLIES 20
TDJ
Lead

@KDJEM.1 This one may be either a hardware bug, HAL problem or a documentation issue.
As far as I can tell, UCPD peripherals on both STM32H5 and STM32U5 are identical.
So why the some code seems to work with H5 but badly crashes U5?
Maybe some one from ST could look into this? UCPD community knowledge is still very limited.

Kraal
Senior III

Hello,

Have you seen the explanation of bit UCPD_DBDIS in the RM, page 454 ? Could this be related ?

Also on page 3447, the software trimming is fully automated for U575 rev X.

Best regards.

 

OlivierR
ST Employee

Hello,

May be this behavior is linked with TCPP01 DB state. Even if you set S8/9/10, TCPP01 chip is still present in Nucleo board, so affect CC1/2 lines.

Try to disactivate TCPP01 DB:

  #define UCPD_DBn_Pin GPIO_PIN_5
  #define UCPD_DBn_GPIO_Port GPIOB
 ....  

  // Set TCPP01 DB  inactive
  HAL_GPIO_WritePin(UCPD_DBn_GPIO_Port, UCPD_DBn_Pin, GPIO_PIN_SET);

According TCPP01 documentation:

OlivierR_2-1692878199877.png

 

TDJ
Lead

@Kraal Thank you, you are correct, STM32U575/585 is an exception and rev X has automatic Rp/Rd trimming, I missed that, but this does not seem to cause the issue. I have also tried disabling DBCC before enabling UCPD
SET_BIT(PWR->UCPDR, PWR_UCPDR_UCPD_DBDIS);
but still no luck.
STM32H563 uses UCPD_DBDIS as well, but failing to activate it does not seem to cause a disaster.

TDJ
Lead

@OlivierR Thank you for some hints. Initially I have considered removing TCPP01 chip, but my understanding is that all it does to CC lines is either disconnects them for protection or when it pulls them down in DBCC mode. What harm could that cause, other than maybe incorrect TYPEC_VSTATE_CCn readings?
But anyway, I tried setting UCPD_DBn high before enabling UCPD. Still no luck.
Nucleo-H563ZI uses TCPP01 configured exactly the same way, but UCPD seems to initialize correctly without enabling TCPP01.

TDJ
Lead

modified repro

 

// precondition: MX_UCPD1_Init() called

#define SET_REG_FIELD(reg, mask, value) reg = ((reg) & ~mask) | (((value) << mask##_Pos) & mask)

// Note: Writing to CFG1-CFG3 registers is only effective when UCPD is disabled (UCPDEN = 0)
// Note: UCPD kernel clock is HSI clock divided by 4 (64/4=16MHz) - called HSI16, although, technically it does not exist
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_PSC_UCPDCLK, 0x01);  // set the ucpd_clk divider to 2 since 6-9 MHz range is recommended (16/2=8MHz)
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_TRANSWIN, 0x09);     // recommended value
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_IFRGAP, 0x0E);       // 15 - USB PD 2.0 nominal value
SET_REG_FIELD(UCPD->CFG1, UCPD_CFG1_HBITCLKDIV, 0x1A);   // ? or 0x00 bypass

LL_UCPD_RxAnalogFilterEnable(UCPD);

// NVIC_DisableIRQ(UCPD1_IRQn);

SET_BIT(PWR->UCPDR, PWR_UCPDR_UCPD_DBDIS);                          // disable DBCC
HAL_GPIO_WritePin(UCPD_DBn_GPIO_Port, UCPD_DBn_Pin, GPIO_PIN_SET);  // enable TCPP01 chip

LL_UCPD_Enable(UCPD);
GPIO_PinState ucpd_flt = HAL_GPIO_ReadPin(UCPD_FLT_GPIO_Port, UCPD_FLT_Pin);  // no fault detected

// Writing to CR & IMR registers is only effective when the peripheral is enabled (UCPDEN = 1)
LL_UCPD_EnableIT_TypeCEventCC1(UCPD);
LL_UCPD_EnableIT_TypeCEventCC2(UCPD);
LL_UCPD_SetSRCRole(UCPD);
LL_UCPD_SetRpResistor(UCPD, LL_UCPD_RESISTOR_DEFAULT);  // <- this line crashes MCU
LL_UCPD_SetccEnable(UCPD, LL_UCPD_CCENABLE_CC1CC2);

 

As you enable CC1/2 interrupts, nn UCPD Interrupt handler side, what did you do?
 

LL_UCPD_EnableIT_TypeCEventCC1(UCPD);

LL_UCPD_EnableIT_TypeCEventCC2(UCPD);

On my side, when I comment these lines there are no hang (HardFault error interrupt)

 

TDJ
Lead

@OlivierR I handle IRQ like this:

 

void UCPD_IRQHandler() {
	// if (IS_SET(UCPD->SR, UCPD_SR_TYPECEVT1)) SET_BIT(UCPD->ICR, UCPD_ICR_TYPECEVT1CF);
	// if (IS_SET(UCPD->SR, UCPD_SR_TYPECEVT2)) SET_BIT(UCPD->ICR, UCPD_ICR_TYPECEVT2CF);
	WRITE_REG(UCPD->ICR, UCPD_ICR_FRSEVTCF | UCPD_ICR_TYPECEVT2CF | UCPD_ICR_TYPECEVT1CF | UCPD_ICR_RXMSGENDCF | UCPD_ICR_RXOVRCF | UCPD_ICR_RXHRSTDETCF | UCPD_ICR_RXORDDETCF
		| UCPD_ICR_TXUNDCF | UCPD_ICR_HRSTSENTCF | UCPD_ICR_HRSTDISCCF | UCPD_ICR_TXMSGABTCF | UCPD_ICR_TXMSGSENTCF | UCPD_ICR_TXMSGDISCCF);  // clear all IRQs
	printf("* UCPD_IRQHandler *\n");
}

 

but whether or not it is enabled/configured seems to make no difference.
Do you use rev X?

What do you mean by Rev X?

May should be nice to remove printf from Interrupt, I will try this Int handler.
I have an MB1549C-U575ZIQ-C03