Page Contents
Custom Board Design
First lets discuss the hardware. There are vendor boards available:
- Evaluation boards are expensive due to the large number of external connectors and integrated circuitry (including FPGAs and HDMI decoders!). These are really meant for sales demos. Any development work done on these would be wasted time since your own custom design would use a different hardware layout and therefore require a totally different device tree.
-
Development boards are cheaper but often cater to the current craze for a raspberry pi form factor. The STM32MP1 chips cater to a different market than the broadcom MPUs. As a result of insisting on using a raspberry pi header, the dev board do not break out all the pins of the MPU.
So lets remedy this situation by designing a development board for the STM32MP1 Application Microprocessor with all MPU pins routed through to 2.54mm headers. No exotic proprietary connectors and only essential external circuitry included. To minimize issues, the ST DK2 dev board was used as a reference design.
The schematics can be found below:
Overview | Power Supply |
---|---|
STM32MP1 Power | STM32MP1 DDR |
---|---|
STM32MP1 GPIO | STM32MP1 Debug |
---|---|
Power Supply Design
There are two options with power supply design: An all-in-one PMIC chip or a discrete power supply. I evaluate and discuss the pros and cons below.
Spoilers: I went with the discrete design.
PMIC: Power Management ICs
Two PMIC chips caught my eye:
- STMicroElectronics STPMIC1
- NXP PF3000 Power Management ICs.
I decided to design a development board for evaluating two power management integrated circuits (PMIC) chips. I managed to squeeze both into a single board, thereby cutting costs 😉
The two PMIC’s are organised into two independantly powered sub-systems.
Each sub-system has a number of external power/signal connectors, along with a list of the jumpers used to configure how those connectors are routed to/from the PMIC chip. The PMICs are configured directly by modifying registers using either a MCU/MPU via the I2C connectors.
Each output has an LED indicator and testpoint. Note that the LED will only light if the PMIC output voltage is set above 2V.
Circuit design notes
The schematic has a separate sheet for both sub-systems. There is one for each chip:
- DEV – The development board sub-system including power/config connectors.
- MAIN – The individual PMIC including the required passive components for bypassing and SMPS/regulator operation. Designed to be reuseable blocks that can easily be incorproated into an existing design.
STPMIC1 DEV | STPMIC1 MAIN |
---|---|
PF3000 DEV | PF3000 MAIN |
---|---|
PCB layout notes
This is a four layer PCB design. The layer stackup is:
- Signal
- Ground
- Small signal and power
- Small signal and ground
Note the ground planes in layer 2 and 4 are connected.
The docs directory contains:
- RevA gerber build files.
- Bill of materials
- CPL pick and place files.
- Related vendor application notes, datasheets and reference designs.
Custom symbols and footprints used in this project can be found in the KicadLibrary repository.
PMIC #1: NXP PF300 Board connector definitions
Connector | Description | Comment |
---|---|---|
J15 | Wall adaptor power input | 3.7V – 5.5V DC Barrel 2.1mm |
J12 | Battery power input | 3.1V – 4.5V 2.54mm Header |
J20 | I2C debug | 1: Ground 2: SCL 3: SDA |
J23 | Digital Interface (see datasheet) |
1: Ground 2: STANDBY 3: RESETBMCU 4: SD_VSEL 5: INTB 6: PWRON |
J21 | PF3000 Power Output | Ground: 2,4,6,8,10,12,14,16,18,20,22,24,26 1: SW1B Buck |
PMIC #1: NXP PF300 Board jumper and switch definitions
Warning: function of jumpers can be inverted using the registers. See datasheet for details.
Jumper/Switch | Description | Setting | Comment |
---|---|---|---|
JP1 | Q2 Pullup | ON | Force Q2 gate to VDBG rail. Use if PGOOD LED becomes erratic. |
JP2 | Q3 Pullup | ON | Force Q3 to VDBG rail. Use if FAIL LED becomes erratic. |
J13 | OTP | 3-2 | Load OTP values from memory into OTP registers |
J13 | OTP | 2-1 | Disable OTP memory and load OTP values from fuses. “Try before buy” mode. |
J16 | I2C Bus Power (VDDIO) | 3-2 | Power from VDGB. 3.3V |
J16 | I2C Bus Power (VDDIO) | 2-1 | Power from Buck 2 output. 1.8V |
J14 | Digital Interface Power (V_PU) | 3-2 | Power from J16 output |
J14 | Digital Interface Power (V_PU) | 2-1 | Power from VSNVS output (fixed 3V) |
J17 | Standby | 3-2 | Enter standby mode |
J17 | Standby | 2-1 | Exit standby mode |
J18 | VCC_SD output range | 3-2 | 1.8V to 1.85V |
J18 | VCC_SD output range | 2-1 | 2.85V to 3.3V |
J19 | Power enable | 2-1 | IC power output is enabled |
SW5 | Power enable | – | Momentary SPST. IC power output is enabled. |
J22 | VPWR override | 3-2 | VPWR enable. Set when J15 DC connector is powered |
J22 | VPWR override | 2-1 | VPWR disable. Set when J12 battery power connector is powered. Warning: Shorts J15 to ground! |
PMIC #2: STPMIC1 Board connector definitions
Connector | Description | Comment |
---|---|---|
J2 | External VIO | 0.5V to 4.2V. I/O voltage (for all digital signals except WAKEUP and PONKEY) |
J3 | External SWIN | 0.5V – 7V. External power source for VSWIN pin. |
J4 | Wall adaptor power input | 0.5V – 7V. DC Barrel 2.1mm |
J1 | Battery power input | 0.5V – 7V. 2.54mm Header |
J10 | I2C debug | 1: Ground 2: SCL 3: SDA |
J5 | Digital Interface (see datasheet) |
1: Ground 2: PONKEY (IN) 3: WAKEUP (IN) 4: RST (BOTH) 5: PWRCTL (IN) 6: INT (OUT) |
J21 | STPMIC1 Power Output | Ground: 2,4,6,8,10,12,14,16,18,20,22,24,26 1: Buck2 |
PMIC #2: STPMIC1 Board jumper and switch definitions
Warning: function of jumpers can be inverted using the registers. See datasheet for details.
Jumper/Switch | Description | Setting | Comment |
---|---|---|---|
J6 | VIO source select | 3-2 | Power source from Buck3 output |
J6 | VIO source select | 2-1 | Power source from VIO Ext (J2) |
J7 | VSWIN source select | 3-2 | Power source from BOOST output |
J7 | VSWIN source select | 2-1 | Power source from SWIN Ext (J3) |
J8 | LDO3 source select | 1-2 | Power source from VBAT (J4 or J1) |
J8 | LDO3 source select | 3-4 | Power source from BUCK2 output |
J8 | LDO3 source select | 5-6 | Power source from BUCK2 output |
J9 | PWRCTL Pullup/Pulldown | 3-2 | Pullup from VIO (J6) |
J9 | PWRCTL Pullup/Pulldown | 2-1 | Pulldown to ground |
SW1 | Wakeup enable | – | Momentary SPST to VBAT |
SW2 | IC Reset | – | Momentary SPST to ground |
SW3 | PONKEY | – | User power on key |
Writing a test driver for the STPMIC1
Driver can be found in this repository.
Exampe usage:
#include <stpmic1.h>
// Redirect stdout to ITM/SWO
int _write(int file, char *ptr, int len)
{
for (int i=0; i<len; i++)
{
ITM_SendChar((*ptr++));
}
return len;
}
int main(void)
{
HAL_Init();
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
// connect using this I2C interface
stpmic1_i2c_connect(&hi2c1);
/*
* Get status register info
*/
stpmic1_main_ctrl_sr();
stpmic1_get_turn_on_sr();
stpmic1_get_turn_off_sr();
stpmic1_get_ocp_ldos_sr();
stpmic1_get_ocp_buck_bsw_sr();
stpmic1_get_restart_sr();
/*
* Boost regulator and load switches
*/
// Enable the VBOOST regulator (5.2V fixed output)
stpmic1_set_register_value(STPMIC_BST_SW_CR, (STPMIC_BST_SW_BST_ON_Mask));
// Enable the PWR_USB (OTG) power switch - internally connected to boost regulator.
stpmic1_set_register_value(STPMIC_BST_SW_CR, (STPMIC_BST_SW_BST_ON_Mask) | (STPMIC_BST_SW_VBUSOTG_ON_Mask));
// Enable the PWR_SW power switch - J7 connected to SWIN (requires ext power source on J3).
stpmic1_set_register_value(STPMIC_BST_SW_CR, STPMIC_BST_SW_SWOUT_ON_Mask);
// Enable the PWR_SW power switch - J7 connected to VBOOST.
stpmic1_set_register_value(STPMIC_BST_SW_CR, (STPMIC_BST_SW_BST_ON_Mask) | (STPMIC_BST_SW_SWOUT_ON_Mask));
// Enable the PWR_USB (OTG) power switch - internally connected to boost regulator.
// AND
// Enable the PWR_SW power switch - J7 connected to SWIN (requires ext power source on J3).
stpmic1_set_register_value(STPMIC_BST_SW_CR, (STPMIC_BST_SW_VBUSOTG_ON_Mask) | (STPMIC_BST_SW_BST_ON_Mask) | (STPMIC_BST_SW_SWOUT_ON_Mask));
/*
* Buck regulator control
*/
// Enable BUCK1 full 1.5V output
stpmic1_set_register_value(STPMIC_BUCK1_MAIN_CR, (STPMIC_BUCK1_MAIN_ENA_Mask | STPMIC_BUCK1_PRESET_63_Mask));
// Enable BUCK2 full 1.5V output
stpmic1_set_register_value(STPMIC_BUCK2_MAIN_CR, (STPMIC_BUCK2_MAIN_ENA_Mask | STPMIC_BUCK2_PRESET_63_Mask));
// Enable BUCK3 full 3.4V output
stpmic1_set_register_value(STPMIC_BUCK3_MAIN_CR, (STPMIC_BUCK3_MAIN_ENA_Mask | STPMIC_BUCK3_PRESET_63_Mask));
// Enable BUCK4 full 3.9V output
stpmic1_set_register_value(STPMIC_BUCK4_MAIN_CR, (STPMIC_BUCK4_MAIN_ENA_Mask | STPMIC_BUCK4_PRESET_63_Mask));
/*
* LDO Control
*/
// LDO1 enable and vout max
stpmic1_set_register_value(STPMIC_LDO1_MAIN_CR, STPMIC_LDO1_MAIN_ENA_Mask | STPMIC_LDO1_PRESET_31_Mask);
// LDO2 enable and vout max
stpmic1_set_register_value(STPMIC_LDO2_MAIN_CR, STPMIC_LDO2_MAIN_ENA_Mask | STPMIC_LDO2_PRESET_31_Mask);
// LDO3 enable and vout max
stpmic1_set_register_value(STPMIC_LDO3_MAIN_CR, STPMIC_LDO3_MAIN_ENA_Mask | STPMIC_LDO3_PRESET_30_Mask);
// LDO5 enable and vout max
stpmic1_set_register_value(STPMIC_LDO5_MAIN_CR, STPMIC_LDO5_MAIN_ENA_Mask | STPMIC_LDO5_PRESET_31_Mask);
// LDO6 enable and vout max
stpmic1_set_register_value(STPMIC_LDO6_MAIN_CR, STPMIC_LDO6_MAIN_ENA_Mask | STPMIC_LDO6_PRESET_31_Mask);
/*
* VREFDDR
*/
// Enable VREFDDR output
stpmic1_set_register_value(STPMIC_REFDDR_MAIN_CR, STPMIC_REFDDR_MAIN_ENA_Mask);
while(1)
{
// do something fun
}
}
Discrete Power Supply
The power supply requirements for microprocessors are always complicated. I decided to use a discrete power supply scheme using a single LDO for the main 3.3V rail, a buck regulator for the DDR 1.35V rail and a load switch to detect the USB 1.8V rail. The latter comes from an internal regulator ands powers the VDD3V3_USBFS and VDD3V3_USBHS. This needs to be enabled only after the 1.8V rail comes up, so this needs to be enabled using a MOSFET. However, you need to pick a transistor that will fully switch on for 1.8V Vgs. After having some issues I played it safe with a load switch: the SIP3250, which turns on as low as 1.2V…according to the datasheet
The characteristics seem to back this up until you get to the Fig.10. Perhaps not quite as good as \small1.2V_{gs} but even at \small1.5V_{gs}, this is more than good enough for these requirements.
Whether this is too much hassle when you can use a single PMIC is debatable. The sheer number of passive components needed to support a PMIC is eye-watering.
The table below lists the power supply scheme on this board:
Power Supply Rail | MPU Pin Name | MPU Pin # | Comment |
---|---|---|---|
3.3v | VDD VBAT VDD_PLL VDD_PLL2 VDD_ANA VDD_DSI PDR_ON_CORE PDR_ON |
K6 H3 J5 G13 L3 A12 N1 N2 |
Linear regulator ([SE8233X2](https://datasheet.lcsc.com/szlcsc/1912111437_Seaward-Elec-SE8233X2_C437587.pdf)) |
3.3v | VDDA VREF+ |
M4 N3 |
via inductor L3 If JP4 is connected (default) |
3.3v | VDD3V3_USBFS VDD3V3_USBHS |
W12 W15 |
via NMOS ([DMG2302U](https://datasheet.octopart.com/DMG2302U-7-Diodes-Inc.-datasheet-103571615.pdf)) when 1.85v rail is detected from MPU |
1.35v | VDD VDDQ VDDCORE VDDQ_DDR |
B2 A1 E7 E15 |
Buck regulator [TPS54202](http://www.ti.com/lit/ds/symlink/tps54202.pdf) |
1.85v | VDDA1V8_REG | V11 | Internal regulator, externally connect to VDDA1V8_DSI (B12) |
1.2v | VDD1V2_DSI_REG | B16 | Internal regulator, externally connected to VDD1V2_DSI_PHY (A16) |
1.1v | VDDA1V1_REG | W11 | Interal regulator, internally connected. |
Note: 3.3v rail is also connected to:
- SWD debug interface
- SDIO connectors (microSD)
- pull-ups for the BOOT pins
- external power output on the pin headers (pin #26 on J1, J2, J3, J4)
Testing the hardware
Before we boot the board with a Linux image. It is helpful to check the MPU is alive and responding. We can use the SEGGER JLink to connect to the cores via the SWD connector (J6).
Connect to the first A7 core (second core is not active by default)
BOOT pins must be set to B0 and B2.
JLinkExe -device STM32MP15XX_A7_0_DUALFLASH -if SWD -speed 4000 -autoconnect 1
SEGGER J-Link Commander V6.98a (Compiled Mar 5 2021 17:04:44)
DLL version V6.98a, compiled Mar 5 2021 17:04:29
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Feb 4 2021 12:59:17
Hardware version: V11.00
S/N: 261002652
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref=3.341V
Device "STM32MP15XX_A7_0_DUALFLASH" selected.
Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end
InitTarget() start
InitTarget() end
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
AP map detection skipped. Manually configured AP map found.
AP[0]: AXI-AP (IDR: Not set)
AP[1]: APB-AP (IDR: Not set)
AP[2]: AHB-AP (IDR: Not set)
Using preconfigured AP[1] as APB-AP
AP[1]: APB-AP found
Found Cortex-A7 r0p5
6 code breakpoints, 4 data breakpoints
Debug architecture ARMv7.1
Data endian: little
Main ID register: 0x410FC075
I-Cache L1: 32 KB, 512 Sets, 32 Bytes/Line, 2-Way
D-Cache L1: 32 KB, 128 Sets, 64 Bytes/Line, 4-Way
Unified-Cache L2: 256 KB, 512 Sets, 64 Bytes/Line, 8-Way
System control register:
Instruction endian: little
Level-1 instruction cache enabled
Level-1 data cache enabled
MMU enabled
Branch prediction enabled
Memory zones:
Zone: Default Description: Default access mode
Zone: APB-AP (AP1) Description: DMA like acc. in AP1 addr. space
Zone: AHB-AP (AP2) Description: DMA like acc. in AP2 addr. space
Cortex-A7 identified.
Connecting to the M4 core
BOOT pins must be set to B2 only.
JLinkExe -device STM32MP15XX_M4_DUALFLASH -if SWD -speed 4000 -autoconnect 1
SEGGER J-Link Commander V6.98a (Compiled Mar 5 2021 17:04:44)
DLL version V6.98a, compiled Mar 5 2021 17:04:29
Connecting to J-Link via USB...O.K.
Firmware: J-Link V11 compiled Feb 4 2021 12:59:17
Hardware version: V11.00
S/N: 261002652
License(s): FlashBP, GDB
OEM: SEGGER-EDU
VTref=3.342V
Device "STM32MP15XX_M4_DUALFLASH" selected.
Connecting to target via SWD
ConfigTargetSettings() start
ConfigTargetSettings() end
InitTarget() start
InitTarget() end
Found SW-DP with ID 0x6BA02477
DPIDR: 0x6BA02477
AP map detection skipped. Manually configured AP map found.
AP[0]: AXI-AP (IDR: Not set)
AP[1]: APB-AP (IDR: Not set)
AP[2]: AHB-AP (IDR: Not set)
AP[2]: Core found
AP[2]: AHB-AP ROM base: 0xE00FF000
CPUID register: 0x410FC241\. Implementer code: 0x41 (ARM)
Found Cortex-M4 r0p1, Little endian.
FPUnit: 6 code (BP) slots and 2 literal slots
Detection of Coresight components via ROM table search disabled by user
Cortex-M4 identified.
Here is a photo successfully connecting to the A7 core on the assembled board using JLink (via SWD). It lives!
Embedded Linux
Yocto
Setting up OpenSTLinux/Yocto distribution
Please see this article for instructions. Stop after completing the Install OpenSTLinux
section.
Adding a custom Yocto layer and machine
An example layer for adding your device tree files can be found here
Clone this layer into the meta-st directory of the OpenSTLinux distribution package.
And run the environment setup script:
~/Projects/Yocto/mp15_2.1.0/distpkg/openstlinux-5.10-dunfell-mp1-21-03-31$ source ./layers/meta-st/scripts/envsetup.sh
Check the layers:
bitbake-layers check-layers
The meta-my-demo-layer is not included yet.
So we still need to add it to the Yocto build:
bitbake-layers add-layer ../layers/meta-st/meta-my-demo-layer/
Check the layers again:
bitbake-layers check-layers
The layer is now added to the bottom of the list. Note that position does not matter, but the priority does.
For instructions on how to create a new layer, see this ST Wiki page.
For instructions on how to create a new machine, see this ST Wiki page.
Now lets look at the layer in more detail.
Directory structure of the custom layer
../layers/meta-st/meta-my-demo-layer/ ├── conf │ ├── eula │ │ ├── en.SLA0048.txt │ │ ├── LICENCE.broadcom_bcm43xx │ │ ├── LICENCE.cypress │ │ ├── ST_EULA_SLA │ │ ├── stm32mp1-demo -> ST_EULA_SLA │ │ └── Vivante_GPU_drivers-End_User_Software_License_Terms.txt │ ├── layer.conf │ └── machine │ └── stm32mp1-demo.conf ├── COPYING.MIT ├── LICENSE.md ├── mx │ ├── ADD_SYMLINK_TO_STM32CUBEIDE_PROJECT_HERE.txt │ ├── fdk2_161 -> /home/chris/STM32CubeIDE/workspace_1.6.1/fdk2_161/ │ ├── fdk2_161_nohse -> /home/chris/STM32CubeIDE/workspace_1.6.1/fdk2_161_nohse/ │ ├── mp157dab_custom -> /home/chris/STM32CubeIDE/workspace_1.6.1/mp157dab_custom │ └── mp157fab_custom -> /home/chris/STM32CubeIDE/workspace_1.6.1/mp157fab_custom ├── README └── README.md
Notes:
– The layer is defined in the layers/meta-st/meta-my-demo-layer/conf/layer.conf
file.
– The EULA stm32mp1-demo symlink file was created according to the ST wiki instructions
– The symlink files under the mx
directory point to the various STM32CubeIDE projects that generate device tree files (more on this in a bit).
– The machine stm32mp1-demo.conf
file was copied from the meta-st-stm32mp-addons layer. We modify this to include the device tree files generated by our STM32CubeIDE project.
STM32CubeIDE
Modifying the OpenSTLinux device tree in STM32CubeIDE
The STM32CubeIDE can be used to generate device tree source file (.dts) for your embedded linux image. These describe the hardware for the board on which linux will run. This is compiled into a device tree binary file (.dtb) which is included on the image and loaded by u-boot along with the Linux kernel zImage.
For those familiar with STM32 CortexM development, STM32CubeIDE is the same pinmux code generation tool. It generates a device tree with “comment sections” that need to be filled out by the user. The simplest option is to create a STM32MP1-DK (development kit) project and copy the required comment sections over to your own dts file. See the forum page for workshop slides that go into more detail about these comment sections.
I have also written this article on the process.
For now we will just clone this project.
Open the project in STM32CubeIDE (v1.6.1) and run the code generator.
Update the symlink in the mx directory: mp157fab_custom
to point to the project.
mp157fab_custom -> /home/chris/Projects/Embedded/mp157fab_custom/
Including the STM32CubeIDE project files into the layer.
As mentioned the mx directory contains a symbolic link to the directories of the STM32CubeIDE project. This is just done for flexibility, if you prefer you can save the entire project in the mx directory.
To tell Yocto that the layer should use these specific device tree files, you must update the variables in the stm32mp1-demo.conf
file.
Variable | Description |
---|---|
CUBEMX_DTB | The prefix of your dts files, e.g. stm32mp157f-fdk2_161-mx |
CUBEMX_PROJECT | The internal STM32CubeIDE project path to the dts files, e.g. mx/fdk2_161/CA7/DeviceTree/fdk2_161 |
The second variable is comprised of the mx
directory, the name of the symbolic link created in the previous step – fdk2_161
– and then the path of the device tree files in the STM32CubeIDE project. You can use your STM32CubeIDE project to determine these variables:
Bitbake
First build should only take ~2 hours. After that updates to the DTS are much quicker and don’t require a full rebuild.
- Init the BitBake env setup:
source ./layers/meta-st/scripts/envsetup.sh
-
Select the new build dir option:
- Select the OpenSTLinux-EPLFS distro:
- Select the demo layer:
The output summary should now have swtiched from
MACHINE : stm32mp1-mx
to
MACHINE : stm32mp1-demo
- Compile the yocto project:
bitbake st-image-core
Booting Linux
The image can be booted using a microSD card. See these instructions for preparing the bitbake output.
Troubleshooting
Please see this article section on dealing with bitbake errors.
`