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 6UL system-on-module:

  • Eight PWM signals (from PWM1 to PWM8) available from the i.MX6UL system-on-chip (multiplexed with other signals).

On the ConnectCore 6UL SBC Express:

  • PWM1, PWM2, PWM3, and PWM4 are available on the expansion header.

On the ConnectCore 6UL SBC Pro:

  • PWM4 is available at EXP_GPIO_1 on the GPIO expansion connector.

  • PWM5 is connected to the parallel display and LVDS display connectors for backlight control.

Kernel configuration

You can manage the i.MX6UL PWM driver support through the following kernel configuration option:

  • i.MX27 PWM support (CONFIG_PWM_IMX27)

This option is enabled as built-in on the default ConnectCore 6UL kernel configuration file.

Kernel driver

The driver for the i.MX6UL PWM is located at:

File Description

drivers/pwm/pwm-imx27.c

PWM driver

Device tree bindings and customization

The i.MX6UL PWM interface is documented at Documentation/devicetree/bindings/pwm/imx-pwm.yaml.

i.MX6UL PWM interfaces

The common i.MX6UL CPU device tree file contains entries for all the PWM channels:

i.MX6UL device tree
pwm1: pwm@2080000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x02080000 0x4000>;
	interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM1>,
		<&clks IMX6UL_CLK_PWM1>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm2: pwm@2084000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x02084000 0x4000>;
	interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM2>,
		<&clks IMX6UL_CLK_PWM2>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm3: pwm@2088000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x02088000 0x4000>;
	interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM3>,
		<&clks IMX6UL_CLK_PWM3>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm4: pwm@208c000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x0208c000 0x4000>;
	interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM4>,
		<&clks IMX6UL_CLK_PWM4>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm5: pwm@20f0000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x020f0000 0x4000>;
	interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM5>,
		<&clks IMX6UL_CLK_PWM5>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm6: pwm@20f4000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x020f4000 0x4000>;
	interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM6>,
		<&clks IMX6UL_CLK_PWM6>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm7: pwm@20f8000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x020f8000 0x4000>;
	interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM7>,
		<&clks IMX6UL_CLK_PWM7>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
};

pwm8: pwm@20fc000 {
	compatible = "fsl,imx6ul-pwm", "fsl,imx27-pwm";
	reg = <0x020fc000 0x4000>;
	interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_PWM8>,
		<&clks IMX6UL_CLK_PWM8>;
	clock-names = "ipg", "per";
	#pwm-cells = <3>;
}

IOMUX configuration

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

i.MX6UL 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 device tree:

  • On the ConnectCore 6UL SBC Express expansion connector:

    Pad Signal PWM

    27

    PWM1/I2C3_SDA_PROT

    PWM1

  • On the ConnectCore 6UL SBC Pro GPIO connector:

    Pad Signal PWM

    12

    EXP_GPIO_1

    PWM4

Example: enable PWM4 on ConnectCore 6UL SBC Express

For example, PWM4 is available on the ConnectCore 6UL SBC Express expansion connector which corresponds to pad LCD_DATA03 of the CPU. In order to enable it, you must:

  • Configure the IOMUX of pad LCD_DATA03 to work as PWM4.

  • Remove any other LCD_DATA03 IOMUX configuration from any active driver pinctrl group.

  • Enable the PWM node.

ConnectCore 6UL SBC Express device tree
&pwm4 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm4>;
	status = "okay";
};

&iomuxc {
	imx6ul-ccimx6ul {
		pinctrl_pwm4: pwm4grp {
			fsl,pins = <
				MX6UL_PAD_LCD_DATA03__PWM4_OUT          0x11080
			>;
		};
	};
};

Depending on the frequency of the PWM signal and the hardware around it, you must enable the pad settings carefully (the numerical value following the IOMUX definition on the device tree). See Documentation/devicetree/bindings/pinctrl/fsl,imx6ul-pinctrl.txt for information about the different values. Also see the NXP application note AN5078 Influence of pin setting on system function and performance for additional information.

Using the PWM channels

Control PWM signal from sysfs

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

On the ConnectCore 6UL SBC Express:

  • PWM1 is enabled (available at pin 27 of Raspberry Pi expansion connector, and at J11 grove connector, through non-populated 0-ohm resistor)

  • All other PWM channels are disabled by default

On the ConnectCore 6UL SBC Pro:

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

  • 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. The indexes are calculated using the number of channels of the previous interface.

Each PWM interface only manages one PWM signal. Check the number of channels of an interface by printing the value of npwm:

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

To access one channel of a PWM interface, export the channel index (0 since there is only one):

# echo 0 > /sys/class/pwm/pwmchip0/export
You won’t be able to request PWM channels that are in use by other drivers, like those 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 6UL platform.

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

See PWM API for more information about the PWM APIx.

See also