Introduction
In this article, you will learn how to configure and control the Pulse Width Modulation (PWM) pins of the SAMA5D2 Series ARM® Cortex®-A5 Microprocessor Unit (MPU) in the Linux® kernel to control LEDs, motors, and other devices.
You will use the ATSAMA5D27-SOM1-EK1. The ATSAMA5D27 SOM1 contains two 3-channel 32-bit Timer/Counters (TC), supporting basic PWM modes, and one full-featured 4-channel 16-bit PWM.
By default, the Device Trees configure the PWM controller to the RGB LED D5. We show you how to edit the Device Trees to control the PWM pins of the mikroBUS connectors.
Since the generic PWM framework was introduced into the Linux kernel, it is easy to implement the driver for a PWM device and access it in user-space via sysfs.
Prerequisites
This application is developed for the ATSAMA5D27-SOM1-EK1 development platform:
This application is developed using the Buildroot build system:
Hardware
For this article, you will be using the ATSAMA5D27-SOM1-EK1.
The PWM controller can control either the RGB LED D5 (default) or the PWM_mBUS1 and PWM_mBUS2 pins of the mikroBUS 1 expansion socket.
Note in the connection tables below, that two of the PWM pins, PB1 and PA31, are used for both the mikroBUS connectors and the RGB LED D5. By default, the Device Trees connect the PWM pins to the RGB LED. You can configure which device is controlled by the PWM pins by editing and recompiling the Device Trees. We will show you how.
This figure shows the expansion capability of the SOM1-EK1.
For more details of the package and pinout of the SAMA5D2, refer to “Table 6-2. Pinouts” in the SAMA5D2 series data sheet.
mikroBUS
You can control pins PB1 and PA31 from the ATSAMA5D27 SOM1, which connects to J25 pin 1 and J30 pin 1 respectively, of the mikroBUS 1 and mikroBUS 2 connector (labeled PWM_mBUS1 and PWM_mBUS2 on the schematic)..
mikroBUS pin | Schematic Name | Package Pin | Comments |
---|---|---|---|
J25 pin 1 | PWM_mBUS1 | PB1 | Conflict with LED_Green |
J30 pin 1 | PWM_mBUS2 | PA31 | Conflict with LED_blue |
mikroBUS 1
mikroBUS 2
Red-Green-Blue (RGB) LED (D5)
You can also control pins PB1, PA31, and PA10, which connect to the RGB LED D5, Green, Red, and Blue, respectively.
Schematic Name | Package Pin | Comment |
---|---|---|
LED_Green | PB1 | Conflict with PWM_mBUS1 |
LED_blue | PA31 | Conflict with PWM_mBUS2 |
LED_Red | PA10 |
Buildroot Configuration
Objective: Using Buildroot, build a bootable image and FLASH onto an SD Memory Card for the ATSAMA5D27-SOM1-EK1 development board.
Follow the steps for building the image in the "Create Project with Default Configuration" article. You will use the default configuration file, atmel_sama5d27_som1_ek_mmc_dev_defconfig.
As already mentioned, the default configuration of the Device Trees connects the PWM pins to the RGB LED D5. To configure the PWM pins for the mikroBUS connectors, enter the edits as shown below.
Device Tree
Objective: Observe how the PWM controller was configured for PWM in the Device Tree. Note the changes shown below to change the connection of the PWM controller from the RGB LED D5 to the PWM_mBUS1 and PWM_mBUS2 pins of the mikroBUS connectors.
Once Buildroot has completed its build, the PWM definitions for the ATSAMA5D27-SOM1-EK1 were configured by a Device Tree. The device tree source include files (DTSI and DTS), are located in the Buildroot output directory, /output/build/linux-linux4sam_6.0/arch/arm/boot/dts/.
1
Examine the sama5d2.dtsi file and observe the PWM0 device assignments:
769 pwm_clk: pwm_clk {
770 #clock-cells = <0>;
771 reg = <38>;
772 atmel,clk-output-range = <0 83000000>;
773 };
.
.
1232 pwm0: pwm@f802c000 {
1233 compatible = "atmel,sama5d2-pwm";
1234 reg = <0xf802c000 0x4000>;
1235 interrupts = <38 IRQ_TYPE_LEVEL_HIGH 7>;
1236 #pwm-cells = <3>;
1237 clocks = <&pwm_clk>;
1238 };
Line 771: The Peripheral Identification (PID) of PWM0 is 38, this definition of the offset will be used to enable the PWM0 clock in Power Management Controller (PMC).
Line 1233: Specifies which driver will be used for this PWM device.
Line 1234: The PWM0 base address is 0xf802c000, size of register block is 0x4000.
Line 1235: The PID of PWM0 is 38, high level triggered, priority seven.
Line 1237: The definition of the PWM0 clock source.
2
Examine the at91-sama5d27_som1_ek.dts file and observe the PWM0 device assignments:
173 pwm0: pwm@f802c000 {
174 pinctrl-names = "default";
175 pinctrl-0 = <&pinctrl_mikrobus1_pwm &pinctrl_mikrobus2_pwm>;
176 status = "okay"; /* Conflict with leds. */
177 };
.
.
490 pinctrl_mikrobus1_pwm: mikrobus1_pwm {
491 pinmux = <PIN_PB1__PWML1>;
492 bias-disable;
493 };
494
495 pinctrl_mikrobus2_pwm: mikrobus2_pwm {
496 pinmux = <PIN_PA31__PWML0>;
497 bias-disable;
498 };
.
.
560 leds {
561 compatible = "gpio-leds";
562 pinctrl-names = "default";
563 pinctrl-0 = <&pinctrl_led_gpio_default>;
564 status = "disabled"; /* Conflict with pwm0. */
565
566 red {
567 label = "red";
568 gpios = <&pioA PIN_PA10 GPIO_ACTIVE_HIGH>;
569 };
570
571 green {
572 label = "green";
573 gpios = <&pioA PIN_PB1 GPIO_ACTIVE_HIGH>;
574 };
575
576 blue {
577 label = "blue";
578 gpios = <&pioA PIN_PA31 GPIO_ACTIVE_HIGH>;
579 linux,default-trigger = "heartbeat";
580 };
581 };
Line 175: Assigns PWM0 pin definitions to the mikroBUS connectors.
Line 176 (change 1): Change the status to “okay” to enable the PWM0 controller.
Line 491: The mux of PB1 will be switched to PWML1.
Line 492: The pull-up/down feature will be disabled.
Line 496: The mux of PA31 will be switched to PWML0.
Line 497: The pull-up/down feature will be disabled.
Line 564 (change 2): Change the status to “disabled” to disable the RGB LED.
Kernel
Objective: Observe how the PWM functionality was configured in the Linux kernel.
Device Driver
2
Select Device Drivers —->.
sysfs File System Support
1
Back up to the Kernel Configuration top-level menu (ESC-ESC twice).
4
Observe that -*- sysfs file system support is selected.
By default, the sysfs support has been selected. As there is no device node file for the PWM controller, you will access the PWM driver via the sysfs in User Space.
Rootfs
You can access the PWM driver via the following sysfs path in user space, /sys/class/pwm.
Several files and sub-folders can be found in this path.
For more details on PWM in Linux, see kernel_dir/documentation/pwm.txt.
- /sys/class/pwm/pwmchipN: Each probed PWM controller will be exported as pwmchipN, where N is the base of the PWM controller.
- /sys/class/pwm/pwmchipN/npwm: The number of PWM channels which this controller supports (read-only).
- /sys/class/pwm/pwmchipN/export: Exports a PWM channel with sysfs (write-only). (The PWM channels are numbered using a per-controller index from 0 to npwm-1.)
- /sys/class/pwm/pwmchipN/unexport: Un-exports a PWM channel from sysfs (write-only).
When a PWM channel is exported, a pwmX directory will be created in the pwmchipN directory, where X is the number of the channel that was exported.
The following properties will be available:
- /sys/class/pwm/pwmchipN/pwmX/period – The total period of the PWM signal (read/write). Value is in nanoseconds and is the sum of the active and inactive time of the PWM.
- /sys/class/pwm/pwmchipN/pwmX/duty_cycle – The active time of the PWM signal (read/write). Value is in nanoseconds and must be less than the period.
- /sys/class/pwm/pwmchipN/pwmX/polarity – Change the polarity of the PWM signal (read/write). This property only works if the PWM controller supports changing the polarity. The polarity can only be changed if the PWM is not enabled. Value is the string "normal" or "inversed".
- /sys/class/pwm/pwmchipN/pwmX/enable – Enable/disable the PWM signal (read/write) where 0 = disabled and 1 = enabled.
Hands-On
1. Hands-on with PWM_mBUS1
1
Reset the target board.
# reboot
2
The following will setup a 10 kHz 90% duty cycle PWM output:
# cd /sys/class/pwm/
# ls
pwmchip0
# cd pwmchip0/
# echo 1 > export
# ls
device npwm pwm1 uevent
export power subsystem unexport
# cd pwm1/
# ls
capture enable polarity uevent
duty_cycle period power
# echo 100000 > period
# echo 90000 > duty_cycle
# echo 1 > enable
2. Hands-on with LED_Green
1
Reset target board.
# reboot
2
Turn off LED_Red.
# echo 10 > /sys/class/gpio/export
# echo out > /sys/class/gpio/PA10/direction
# echo 0 > /sys/class/gpio/PA10/value
3
Turn off LED_Blue.
# echo 0 > /sys/class/pwm/pwmchip0/export
# echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/period
# echo 10000000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
# echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
4
Set up PWM channel 1 output.
# cd /sys/class/pwm/pwmchip0/
# echo 1 > export
# cd pwm1/
5
Adjust LED_Green brightness.
# echo 10000000 > period
# echo 10000000 > duty_cycle
# echo 1 > enable
# echo 9000000 > duty_cycle
# echo 8000000 > duty_cycle
# echo 7000000 > duty_cycle
# echo 6000000 > duty_cycle
# echo 5000000 > duty_cycle
# echo 4000000 > duty_cycle
# echo 3000000 > duty_cycle
# echo 2000000 > duty_cycle
# echo 1000000 > duty_cycle
6
Set LED_Green blink.
# echo 0 > enable
# echo 100000000 > period
# echo 50000000 > duty_cycle
# echo 1 > enable
3. Hands-on with Synchronous Channels
Some channels can be linked together as synchronous channels.
Refer to the “55.6.2.9 Synchronous Channels” chapter in the SAMA5D2 data sheet for more detailed information about this feature.
In Linux, the current PWM device model doesn’t support this feature. We can test this feature through a direct register setting via the devmem2 command.
The following shows the command sequence for using PWM0 and PWM1 as synchronous channels.
1
Reset target board.
# reboot
2
These are commands for PWM channel initialization:
a
Enable the PWM0 and PWM1 SYNC feature.
# devmem2 0xF802C020 w 0x3
# cd /sys/class/pwm/pwmchip0/
# echo 0 > export
# echo 1 > export
# echo 10000000 > pwm1/period
# echo 9000000 > pwm1/duty_cycle
b
This is dummy enabling for PWM1, used for writing duty cycle configurations:
# echo 1 > pwm1/enable
c
Since the SYNC feature of PWM1 has been enabled, all SYNC channels are enabled together by enabling channel 0.
# echo 10000000 > pwm0/period
# echo 2000000 > pwm0/duty_cycle
d
Here the output of PWM0 and PWM1 will be enabled together:
# echo 1 > pwm0/enable
Summary
In this article, you used Buildroot to build an image with PWM support for the ATSAMA5D2 series MPU. You walked through the Device Tree and Kernel to observe how the embedded Linux system configures the source code for building. You also edited the Device Trees to control the PWM pins of the mikroBUS connectors. Finally, you tried some hands-on exercises to see the PWM controller in action.