Here’s my take on getting that pwm running. I have an amp and piezo element attached to it, so ignore that. What you probably are looking for can be found in the summary block. And it isn’t perfect. I have on my “wouldn’t it be nice” list to figure out why It sometimes quits when I start pushing the boundaries regarding the period and duty cycle.
Oh, and take note that duty cycle is really the on time for each period and not a percentage of the period.
///
/// This section covers the functionality of the sounder
/// The following commands will perform action(s) similar to this function:
/// config-pin p9.42 pwm
/// echo 0 /sys/class/pwm/pwmchip0/export
/// echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period
/// echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
/// echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
/// [at this point the sounder squeals like a square wave]
/// echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable
/// [at this point the sounder should go quiet]
///
/// The frequency to drive the sounder at
/// The duration of time to drive the sounder
/// reports the current board temp to stdout
void do_beep(float frequency,float duration)
{
long int period;
period = (long int)((float)1000000000.0 / frequency);
struct timespec sNapPeriod, sNapRemaining;
char periodstring[20],dutystring[20];
snprintf(periodstring,80, “%ld”, period);
snprintf(dutystring, 20, “%ld”, (period / 2));
// set up a nap time to pace pwm configuration
sNapPeriod.tv_sec = 0;
sNapPeriod.tv_nsec = (long) 10000000; // 10 million nanosecond equals 0.01 seconds
sNapRemaining.tv_sec = 0;
sNapRemaining.tv_nsec = 0;
// The PWM is controlled through the /sys interface. The following is a link to
// a source for one of the stock beaglebone libraries that involve PWM, not to mention
// a cape that we're not using. The bad news is that the controlling path(s) for these
// devices changes relative to the version of the kernel.
// For example: going from 4.19.94-ti-r42 to 4.19.232-bone75, the controlling paths change
// /sys/class/pwm/pwmchip0/pwm-0:0/ changes to /sys/class/pwm/pwmchip0/pwm0/
// There are libraries that involve accessing them. Reviewing their source, however, shows that
// they are tied to the kernel version being used at the time the following link shows how
// the librobotcontrol does their manipulation of the PWM.
// https://git.beagleboard.org/beagleboard/librobotcontrol/-/blob/master/library/src/io/pwm.c
// Set P9.42 to PWM mode, if not already done.
//This is effectively what system("config-pin P9_42 pwm") does
int pwmfio;
if (access("/sys/devices/platform/ocp/ocp:P9_42_pinmux/state", F_OK) != 0)
{
printf("ERROR! Pinmux control for the sounder's gpio line is absent!");
}
else
{
if ((access("/sys/devices/platform/ocp/ocp:P9_42_pinmux/state", W_OK) != 0)
|| (access("/sys/class/pwm/pwmchip0/export", W_OK) != 0))
{
printf("Sorry, write permissions denied for pwm setup, Try running as root\n");
}
else
{
nanosleep(&sNapPeriod, &sNapRemaining);
pwmfio = open("/sys/devices/platform/ocp/ocp:P9_42_pinmux/state", O_WRONLY);
write(pwmfio, "pwm", 3);
close(pwmfio);
nanosleep(&sNapPeriod, &sNapRemaining);
pwmfio = open("/sys/class/pwm/pwmchip0/export", O_WRONLY);
write(pwmfio, "0", 1);
close(pwmfio);
// Set the period in nanoseconds. 1 million should give 1 kHz
pwmfio = open("/sys/class/pwm/pwmchip0/pwm-0:0/period", O_WRONLY);
write(pwmfio, periodstring, 20);
close(pwmfio);
nanosleep(&sNapPeriod, &sNapRemaining);
// set the duty cycle to half the period to get 50% square wave
pwmfio = open("/sys/class/pwm/pwmchip0/pwm-0:0/duty_cycle", O_WRONLY);
write(pwmfio, dutystring, 20);
close(pwmfio);
// set enable to 1 to get it to start making noise.
pwmfio = open("/sys/class/pwm/pwmchip0/pwm-0:0/enable", O_WRONLY);
write(pwmfio, "1", 1);
close(pwmfio);
// set up a nap and wait a couple seconds to annoy the user
sNapPeriod.tv_sec = (time_t)trunc(duration);
sNapPeriod.tv_nsec = (long)(fmod(duration, 1.0) * 1000000000.0); // 100 million nanosecond equals 0.1 seconds
sNapRemaining.tv_sec = 0;
sNapRemaining.tv_nsec = 0;
nanosleep(&sNapPeriod, &sNapRemaining);
// shut off the pwm to quiet the speaker
pwmfio = open("/sys/class/pwm/pwmchip0/pwm-0:0/enable", O_WRONLY);
write(pwmfio, "0", 1);
close(pwmfio);
}
}
} // end of do_beep()