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);

 

20 REPLIES 20

I got it. printf is the culprit.
When I'm using your IT handler (with the printf) + IAR in debug mode, we observed no hang.
When I'm using your IT handler (with the printf) + No IDE, no debug, we observed hang.
When I'm using your IT handler (without the printf) , we observed no hang in any case.

We have some api to set/reset printf gbd mode, gime some time....
 

TDJ
Lead

@OlivierR I cannot confirm. My Nucleo hangs even if IRQ is disabled. Here is what I think is a minimum code to cause a crash.

 

// precondition: MX_UCPD1_Init() called -> peripheral clock enable
#define SET_REG_FIELD(reg, mask, value) reg = ((reg) & ~mask) | (((value) << mask##_Pos) & mask)
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
NVIC_DisableIRQ(UCPD1_IRQn);                                        // disable UCPD IRQ, just in case
SET_BIT(PWR->UCPDR, PWR_UCPDR_UCPD_DBDIS);                          // disable UCPD DBCC, probably does not matter
LL_UCPD_Enable(UCPD);
LL_UCPD_SetSRCRole(UCPD);
LL_UCPD_SetRpResistor(UCPD, LL_UCPD_RESISTOR_DEFAULT);
LL_UCPD_SetccEnable(UCPD, LL_UCPD_CCENABLE_CC1CC2);  // <- this line crashes MCU

 

Note that now it crashes on the next line.
Why printf() in ISR would cause a problem - unless it is interrupted by, but it it is not.
Why on on STM32H5 it works OK? I think there is some deeper issue here.

If printf output is done using UART, there will be no hang.

If printf output is done using IAR/TerminalIO(so SWO), there will be a hang if you start the application without IAR connected.

Regarding VBUS, did you provide 5V using a jumper on JP6?

 

Kraal
Senior III

@TDJsorry to ask something again, did you had set PWREN bit in RCC_AHB3ENR before disabling UCPD DBCC ? Might be useless, since it's working on H5...

@OlivierR Yes, printf() uses UART1.
Yes, I enabled 5V on VBUS with an extra JP6 jumper, but that does not seem to make a difference. Why would it?

TDJ
Lead

@Kraal Thanks for another idea. I tried adding this line
SET_BIT(RCC->AHB3ENR, RCC_AHB3ENR_PWREN);
but still no luck

are you able to share your project? may be something goes wrong on rcc/syscfg side.

 

TDJ
Lead

@OlivierR The prj is shared here. Many thanks for looking into it.
https://drive.google.com/file/d/1BMSVf1gMVvKlC68eiJ1xVRCIvA6GgbeG/view?usp=sharing
It is 99% CubeMX generated, besides the code in USER CODE sections, IOC file included.

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

TDJ
Lead

@OlivierR Problem solved! What was missing was HSI clock activation - UCPD depends on it.
I believe it is a CubeMX bug. STM32U5 UCPD is clearly enabled, but CubeMX does not think it is enabled and probably for that reason it does not configure HCI clock. This does not happen with STM32H5. It indicates that CubeMX QA process may still have space for improvement.
Thank you for your help.

TDJ_0-1693034363428.png

TDJ_1-1693034429119.png