Pulse-width modulation (PWM) is a technique that modifies the duty cycle of a pulsing signal to encode information or to control the amount of energy provided to a charge.

On the ConnectCore MP15 system-on-module:

  • Eight Advanced-control timers signals (from TIM1 to TIM8) available from the STM32MP15 system-on-chip (multiplexed with other signals) that can be used to generate PWM output waveform.

On the ConnectCore MP15 Development Kit:

  • PWM2 channel 1 (Port A GPIO15) is used for display backlight.

  • PWM4 channel 1 (Port B GPIO6) is available at PWM pin of MikroBus connector.

Kernel configuration

You can manage the STM32MP15 PWM driver support through the following kernel configuration options:

  • PWM support (CONFIG_PWM)

  • STM32 PWM support (CONFIG_PWM_STM32)

  • STM32 PWM low power support (CONFIG_PWM_STM32_LP)

These options are enabled as built-in on the default ConnectCore MP15 kernel configuration file.

Kernel driver

The driver for the STM32MP15 PWM is located at:

File Description

drivers/pwm/pwm-stm32.c

STM32 PWM driver

drivers/pwm/pwm-stm32-lp.c

STM32 PWM LP driver

Device tree bindings and customization

The STM32MP15 PWM interface is documented at Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml.

The STM32MP15 PWM LP interface is documented at Documentation/devicetree/bindings/mfd/st,stm32-lptimer.yaml.

STM32MP15 PWM interfaces

The common STM32MP15 CPU device tree file contains entries for all the timers that can have PWM functionality (excerpt shows a few):

STM32MP15 device tree
timers2: timer@40000000 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "st,stm32-timers";
	reg = <0x40000000 0x400>;
	clocks = <&rcc TIM2_K>;
	clock-names = "int";
	dmas = <&dmamux1 18 0x400 0x80000001>,
	       <&dmamux1 19 0x400 0x80000001>,
	       <&dmamux1 20 0x400 0x80000001>,
	       <&dmamux1 21 0x400 0x80000001>,
	       <&dmamux1 22 0x400 0x80000001>;
	dma-names = "ch1", "ch2", "ch3", "ch4", "up";
	status = "disabled";

	pwm {
		compatible = "st,stm32-pwm";
		#pwm-cells = <3>;
		status = "disabled";
	};

	timer@1 {
		compatible = "st,stm32h7-timer-trigger";
		reg = <1>;
		status = "disabled";
	};

	counter {
		compatible = "st,stm32-timer-counter";
		status = "disabled";
	};
};

lptimer1: timer@40009000 {
	#address-cells = <1>;
	#size-cells = <0>;
	compatible = "st,stm32-lptimer";
	reg = <0x40009000 0x400>;
	interrupts-extended = <&exti 47 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&rcc LPTIM1_K>;
	clock-names = "mux";
	power-domains = <&pd_core>;
	wakeup-source;
	status = "disabled";

	pwm {
		compatible = "st,stm32-pwm-lp";
		#pwm-cells = <3>;
		status = "disabled";
	};

	trigger@0 {
		compatible = "st,stm32-lptimer-trigger";
		reg = <0>;
		status = "disabled";
	};

	counter {
		compatible = "st,stm32-lptimer-counter";
		status = "disabled";
	};

	timer {
		compatible = "st,stm32-lptimer-timer";
		status = "disabled";
	};
};

PINCTRL configuration

You must configure the pads that are to be used as STM32MP15 PWMs. See Pin multiplexing (IOMUX).

STM32MP15 pads should only have one IOMUX configuration. Remove other configurations for those pads, like GPIO, when configuring them as PWMs.

The following external pads are configured as PWMs on the default ConnectCore MP15 Development Kit device tree:

  • On the LVDS connector:

    Pad Signal PWM

    16

    BCKL_PWM

    PWM2 channel 1 (TIM2_CH1)

  • On the mikroBUS™ connector J31:

    Pad Signal PWM

    1

    MIKROBUS_PWM

    PWM4 channel 1 (TIM4_CH1)

Example: enable PWM4 on ConnectCore MP15 Development Kit

For example, PWM4 is available on the ConnectCore MP15 Development Kit MikroBus connector which corresponds to pad Port B GPIO6 (TIM4_CH1) of the CPU. In order to enable it, you must:

  • Configure the pad Port B GPIO6 (TIM4_CH1)

  • Enable the PWM node.

ConnectCore MP15 Development Kit device tree
&timers4 {
	/delete-property/dmas;
	/delete-property/dma-names;
	status = "okay";
	pwm4: pwm {
		pinctrl-0 = <&ccmp15_pwm4_pins>;
		pinctrl-1 = <&ccmp15_pwm4_sleep_pins>;
		pinctrl-names = "default", "sleep";
		status = "okay";
	};
	timer@3 {
		status = "okay";
	};
};

&pinctrl {
	ccmp15_pwm4_pins: ccmp15-pwm4-0 {
		pins {
			pinmux = <STM32_PINMUX('B', 6, AF2)>; /* TIM4_CH1 */
			bias-disable;
			drive-push-pull;
			slew-rate = <0>;
		};
	};

	ccmp15_pwm4_sleep_pins: ccmp15-pwm4-sleep-0 {
		pins {
			pinmux = <STM32_PINMUX('B', 6, ANALOG)>;
		};
	};
};

Using the PWM channels

Control PWM signal from sysfs

Each of the eight TIM interfaces is registered in the system as a standalone PWM controller.

On the ConnectCore MP15 Development Kit:

  • PWM2 is enabled (used for backlight control of LCD and LVDS displays)

  • PWM4 is enabled on pin 1 of MikroBus™ connector (J31)

  • All other PWM channels are disabled by default

The PWM interfaces appear under /sys/class/pwm:

# ls /sys/class/pwm/
pwmchip0

The PWM interfaces begin numbering with an index of 0.

Each PWM interface can manage several PWM channels. Check the number of channels of an interface by printing the value of npwm:

# cat /sys/class/pwm/pwmchip0/npwm
4

To access a channel of the PWM interface, write the channel index to the export descriptor. Notice the hardware manuals name the channels starting from 1 but Linux indexes start at 0. To access channel 1, write 0 to the export descriptor:

# echo 0 > /sys/class/pwm/pwmchip0/export
To get a PWM output on a given pad, the selected channel must match the pinctrl functionality for that pad. For instance, in the example above, pad at Port B GPIO6 can function as PWM 4 channel 1, thus the 0 on the command. Exporting a different channel would require to use a different pinctrl on a different pad.
You won’t be able to request PWM channels that are in use by other drivers, like the one used by the backlight.

Now you can access the PWM channel and configure its settings:

# ls /sys/class/pwm/pwmchip0/pwm0/
duty_cycle  enable      period      polarity    power       uevent

Period and duty cycle must be given in nanoseconds. For example, to configure a 100kHz signal with 20% duty cycle:

# echo 10000 > /sys/class/pwm/pwmchip0/pwm0/period
# echo 2000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle

To enable the PWM signal:

# echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable

The default polarity is normal (active high for the duty cycle). To invert the polarity:

# echo inversed > /sys/class/pwm/pwmchip0/pwm0/polarity

Using Digi APIx library from a C application

An example application called apix-pwm-example is included in the dey-examples-digiapix recipe (part of dey-examples package) of the meta-digi layer. This application shows how to generate a PWM signal using Digi APIx library on the ConnectCore MP15 platform.

Go to GitHub to see the application instructions and source code.

See PWM API for more information about the PWM APIx.

See also