Site Tools


Sidebar

Translations of this page?:



TechWiki

GW60 Rollo

  • GW60 Superrollo
    • Hardware
    • Programming
    • S/W extension
  • TRADFRI Modul
    • Modul H/W
    • Programming
    • Tools
  • GW60 TRADFRI adapter
    • Schematic
    • Programming adapter
    • Housing
    • Integration

Laser Cutter

3D Printer

QuadCopter

RC car

Wiki

Misc

pwm_output

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:

Example C-Program (part of RC-Test program:

pwm.h
/*
 * pwm.h
 *
 *  Created on: Jan 4, 2016
 *      Author: rcar
 */
 
#ifndef PWM_H_
#define PWM_H_
 
#include <stdbool.h>
 
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_ */
pwm.c
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <stdbool.h>
#include <errno.h>
#include <sys/stat.h>
 
#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");
		}
	}
}
pwm_output.txt · Last modified: 2016/01/10 21:27 by bullar