RaspberrPi project source code
guowenxue
2024-05-27 2c971f2fcf6c6322a0ea584b2af4c3cef20d3d63
commit | author | age
d6b4a7 1 /*********************************************************************************
G 2  *      Copyright:  (C) 2021 LingYun IoT System Studio
3  *                  All rights reserved.
4  *
5  *       Filename:  pwm.c
6  *    Description:  This file is used to control PWM buzzer/Led
7  *
8  * Pin connection:
9  *               PWM Module              Raspberry Pi Board
10  *                  VCC       <----->      5V
11  *                 buzzer     <----->      #Pin32(BCM GPIO12)
12  *                  Led       <----->      #Pin33(BCM GPIO13)
13  *                  GND       <----->      GND
14  *
15  * /boot/config.txt:
16  *
17  *          dtoverlay=pwm,pin=12,func=4 (Buzzer)
18  *          dtoverlay=pwm,pin=13,func=4 (Led)
19  *
20  ********************************************************************************/
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <dirent.h>
27 #include <string.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <signal.h>
31 #include <getopt.h>
32 #include <libgen.h>
33
34 #include <gpiod.h>
35
36 #define PWMCHIP_PATH      "/sys/class/pwm/pwmchip0"
37
38 #define ENABLE            1
39 #define DISABLE           0
40
41 int init_pwm(int channel, int freq, int duty);
42 int turn_pwm(int channel, int status);
43 int term_pwm(int channel);
44 static inline void msleep(unsigned long ms);
45
46 static inline void banner(const char *progname)
47 {
48     printf("%s program Version v1.0.0\n", progname);
49     printf("Copyright (C) 2023 LingYun IoT System Studio.\n");
50 }
51
52 static void program_usage(const char *progname)
53 {
54
55     printf("Usage: %s [OPTION]...\n", progname);
56     printf(" This is pwm control program. \n");
57
58     printf(" -c[channel ]  Specify PWM channel, such as 0\n");
59     printf(" -f[freq    ]  Specify PWM frequency, default 2500(Hz)\n");
cbbab6 60     printf(" -d[duty    ]  Specify PWM duty, default 50(50%%)\n");
d6b4a7 61     printf(" -s[status  ]  Specify PWM status: 1->on(default), 0->off\n");
G 62     printf(" -h[help    ]  Display this help information\n");
63     printf(" -v[version ]  Display the program version\n");
64     printf("\n");
65
66     printf("Example buzzer : %s -c 0 -f 2750 -d 50 -s 1\n", progname);
67     printf("Example Led    : %s -c 1 -f 100 -d 50 -s 1\n", progname);
68     printf("Example disable: %s -c 0 -s 0\n", progname);
69
70     printf("\n");
71     banner(progname);
72     return;
73 }
74
75 int main(int argc, char **argv)
76 {
77     int             rv;
78     char           *progname=NULL;
79     int             channel = -1;
80     int             freq = 2500;
81     int             duty = 50;
82     int             status = ENABLE;
83
84     struct option long_options[] = {
85         {"channel", required_argument, NULL, 'c'},
86         {"freq", required_argument, NULL, 'f'},
87         {"duty", required_argument, NULL, 'd'},
88         {"status", required_argument, NULL, 's'},
89         {"version", no_argument, NULL, 'v'},
90         {"help", no_argument, NULL, 'h'},
91         {NULL, 0, NULL, 0}
92     };
93
94     progname = basename(argv[0]);
95
96     /* Parser the command line parameters */
97     while ((rv = getopt_long(argc, argv, "c:f:d:s:vh", long_options, NULL)) != -1)
98     {
99         switch (rv)
100         {
101             case 'c': /*  Set pwm channel, such as 0,1 */
102                 channel = atoi(optarg);
103                 break;
104
105             case 'f': /*  Set pwm frequency */
106                 freq = atoi(optarg);
107                 break;
108
109             case 'd': /*  Set pwm duty cycle */
110                 duty = atoi(optarg);
111                 break;
112
113             case 's': /*  Set pwm status, 0 for disable and 1 for enable */
114                 status = atoi(optarg);
115                 break;
116
117             case 'v':  /* Get software version */
118                 banner(progname);
119                 return EXIT_SUCCESS;
120
121             case 'h':  /* Get help information */
122                 program_usage(progname);
123                 return 0;
124
125             default:
126                 break;
127         }
128     }
129
130     if(channel < 0 )
131     {
132         program_usage(progname);
133         return 0;
134     }
135
136     if( status )
137     {
138         if( (rv=init_pwm(channel, freq, duty)) < 0 )
139         {
140             printf("initial PWM failure, rv=%d\n", rv);
141             return 1;
142         }
143
144         turn_pwm(channel, ENABLE);
145     }
146     else
147     {
148         term_pwm(channel);
149     }
150
151     return 0;
152 }
153
154 /* check PWM $channel export or not */
155 int check_pwm(int channel)
156 {
157     char          path[256];
158
159     /* check /sys/class/pwm/pwmchip0/pwmN exist or not */
160     snprintf(path, sizeof(path), "%s/pwm%d", PWMCHIP_PATH, channel);
161     return access(path, F_OK) ? 0 : 1;
162 }
163
164 /* export($export=1)/unexport($export=0) PWM $channel */
165 int export_pwm(int channel, int export)
166 {
167     int           fd;
168     char          buf[32];
169     char          path[256];
170
171     if( export && check_pwm(channel) )
172         return 0; /* export already when export  */
173     else if( !export && !check_pwm(channel) )
174         return 0; /* unexport already when unexport  */
175
176     /* export PWM channel by echo N > /sys/class/pwm/pwmchip0/export */
177     snprintf(path, sizeof(path), "%s/%s", PWMCHIP_PATH, export?"export":"unexport");
178     if( (fd=open(path, O_WRONLY)) < 0 )
179     {
180         printf("open '%s' failed: %s\n", path, strerror(errno));
181         return -3;
182     }
183
184     snprintf(buf, sizeof(buf), "%d", channel);
185     write(fd, buf, strlen(buf));
186
187     msleep(100);
188
189     if( export && check_pwm(channel) )
190         return 0; /* export already when export  */
191     else if( !export && !check_pwm(channel) )
192         return 0; /* unexport already when unexport  */
193
194     return -4;
195 }
196
197 /* configure PWM $channel */
198 int config_pwm(int channel, int freq, int duty) 
199 {
200     int           fd;
201     char          buf[32];
202     char          path[256];
203     int           period;
204     int           duty_cycle;
205
206     if( !check_pwm(channel) )
207         return -2;
208
209     /* open PWM period file and write period in ns */
210     snprintf(path, sizeof(path), "%s/pwm%d/period", PWMCHIP_PATH, channel);
211     if( (fd=open(path, O_WRONLY)) < 0 )
212     {
213         printf("open '%s' failed: %s\n", path, strerror(errno));
214         return -3;
215     }
216     period = 1000000000/freq;
217     snprintf(buf, sizeof(buf), "%d", period);
218     write(fd, buf, strlen(buf));
219
220     /* open PWM duty_cycle file and write duty */
221     snprintf(path, sizeof(path), "%s/pwm%d/duty_cycle", PWMCHIP_PATH, channel);
222     if( (fd=open(path, O_WRONLY)) < 0 )
223     {
224         printf("open '%s' failed: %s\n", path, strerror(errno));
225         return -3;
226     }
227     duty_cycle = (period*duty) / 100;
228     snprintf(buf, sizeof(buf), "%d", duty_cycle);
229     write(fd, buf, strlen(buf));
230
231     return 0;
232 }
233
234 int init_pwm(int channel, int freq, int duty)
235 {
236     int           rv;
237     char          buf[32];
238     char          path[256];
239
240     if( (rv=export_pwm(channel, 1)) )
241     {
242         printf("export PWM channel[%d] failed, rv=%d\n", channel, rv);
243         return rv; 
244     }
245
246     if( (rv=config_pwm(channel, freq, duty)) )
247     {
248         printf("config PWM channel[%d] failed, rv=%d\n", channel, rv);
249         return rv;
250     }
251
252     printf("config pwm%d with freq[%d] duty[%d] okay\n", channel, freq, duty);
253
254     return 0;
255 }
256
257 int turn_pwm(int channel, int status)
258 {
259     int           fd;
260     char          buf[32];
261     char          path[256];
262
263     if( !check_pwm(channel) )
264         return -1;
265
266     /* open PWM enable file and enable(1)/disable(0) it */
267     snprintf(path, sizeof(path), "%s/pwm%d/enable", PWMCHIP_PATH, channel);
268     if( (fd=open(path, O_WRONLY)) < 0 )
269     {
270         printf("open '%s' failed: %s\n", path, strerror(errno));
271         return -3;
272     }
273     snprintf(buf, sizeof(buf), "%d", status?1:0);
274     write(fd, buf, strlen(buf));
275
276     printf("pwm[%d] %s\n", channel, status?"enable":"disable");
277
278     return 0;
279 }
280
281 int term_pwm(int channel)
282 {
283     if( !check_pwm(channel) )
284         return 0;
285
286     turn_pwm(channel, DISABLE);
287     export_pwm(channel, 0);
288
289     return 0;
290 }
291
292 static inline void msleep(unsigned long ms)
293 {
294     struct timespec cSleep;
295     unsigned long ulTmp;
296
297     cSleep.tv_sec = ms / 1000;
298     if (cSleep.tv_sec == 0)
299     {
300         ulTmp = ms * 10000;
301         cSleep.tv_nsec = ulTmp * 100;
302     }
303     else
304     {
305         cSleep.tv_nsec = 0;
306     }
307
308     nanosleep(&cSleep, 0);
309
310     return ;
311 }