From 1e563e2b731d928942f43e1341c8c50b0faf1c01 Mon Sep 17 00:00:00 2001 From: guowenxue <guowenxue@gmail.com> Date: Fri, 31 May 2024 11:39:31 +0800 Subject: [PATCH] APPS:IGKBoard-IMX6ULL: Add test-apps source code: --- drivers/test-apps/pwm.c | 341 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 341 insertions(+), 0 deletions(-) diff --git a/drivers/test-apps/pwm.c b/drivers/test-apps/pwm.c new file mode 100644 index 0000000..c855da6 --- /dev/null +++ b/drivers/test-apps/pwm.c @@ -0,0 +1,341 @@ +/********************************************************************************* + * Copyright: (C) 2021 LingYun IoT System Studio + * All rights reserved. + * + * Filename: pwm.c + * Description: This file is used to control PWM buzzer/Led + * + * Pin connection: + * PWM Module IGKBoard + * VCC <-----> 5V + * Led <-----> #Pin28(PWM8) + * GND <-----> GND + * + * + * + ********************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <signal.h> +#include <getopt.h> +#include <libgen.h> + +#define PWM_SYS_PATH "/sys/class/pwm/pwmchip0" + +#define ENABLE 1 +#define DISABLE 0 + + +typedef struct pwm_s +{ + char pwm_path[64]; /* PWM path, such as /sys/class/pwm/pwmchip0 */ + char chn_path[64]; /* channel path, such as /sys/class/pwm/pwmchip0/pwm0 */ + int pwm_num; /* pwm number */ + int chn_num; /* channel number */ +} pwm_t; + + +int init_pwm(pwm_t *pwm, int pwm_num, int chn_num); +int conf_pwm(pwm_t *pwm, int freq, int duty); +int turn_pwm(pwm_t *pwm, int status); +int term_pwm(pwm_t *pwm); + +static inline void msleep(unsigned long ms); + +static inline void banner(const char *progname) +{ + printf("%s program Version v1.0.0\n", progname); + printf("Copyright (C) 2023 LingYun IoT System Studio.\n"); +} + +static void program_usage(const char *progname) +{ + + printf("Usage: %s [OPTION]...\n", progname); + printf(" This is pwm control program. \n"); + + printf(" -p[pwm ] Specify PWM chip, such as 1 for pwmchip1\n"); + printf(" -c[channel ] Specify PWM channel, such as 0\n"); + printf(" -f[freq ] Specify PWM frequency, default 2500(Hz)\n"); + printf(" -d[duty ] Specify PWM duty, default 50(50%%)\n"); + printf(" -s[status ] Specify PWM status: 1->on(default), 0->off\n"); + printf(" -h[help ] Display this help information\n"); + printf(" -v[version ] Display the program version\n"); + printf("\n"); + + printf("Example buzzer : %s -p 1 -c 0 -f 10000 -d 50 -s 1\n", progname); + printf("Example Led : %s -p 1 -c 1 -f 100 -d 50 -s 1\n", progname); + printf("Example disable: %s -p 1 -c 0 -s 0\n", progname); + + printf("\n"); + banner(progname); + return; +} + +int main(int argc, char **argv) +{ + int rv; + char *progname=NULL; + int chn_num = -1; + int pwm_num = -1; + int freq = 2500; + int duty = 50; + int status = ENABLE; + pwm_t pwm; + + struct option long_options[] = { + {"pwm", required_argument, NULL, 'p'}, + {"channel", required_argument, NULL, 'c'}, + {"freq", required_argument, NULL, 'f'}, + {"duty", required_argument, NULL, 'd'}, + {"status", required_argument, NULL, 's'}, + {"version", no_argument, NULL, 'v'}, + {"help", no_argument, NULL, 'h'}, + {NULL, 0, NULL, 0} + }; + + progname = basename(argv[0]); + + /* Parser the command line parameters */ + while ((rv = getopt_long(argc, argv, "p:c:f:d:s:vh", long_options, NULL)) != -1) + { + switch (rv) + { + case 'p': /* Set pwm chip, such as 1 for pwmchip1 */ + pwm_num = atoi(optarg); + break; + + case 'c': /* Set pwm channel, such as 0,1 */ + chn_num = atoi(optarg); + break; + + case 'f': /* Set pwm frequency */ + freq = atoi(optarg); + break; + + case 'd': /* Set pwm duty cycle */ + duty = atoi(optarg); + break; + + case 's': /* Set pwm status, 0 for disable and 1 for enable */ + status = atoi(optarg); + break; + + case 'v': /* Get software version */ + banner(progname); + return EXIT_SUCCESS; + + case 'h': /* Get help information */ + program_usage(progname); + return 0; + + default: + break; + } + } + + if( pwm_num<0 || chn_num<0 ) + { + program_usage(progname); + return 0; + } + + init_pwm(&pwm, pwm_num, chn_num); + + + if( status ) + { + if( (rv=conf_pwm(&pwm, freq, duty)) < 0 ) + { + printf("Configure PWM failure, rv=%d\n", rv); + return 1; + } + + turn_pwm(&pwm, ENABLE); + } + else + { + term_pwm(&pwm); + } + + return 0; +} + +int init_pwm(pwm_t *pwm, int pwm_num, int chn_num) +{ + if( !pwm || pwm_num<0 || chn_num<0 ) + { + printf("Invalid input arguments\n"); + return -1; + } + + snprintf(pwm->pwm_path, sizeof(pwm->pwm_path), "/sys/class/pwm/pwmchip%d", pwm_num); + snprintf(pwm->chn_path, sizeof(pwm->chn_path), "/sys/class/pwm/pwmchip%d/pwm%d", pwm_num, chn_num); + pwm->pwm_num = pwm_num; + pwm->chn_num = chn_num; + + return 0; +} + +/* check PWM $channel export or not */ +int check_pwm(pwm_t *pwm) +{ + /* check /sys/class/pwm/pwmchipX/pwmY exist or not */ + return access(pwm->chn_path, F_OK) ? 0 : 1; +} + +/* export($export=1)/unexport($export=0) PWM $channel */ +int export_pwm(pwm_t *pwm, int export) +{ + int fd; + char buf[32]; + char path[256]; + + if( export && check_pwm(pwm) ) + return 0; /* export already when export */ + else if( !export && !check_pwm(pwm) ) + return 0; /* unexport already when unexport */ + + /* export PWM channel by echo Y > /sys/class/pwm/pwmchipX/export */ + snprintf(path, sizeof(path), "%s/%s", pwm->pwm_path, export?"export":"unexport"); + if( (fd=open(path, O_WRONLY)) < 0 ) + { + printf("open '%s' failed: %s\n", path, strerror(errno)); + return -3; + } + + snprintf(buf, sizeof(buf), "%d", pwm->chn_num); + write(fd, buf, strlen(buf)); + + msleep(100); + + if( export && check_pwm(pwm) ) + return 0; /* export already when export */ + else if( !export && !check_pwm(pwm) ) + return 0; /* unexport already when unexport */ + + return -4; +} + +/* set PWM $channel */ +int set_pwm(pwm_t *pwm, int freq, int duty) +{ + int fd; + char buf[32]; + char path[256]; + int period; + int duty_cycle; + + if( !check_pwm(pwm) ) + return -2; + + /* open PWM period file and write period in ns */ + snprintf(path, sizeof(path), "%s/period", pwm->chn_path); + if( (fd=open(path, O_WRONLY)) < 0 ) + { + printf("open '%s' failed: %s\n", path, strerror(errno)); + return -3; + } + period = 1000000000/freq; + snprintf(buf, sizeof(buf), "%d", period); + write(fd, buf, strlen(buf)); + + /* open PWM duty_cycle file and write duty */ + snprintf(path, sizeof(path), "%s/duty_cycle", pwm->chn_path); + if( (fd=open(path, O_WRONLY)) < 0 ) + { + printf("open '%s' failed: %s\n", path, strerror(errno)); + return -3; + } + duty_cycle = (period*duty) / 100; + snprintf(buf, sizeof(buf), "%d", duty_cycle); + write(fd, buf, strlen(buf)); + + return 0; +} + +int conf_pwm(pwm_t *pwm, int freq, int duty) +{ + int rv; + char buf[32]; + char path[256]; + + if( (rv=export_pwm(pwm, 1)) ) + { + printf("export PWM channel[%d] failed, rv=%d\n", pwm->chn_num, rv); + return rv; + } + + if( (rv=set_pwm(pwm, freq, duty)) ) + { + printf("config PWM channel[%d] failed, rv=%d\n", pwm->chn_num, rv); + return rv; + } + + printf("config pwm%d channel%d with freq[%d] duty[%d] okay\n", pwm->pwm_num, pwm->chn_num, freq, duty); + + return 0; +} + +int turn_pwm(pwm_t *pwm, int status) +{ + int fd; + char buf[32]; + char path[256]; + + if( !check_pwm(pwm) ) + return -1; + + /* open PWM enable file and enable(1)/disable(0) it */ + snprintf(path, sizeof(path), "%s/enable", pwm->chn_path); + if( (fd=open(path, O_WRONLY)) < 0 ) + { + printf("open '%s' failed: %s\n", path, strerror(errno)); + return -3; + } + snprintf(buf, sizeof(buf), "%d", status?1:0); + write(fd, buf, strlen(buf)); + + printf("pwm[%d] channel[%d]%s\n", pwm->pwm_num, pwm->chn_num, status?"enable":"disable"); + + return 0; +} + +int term_pwm(pwm_t *pwm) +{ + if( !check_pwm(pwm) ) + return 0; + + turn_pwm(pwm, DISABLE); + export_pwm(pwm, 0); + + return 0; +} + +static inline void msleep(unsigned long ms) +{ + struct timespec cSleep; + unsigned long ulTmp; + + cSleep.tv_sec = ms / 1000; + if (cSleep.tv_sec == 0) + { + ulTmp = ms * 10000; + cSleep.tv_nsec = ulTmp * 100; + } + else + { + cSleep.tv_nsec = 0; + } + + nanosleep(&cSleep, 0); + + return ; +} -- Gitblit v1.9.1