Target description
This tutorial helps to:
- Use the X-NUCLEO-SNK1M1 shield that includes a TCPP01-M12 protection circuit and provides a USB Type-C® connector
- Create a USB-PD Sink Device with the NUCLEO-G071RB board and the X-NUCLEO-SNK1M1 or X-NUCLEO-USBPDM1 shield by using STM32CubeIDE software
Prerequisites
- Computer with Windows 7 (or higher)
- Computer with Windows 7 (or higher)
Hardware
Software
Literature
- UM2324 NUCLEO-G071RB User Manual
- UM2773 X-NUCLEO-SNK1M1 User Manual
- AN5418 How to build a simple USB-PD sink application with STM32CubeMX
How to Create a STM32G0 USB-PD Device with STM32CubeIDE.
Create a USB-PD Sink Device
Total 45min
1. Software pack installation
Open STM32CubeMX, in the software pack area, click on the install/remove button
Then select the STMicroelectronics tab, scroll down to the X-Cube-TCPP software pack, and click on the install button if it is not already installed.
2. Creating the project
5min
In STM32CubeMX, create a New STM32 Project. As a target selection, choose the NUCLEO-G071RB from the Board Selector Tab
Click "Start Project", then in the file menu, Create a new folder at your project's name, and click "Save".
When prompted for initializing peripherals with their default mode, click No.
3. Configuring the system
At this point, your project is created and in the next steps, we will configure the peripherals and options needed for the project.
3.1. Clear the pinout
To start from a blank configuration, click on the Pinout menu and select Clear Pinouts. This will reset the pinouts in the Pinout view.
3.2. Select the X-CUBE-TCPP software pack
From the software pack menu,
Select the X-CUBE-TCPP Software pack and enable its Sink application, the tcpp01 Board part and the X-NUCLEO-SNK1M1 Board support.
3.3. Configure UCPD peripheral
In the Connectivity tab, select the UCPD1 peripheral and enable it in sink mode. Under the NVIC Settings tab, enable UCPD global interrupts.
Under the DMA Settings tab, add UCPD1_RX and UCPD1_TX DMA requests. Select DMA1 channel 4 for RX and DMA1 channel 2 for TX.
3.4. Configure FreeRTOS Middleware
In the Middleware section, enable FreeRTOS with CMSIS_V1 interface. Under the Config Parameters tab, change "TOTAL_HEAP_SIZE" to 7000 bytes.
3.5. Configure USBPD Middleware
In the Middleware section, enable USBPD with the following configuration:
- Port Configuration: Port 0: UCPD1
- Stack Configuration: PD3 Full Stack
- Timer service Source: TIM1
Under the PDO General Definitions tab, verify the following configuration:
- Number of Sink PDOs for port 0: 1
- Port 0 Sink PDO 1 0x00019096 (correspond to a 5V / 1.5A, dual-role data sink)
The following table is extracted from USB Power Delivery Specification, Table 6-14 Fixed Supply PDO - Sink. Used values and associated decoding for this project have been added to the table.
Bit(s) | Description | Used value | Decoding |
---|---|---|---|
B31..30 | Fixed supply | 00b | Fixed |
B29 | Dual-Role Power | 0b | No |
B28 | Higher capability | 0b | No |
B27 | Unconstrained Power | 0b | No |
B26 | USB Communications Capable | 0b | No |
B25 | Dual-Role Data | 0b | No |
B24..23 | Fast Role Swap support | 00b | No |
B22..20 | Reserved - Must be set to zero | 0b | No |
B19..10 | Voltage in 50mV units | 0001100100b | 5V |
B9..0 | Maximum current in 10mA units | 0010010110b | 1.5A |
3.6. Configure ADC peripheral
For the Power Delivery stack to work, VBUS needs to be monitored. To do it, an ADC needs to be configured to measure the VBUS voltage and current.
As we are going to use the X-NUCLEO-SNK1M1 BSP, the ADC configuration does not need to be done in CubeMX.
As we need the ADC HAL drivers for it to work properly, we still need to configure the ADC in CubeMX for it to include the driver files, but the actual configuration and init function will not be called in our project.
In the Analog section, enable ADC1 peripheral channel 0. Leave the configuration as default, as the software pack will reconfigure it.
3.7. Enable the software pack
In the middleware and software pack category, select the X-CUBE-TCPP software pack. Enable the 'Source' Application, the 'tcpp01' Board Part and the 'X-NUCLEO-SNK1M1' Board support.
3.8. Configure Clocks
Under the Clock Configuration main tab, change system clock mux to PLLCLK. It sets the HCLK clock to 64 MHz.
3.9. [OPTIONAL] Configure Tracer for debug
3.9.1. Configure LPUART
On the STM32G0 Nucleo-64 board, the Virtual COM port connected to the ST-LINK is the LPUART1.
In the Connectivity section, enable LPUART1 in Asynchronous mode, and baud rate 921600 bauds. Leave the rest as default.
In the pinout view, left-click PA2 and PA3 to remap them to LPUART1_TX and LPUART1_RX.
Under the DMA Configuration tab, add a request for LPUART1_TX. Use DMA1 channel 3.
Finally, under the NVIC Settings tab, enable LPUART1 global interrupts.
3.9.2. Configure embedded tracer
In the Utilities section, select TRACER_EMB and use LPUART1 as the trace source.
Then, go back to the USBPD middleware configuration and check the Tracer Source checkbox.
3.9.3. Configure UCPD monitor firmware responder for debug
The firmware interactive stack responder can be activated if interaction with the USB-PD stack is needed, using the UCPD monitor tool. STM32CubeMonUCPD. GUI can be activated only with tracer. In the "Utilities" section, enable GUI_INTERFACE, then enter free text to describe the board.
4. Configure project
5min
Under the Project Manager main tab, configure the minimum stack size to 0xC00 under the Project tab. This is a first value, which can be tuned later, depending on application needs.
Under the Advanced Settings tab, change the LPUART driver to LL to save a bit of memory heap size. As we do not need ADC initialization functions (handled by the BSP drivers), uncheck Generate Code for the MX_ADC1_Init functions.
5. Generate code
Save your file with Ctrl+s and select generate code.
A warning appears, informing that a proper HAL time base is not defined. It is safer to use a dedicated timer as a HAL time base source.
For this demonstration, the below warning can be ignored by clicking Yes.
6. Configure the shield's jumpers
Place jumpers on the X-NUCLEO-SNK1M1 shield as shown in the picture.
7. Compile and run the application
The compilation must be performed without error or warnings.
Build the application by clicking on the button (or select Project/Build Project).
Run the application by clicking on the button (or select Run/Run)
8. Establish the first explicit contract
5min
With your application running on the board, launch the STM32CubeMonitor-UCPD application.
The user's board must appear in the list when clicking "Refresh list of connected boards", so double click on the
corresponding line (or click "NEXT").
Note: The ComPort may be different. It depends on the number of boards installed on the computer. Then double click on the desired UCPD port, here Port 0, or select it and click "NEXT".
Click on the TRACES button in the bottom right corner to get protocol traces. You can then plug a power delivery source into the USB Type-C® receptacle of the X-NUCLEO-SKN1M1 shield. The screen may look like this:
The figure above shows the communication between the STM32G0 and the power delivery source on the right panel. It is possible to verify the correct sequence to reach an explicit contract:
- The capabilities are sent by the source (IN green message).
- The request is sent by the STM32G0 (OUT orange message).
- The ACCEPT and the PS_RDY are sent by the source (IN green message).
- The contract negotiation ends by the POWER_EXPLICIT_CONTRACT notification (blue message).
For more details on how to use this tool, refer to UM2468. And for more details on the protocol, refer to UM2552. Note that this trace is very helpful for debugging and application development.
9. For information, code inserted by the software pack
Following code has been automatically inserted by the software pack in:
main.c |
Between the /* USER CODE BEGIN-END ADC1_Init 2 */ tags:
/* USER CODE BEGIN ADC1_Init 2 */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start(&hadc1);
/* USER CODE END ADC1_Init 2 */
|
usbpd_dpm_user.h |
In the USBPD_DPM_GetDataInfo function:
case USBPD_CORE_DATATYPE_SNK_PDO: /*!< Handling of port Sink PDO, requested by get sink capa*/
USBPD_PWR_IF_GetPortPDOs(PortNum, DataId, Ptr, Size);
*Size *= 4;
break;
Between the /* USER CODE BEGIN-END USBPD_DPM_SNK_EvaluateCapabilities */ tags: /* USER CODE BEGIN USBPD_DPM_SNK_EvaluateCapabilities */
USBPD_SNKRDO_TypeDef rdo;
/* Initialize RDO */
rdo.d32 = 0;
/* Prepare the requested pdo */
rdo.FixedVariableRDO.ObjectPosition = 1;
rdo.FixedVariableRDO.OperatingCurrentIn10mAunits = 50;
rdo.FixedVariableRDO.MaxOperatingCurrent10mAunits = 50;
rdo.FixedVariableRDO.CapabilityMismatch = 0;
*PtrPowerObjectType = USBPD_CORE_PDO_TYPE_FIXED;
*PtrRequestData = rdo.d32;
/* USER CODE END USBPD_DPM_SNK_EvaluateCapabilities */
|
usbpd_pwr_user.c |
Between the /* USER CODE BEGIN-END include */ tags:
/* USER CODE BEGIN include */
#include "main.h"
/* USER CODE END include */
Between the /* USER CODE BEGIN-END BSP_USBPD_PWR_VBUSGetVoltage */ tags: /* USER CODE BEGIN BSP_USBPD_PWR_VBUSGetVoltage */
/* Check if instance is valid */
int32_t ret = BSP_ERROR_NONE;
if ((Instance >= USBPD_PWR_INSTANCES_NBR) || (NULL == pVoltage))
{
ret = BSP_ERROR_WRONG_PARAM;
*pVoltage = 0;
}
else
{
uint32_t val;
val = __LL_ADC_CALC_DATA_TO_VOLTAGE( VDDA_APPLI, \
LL_ADC_REG_ReadConversionData12(ADC1), \
LL_ADC_RESOLUTION_12B); /* mV */
/* X-NUCLEO-USBPDM board is used */
/* Value is multiplied by 5.97 (Divider R6/R7 (40.2K/200K) for VSENSE) */
val *= 597;
val /= 100;
*pVoltage = val;
}
return ret;
/* USER CODE END BSP_USBPD_PWR_VBUSGetVoltage */
|
10. [OPTIONAL] Advanced USB-PD application
From this point, you built the most simple sink possible, which does not handle matching the sink and source PDO. This must be done with user code. This is done in USBPD_DPM_SNK_EvaluateCapabilities function. For now, this function does nothing more than to ask for the first available source PDO, which is 5V.
To select a specific PDO (for example 9V), you must select the corresponding source PDO number. This can be done with user code that matches the sink PDO defined previously in STM32CubeMX, and the corresponding available source PDO.
This section provides the code of a possible implementation of this system.
You need to:
- Add all the sink PDO you want to support in STM32CubeMX
- Add the user code provided below in your application
10.1. Add the supported sink PDO
Re-open the STM32CubeMX view. In the Middleware section, for the USBPD middleware, under the PDO General Definitions tab, add the number of PDO you want your sink to support. For this example, we defined 3PDO, corresponding to a simple sink configuration of 5V/1.5A, 9V/1.5A, and 15V/1.5A. This was done by setting the PDO to:
- 0x00019096 (Fixed PDO: 5V 1.5A)
- 0x0002D096 (Fixed PDO: 9V 1.5A)
- 0x0004B096 (Fixed PDO: 15V 1.5A)
10.2. Get the usbpd_user_services.c/h files on GitHub
Get the usbpd_user_services.c/h files on GitHub by visiting the following links:
Copy the usbpd_user_services.c/h files in your application USBPD folder.
Then, to tell STM32CubeMX to include these files upon code generation, create a file named ".extSettings" at the project's root folder (please mind the dot character in the filename) and fill it with the following code:
[ProjectFiles]
HeaderPath=
[Others]
Define=
HALModule=
[Groups]
USBPD=USBPD/usbpd_user_services.c
usbpd_dpm_user.c |
Between the /* USER CODE BEGIN-END Includes */ tags:
/* USER CODE BEGIN Includes */
#include "usbpd_user_services.h"
/* USER CODE END Includes */
|
Add the following code between the /* USER CODE BEGIN-END USBPD_DPM_SetDataInfo */ tags, in the switch:
/* Case Received Source PDO values Data information :
*/
case USBPD_CORE_DATATYPE_RCV_SRC_PDO: /*!< Storage of Received Source PDO values */
USBPD_USER_SERV_StoreSRCPDO(PortNum, Ptr, Size);
break;
Add the following code between the /* USER CODE BEGIN-END USBPD_DPM_SNK_EvaluateCapabilities */ tags (replace the previously added code):
/* USER CODE BEGIN USBPD_DPM_SNK_EvaluateCapabilities */
USBPD_USER_SERV_EvaluateCapa(PortNum, PtrRequestData, PtrPowerObjectType);
/* USER CODE END USBPD_DPM_SNK_EvaluateCapabilities */
You can now re-generate the code, build it and run it. Your application asks for the highest voltage matching PDO (voltage/current supported by the source and the sink).
You can modify this user code further for example to choose the highest power PDO instead of the highest voltage.
You can find other applicative examples on GitHub: x-cube-tcpp
10.3. Configure GPIOs
For the X-NUCLEO-SNK1M1 shield, two additional GPIO settings are required(not in X-NUCLEO-USBPDM1 because the settings are forced by jumpers).
- PB6 (DB_OUT for dead battery disabling) GPIO output to HIGH
- PC10 (VCC_OUT pin to power on the TCPP01‑M12) GPIO output to HIGH
To set this configuration, left-click pins PB6 and PC10 in the Pinout view, and set pins to GPIO_Output. In the System Core section, under GPIO, change the GPIO output level for both pins to High, and set a User label DB_OUT for PB6 AND VCC_OUT for PC10.
For a real application, these GPIO settings must be performed after the UCPD initialization.
11. Project with a custom board
This chapter allows to build an USBPD Source application using a custom board with a STM32 MCU from series G0, G4, H5, L5 or U5 that includes the UCPD peripheral.
- As in the chapter 2, create the project
- As in the chapter 3.1, clear the pinout
- As per chapter 3.2, Select the X-CUBE-TCPP software pack
But do not select the board support for X-NUCLEO-SNK1M1 as your application is based on a custom board
- As in the chapter 3.3, Configure UCPD Peripheral
- As in the chapter 3.4, Configure FreeRTOS Middleware
- As in the chapter 3.5, Configure USBPD Middleware
- Configure ADC Peripheral
Select and configure the ADC and its channel on which Vbus is connected for monitoring Select the ADC and it Channel, Adjust the clock prescaler, Keep 12 Bits resolution, Enable the continuous conversion mode, And set a medium cycle sampling time
- Configure GPIO
Enable and configure the External Interrupt input where the TCPP01 FLG signal is connected Select it in the pinout view In the GPIO category, set it as External Interrupt Mode with Falling edge trigger detection Enable its Pull-up
In the Pinout view, select the GPIO Output for TCPP02 Enable
- Enable the software Pack
In the middleware category, select the X-Cube-TCPP Software pack and enable its application and Board Part
- Assign ressources to the application requirements
- As in the chapter 4,Configure Project
But in the Advanced settings keep ADC and I2C initialization code generation.
- As in the chapter 5, Generate code
- As in the chapter 7, Compile and run the application
12. References