Source

gadgets / gadgets / io / pwm.py

import os
import glob

from gadgets.io.io import IO

class PWMFactory(object):

    def __init__(self, pin, frequency=1.0):
        self._pin = pin
        self._frequency = frequency

    def __call__(self):
        return PWM(self._pin, frequency=self._frequency)
        

class PWM(IO):
    """
    Uses the pwm pins' sysfs interface.  You can use a pwm pin like this:

        >>> from gadgets.pins.beaglebone import pins
        >>> from gadgets.io import GPIO
        >>> pwm = PWM(pins['pwm'][8][13])

    Now you can turn it on and vary the duty percent:

        >>> pwm.on() #turns the pin on with a 100 duty_percent
        >>> pwm.duty_percent = 50
    
    NOTE:  The beaglebone pwm clock must be enabled before using this class.
    You can enable it by calling enable-pwm from the command line (requires
    gadgets and python-mmap to be installed)

    # echo 20000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/period

    so  20000000= 0.02 seconds

    # echo 10000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/duty

    so  10000000 = 0.01 seconds
    """
    
    _command_template = 'echo {0} > {1}/{2}'
    _command_path_template = '/sys/devices/{0}'
    _one_second = 1000000000

    def __init__(self, pin, frequency=1.0):
        """
        mux:  the name that appears in the omap_mux directory
        directory: the directory for the pwm pin in /sys/class/pwm
        mode:  the mux mode of the pin that enables pwm
        frequency:  the pwm frequency in Hz
        mux_path:  defaults to /sys/kernel/debug/omap_mux
        """
        self._current_value = None
        directory = self._find_directory(pin['directory'])
        self._command = self._command_path_template.format(directory)
        self._write_value('run', '0')
        period = int(self._one_second * frequency)
        self._write_value('period', period)
        self._status = False

    @property
    def status(self):
        return self._status
        
    def _find_directory(self, directory):
        """
        The directory names change when using pwm under
        the device tree overlay, so this finds the directory.
        """
        filenames = glob.glob(self._command_path_template.format(directory))
        if len(filenames != 1:
            raise GadgetsError("the pwm glob didn't find a pwm directory: {0}".format(directory)
        return filenames[0]

    def on(self):
        """
        turns on the pwm and sets the duty cycle to 100
        """
        self.duty_percent = 100
        self._status = True

    def off(self):
        """
        turns off the pwm and sets the duty cycle to 0
        """
        self.duty_percent = 0
        self._status = False
        self._write_value('run', '0')

    def close(self):
        pass

    @property
    def duty_percent(self):
        return self._current_value

    @property
    def value(self):
        return self.duty_percent

    @duty_percent.setter
    def duty_percent(self, value):
        """
        duty_percent(value)
        value: an integer from 0 to 100

        Writes to the sysfs duty_percent interface.  If the pwm
        was turned off before this call, the pwm will be turned
        on.
        """
        if self._current_value != value:
            self._write_value('run', '1')
            self._current_value = value
            value = self._one_second * (value / 100)
            self._write_value('duty', value)

    def _write_value(self, path, value):
        command = self._command_template.format(value, self._command, path)
        os.system(command)