[[PageOutline]] = Pulse Width Modulation (PWM) = Pulse Width Modulation refers to a modulation technique where a digital output signal will alternate high and low with possibly differing on/off times. PWM signals are commonly used in embedded systems for: * controlling analog devices (by using an RC circuit to convert the digital PWM signal to an analog voltage) * controlling the brightness of an LED * controlling the position of an RC hobby stepper motor When working with PWM's the following terminology is commonly used: * period - represents the period the PWM signal alternates between its off/on times * duty-cycle - represents the on time as a percentage of the duty cycle (ie 10% duty-cycle means the signal is on for 10% of the period and off for 90% of the period) Many Gateworks boards have on-board PWM controllers and offer one or more PWM outputs with 3.3V TTL voltage levels. References: - https://en.wikipedia.org/wiki/Pulse-width_modulation [=#hardware-mapping] = PWM mapping = The various product hardware manuals will call out what PWM devices are available on each board. The hardware mapping of the PWM controllers is defined in the Linux kernel device-tree for Ventana (ie http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi). If debugfs is enabled in the kernel (as it is on Gateworks BSP's) you can see a nice table of PWM mapping via {{{/sys/kernel/debug/pwm}}} showing each PWM controller by name, a list of the PWM's it provides, what driver (if any) has control over them, and their state. For example: {{{ #!bash root@ventana:~# cat /sys/kernel/debug/pwm platform/208c000.pwm, 1 PWM device pwm-0 (backlight ): requested enabled platform/2088000.pwm, 1 PWM device pwm-0 ((null) ): platform/2084000.pwm, 1 PWM device pwm-0 (sysfs ): requested enabled platform/2080000.pwm, 1 PWM device pwm-0 ((null) ): }}} * The above is an IMX6 showing its 4 controllers available, each controller providing 1 PWM pin. The first one shown (0x208c000 maps to IMX PWM4) is used by the backlight driver. The 2nd (0x2088000 maps to IMX PWM3) is unused. The third one (0x2084000 maps to IMX PWM2) is exported for use by sysfs. The fourth (0x2080000 maps to IMX PWM1) is unused. == Ventana PWM mapping == The IMX6 SoC has 4 PWM controllers each having a single PWM signal: ||= IMX6 controller address =||= IMX6 pwm =|| || pwm@02080000 || pwm1 || || pwm@02084000 || pwm2 || || pwm@02088000 || pwm3 || || pwm@0208c000 || pwm4 || Only the controllers enabled in the device-tree will be registered therefore you won't always see pwmchip0-3 and can't depend on that mapping to be consistent as it varies board to board and is also dependent on which (if any) DIO's you may have configured as PWM via the bootloader {{{hwconfig}}} variable. You must look at the symlink /sys/class/pwm/pwmchip*/device to see what controller is linked to. The Ventana bootloader {{{hwconfig}}} env variable must be properly set to configure PWM mode for the DIO pin, otherwise the pin will be muxed to the GPIO controller and the pwmchip controller will be disabled. For example, to configure DIO1 as a PWM and DIO0, DIO2, DIO3 as GPIO: {{{ #!bash Ventana> setenv hwconfig 'dio0:mode=gpio;dio1:mode=pwm;dio2:mode=gpio;dio3:mode=gpio' Ventana> saveenv }}} For example a GW53xx which has DIO1 configured as a GPIO, and DIO2 configured as a PWM (PWM3) shows: * bootloader {{{hwconfig}}} {{{ #!bash root@ventana:~# fw_printenv | grep hwconfig hwconfig=dio0:mode=gpio;dio1:mode=pwm;dio2:mode=gpio;dio3:mode=gpio }}} * /sys/kernel/debug/pwm: {{{ #!bash root@ventana:~# cat /sys/kernel/debug/pwm platform/208c000.pwm, 1 PWM device pwm-0 (backlight ): requested enabled platform/2088000.pwm, 1 PWM device pwm-0 ((null) ): platform/2080000.pwm, 1 PWM device pwm-0 ((null) ): }}} * /sys/class/pwmchip* linkage: {{{ #!bash root@ventana:~# ls -l /sys/class/pwm/pwmchip*/device lrwxrwxrwx 1 root root 0 Dec 18 15:33 /sys/class/pwm/pwmchip0/device -> ../../../2080000.pwm lrwxrwxrwx 1 root root 0 Dec 18 15:33 /sys/class/pwm/pwmchip1/device -> ../../../2088000.pwm lrwxrwxrwx 1 root root 0 Dec 18 15:33 /sys/class/pwm/pwmchip2/device -> ../../../208c000.pwm }}} - shows that IMX6 pwm1 is /sys/class/pwm/pwmchip0 (because its linked to the controller address 0x2080000). This is unused but it is present because its controller's node was not specifically 'disabled' in the device-tree. - shows that IMX6 pwm3 is /sys/class/pwm/pwmchip1 (because its linked to the controller address 0x2088000). This is PWM3 which on the GW53xx is mapped to DIO2 coming out J4.3. This is present because the bootloader {{{hwconfig}}} specified DIO2 as a PWM. - shows that IMX6 pwm4 is /sys/class/pwm/pwmchip2 (because its linked to the controller address 0x208c000). This is PWM4 which on the GW53xx is mapped to the backlight controller present on the LVDS connector. You can use the following script will provide the sysfs path for an IMX PWM: {{{ #!bash #!/bin/sh # match IMX PWM{$1} with available pwm controllers for i in $(ls /sys/class/pwm); do link=$(readlink /sys/class/pwm/$i) IMXPWM= case "$link" in *2080000*) IMXPWM=1;; *2084000*) IMXPWM=2;; *2088000*) IMXPWM=3;; *208c000*) IMXPWM=4;; esac [ $IMXPWM -a $IMXPWM == $1 ] && { chip=$i; break; } done [ $chip ] || { echo "chip not found for IMX PWM$1"; exit; } path="/sys/class/pwm/$chip" # export first pwm for chip echo "$path/pwm0" [ -d $path/pwm0 ] || { echo 0 > $path/export; } [ -d $path/pwm0 ] || { echo "Export failed - not PWM$1 not available"; } }}} Example use: {{{ #!bash root@ventana:/ # /data/test 2 # get path for IMX PWM2 /sys/class/pwm/pwmchip1/pwm0 }}} The following table shows what PWM's are available on the various Ventana baseboards: ||= '''Board''' =||= '''DIO''',,(1),, =||= '''Connector''',,(2),, =||= '''IMX6_PAD''',,(3),, =||= '''IMX6 GPIO''',,(4),, =||= '''linux gpio''',,(5),, =||= '''linux PWM''',,(6),, =|| || GW51xx || DIO1 || J11.7 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW51xx || DIO2 || J11.6 || PAD_SD1_DATA1 || GPIO1_IO17 || gpio-17 || PWM3 (0x02088000) || || GW51xx || DIO3 || J11.8 || PAD_SD1_CMD || GPIO1_IO18 || gpio-18 || PWM4 (0x0208C000) || || || || GW52xx || DIO1 || J4.2 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW52xx || DIO2 || J4.3 || PAD_SD1_DATA1 || GPIO1_IO17 || gpio-17 || PWM3 (0x02088000) || || GW52xx || - || J6.5 || PAD_SD1_CMD || GPIO1_IO18 || gpio-18 || PWM4 (0x0208C000) || || || || GW53xx || DIO1 || J4.2 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW53xx || DIO2 || J4.3 || PAD_SD1_DATA1 || GPIO1_IO17 || gpio-17 || PWM3 (0x02088000) || || GW53xx || - || J6.5 || PAD_SD1_CMD || GPIO1_IO18 || gpio-18 || PWM4 (0x0208C000) || || || || GW54xx || DIO0 || J16.1 || PAD_GPIO_9 || GPIO1_IO09 || gpio-9 || PWM1 (0x02080000) || || GW54xx || DIO1 || J16.2 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW54xx || DIO2 || J16.3 || PAD_SD4_DATA1 || GPIO2_IO09 || gpio-41 || PWM3 (0x02088000) || || GW54xx || DIO3,,(7),, || J16.4 || PAD_SD4_DATA2 || GPIO2_IO10 || gpio-42 || PWM4 (0x0208C000) || || GW54xx || - || J6.5 || PAD_SD1_CMD || GPIO1_IO18 || gpio-18 || PWM4 (0x0208C000) || || || || GW553x || DIO1 || J10.7 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW553x || DIO2 || J10.6 || PAD_SD1_DATA1 || GPIO1_IO17 || gpio-17 || PWM3 (0x02088000) || || GW53xx || DIO3 || J10.8 || PAD_SD1_CMD || GPIO1_IO18 || gpio-18 || PWM4 (0x0208C000) || || || || GW552x || DIO1 || J8.11 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW552x || DIO2 || J8.10 || PAD_SD1_DATA1 || GPIO1_IO17 || gpio-17 || PWM3 (0x02088000) || || || || GW551x || DIO1 || J3.19 || PAD_SD1_DATA2 || GPIO1_IO19 || gpio-19 || PWM2 (0x02084000) || || GW551x || DIO2 || J3.20 || PAD_SD1_DATA1 || GPIO2_IO17 || gpio-17 || PWM3 (0x02088000) || || 1. This is the signal name from the [http://www.gateworks.com/usermanuals Ventana hardware manuals] 2. This is the connector pinout. The 5th pin on 5-pin connectors is GND 3. Consult the IMX6 Reference manuals for PAD info: [http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6DQRM.pdf IMX6DQRM] [http://cache.freescale.com/files/32bit/doc/ref_manual/IMX6SDLRM.pdf IMX6SDLRM] 4. This is the GPIO block and IO the PAD is pinmux'd to when hwconfig is configured for GPIO 5. This is the gpio mapped in linux accessible via /sys/class/gpio. Note that the pinmux and IO configuration are done by the [wiki:ventana/bootloader#DIOconfiguration bootloader], but you will need to manually export the GPIO to use it (see [wiki:gpio here] for details) 6. This is the PWM that the PAD is pinmux'd to by the bootloader with hwconfig is conifgured for PWM. [wiki:ventana/bootloader#DIOconfiguration u-boot hwconfig to configure DIO pinmux/config] 7. The GW5400 PWM4 can be routed to two different pads/connectors. By default the Ventana kernel device-tree's map PWM4 to the J6.5 backlight connector. If you want to use PWM4 as DIO3 on J16.4 you need to change the kernel device-tree and should contact support@gateworks.com for details. See also: * [wiki:ventana/DigitalIO Ventana Digital IO Mapping Page] * [http://www.gateworks.com/usermanuals Board specific hardware manual] [=#linux] = Linux PWM and pwm class = The Linux kernel con provide pwm functionality to userspace via a pwm class accessed via sysfs (/sys/class/pwm/). For userspace access this requires sysfs kernel support (CONFIG_SYSFS) and the sysfs filesystem mounted which is standard for most linux systems including Gateworks BSP's). This framework allows boards to define PWM controllers and allow userspace to make use of them by adjusting their period, duty-cycle, and enable. Note that any pwm that is registered for use by a driver is not available for exporting for userspace control. You can {{{cat /sys/kernel/debug/pwm}}} to see what pwm's are currently registered with the kernel (those shown to be owned by {{{sysfs}}} are exported for userspace, those shown as {{{null}}} are not exported or in use by any driver). Note that the pwm sysfs API is slightly different from the gpio sysfs API: * the individual pwm's from a pwmchip (controller) are in the subdir of the pwmchip and all start with index 0 (whereas gpio's are exported to /sys/class/gpio and keep increasing in number) Each exported pwm will be in the sub-directory of it's controller chip and will be 0 based. For example, the 2nd pwm of a pwm controller that has 16 pwm's which was the 3rd pwm controller to be registered will be /sys/class/pwmchip2/pwm1 (0 based). You can determine which pwmchip is which by either looking at {{{/sys/kernel/debug/pwm}}} or the symlink of the device file in the pwmchip directory. Here are some example use cases for using pwm-class via syfs: * to see pwm names and state: (requires debugfs kernel support and fs mounted) {{{ #!bash cat /sys/kernel/debug/pwm }}} * to export a PWM that is not currently in use: {{{ #!bash echo 0 > /sys/class/pwm/pwmchip0/export # export the first pwm (pwm0) on the first pwm controller (pwmchip0) }}} * to change the period of the PWM signal (value is in nanoseconds and is the sum of the active and inactive time of the PWM) {{{ #!bash echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period # set 1ms period cat /sys/class/pwm/pwmchip0/pwm0/period # see period }}} * to change the duty cycle of the PWM signal (value is in nanoseconds refers to the time the signal is active and must be less than the period) {{{ #!bash echo 500000 > /sys/class/pwm/pwmchip0/pwm0/period # set 500us (50% duty-cycle if period is 1ms) cat /sys/class/pwm/pwmchip0/pwm0/duty_cycle # see duty_cycle }}} * to change the polarity of the PWM signal: (*Note not supported on i.MX6 PWM) {{{ #!bash echo normal > /sys/class/pwm/pwmchip0/pwm0/polarity # set normal polarity echo inversed > /sys/class/pwm/pwmchip0/pwm0/polarity # set inverted polarity cat /sys/class/pwm/pwmchip0/pwm0/polarity # see polarity }}} * to enable/disable a PWM signal: {{{ #!bash echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable # enable output echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable # disable output }}} References: - [http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/pwm.txt Documentation/pwm.txt] = PWM based LEDs = See wiki:linux/led = PWM based Backlight = See wiki:linux/backlight