From fca8f5db4d521d8805777a782f9d2b0285f61a28 Mon Sep 17 00:00:00 2001 From: Aleksei Date: Sat, 19 Feb 2022 20:44:43 +0300 Subject: [PATCH] duty_cycle bug fixed fixed duty-cycle bug: you cant set frequency, if old duty-cycle value is not valid for new frequency changed duty-cycle logic: now duty cycle in range in float 0.0 .. 1.0 and recalculates, depending of the frequency class attributes are private now the sysPWM class has constructor with frequency argument. I could not find a case, when I need an instance without frequency. --- syspwm.py | 118 +++++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 55 deletions(-) diff --git a/syspwm.py b/syspwm.py index 2272681..8ce49d5 100644 --- a/syspwm.py +++ b/syspwm.py @@ -22,61 +22,69 @@ class SysPWMException(Exception): # /sys/ pwm interface described here: http://www.jumpnowtek.com/rpi/Using-the-Raspberry-Pi-Hardware-PWM-timers.html class SysPWM(object): - chippath = "/sys/class/pwm/pwmchip0" - - def __init__(self,pwm): - self.pwm=pwm - self.pwmdir="{chippath}/pwm{pwm}".format(chippath=self.chippath,pwm=self.pwm) - if not self.overlay_loaded(): - raise SysPWMException("Need to add 'dtoverlay=pwm-2chan' to /boot/config.txt and reboot") - if not self.export_writable(): - raise SysPWMException("Need write access to files in '{chippath}'".format(chippath=self.chippath)) - if not self.pwmX_exists(): - self.create_pwmX() - return - - def overlay_loaded(self): - return os.path.isdir(self.chippath) - - def export_writable(self): - return os.access("{chippath}/export".format(chippath=self.chippath), os.W_OK) - - def pwmX_exists(self): - return os.path.isdir(self.pwmdir) - - def echo(self,m,fil): - #print "echo {m} > {fil}".format(m=m,fil=fil) - with open(fil,'w') as f: - f.write("{m}\n".format(m=m)) - - def create_pwmX(self): - pwmexport = "{chippath}/export".format(chippath=self.chippath) - self.echo(self.pwm,pwmexport) - - def enable(self,disable=False): - enable = "{pwmdir}/enable".format(pwmdir=self.pwmdir) - num = 1 - if disable: - num = 0 - self.echo(num,enable) - - def disable(self): - return self.enable(disable=True) - - def set_duty_cycle(self,milliseconds): - # /sys/ iface, 2ms is 2000000 - # gpio cmd, 2ms is 200 - dc = int(milliseconds * 1000000) - duty_cycle = "{pwmdir}/duty_cycle".format(pwmdir=self.pwmdir) - self.echo(dc,duty_cycle) - - def set_frequency(self,hz): - per = (1 / float(hz)) - per *= 1000 # now in milliseconds - per *= 1000000 # now in.. whatever - per = int(per) - period = "{pwmdir}/period".format(pwmdir=self.pwmdir) - self.echo(per,period) + __chippath = "/sys/class/pwm/pwmchip0" + __pwm = None + __pwmdir = None + __period_ns = 0 + __frequency_hz = 0 + __duty_cycle = 0 + + def __init__(self,pwm,frequency): + self.__pwm=pwm + self.__pwmdir="{chippath}/pwm{pwm}".format(chippath=self.__chippath,pwm=self.__pwm) + if not self.overlay_loaded(): + raise SysPWMException("Need to add 'dtoverlay=pwm-2chan' to /boot/config.txt and reboot") + if not self.export_writable(): + raise SysPWMException("Need write access to files in '{chippath}'".format(chippath=self.__chippath)) + if not self.pwmX_exists(): + self.create_pwmX() + self.set_frequency(frequency) + return + + def overlay_loaded(self): + return os.path.isdir(self.__chippath) + + def export_writable(self): + return os.access("{chippath}/export".format(chippath=self.__chippath), os.W_OK) + + def pwmX_exists(self): + return os.path.isdir(self.__pwmdir) + + def echo(self,m,fil): + #print "echo {m} > {fil}".format(m=m,fil=fil) + with open(fil,'w') as f: + f.write("{m}\n".format(m=m)) + + def create_pwmX(self): + pwmexport = "{chippath}/export".format(chippath=self.__chippath) + self.echo(self.__pwm,pwmexport) + + def enable(self,disable=False): + enable = "{pwmdir}/enable".format(pwmdir=self.__pwmdir) + num = 1 + if disable: + num = 0 + self.echo(num,enable) + + def disable(self): + return self.enable(disable=True) + + def set_duty_cycle(self,duty_cycle): + self.__duty_cycle = max(0, min(1, duty_cycle)) + duty_cycle_ns = int(self.__duty_cycle*self.__period_ns) + path = "{pwmdir}/duty_cycle".format(pwmdir=self.__pwmdir) + self.echo(duty_cycle_ns, path) + + def set_frequency(self,frequency): + old_dc = self.__duty_cycle + self.set_duty_cycle(0) + + self.__frequency = int(frequency) + self.__period_ns = int((1.0/self.__frequency)*1e9) + + self.set_duty_cycle(old_dc) + path = "{pwmdir}/period".format(pwmdir=self.__pwmdir) + self.echo(self.__period_ns,path) if __name__ == "__main__": from time import sleep