======= PWM ======
The yocto kernel support the PWM on stout. The PWM is implemented as simple sysfs interface
Supported channels:
PWM0..2 = shared with other function (needs reprogramming of CPLD)
PWM3 = pwmchip0
PWM4 = pwmchip1
/sys/class/pwm/
`-- pwmchipN/ for each PWM chip (N = 0 or 1)
|-- export (w/o) ask the kernel to export a PWM channel
|-- npwm (r/o) number of PWM channels in this PWM chip
|-- pwmX/ for each exported PWM channel (X = 0 or 1)
| |-- duty_cycle (r/w) duty cycle (in nanoseconds)
| |-- enable (r/w) enable/disable PWM (0 is disabled, 1 is enabled)
| |-- period (r/w) period (in nanoseconds)
| `-- polarity (r/w) polarity of PWM (normal/inversed)
`-- unexport (w/o) return a PWM channel to the kernel
Examples (command line):
cd /sys/class/pwm
cd pwmchip0
echo 0 > export ' get PWM control from kernel '
cd pwm0
echo 20000000 > period ' set period to 20ms (50Hz = RC servo signal) '
echo 2000000 > duty_cycle ' set duty cycle to 2ms '
echo 1 > enable ' enable output '
echo 0 > enable ' disable output '
cd ..
echo 0 > unexport ' release PWM to kernel '
Output on PWM0:
{{::hantek100_1.gif?400|}}
Example C-Program (part of RC-Test program:
/*
* pwm.h
*
* Created on: Jan 4, 2016
* Author: rcar
*/
#ifndef PWM_H_
#define PWM_H_
#include
struct pwmdata {
uint32_t dutycyc;
uint32_t period;
bool enabled;
};
void pwmtest(int pwmch, int pwmval);
bool pwmcheckexport(int pwmch);
void pwmexport(int pwmch, int pwmval);
void pwmGetValue(int pwmch, struct pwmdata *pwm);
void pwmSetValue(int pwmch, struct pwmdata pwm);
void pwmstatus(void);
#endif /* PWM_H_ */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "pwm.h"
/* PWM implemented as simple sysfs interface on stout
*
* supported channels:
* pwmchip0 = PWM3 (STEER)
* pwmchip1 = PWM4 (MOTOR)
*
* /sys/class/pwm/
* `-- pwmchipN/ for each PWM chip
* |-- export (w/o) ask the kernel to export a PWM channel
* |-- npwm (r/o) number of PWM channels in this PWM chip
* |-- pwmX/ for each exported PWM channel
* | |-- duty_cycle (r/w) duty cycle (in nanoseconds)
* | |-- enable (r/w) enable/disable PWM (0 is disabled, 1 is enabled)
* | |-- period (r/w) period (in nanoseconds)
* | `-- polarity (r/w) polarity of PWM (normal/inversed)
* `-- unexport (w/o) return a PWM channel to the kernel
*/
struct pwmdata pwm;
//------------------------------------------------------------------------
/* sleep until a key is pressed and return value. echo = 0 disables key echo. */
int keypress(unsigned char echo)
{
struct termios savedState, newState;
int c;
if (-1 == tcgetattr(STDIN_FILENO, &savedState))
{
return EOF; /* error on tcgetattr */
}
newState = savedState;
if ((echo = !echo)) /* yes i'm doing an assignment in an if clause */
{
echo = ECHO; /* echo bit to disable echo */
}
/* disable canonical input and disable echo. set minimal input to 1. */
newState.c_lflag &= ~(echo | ICANON);
newState.c_cc[VMIN] = 1;
if (-1 == tcsetattr(STDIN_FILENO, TCSANOW, &newState))
{
return EOF; /* error on tcsetattr */
}
c = getchar(); /* block (withot spinning) until we get a keypress */
/* restore the saved state */
if (-1 == tcsetattr(STDIN_FILENO, TCSANOW, &savedState))
{
return EOF; /* error on tcsetattr */
}
return c;
}
//------------------------------------------------------------------------
/* PWM activate
* Ask kernel to export PWM channel
*/
void pwmExport(int pwmch) {
char path[50]; // Buffer for path
int fd; // File descriptor
int res;
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/export", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("not able to write on export\n");
exit(1);
}
res = write(fd, "0", 1);
if (res < 0)
{
perror("Can't activate PWM (write)\n");
exit(1);
}
close(fd);
}
//------------------------------------------------------------------------
/* PWM deactivate
* release PWM channel back to kernel
*/
void pwmUnExport(int pwmch) {
char path[50]; // Buffer for path
int fd; // File descriptor
int res; // result
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/unexport", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("not able to write on un-export\n");
exit(1);
}
res = write(fd, "0", 1);
if (res < 0)
{
perror("not able to un-activate PWM (write)\n");
exit(1);
}
close(fd);
}
//------------------------------------------------------------------------
/* Set parameter of PWM (period and duty cycle)
*/
void pwmSetValue(int pwmch, struct pwmdata pwm)
{
char path[50]; // Buffer for path
char value[10];
int fd; // File descriptor
int res; // result
if (pwmcheckexport(pwmch)) {
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/period", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("Can't access PWM channel (open)!\n");
exit(1);
}
snprintf(value, sizeof(value), "%d", pwm.period*1000);
res = write(fd,value,sizeof(value));
if (res < 0)
{
perror("Can't access PWM channel (write)!\n");
exit(1);
}
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/duty_cycle", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("Can't access PWM channel (open)!\n");
exit(1);
}
snprintf(value, sizeof(value), "%d", pwm.dutycyc*1000);
res = write(fd,value,sizeof(value));
if (res < 0)
{
perror("Can't access PWM channel (write)!\n");
exit(1);
}
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/enable", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("Can't access PWM channel (open)!\n");
exit(1);
}
if (pwm.enabled) snprintf(value, sizeof(value), "1");
else snprintf(value, sizeof(value), "0");
res = write(fd,value,sizeof(value));
if (res < 0)
{
perror("Can't access PWM channel (write)!\n");
exit(1);
}
close(fd);
printf("PWM parameter set!\n");
} else printf("PWM channel to exported. Can't set values!\n");
}
//------------------------------------------------------------------------
void pwmGetValue(int pwmch, struct pwmdata *pwm) {
char path[50]; // Buffer for path
char value[10];
int fd; // File descriptor
int res; // result
if (pwmcheckexport(pwmch)) {
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/period", pwmch);
fd = open(path, O_RDONLY);
res = read(fd,value,sizeof(value));
(*pwm).period = atol(value)/1000;
close(fd);
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/duty_cycle", pwmch);
fd = open(path, O_RDONLY);
res = read(fd,value,sizeof(value));
(*pwm).dutycyc = atol(value)/1000;
close(fd);
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/enable", pwmch);
fd = open(path, O_RDONLY);
res = read(fd,value,sizeof(value));
res = atoi(value);
if (res == 1) (*pwm).enabled = true;
else (*pwm).enabled = false;
close(fd);
}
}
//------------------------------------------------------------------------
/* Enable PWM
* Ergebnis: -1 = Fehler, 0 = O.K.
*/
void pwmEnable(int pwmch, bool enable) {
char path[50]; // Buffer for path
int fd; // File descriptor
int res; // result
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0/enable", pwmch);
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("Can't access PWM channel (open)!\n");
exit(1);
}
if (enable) res = write(fd, "1", 1);
else res = write(fd, "0", 1);
if (res < 0)
{
perror("Can't access PWM channel (write)!\n");
exit(1);
}
close(fd);
}
//------------------------------------------------------------------------
// check whether PWM channel is exported or not from Kernel
bool pwmcheckexport(int pwmch) {
char path[50]; // Buffer for path
struct stat s;
snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm0", pwmch);
int err = stat(path, &s);
if(-1 == err) {
if(ENOENT == errno) {
return false;
} else {
perror("stat");
exit(1);
}
} else {
if(S_ISDIR(s.st_mode)) {
return true;
}
}
return false;
}
//------------------------------------------------------------------------
// un-/export PWM channel from Kernel
void pwmexport(int pwmch, int pwmval) {
if (pwmval == 1) {
if (pwmcheckexport(pwmch)) printf("PWM channel %d already exported\n",pwmch);
else {
printf("Export PWM channel %d\n", pwmch);
pwmExport(pwmch);
}
} else {
if (!pwmcheckexport(pwmch)) printf("PWM channel %d already unexported\n",pwmch);
else {
printf("Un-Export PWM channel %d\n", pwmch);
pwmUnExport(pwmch);
}
}
}
//------------------------------------------------------------------------
// list status pf PWM channels
void pwmstatus(void) {
int i;
printf("PWM Status\n");
printf("CH\tPERIOD[us]\tDUTY_CYCLE[us]\tENABLED\n");
// 0 20000 1500 NORMAL YES
// 0 ### NOT EXPORTED ###
// channel 0+1
for(i=0;i<2;i++) {
if (!pwmcheckexport(i)) {
printf("%d\t### NOT EXPORTED ###\n",i);
} else {
pwmGetValue(i, &pwm);
printf("%d\t%d\t\t%d\t\t",i, pwm.period, pwm.dutycyc);
if (pwm.enabled) printf("YES\n");
else printf("NO\n");
}
}
}