/********************************************************************************* * 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 Raspberry Pi Board * VCC <-----> 5V * buzzer <-----> #Pin32(BCM GPIO12) * Led <-----> #Pin33(BCM GPIO13) * GND <-----> GND * * /boot/config.txt: * * dtoverlay=pwm,pin=12,func=4 (Buzzer) * dtoverlay=pwm,pin=13,func=4 (Led) * ********************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "logger.h" #include "util_proc.h" #include "pwm.h" /* check PWM $channel export or not */ int check_pwm(int channel) { char path[256]; /* check /sys/class/pwm/pwmchip0/pwmN exist or not */ snprintf(path, sizeof(path), "%s/pwm%d", PWMCHIP_PATH, channel); return access(path, F_OK) ? 0 : 1; } /* export($export=1)/unexport($export=0) PWM $channel */ int export_pwm(int channel, int export) { int fd; char buf[32]; char path[256]; if( export && check_pwm(channel) ) return 0; /* export already when export */ else if( !export && !check_pwm(channel) ) return 0; /* unexport already when unexport */ /* export PWM channel by echo N > /sys/class/pwm/pwmchip0/export */ snprintf(path, sizeof(path), "%s/%s", PWMCHIP_PATH, export?"export":"unexport"); if( (fd=open(path, O_WRONLY)) < 0 ) { log_error("open '%s' failed: %s\n", path, strerror(errno)); return -3; } snprintf(buf, sizeof(buf), "%d", channel); write(fd, buf, strlen(buf)); msleep(100); if( export && check_pwm(channel) ) return 0; /* export already when export */ else if( !export && !check_pwm(channel) ) return 0; /* unexport already when unexport */ return -4; } /* configure PWM $channel */ int config_pwm(int channel, int freq, int duty) { int fd; char buf[32]; char path[256]; int period; int duty_cycle; if( !check_pwm(channel) ) return -2; /* open PWM period file and write period in ns */ snprintf(path, sizeof(path), "%s/pwm%d/period", PWMCHIP_PATH, channel); if( (fd=open(path, O_WRONLY)) < 0 ) { log_error("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/pwm%d/duty_cycle", PWMCHIP_PATH, channel); if( (fd=open(path, O_WRONLY)) < 0 ) { log_error("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 init_pwm(int channel, int freq, int duty) { int rv; char buf[32]; char path[256]; if( (rv=export_pwm(channel, 1)) ) { log_error("export PWM channel[%d] failed, rv=%d\n", channel, rv); return rv; } if( (rv=config_pwm(channel, freq, duty)) ) { log_error("config PWM channel[%d] failed, rv=%d\n", channel, rv); return rv; } log_debug("config pwm%d with freq[%d] duty[%d] okay\n", channel, freq, duty); return 0; } int turn_pwm(int channel, int status) { int fd; char buf[32]; char path[256]; if( !check_pwm(channel) ) return -1; /* open PWM enable file and enable(1)/disable(0) it */ snprintf(path, sizeof(path), "%s/pwm%d/enable", PWMCHIP_PATH, channel); if( (fd=open(path, O_WRONLY)) < 0 ) { log_error("open '%s' failed: %s\n", path, strerror(errno)); return -3; } snprintf(buf, sizeof(buf), "%d", status?1:0); write(fd, buf, strlen(buf)); log_debug("pwm[%d] %s\n", channel, status?"enable":"disable"); return 0; } int term_pwm(int channel) { if( !check_pwm(channel) ) return 0; turn_pwm(channel, DISABLE); export_pwm(channel, 0); return 0; } int turn_beep(int times) { int rv; /* stop beeper beep */ if(times == 0) { log_debug("Stop beeper\n"); term_pwm(CHN_BEEPER); return 0; } rv = init_pwm(CHN_BEEPER, FRQ_BEEPER, 50); if(rv < 0) { log_error("Initial beeper pwm[%d] failed, rv=%d\n", CHN_BEEPER); return -2; } /* turn beeper beep ceaselessly */ if( times < 0) { turn_pwm(CHN_BEEPER, ENABLE); return 0; } while( times-- ) { turn_pwm(CHN_BEEPER, ENABLE); msleep(800); turn_pwm(CHN_BEEPER, DISABLE); msleep(800); } term_pwm(CHN_BEEPER); return 0; }