A PWM (Pulse-Width Modulator) is a component used for controlling power to inertial electrical devices. It generates a periodic waveform with positive width that can be controlled, which allows the waveform’s average value to be modified.
The average value of voltage fed to the load is controlled by rapidly turning the switch between the supply and the load on and off. The longer the switch is on compared to the off, the higher the power supplied to the load will be.
The ConnectCore platforms have several PWM interfaces. You can find more information in Hardware reference manuals and Pulse-Width Modulation (PWM).
Digi adds an API to Linux to manage these PWM interfaces. To use this API, include the following header file:
#include <libdigiapix/pwm.h>
You can configure the interfaces and set the working frequency and duty cycle.
Request a PWM
You can request a PWM with one of the following functions:
Function | Description |
---|---|
|
Requests a PWM by its chip number and channel number. It returns a pointer to |
|
Requests a PWM by its alias name. The PWM alias mapping must be defined in the It returns a pointer to |
The requested PWM must be freed once it is no longer needed. See Free a PWM. |
Both functions may fail and return NULL
for the following reasons:
-
The provided chip and channel numbers, or the associated chip and channel numbers to the given alias cannot be exported.
-
The API encountered problems allocating memory to initialize the PWM. Your system may have run out of resources.
-
The request mode is configured to
REQUEST_WEAK
and the PWM is already exported.
When requesting a PWM, you can select the request mode from the following request_mode_t
values:
-
REQUEST_SHARED
: If the PWM is already exported, it will not be unexported on free. If it is not exported, it will be unexported on free. -
REQUEST_GREEDY
: The PWM will be always unexported on free. -
REQUEST_WEAK
: If the PWM is already exported, the request will fail. It will always be unexported on free.
/* Request a PWM using its alias */
pwm_t *pwm1 = ldx_pwm_request_by_alias("DEFAULT_PWM", REQUEST_SHARED);
/* Request a PWM located in the chip = 1 channel = 0 */
pwm_t *pwm2 = ldx_pwm_request(1, 0, REQUEST_SHARED);
Once you have requested the PWM, you can enable it or verify whether it is enabled or not using the following functions:
Function | Description |
---|---|
|
Retrieves the enable status of the PWM:
|
|
Changes the enable status of the PWM:
It returns |
/* Enable pwm1 */
ldx_pwm_enable(pwm1, PWM_ENABLED);
/* Disable pwm2 */
ldx_pwm_enable(pwm2, PWM_ENABLED);
printf("The PWM 1 (chip %d, channel %d) is %s\n",
pwm1->pwm_chip, pwm1->pwm_channel,
ldx_pwm_is_enabled(pwm1) == PWM_ENABLED ? "enabled" : "disabled");
printf("The PWM 2 (chip %d, channel %d) is %s\n",
pwm2->pwm_chip, pwm2->pwm_channel,
ldx_pwm_is_enabled(pwm2) == PWM_ENABLED ? "enabled" : "disabled");
Establish PWM aliases
To help you identify the PWMs of your design, you can assign aliases to your PWM Linux IDs.
Map the assigned chip number, channel, and name in the /etc/libdigiapix.conf
file:
-
Add a section called [PWM], if one does not already exist.
-
Below the section name, add the list of mapped PWMs following the format:
<alias> = <pwm_chip>,<pwm_channel>
Where:
-
<alias>
is the human-readable name for the PWM. -
<pwm_chip>
is the PWM chip. -
<pwm_channel>
is the PWM channel used by that PWM chip.
-
[PWM]
# PWM1 on Expansion connector (pin 27).
DEFAULT_PWM = 0,0
For example, using the configuration above, you can request a PWM with the API using DEFAULT_PWM
alias.
See Request a PWM.
You can get the chip and the channel associated with an alias using these functions:
int ldx_pwm_get_chip(const char * const pwm_alias);
int ldx_pwm_get_channel(const char * const pwm_alias);
For information on including libdigiapix.conf in your Digi Embedded Yocto images, see Define interface aliases.
|
Free a PWM
You must free a requested PWM when it is no longer required.
To do so, use the ldx_pwm_free()
function.
int ldx_pwm_free(pwm_t *pwm);
pwm_t *pwm = ...;
/* [...] */
ldx_pwm_free(pwm);
Configure the PWM frequency
You can read and set the PWM frequency value:
Function | Description |
---|---|
|
Retrieves the value of the PWM channel frequency in Hz. If there is an error, the function returns -1. |
|
Sets the frequency of the PWM channel in Hz. It returns a
|
The PWM frequency range is:
-
Minimum value: 1 Hz.
-
Maximum value: 1000000000 Hz (1 GHz).
If you try to set a frequency value less than the current duty cycle for that PWM channel, a PWM_CONFIG_ERROR_INVALID
error is returned.
The minimum PWM period that can be get/set (1 ns) can create a mismatch between the configured and the desired frequencies, particularly with values greater than 1 MHz. |
For a more accurate configuration, see Configure the PWM period.
Calculate the final configured frequency:
ns = [1000000000 / f] F = [1000000000 / ns] [x] means the nearest integer to x, for example [1.6] = 2, [3.4] = 3
Desired frequency (MHz) | Configured frequency (MHz) |
---|---|
1000 |
1000 |
750 |
1000 |
650 |
500 |
500 |
500 |
350 |
333.33 |
250 |
250 |
100 |
100 |
75 |
76.92 |
65 |
66.67 |
50 |
50 |
35 |
34.48 |
15 |
14.93 |
7 |
6.99 |
4.5 |
4.504 |
1.5 |
1.499 |
pwm_t *pwm = ...;
/* Configure a frequency of 1000 Hz */
ldx_pwm_set_freq(pwm, 1000);
printf("The frequency for PWM %d.%d is %l Hz\n",
pwm->pwm_chip, pwm->pwm_channel, ldx_pwm_get_freq(pwm));
Configure the PWM period
You can read and set the PWM period value:
Function | Description |
---|---|
|
Retrieves the value of the PWM channel period in nanoseconds. If there is some error, the function returns -1. |
|
Sets the period of the PWM channel in nanoseconds. It returns a
|
The PWM period range is:
-
Minimum value: 1 ns.
-
Maximum value: 2147483647 ns.
If you try to set a period value less than the current duty cycle for that PWM channel, a PWM_CONFIG_ERROR_INVALID
error is returned.
pwm_t *pwm = ...;
/* Configure a period of 1000000 ns, 1 ms */
ldx_pwm_set_period(pwm, 1000000);
printf("The period for PWM %d.%d is %d ns\n",
pwm->pwm_chip, pwm->pwm_channel, ldx_pwm_get_period(pwm));
Manage the duty cycle
You can manage and work with the duty cycle using one of two methods: nanoseconds or percentage.
Work with percentage
You can read and set the PWM duty cycle in percentage with the following functions:
Function | Description |
---|---|
|
Retrieves the duty cycle percentage of a PWM signal. If there is some error, the function returns -1. |
|
Sets the duty cycle percentage for the selected PWM. It returns a
|
pwm_t *pwm = ...;
/* Configure a period of 1000000 ns (1 ms) */
ldx_pwm_set_period(pwm, 1000000);
/* Configure a duty cycle of 50% (0.5 ms) */
ldx_pwm_set_duty_cycle_percentage(pwm, 50);
printf("The duty cycle for PWM %d.%d is %d%%\n",
pwm->pwm_chip, pwm->pwm_channel, ldx_pwm_get_duty_cycle_percentage(pwm));
Work with nanoseconds
You can read and set the PWM duty cycle in nanoseconds with the following functions:
Function | Description |
---|---|
|
Retrieves the value of the PWM channel duty cycle in nanoseconds. If there is an error, the function returns -1. |
|
Sets the duty cycle in nanoseconds for the selected PWM channel. It returns a
|
The PWM duty cycle range is:
-
Minimum value: 1 ns.
-
Maximum value: less than the current period.
If you try to set a duty cycle value greater than the current period for that PWM channel, a PWM_CONFIG_ERROR_INVALID
error is returned.
pwm_t *pwm = ...;
/* Configure a period of 1000000 ns (1 ms) */
ldx_pwm_set_period(pwm, 1000000);
/* Configure a duty cycle of 500000 ns (0.5 ms) */
ldx_pwm_set_duty_cycle(pwm, 500000);
printf("The duty cycle for PWM %d.%d is %d ns\n",
pwm->pwm_chip, pwm->pwm_channel, ldx_pwm_get_duty_cycle(pwm));
Change the polarity
You can read and set the PWM polarity with the following functions:
Function | Description |
---|---|
|
Retrieves the value of the PWM polarity.
|
|
Changes the polarity of the selected PWM channel:
It returns |
You can only change the polarity if the PWM is not enabled; otherwise, EXIT_FAILURE is returned.
|
Not all platforms support changing the PWM polarity. See Pulse-Width Modulation (PWM) for more information.
pwm_t *pwm = ...;
ldx_pwm_set_polarity(pwm, PWM_INVERSED);
printf("The polarity for PWM %d.%d is %d\n",
pwm->pwm_chip, pwm->pwm_channel, ldx_pwm_get_polarity(pwm));
PWM example
In this example, one PWM line of the board is enabled using a frequency of 1000Hz. Then, the duty cycle is progressively modified in a loop from 10% to 90% and vice-versa.
You can import the example in Eclipse using the Digi Embedded Yocto plugin. For more information, see Create a new DEY sample project. This example is included in Digi Embedded Yocto. Go to GitHub to see the application source code.