RaspberrPi project source code
Guo Wenxue
6 days ago f7889e2ceddbc3e15ea4b5377d831f4432169f76
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 "logger.h"
35 #include "util_proc.h"
36 #include "pwm.h"
37
38 /* check PWM $channel export or not */
39 int check_pwm(int channel)
40 {
41     char          path[256];
42
43     /* check /sys/class/pwm/pwmchip0/pwmN exist or not */
44     snprintf(path, sizeof(path), "%s/pwm%d", PWMCHIP_PATH, channel);
45     return access(path, F_OK) ? 0 : 1;
46 }
47
48 /* export($export=1)/unexport($export=0) PWM $channel */
49 int export_pwm(int channel, int export)
50 {
51     int           fd;
52     char          buf[32];
53     char          path[256];
54
55     if( export && check_pwm(channel) )
56         return 0; /* export already when export  */
57     else if( !export && !check_pwm(channel) )
58         return 0; /* unexport already when unexport  */
59
60     /* export PWM channel by echo N > /sys/class/pwm/pwmchip0/export */
61     snprintf(path, sizeof(path), "%s/%s", PWMCHIP_PATH, export?"export":"unexport");
62     if( (fd=open(path, O_WRONLY)) < 0 )
63     {
64         log_error("open '%s' failed: %s\n", path, strerror(errno));
65         return -3;
66     }
67
68     snprintf(buf, sizeof(buf), "%d", channel);
69     write(fd, buf, strlen(buf));
70
71     msleep(100);
72
73     if( export && check_pwm(channel) )
74         return 0; /* export already when export  */
75     else if( !export && !check_pwm(channel) )
76         return 0; /* unexport already when unexport  */
77
78     return -4;
79 }
80
81 /* configure PWM $channel */
82 int config_pwm(int channel, int freq, int duty) 
83 {
84     int           fd;
85     char          buf[32];
86     char          path[256];
87     int           period;
88     int           duty_cycle;
89
90     if( !check_pwm(channel) )
91         return -2;
92
93     /* open PWM period file and write period in ns */
94     snprintf(path, sizeof(path), "%s/pwm%d/period", PWMCHIP_PATH, channel);
95     if( (fd=open(path, O_WRONLY)) < 0 )
96     {
97         log_error("open '%s' failed: %s\n", path, strerror(errno));
98         return -3;
99     }
100     period = 1000000000/freq;
101     snprintf(buf, sizeof(buf), "%d", period);
102     write(fd, buf, strlen(buf));
103
104     /* open PWM duty_cycle file and write duty */
105     snprintf(path, sizeof(path), "%s/pwm%d/duty_cycle", PWMCHIP_PATH, channel);
106     if( (fd=open(path, O_WRONLY)) < 0 )
107     {
108         log_error("open '%s' failed: %s\n", path, strerror(errno));
109         return -3;
110     }
111     duty_cycle = (period*duty) / 100;
112     snprintf(buf, sizeof(buf), "%d", duty_cycle);
113     write(fd, buf, strlen(buf));
114
115     return 0;
116 }
117
118 int init_pwm(int channel, int freq, int duty)
119 {
120     int           rv;
121     char          buf[32];
122     char          path[256];
123
124     if( (rv=export_pwm(channel, 1)) )
125     {
126         log_error("export PWM channel[%d] failed, rv=%d\n", channel, rv);
127         return rv; 
128     }
129
130     if( (rv=config_pwm(channel, freq, duty)) )
131     {
132         log_error("config PWM channel[%d] failed, rv=%d\n", channel, rv);
133         return rv;
134     }
135
136     log_debug("config pwm%d with freq[%d] duty[%d] okay\n", channel, freq, duty);
137
138     return 0;
139 }
140
141 int turn_pwm(int channel, int status)
142 {
143     int           fd;
144     char          buf[32];
145     char          path[256];
146
147     if( !check_pwm(channel) )
148         return -1;
149
150     /* open PWM enable file and enable(1)/disable(0) it */
151     snprintf(path, sizeof(path), "%s/pwm%d/enable", PWMCHIP_PATH, channel);
152     if( (fd=open(path, O_WRONLY)) < 0 )
153     {
154         log_error("open '%s' failed: %s\n", path, strerror(errno));
155         return -3;
156     }
157     snprintf(buf, sizeof(buf), "%d", status?1:0);
158     write(fd, buf, strlen(buf));
159
160     log_debug("pwm[%d] %s\n", channel, status?"enable":"disable");
161
162     return 0;
163 }
164
165 int term_pwm(int channel)
166 {
167     if( !check_pwm(channel) )
168         return 0;
169
170     turn_pwm(channel, DISABLE);
171     export_pwm(channel, 0);
172
173     return 0;
174 }
175
176 int turn_beep(int times)
177 {
178     int           rv;
179
180     /* stop beeper beep */
181     if(times == 0)
182     {
183         log_debug("Stop beeper\n");
184         term_pwm(CHN_BEEPER);
185         return 0;
186     }
187
188     rv = init_pwm(CHN_BEEPER, FRQ_BEEPER, 50);
189     if(rv < 0)
190     {
191         log_error("Initial beeper pwm[%d] failed, rv=%d\n", CHN_BEEPER);
192         return -2;
193     }
194
195     /* turn beeper beep ceaselessly */
196     if( times < 0)
197     {
198         turn_pwm(CHN_BEEPER, ENABLE);
199         return 0;
200     }
201
202     while( times-- )
203     {
204         turn_pwm(CHN_BEEPER, ENABLE);
205         msleep(800);
206
207         turn_pwm(CHN_BEEPER, DISABLE);
208         msleep(800);
209     }
210     
211     term_pwm(CHN_BEEPER);
212     return 0;
213 }