Exemple #1
0
class dac8568():
    def __init__(self, dev):
        self.dev = SpiDev()
        try:
            self.dev.open(4,dev)
        except IOError as e:
            print("Error opening /dev/spidev4.%d: %s" % (dev, e))
            raise

    def build_command(self, control, addr, data):
        prefix = 0
        features = 0
        cmd = [0,0,0,0]
        cmd[3] = (0xf    & features) << 0 | (0xf & data) << 4
        cmd[2] = (0x0ff0 & data) >> 4
        cmd[1] = (0xf000 & data) >> 12    | (0xf & addr) << 4
        cmd[0] = (0xf    & control) << 0  | (0xf & prefix) << 4
        return cmd
       
    # indexed by label number, mapping to DAC channel number
    channel_map = (0,2,4,6,7,5,3,1)
    write_mode = { 'WRITE': 0x0,
                   'UPDATE': 0x1,
                   'WRITE_UPDATE_ALL': 0x2,
                   'WRITE_UPDATE': 0x3 }

    def write(self, addr, data, mode = write_mode['WRITE_UPDATE']):
        addr = self.channel_map[addr]
        cmd  = self.build_command(mode, addr, data)
        self.dev.writebytes(cmd)
Exemple #2
0
class dac8568():
    def __init__(self, dev):
        self.dev = SpiDev()
        try:
            self.dev.open(4, dev)
        except IOError as e:
            print("Error opening /dev/spidev4.%d: %s" % (dev, e))
            raise

    def build_command(self, control, addr, data):
        prefix = 0
        features = 0
        cmd = [0, 0, 0, 0]
        cmd[3] = (0xf & features) << 0 | (0xf & data) << 4
        cmd[2] = (0x0ff0 & data) >> 4
        cmd[1] = (0xf000 & data) >> 12 | (0xf & addr) << 4
        cmd[0] = (0xf & control) << 0 | (0xf & prefix) << 4
        return cmd

    # indexed by label number, mapping to DAC channel number
    channel_map = (0, 2, 4, 6, 7, 5, 3, 1)
    write_mode = {
        'WRITE': 0x0,
        'UPDATE': 0x1,
        'WRITE_UPDATE_ALL': 0x2,
        'WRITE_UPDATE': 0x3
    }

    def write(self, addr, data, mode=write_mode['WRITE_UPDATE']):
        addr = self.channel_map[addr]
        cmd = self.build_command(mode, addr, data)
        self.dev.writebytes(cmd)
Exemple #3
0
class PiFaceGpioDigital(PiFaceGPIO):
    """PiFace GPIO pin implementing SPI."""

    ADDR_0 = 0x01000000  # 0x40 [0100 0000]
    ADDR_1 = 0x01000010  # 0x42 [0100 0010]
    ADDR_2 = 0x01000100  # 0x44 [0100 0100]
    ADDR_3 = 0x01000110  # 0x46 [0100 0110]
    DEF_ADDR = ADDR_0

    REGISTER_IODIR_A = 0x00
    REGISTER_IODIR_B = 0x01
    REGISTER_GPINTEN_A = 0x04
    REGISTER_GPINTEN_B = 0x05
    REGISTER_DEFVAL_A = 0x06
    REGISTER_DEFVAL_B = 0x07
    REGISTER_INTCON_A = 0x08
    REGISTER_INTCON_B = 0x09
    REGISTER_IOCON_A = 0x0A
    REGISTER_IOCON_B = 0x0B
    REGISTER_GPPU_A = 0x0C
    REGISTER_GPPU_B = 0x0D
    REGISTER_INTF_A = 0x0E
    REGISTER_INTF_B = 0x0F
    REGISTER_INTCAP_A = 0x10
    REGISTER_INTCAP_B = 0x11
    REGISTER_GPIO_A = 0x12
    REGISTER_GPIO_B = 0x13

    GPIO_A_OFFSET = 0
    GPIO_B_OFFSET = 1000

    IOCON_UNUSED = 0x01
    IOCON_INTPOL = 0x02
    IOCON_ODR = 0x04
    IOCON_HAEN = 0x08
    IOCON_DISSLW = 0x10
    IOCON_SEQOP = 0x20
    IOCON_MIRROR = 0x40
    IOCON_BANK_MODE = 0x80

    BUS_SPEED = 1000000
    WRT_FLAG = 0x00
    RD_FLAG = 0x01

    def __init__(self, pn, initial_val, spi_address, spi_speed):
        """Initialize a new instance of the raspy.io.pi_face_gpio_digital.PiFaceGpioDigital class.

        :param raspy.io.pi_face_pins.PiFacePin pn: The PiFace pin to control.
        :param int initial_val: The initial value (state) to set the pin to.
        Default is PinState.LOW.
        :param int spi_address: The SPI address to use. (Should be ADDRESS_0,
        ADDRESS_1, ADDRESS_2, or ADDRESS_3).
        :param int spi_speed: The clock speed to set the bus to. Can be powers
        of 2 (500KHz minimum up to 32MHz maximum). If not specified, the
        default of SPI_SPEED (1MHz) will be used.
        :raises: raspy.io.io_exception.IOException if unable to read or write
        to the SPI bus.
        """
        PiFaceGPIO.__init__(self, pn, initial_val, pn.name)

        if spi_speed is None or not isinstance(spi_speed, (int, long)):
            spi_speed = self.BUS_SPEED

        self.__speed = spi_speed
        self.__spi = SpiDev()
        try:
            self.__spi.open(0, 0)
        except Exception:
            raise IOException("Unable to open SPI device 0 on bus 0.")

        self.__spi.max_speed_hz = self.__speed
        self.__address = self.DEF_ADDR
        if spi_address is not None:
            self.__address = spi_address

        self.__currentStatesA = 0x00000000
        self.__currentStatesB = 0x11111111
        self.__currentDirectionA = 0x00000000
        self.__currentDirectionB = 0x11111111
        self.__currentPullupA = 0x00000000
        self.__currentPullupB = 0x11111111
        self.__oldState = pin_state.LOW
        self.__pullResistance = pin_pull_resistance.Off
        self.__pollThread = None
        self.__pollRunning = False
        self.__stopEvent = threading.Event()
        self.__stopEvent.set()

        # IOCON - I/O EXPANDER CONFIGURATION REGISTER
        #
        # bit 7 BANK: Controls how the registers are addressed
        #     1 = The registers associated with each port are separated into
        # different banks
        # 0 = The registers are in the same bank (addresses are sequential)
        # bit 6 MIRROR: INT Pins Mirror bit
        # 1 = The INT pins are internally connected
        # 0 = The INT pins are not connected. INTA is associated with PortA and
        # INTB is associated with PortB
        # bit 5 SEQOP: Sequential Operation mode bit.
        # 1 = Sequential operation disabled, address pointer does not
        # increment.
        # 0 = Sequential operation enabled, address pointer increments.
        # bit 4 DISSLW: Slew Rate control bit for SDA output.
        # 1 = Slew rate disabled.
        # 0 = Slew rate enabled.
        # bit 3 HAEN: Hardware Address Enable bit (MCP23S17 only).
        # Address pins are always enabled on MCP23017.
        # 1 = Enables the MCP23S17 address pins.
        # 0 = Disables the MCP23S17 address pins.
        # bit 2 ODR: This bit configures the INT pin as an open-drain output.
        # 1 = Open-drain output (overrides the INTPOL bit).
        # 0 = Active driver output (INTPOL bit sets the polarity).
        # bit 1 INTPOL: This bit sets the polarity of the INT output pin.
        # 1 = Active-high.
        # 0 = Active-low.
        # bit 0 Unimplemented: Read as '0'.
        #

        # write io configuration. enable hardware address.
        self.__write(self.REGISTER_IOCON_A, self.IOCON_SEQOP | self.IOCON_HAEN)
        self.__write(self.REGISTER_IOCON_B, self.IOCON_SEQOP | self.IOCON_HAEN)

        # read initial GPIO pin states
        self.__currentStatesA = self.__read(self.REGISTER_GPIO_A)
        self.__currentStatesB = self.__read(self.REGISTER_GPIO_B)

        # set all default pin pull up resistors
        # (1 = Pull-up enabled.)
        # (0 = Pull-up disabled.)
        self.__write(self.REGISTER_IODIR_A, self.__currentDirectionA)
        self.__write(self.REGISTER_IODIR_B, self.__currentDirectionB)

        # set all default pin states
        self.__write(self.REGISTER_GPIO_A, self.__currentStatesA)
        self.__write(self.REGISTER_GPIO_B, self.__currentStatesB)

        # set all default pin pull up resistors
        # (1 = Pull-up enabled.)
        # (0 = Pull-up disabled.)
        self.__write(self.REGISTER_GPPU_A, self.__currentPullupA)
        self.__write(self.REGISTER_GPPU_B, self.__currentPullupB)

        # set all default pin interrupts
        # (if pin direction is input (1), then enable interrupt for pin)
        # (1 = Enable GPIO input pin for interrupt-on-change event.)
        # (0 = Disable GPIO input pin for interrupt-on-change event.)
        self.__write(self.REGISTER_GPINTEN_A, self.__currentDirectionA)
        self.__write(self.REGISTER_GPINTEN_B, self.__currentDirectionB)

        # set all default pin interrupt default values
        # (comparison value registers are not used in this implementation)
        self.__write(self.REGISTER_DEFVAL_A, 0x00)
        self.__write(self.REGISTER_DEFVAL_B, 0x00)

        # set all default pin interrupt comparison behaviors
        # (1 = Controls how the associated pin value is compared for
        # interrupt-on-change.)
        # (0 = Pin value is compared against the previous pin value.)
        self.__write(self.REGISTER_INTCON_A, 0x00)
        self.__write(self.REGISTER_INTCON_B, 0x00)

        # reset/clear interrupt flags
        if self.__currentDirectionA > 0:
            self.__read(self.REGISTER_INTCAP_A)

        if self.__currentDirectionB > 0:
            self.__read(self.REGISTER_INTCAP_B)

    def __write(self, register, data):
        """Write the specified byte to the specified register.

        :param int register: The register to write to. This should be one of
        the register constants.
        :param int data: A single byte to write to the register.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI bus.
        """
        # create packet in data buffer.
        packet = [
            self.__address | self.WRT_FLAG,  # address byte
            register,  # register byte
            data  # data byte
        ]

        try:
            self.__spi.writebytes(packet)
        except (IOError, SystemError, RuntimeError) as ex:
            err_msg = "Failed to write to SPI bus device at address "
            err_msg += str(self.__address) + " on channel /dev/spidev0.0"
            err_msg += str(ex)
            raise IOException(err_msg)

    def __read(self, register):
        """Read a single byte from the specified register.

        :param int register: The register to write to. This should be one of
        the register constants.
        :returns: The byte read.
        :rtype: int
        :raises: raspy.io.io_exception.IOException if unable to read from
        the SPI bus.
        """
        # create packet in data buffer.
        packet = [
            self.__address | self.RD_FLAG,  # address byte
            register,  # register byte
            0x00000000  # data byte
        ]

        result = 0
        try:
            temp = self.__spi.xfer(packet, self.__speed)
            if temp is not None:
                result = temp[2] & 0xFF
        except (IOError, SystemError, RuntimeError) as ex:
            err_msg = "Failed to write to SPI bus device at address "
            err_msg += str(self.__address) + " on channel /dev/spidev0.0"
            err_msg += str(ex)
            raise IOException(err_msg)

        return result

    def __set_state_a(self, state):
        """Set the state of this pin if on Port A (outputs).

        :param int state: The state to set.
        :raises: raspy.io.io_exception.IOException if unable to write to
        the SPI port.
        """
        # determine pin address.
        pin_address = self.inner_pin.value - self.GPIO_A_OFFSET

        # determine state value for pin bit
        if state == pin_state.HIGH:
            self.__currentStatesA |= pin_address
        else:
            self.__currentStatesA &= ~pin_address

        # update state value.
        self.__write(self.REGISTER_GPIO_A, self.__currentStatesA)

    def __set_state_b(self, state):
        """Set the state of this pin if on Port B (inputs).

        :param int state: The state to set.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        # determine pin address
        pin_address = self.inner_pin.value - self.GPIO_B_OFFSET

        # determine state value for pin bit
        if state == pin_state.HIGH:
            self.__currentStatesB |= pin_address
        else:
            self.__currentStatesB &= ~pin_address

        # update state value.
        self.__write(self.REGISTER_GPIO_B, self.__currentStatesB)

    def __set_state(self, state):
        """Set the state of this pin.

        :param int state: The state to set.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        if self.state == state:
            return

        self.__oldState = self.state
        PiFaceGPIO.write(self, state)

        # determine A or B port based on pin address.
        if self.inner_pin.value == self.GPIO_B_OFFSET:
            self.__set_state_a(state)
        else:
            self.__set_state_b(state)

    def write(self, state):
        """Write a value to the pin.

        :param int state: The pin state value to write to the pin.
        :raises: raspy.ObjectDisposedException if this instance has been
        disposed.
        """
        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        PiFaceGPIO.write(self, state)
        self.__set_state(state)

    def __evaluate_pin_for_change_a(self, state):
        """Evaluate Port A for pin change.

        If the state is different compared to the specified state, then emits
        a raspy.io.gpio.EVENT_GPIO_STATE_CHANGED event.

        :param int state: The state to check against.
        """
        # determine pin address.
        pin_address = self.inner_pin.value - self.GPIO_A_OFFSET

        # determine if state changed.
        if (state & pin_address) != (self.__currentStatesA & pin_address):
            # Determine new state value for pin bit.
            new_state = pin_state.LOW
            if (state & pin_address) == pin_address:
                new_state = pin_state.HIGH

            if new_state == pin_state.HIGH:
                self.__currentStatesA |= pin_address
            else:
                self.__currentStatesA &= ~pin_address

            # change detected for pin.
            evt = PinStateChangeEvent(self.__oldState, new_state, pin_address)
            self.on_pin_state_change(evt)

    def __evaluate_pin_for_change_b(self, state):
        """Evaluate Port B for pin change.

        If the state is different compared to the specified state, then emits
        a raspy.io.Gpio.EVENT_GPIO_STATE_CHANGED event.

        :param int state: The state to check against.
        """
        # determine pin address.
        pin_address = self.inner_pin.value - self.GPIO_B_OFFSET

        # determine if state changed.
        if (state & pin_address) != (self.__currentStatesB & pin_address):
            # Determine new state value for pin bit.
            new_state = pin_state.LOW
            if (state & pin_address) == pin_address:
                new_state = pin_state.HIGH

            if new_state == pin_state.HIGH:
                self.__currentStatesB |= pin_address
            else:
                self.__currentStatesB &= ~pin_address

            # change detected for pin.
            evt = PinStateChangeEvent(self.__oldState, new_state, pin_address)
            self.on_pin_state_change(evt)

    def __set_mode_a(self, mode):
        """Set the mode of this pin on Port A.

        :param int mode: The pin mode to set.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI bus.
        """
        pin_address = self.inner_pin.value - self.GPIO_A_OFFSET

        if mode == pin_mode.IN:
            self.__currentDirectionA |= pin_address
        elif mode == pin_mode.OUT:
            self.__currentDirectionA &= ~pin_address

        self.__write(self.REGISTER_IODIR_A, self.__currentDirectionA)
        self.__write(self.REGISTER_GPINTEN_A, self.__currentDirectionA)

    def __set_mode_b(self, mode):
        """Set the mode of this pin on Port B.

        :param int mode: The pin mode to set.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI bus.
        """
        pin_address = self.inner_pin.value - self.GPIO_B_OFFSET

        if mode == pin_mode.IN:
            self.__currentDirectionB |= pin_address
        elif mode == pin_mode.OUT:
            self.__currentDirectionB &= ~pin_address

        self.__write(self.REGISTER_IODIR_B, self.__currentDirectionB)
        self.__write(self.REGISTER_GPINTEN_B, self.__currentDirectionB)

    def __background_poll(self):
        """The background (asynchronous) poll cycle routine.

        This is the callback executed by the poll thread.

        :raises: raspy.io.IOException if unable to write to the SPI bus.
        """
        while not self.__stopEvent.is_set():
            # only process for interrupts if a pin on port A is configured as
            # an input pin.
            pin_interrupt_state = -1
            if self.__currentDirectionA > 0:
                # process interrupts for port A.
                pin_interrupt_a = self.__read(self.REGISTER_INTF_A)

                # validate that there is at least one interrupt active on port
                # A.
                if pin_interrupt_a > 0:
                    # read the current pin states on port A.
                    pin_interrupt_state = self.__read(self.REGISTER_GPIO_A)

                    # is there an interrupt flag on this pin?
                    self.__evaluate_pin_for_change_a(pin_interrupt_state)

            # only process for interrupts if a pin on port B is configured as
            # an input pin.
            if self.__currentDirectionB > 0:
                # process interrupts for port B.
                pin_interrupt_b = self.__read(self.REGISTER_INTF_B)

                # validate that there is at least one interrupt active on port
                # B.
                if pin_interrupt_b > 0:
                    # read the current pin states on port B.
                    pin_interrupt_state = self.__read(self.REGISTER_GPIO_B)

                    # is there an interrupt flag on this pin?
                    self.__evaluate_pin_for_change_b(pin_interrupt_state)

    def cancel_poll(self):
        """Cancel an input poll cycle (if running) started by poll()."""
        if self.is_disposed:
            return

        if self.__stopEvent.is_set() or self.__pollThread is None:
            return

        self.__stopEvent.set()
        self.__pollRunning = False

    def poll(self):
        """Start a pin poll cycle.

        This will monitor the pin and check for state changes. If a state
        change is detected, the raspy.io.Gpio.EVENT_GPIO_STATE_CHANGED event
        will be emitted. The poll cycle runs asynchronously until stopped by
        the cancel_poll() method or when this object instance is disposed.

        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.
        :raises: raspy.invalid_operation_exception.InvalidOperationException
        if the poll thread is already running.
        """
        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        if self.__pollRunning:
            raise InvalidOperationException("Poll thread already running.")

        self.__stopEvent.clear()
        self.__pollThread = threading.Thread(target=self.__background_poll)
        self.__pollThread.name = "PiFaceGpioPoller"
        self.__pollThread.daemon = True
        self.__pollThread.start()
        self.__pollRunning = True

    @property
    def mode(self):
        """Get the pin mode.

        :returns: The pin mode.
        :rtype: int
        """
        return super(PiFaceGPIO, self).mode

    @mode.setter
    def mode(self, p_mode):
        """Set the pin mode.

        :param int p_mode: The pin mode to set.
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.
        """
        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        if p_mode is None:
            p_mode = p_mode.TRI

        PiFaceGPIO.mode.fset(self, p_mode)

        # determine A or B port based on pin address
        if self.inner_pin.value < self.GPIO_B_OFFSET:
            self.__set_mode_a(p_mode)
        else:
            self.__set_mode_b(p_mode)

        # if any pins are configured as input pins, then we need to start the
        # interrupt monitoring poll timer.
        if self.__currentDirectionA > 0 or self.__currentDirectionB > 0:
            self.poll()
        else:
            self.cancel_poll()

    def provision(self):
        """Provision this pin.

        :raises: raspy.ObjectDisposedException if this instance has been
        disposed.
        """
        self.write(PiFaceGPIO.get_initial_pin_value(self))

    def __set_pull_resistance_a(self, resistance):
        """Set the pin pull-up/down resistance for port A.

        :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The
        pin pull resistance flag to set. Can enable the internal pull-up or
        pull-down resistor, or disable it.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        pin_address = self.inner_pin.value - self.GPIO_A_OFFSET

        if resistance.value == pin_pull_resistance.PullUp.value:
            self.__currentPullupA |= pin_address
        else:
            self.__currentPullupA &= ~pin_address

        self.__write(self.REGISTER_GPPU_A, self.__currentPullupA)

    def __set_pull_resistance_b(self, resistance):
        """Set the pin pull-up/down resistance for port B.

        :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The
        pin pull resistance flag to set. Can enable the internal pull-up or
        pull-down resistor, or disable it.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        pin_address = self.inner_pin.value - self.GPIO_B_OFFSET

        if resistance.value == pin_pull_resistance.PullUp.value:
            self.__currentPullupB |= pin_address
        else:
            self.__currentPullupB &= ~pin_address

        self.__write(self.REGISTER_GPPU_B, self.__currentPullupB)

    @property
    def pull_resistance(self):
        """Get the pin pull-up/down resistance.

        :returns: The pin pull resistance.
        :rtype: raspy.io.pin_pull_resistance.PinPullResistance
        """
        return self.__pullResistance

    @pull_resistance.setter
    def pull_resistance(self, resistance):
        """Set the pin pull-up/down resistance.

        :param raspy.io.pin_pull_resistance.PinPullResistance resistance: The
        pin pull resistance.
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        if self.__pullResistance.value == resistance.value:
            return

        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        self.__pullResistance = resistance
        if self.inner_pin.value > self.GPIO_B_OFFSET:
            self.__set_pull_resistance_a(resistance)
        else:
            self.__set_pull_resistance_b(resistance)

    def read(self):
        """Read a value from the pin.

        :returns: The state (value) of the pin.
        :rtype: int
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.
        :raises: raspy.io.io_exception.IOException if unable to read from the
        SPI port.
        """
        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        if self.inner_pin.value < self.GPIO_B_OFFSET:
            return self.__read(self.REGISTER_GPIO_A)

        return self.__read(self.REGISTER_GPIO_B)

    def __get_state_a(self):
        """Get the state of the pin if on Port A.

        :returns: The state of the pin.
        :rtype: int
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        pin_address = self.inner_pin.value - self.GPIO_A_OFFSET
        temp_state = (self.__currentStatesA & pin_address)
        my_state = pin_state.LOW
        if temp_state == pin_address:
            my_state = pin_state.HIGH

        super(PiFaceGPIO, self).write(my_state)
        return my_state

    def __get_state_b(self):
        """Get the state of the pin if on Port B.

        :returns: The state of the pin.
        :rtype: int
        :raises: raspy.io.io_exception.IOException if unable to write to the
        SPI port.
        """
        pin_address = self.inner_pin.value - self.GPIO_B_OFFSET
        temp_state = (self.__currentStatesB & pin_address)
        my_state = pin_state.LOW
        if temp_state == pin_address:
            my_state = pin_state.HIGH

        super(PiFaceGPIO, self).write(my_state)
        return my_state

    @property
    def state(self):
        """Get the state of the pin.

        :returns: The pin state.
        :rtype: int
        :raises: raspy.object_disposed_exception.ObjectDisposedException if
        this instance has been disposed.
        :raises: raspy.io.io_exception.IOException if unable to read from the
        SPI port.
        """
        if self.is_disposed:
            raise ObjectDisposedException("PiFaceGpioDigital")

        if self.inner_pin.value < self.GPIO_B_OFFSET:
            result = self.__get_state_a()
        else:
            result = self.__get_state_b()

        return result

    def dispose(self):
        """Dispose managed resources.

        Performs application-defined tasks associated with freeing, releasing,
        or resetting resources.
        """
        if self.is_disposed:
            return

        self.cancel_poll()
        self.__spi = None
        super(PiFaceGPIO, self).dispose()
Exemple #4
0
class CpPhy(object):
	# Profibus baud-rates
	PB_PHY_BAUD_9600	= 0
	PB_PHY_BAUD_19200	= 1
	PB_PHY_BAUD_45450	= 2
	PB_PHY_BAUD_93750	= 3
	PB_PHY_BAUD_187500	= 4
	PB_PHY_BAUD_500000	= 5
	PB_PHY_BAUD_1500000	= 6
	PB_PHY_BAUD_3000000	= 7
	PB_PHY_BAUD_6000000	= 8
	PB_PHY_BAUD_12000000	= 9

	# RTS mode
	PB_PHY_RTS_ALWAYS_LO	= 0
	PB_PHY_RTS_ALWAYS_HI	= 1
	PB_PHY_RTS_SENDING_HI	= 2
	PB_PHY_RTS_SENDING_LO	= 3

	# GPIO numbers (BCM)
	GPIO_RESET		= 17
	GPIO_IRQ		= 27
	GPIO_SS			= 8
	GPIO_MISO		= 9
	GPIO_MOSI		= 10
	GPIO_SCK		= 11

	baud2id = {
		9600		: PB_PHY_BAUD_9600,
		19200		: PB_PHY_BAUD_19200,
		45450		: PB_PHY_BAUD_45450,
		93750		: PB_PHY_BAUD_93750,
		187500		: PB_PHY_BAUD_187500,
		500000		: PB_PHY_BAUD_500000,
		1500000		: PB_PHY_BAUD_1500000,
		3000000		: PB_PHY_BAUD_3000000,
		6000000		: PB_PHY_BAUD_6000000,
		12000000	: PB_PHY_BAUD_12000000,
	}

	def __init__(self, device=0, chipselect=0, debug=False):
		self.device = device
		self.chipselect = chipselect
		self.debug = debug

		try:
			try:
				# Initialize GPIOs
				GPIO.setmode(GPIO.BCM) # Use Broadcom numbers
				GPIO.setwarnings(False)
				GPIO.setup(self.GPIO_RESET, GPIO.OUT, initial=GPIO.LOW)
				GPIO.setup(self.GPIO_IRQ, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
				GPIO.add_event_detect(self.GPIO_IRQ, GPIO.RISING)
				time.sleep(0.05)
			except RuntimeError as e:
				raise PhyError("Failed to initialize GPIOs: %s" %\
					str(e))

			# Initialize SPI
			try:
				self.spi = SpiDev()
				self.spi.open(device, chipselect)
			except IOError as e:
				raise PhyError("Failed to open SPI device %d.%d: %s" %\
					(device, chipselect, str(e)))
			try:
				self.spi.mode = 0;
				self.spi.bits_per_word = 8;
				self.spi.cshigh = False
				self.spi.lsbfirst = False
				self.spi.max_speed_hz = 200000;
			except IOError as e:
				try:
					self.spi.close()
					self.spi = None
				except:
					pass
				raise PhyError("Failed to configure SPI device %d.%d: %s" %\
					(device, chipselect, str(e)))

			# Get the controller out of hardware reset
			GPIO.output(self.GPIO_RESET, GPIO.HIGH)
			time.sleep(0.2)

			# Send a software reset
			self.sendReset()
			# Upload default config
			self.profibusSetPhyConfig()
		except:
			GPIO.cleanup()
			raise

	def cleanup(self):
		self.spi.close()
		self.spi = None
		GPIO.cleanup()

	# Poll for received packet.
	# timeout => In seconds. 0 = none, Negative = unlimited.
	def poll(self, timeout=0):
		limit = TimeLimited(timeout)
		while GPIO.event_detected(self.GPIO_IRQ):
			if limit.exceed():
				return None
			limit.sleep(0.001)
		limit.add(0.5)
		while not limit.exceed():
			fc = self.spi.readbytes(1)[0]
			if fc != CpPhyMessage.RPI_PACK_NOP:
				break
		else:
			return None
		reply = [ fc ]
		reply.extend(self.spi.readbytes(CpPhyMessage.RASPI_PACK_HDR_LEN - 1))
		payloadLen = reply[1] & 0xFF
		if payloadLen:
			reply.extend(self.spi.readbytes(payloadLen))
		message = CpPhyMessage(0)
		message.setRawData(reply)
		if self.debug:
			print("[PHY] recv msg:", message)
		return message

	def __sendMessage(self, message):
		if self.debug:
			print("[PHY] send msg:", message)
		self.spi.writebytes(message.getRawData())

	def sendReset(self):
		self.__sendMessage(CpPhyMessage(CpPhyMessage.RPI_PACK_RESET))
		reply = self.poll(timeout=-1)
		if reply.fc != CpPhyMessage.RPI_PACK_ACK:
			raise PhyError("Failed to reset PHY")

	def profibusSetPhyConfig(self, baudrate=19200,
				 rxTimeoutMs=100,
				 bitErrorChecks=True,
				 rtsMode=PB_PHY_RTS_SENDING_HI):
		try:
			baudID = self.baud2id[baudrate]
		except KeyError:
			raise PhyError("Invalid baud-rate")
		if rxTimeoutMs < 1 or rxTimeoutMs > 255:
			raise PhyError("Invalid RX timeout")
		payload = [ baudID,
			    rxTimeoutMs,
			    1 if bitErrorChecks else 0,
			    rtsMode & 0xFF ]
		message = CpPhyMessage(CpPhyMessage.RPI_PACK_SETCFG, payload)
		self.__sendMessage(message)
		reply = self.poll(timeout=-1)
		if reply.fc != CpPhyMessage.RPI_PACK_ACK:
			raise PhyError("Failed to upload config")

	def profibusSend_SDN(self, telegramData):
		self.__sendMessage(CpPhyMessage(CpPhyMessage.RPI_PACK_PB_SDN,
						telegramData))

	def profibusSend_SRD(self, telegramData):
		self.__sendMessage(CpPhyMessage(CpPhyMessage.RPI_PACK_PB_SRD,
						telegramData))
Exemple #5
0
class SSD1331:

    # SSD1331 Commands
    _CMD_DRAWLINE     = 0x21
    _CMD_DRAWRECT     = 0x22
    _CMD_FILL         = 0x26
    _CMD_SETCOLUMN    = 0x15
    _CMD_SETROW       = 0x75
    _CMD_CONTRASTA    = 0x81
    _CMD_CONTRASTB    = 0x82
    _CMD_CONTRASTC    = 0x83
    _CMD_MASTERCURRENT= 0x87
    _CMD_SETREMAP     = 0xA0
    _CMD_STARTLINE    = 0xA1
    _CMD_DISPLAYOFFSET= 0xA2
    _CMD_NORMALDISPLAY= 0xA4
    _CMD_DISPLAYALLON = 0xA5
    _CMD_DISPLAYALLOFF= 0xA6
    _CMD_INVERTDISPLAY= 0xA7
    _CMD_SETMULTIPLEX = 0xA8
    _CMD_SETMASTER    = 0xAD
    _CMD_DISPLAYOFF   = 0xAE
    _CMD_DISPLAYON    = 0xAF
    _CMD_POWERMODE    = 0xB0
    _CMD_PRECHARGE    = 0xB1
    _CMD_CLOCKDIV     = 0xB3
    _CMD_PRECHARGEA   = 0x8A
    _CMD_PRECHARGEB   = 0x8B
    _CMD_PRECHARGEC   = 0x8C
    _CMD_PRECHARGELEVEL=0xBB
    _CMD_VCOMH        = 0xBE

    _WIDTH = 96
    _HEIGHT= 64


    def __init__(self,RSpin,DSpin,SPIcs=0,SPIclk=10000000,SPImosi=0):
        '''Initialize the class.
            RSpin  = Reset GPIO pin      , connected to RS
            DSpin  = Data Select GPIO pin, connected to DS
            SPIsc  = SPI Chip select     , connected to CS, default=0
            SPIclk = SPI Clock           ,                  default=1000000
            SPImosi= SPI Mosi            ,                  default=0
        Currently the class only implements hardware SPI    '''

        self._RS = RSpin
        self._DS = DSpin
        self._SPIcs = SPIcs
        self._SPIclk= SPIclk

        self._spi = SpiDev(0,SPIcs)
        self._spi.mode = 3
        self._spi.max_speed_hz=SPIclk

        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self._RS,GPIO.OUT)
        GPIO.setup(self._DS,GPIO.OUT)

        self.ReInitialize()

    def WriteCommand(self,c):
        '''Write command 'c' over the SPI.'''

        GPIO.output(self._DS,0)  # Data Select low selects commands.

        if type(c) is int:
            self._spi.writebytes([c])
        else:
            self._spi.writebytes(c)

    def WriteData(self,c):
        '''Write command 'c' over the SPI.'''

        GPIO.output(self._DS,1)  # Data Select low selects commands.

        if type(c) is int:
            self._spi.writebytes([c])
        else:
            for i in range(len(c)//4096):     # Break the array into 4096 bytes max.
                self._spi.writebytes(c[i*4096:(i+1)*4096])

    def Reset(self):
        '''Reset the chip'''
        GPIO.output(self._RS,1)
        time.sleep(0.05)
        GPIO.output(self._RS,0)
        time.sleep(0.05)
        GPIO.output(self._RS,1)
        time.sleep(0.05)

    def ReInitialize(self):
        '''Reinitialize the chip that drives the display.'''

        self.Reset()
        # Initialization Sequence
        commands=[
            self._CMD_DISPLAYOFF, # 0xAE
            self._CMD_SETREMAP  , # 0xA0
            0x72,   # Bit0 = 0 = Horizontal address increment.
                    # Bit1 = 1 = RAM column 0 - 95 maps to Pin Seg 95-0
                    # Bit2 = 0 = RGB order.
                    # Bit3 = 0 = Disable left-right swapping on COM
                    # Bit4 = 1 = Scan from COM[N-1] to COM0
                    # Bit5 = 1 = Enable COM split IDD Even
                    # Bit7,6 = 0,1 = 65k color format.
        ]
        self.WriteCommand(commands)
        # RGB data order
        self.WriteCommand(0x72)
        self.WriteCommand(self._CMD_STARTLINE) 	# 0xA1
        self.WriteCommand(0x0)
        self.WriteCommand(self._CMD_DISPLAYOFFSET) 	# 0xA2
        self.WriteCommand(0x0)
        self.WriteCommand(self._CMD_NORMALDISPLAY)  	# 0xA4
        self.WriteCommand(self._CMD_SETMULTIPLEX) 	# 0xA8
        self.WriteCommand(0x3F)  			# 0x3F 1/64 duty
        self.WriteCommand(self._CMD_SETMASTER)  	# 0xAD
        self.WriteCommand(0x8E)
        self.WriteCommand(self._CMD_POWERMODE)  	# 0xB0
        self.WriteCommand(0x0B)
        self.WriteCommand(self._CMD_PRECHARGE)  	# 0xB1
        self.WriteCommand(0x31)
        self.WriteCommand(self._CMD_CLOCKDIV)  	# 0xB3
        self.WriteCommand(0xF0)  # 7:4 = Oscillator Frequency, 3:0 = CLK Div Ratio (A[3:0]+1 = 1..16)
        self.WriteCommand(self._CMD_PRECHARGEA)  	# 0x8A
        self.WriteCommand(0x64)
        self.WriteCommand(self._CMD_PRECHARGEB)  	# 0x8B
        self.WriteCommand(0x78)
        self.WriteCommand(self._CMD_PRECHARGEA)  	# 0x8C
        self.WriteCommand(0x64)
        self.WriteCommand(self._CMD_PRECHARGELEVEL)  	# 0xBB
        self.WriteCommand(0x3A)
        self.WriteCommand(self._CMD_VCOMH)  		# 0xBE
        self.WriteCommand(0x3E)
        self.WriteCommand(self._CMD_MASTERCURRENT)  	# 0x87
        self.WriteCommand(0x06)
        self.WriteCommand(self._CMD_CONTRASTA)  	# 0x81
        self.WriteCommand(0x91)
        self.WriteCommand(self._CMD_CONTRASTB)  	# 0x82
        self.WriteCommand(0x50)
        self.WriteCommand(self._CMD_CONTRASTC)  	# 0x83
        self.WriteCommand(0x7D)
        self.WriteCommand(self._CMD_DISPLAYON)	#--turn on oled panel


    def GoTo(self,xy0,xy1=None):
        '''Move the cursor to xy0=[x,y] with end of writing at xy1'''
        if xy1 is None:
            xy1=[self._WIDTH-1,self._HEIGHT-1]

        if xy0[0] >= self._WIDTH or xy0[1] >= self._HEIGHT:
            return

        # set x and y coordinate
        self.WriteCommand(self._CMD_SETCOLUMN);
        self.WriteCommand(xy0[0]);
        self.WriteCommand(xy1[0]);

        self.WriteCommand(self._CMD_SETROW);
        self.WriteCommand(xy0[1]);
        self.WriteCommand(xy1[1]);

    def DrawPixel(self,xy,color):
        '''Color Pixel at xy=[x,y] with color'''
        self.GoTo(xy[0], xy[1]);
        self.WriteData([color >> 8,color&0x0F]);

    def DrawLine(self,xy0,xy1,color):
        '''Draw a line from xy0 ([x,y]) to xy1 in color'''
        if xy0[0]<0 or xy0[0]>self._WIDTH or xy0[1]<0 or xy0[1]>self._HEIGHT:
            return(-1)
        if xy1[0]<0 or xy1[0]>self._WIDTH or xy1[1]<0 or xy1[1]>self._HEIGHT:
            return(-2)
        self.WriteCommand([self._CMD_DRAWLINE]+xy0+xy1+[color])

    def DrawBox(self,xy0,xy1,color,fill):
        '''Draw a Box with corners xy0 ([x,y]) to xy1 in color with fill color.
        If fill is None, the fill will be turned off.'''
        if xy0[0]<0 or xy0[0]>self._WIDTH or xy0[1]<0 or xy0[1]>self._HEIGHT:
            return(-1)
        if xy1[0]<0 or xy1[0]>self._WIDTH or xy1[1]<0 or xy1[1]>self._HEIGHT:
            return(-2)
        self.WriteCommand(self._CMD_FILL)
        if fill is None:
            self.WriteCommand(0)
        else:
            self.WriteCommand(1)
        self.WriteCommand([self._CMD_DRAWRECT]+xy0+xy1+self.MakeColorCBA(color)+self.MakeColorCBA(fill))

    def DrawImage(self,image,xy0=None,xy1=None):
        '''Draw the image at xy. Usually xy=[0,0] (default
        :param image: The image to render
        :type image: PIL.Image.Image '''
        if xy0 is None:
            xy0=[0,0]
        if xy1 is None:
            xy1=[self._WIDTH-1,self._HEIGHT-1]

        buf = [0]*(xy1[0]-xy0[0]+1)*(xy1[1]-xy0[1]+1)*2
        i=0
        for pixel in image.getdata():
            buf[i]   = (pixel[0] & 0xF8) | (pixel[1] >> 5)
            buf[i+1] = (pixel[1] << 5 )  | (pixel[2] >> 3 )
            i += 2
        self.GoTo(xy0,xy1)
        self.WriteData(buf)

    def MakeColor(self,R,G=None,B=None):
        '''Create a 16-bit color from [R,G,B] intput'''
        if type(R) is tuple or type(R) is list:
            C=R
        else:
            C=[R,G,B]
        color= ((C[0]&0xF8)<<8) | ((C[1]&0xFC)<<3) | ((C[2]&0xF8)>>3)
        return(color)

    def Make2Color(self,C):
        '''Create a 2 byte color '''
        color= self.MakeColor(C)
        return([color>>8,color&0xFF])

    def MakeColorCBA(self,color):
        '''Internally used to decode color to CBA and send out.'''
        if color is None:
            return([0,0,0])

        if type(color) is tuple or type(color) is list:
            C = color[0]>>3
            B = color[1]>>2
            A = color[2]>>3
        else: # Color is 16-bit 565 format
            C = color>>11 & 0x1F
            B = color>>5  & 0x3F
            A = color     & 0x1F
        return([C,B,A])
Exemple #6
0
class CpPhy(object):
    # Profibus baud-rates
    PB_PHY_BAUD_9600 = 0
    PB_PHY_BAUD_19200 = 1
    PB_PHY_BAUD_45450 = 2
    PB_PHY_BAUD_93750 = 3
    PB_PHY_BAUD_187500 = 4
    PB_PHY_BAUD_500000 = 5
    PB_PHY_BAUD_1500000 = 6
    PB_PHY_BAUD_3000000 = 7
    PB_PHY_BAUD_6000000 = 8
    PB_PHY_BAUD_12000000 = 9

    # RTS mode
    PB_PHY_RTS_ALWAYS_LO = 0
    PB_PHY_RTS_ALWAYS_HI = 1
    PB_PHY_RTS_SENDING_HI = 2
    PB_PHY_RTS_SENDING_LO = 3

    # GPIO numbers (BCM)
    GPIO_RESET = 17
    GPIO_IRQ = 27
    GPIO_SS = 8
    GPIO_MISO = 9
    GPIO_MOSI = 10
    GPIO_SCK = 11

    baud2id = {
        9600: PB_PHY_BAUD_9600,
        19200: PB_PHY_BAUD_19200,
        45450: PB_PHY_BAUD_45450,
        93750: PB_PHY_BAUD_93750,
        187500: PB_PHY_BAUD_187500,
        500000: PB_PHY_BAUD_500000,
        1500000: PB_PHY_BAUD_1500000,
        3000000: PB_PHY_BAUD_3000000,
        6000000: PB_PHY_BAUD_6000000,
        12000000: PB_PHY_BAUD_12000000,
    }

    def __init__(self, device=0, chipselect=0, debug=False):
        self.device = device
        self.chipselect = chipselect
        self.debug = debug

        try:
            try:
                # Initialize GPIOs
                GPIO.setmode(GPIO.BCM)  # Use Broadcom numbers
                GPIO.setwarnings(False)
                GPIO.setup(self.GPIO_RESET, GPIO.OUT, initial=GPIO.LOW)
                GPIO.setup(self.GPIO_IRQ, GPIO.IN, pull_up_down=GPIO.PUD_OFF)
                GPIO.add_event_detect(self.GPIO_IRQ, GPIO.RISING)
                time.sleep(0.05)
            except RuntimeError as e:
                raise PhyError("Failed to initialize GPIOs: %s" %\
                 str(e))

            # Initialize SPI
            try:
                self.spi = SpiDev()
                self.spi.open(device, chipselect)
            except IOError as e:
                raise PhyError("Failed to open SPI device %d.%d: %s" %\
                 (device, chipselect, str(e)))
            try:
                self.spi.mode = 0
                self.spi.bits_per_word = 8
                self.spi.cshigh = False
                self.spi.lsbfirst = False
                self.spi.max_speed_hz = 200000
            except IOError as e:
                try:
                    self.spi.close()
                    self.spi = None
                except:
                    pass
                raise PhyError("Failed to configure SPI device %d.%d: %s" %\
                 (device, chipselect, str(e)))

            # Get the controller out of hardware reset
            GPIO.output(self.GPIO_RESET, GPIO.HIGH)
            time.sleep(0.2)

            # Send a software reset
            self.sendReset()
            # Upload default config
            self.profibusSetPhyConfig()
        except:
            GPIO.cleanup()
            raise

    def cleanup(self):
        self.spi.close()
        self.spi = None
        GPIO.cleanup()

    # Poll for received packet.
    # timeout => In seconds. 0 = none, Negative = unlimited.
    def poll(self, timeout=0):
        limit = TimeLimited(timeout)
        while GPIO.event_detected(self.GPIO_IRQ):
            if limit.exceed():
                return None
            limit.sleep(0.001)
        limit.add(0.5)
        while not limit.exceed():
            fc = self.spi.readbytes(1)[0]
            if fc != CpPhyMessage.RPI_PACK_NOP:
                break
        else:
            return None
        reply = [fc]
        reply.extend(self.spi.readbytes(CpPhyMessage.RASPI_PACK_HDR_LEN - 1))
        payloadLen = reply[1] & 0xFF
        if payloadLen:
            reply.extend(self.spi.readbytes(payloadLen))
        message = CpPhyMessage(0)
        message.setRawData(reply)
        if self.debug:
            print("[PHY] recv msg:", message)
        return message

    def __sendMessage(self, message):
        if self.debug:
            print("[PHY] send msg:", message)
        self.spi.writebytes(message.getRawData())

    def sendReset(self):
        self.__sendMessage(CpPhyMessage(CpPhyMessage.RPI_PACK_RESET))
        reply = self.poll(timeout=-1)
        if reply.fc != CpPhyMessage.RPI_PACK_ACK:
            raise PhyError("Failed to reset PHY")

    def profibusSetPhyConfig(self,
                             baudrate=19200,
                             rxTimeoutMs=100,
                             bitErrorChecks=True,
                             rtsMode=PB_PHY_RTS_SENDING_HI):
        try:
            baudID = self.baud2id[baudrate]
        except KeyError:
            raise PhyError("Invalid baud-rate")
        if rxTimeoutMs < 1 or rxTimeoutMs > 255:
            raise PhyError("Invalid RX timeout")
        payload = [
            baudID, rxTimeoutMs, 1 if bitErrorChecks else 0, rtsMode & 0xFF
        ]
        message = CpPhyMessage(CpPhyMessage.RPI_PACK_SETCFG, payload)
        self.__sendMessage(message)
        reply = self.poll(timeout=-1)
        if reply.fc != CpPhyMessage.RPI_PACK_ACK:
            raise PhyError("Failed to upload config")

    def profibusSend_SDN(self, telegramData):
        self.__sendMessage(
            CpPhyMessage(CpPhyMessage.RPI_PACK_PB_SDN, telegramData))

    def profibusSend_SRD(self, telegramData):
        self.__sendMessage(
            CpPhyMessage(CpPhyMessage.RPI_PACK_PB_SRD, telegramData))
Exemple #7
0
class MAX7219:
    def __init__(self, DATA_pin, CLK_pin, CS_bar_pin, mode=1):
        '''This class helps with driving a MAX7219 LED module using either regular
        GPIO pins, or SPI hardware interface.
        For SPI hardware, set DATA_pin=0, CS_bar_pin=0 or 1, CLK_pin= bus speed (1000000)
        For GPIO "bit-bang" interface, set DATA_pin = Data in (dat),
        CS_bar = to Chip Select (cs), and CLK_pin= Clock (clk)
        A final argument, mode=1 (default) sets number decoding, while
        mode=0 sets raw mode, see the MAX7219 chip data sheet.
        -------
        This code expects the pin numbers in the BSM standard.
        The Raspberry Pi interfacing is done through the RPi.GPIO module
        or the spi module'''

        self.DATA = DATA_pin
        self.CS_bar = CS_bar_pin
        self.CLK = CLK_pin
        self.Mode = mode
        self._dev = None

        if self.DATA > 0:
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.CLK, GPIO.OUT)
            GPIO.setup(self.DATA, GPIO.OUT)
            GPIO.setup(self.CS_bar, GPIO.OUT)

            GPIO.output(self.CLK, 0)
            GPIO.output(self.DATA, 0)
            GPIO.output(self.CS_bar, 1)
        else:
            if self.CLK < 100:
                self.CLK = 1000000
            self._dev = SpiDev(0, self.CS_bar)
            self._dev.mode = 0
            self._dev.max_speed_hz = self.CLK
            self._dev.bits_per_word = 8
        self.Init(mode)

    def Init(self, mode):
        ''' Initialize the MAX7219 Chip. Mode=1 is for numbers, mode=2 is no-decode.
        This will send an initialization sequence to the chip.
        With an __init__ this method is already called.'''
        self.WriteLocChar(0x0F, 0x01)  # Test ON
        time.sleep(0.5)
        self.WriteLocChar(0x0F, 0x00)  # Test OFF

        self.WriteLocChar(0x0B, 0x07)  # All 8 digits
        self.WriteLocChar(0x0A, 0x0B)  # Quite bright
        self.WriteLocChar(0x0C, 1)  # Set for normal operation.
        if mode == 1:
            self.Mode = 1
            self.WriteLocChar(0x09, 0xFF)  # Decode mode
        else:
            self.Mode = 0
            self.WriteLocChar(0x09, 0x00)  # Raw mode

        self.Clear()

    def __del__(
            self):  # This is automatically called when the class is deleted.
        '''Delete and cleanup.'''
        self.WriteLocChar(0x0C, 0x0)  # Turn off
        if self.DATA > 0:
            GPIO.cleanup(self.CLK)
            GPIO.cleanup(self.DATA)
            GPIO.cleanup(self.CS_bar)
        else:
            self._dev.close()

    def Clear(self):
        '''Clear the display to all blanks. (it looks off) '''
        for i in range(8):
            if self.Mode == 1:
                self.WriteLocChar(i + 1, 0x0F)  # Blank
            else:
                self.WriteLocChar(i + 1, 0x00)  # Blank

    def SetBrightness(self, B):
        '''Set the display brightness to B, where 0<=B<16'''
        B = B & 0x0F
        self.WriteLocChar(0x0A, B)  # Set brightness

    def WriteData(self, data):
        '''Write the 16 bit data to the output using SPI or
         "bit-banged" SPI on the GPIO output line.
        This is a "raw" mode write, used internally in these methods.'''
        if self.DATA > 0:
            GPIO.output(self.CS_bar, 0)

            for i in range(16):  # send out 16 bits of data sequentially.
                GPIO.output(self.CLK, 0)
                #time.sleep(0.00001)
                bit = data & 0x8000
                GPIO.output(self.DATA, bit)
                #time.sleep(0.00001)
                GPIO.output(self.CLK, 1)
                #time.sleep(0.00001)
                data <<= 1
                if (i == 7):
                    GPIO.output(self.CLK, 0)
                    GPIO.output(self.DATA, 0)
                #    time.sleep(0.00003)

            GPIO.output(self.DATA, 0)
            GPIO.output(self.CLK, 0)
            GPIO.output(self.CS_bar, 1)
        else:
            self._dev.writebytes([
                (data >> 8) & 0xFF, data & 0xFF
            ])  # Write the first and second byte from data.

    def WriteLocChar(self, loc, dat):
        '''Write dat to loc. If the mode is 1 then dat is a number and loc is the location.
        If mode is 0 then dat is an 8 bit LED position.
        This is used internally to display the numbers/characters.'''
        if self.DATA > 0:
            out = (loc << 8)
            out += dat
            #out += 0b0000000000000000  # Dummy bits
            self.WriteData(out)
        else:
            self._dev.writebytes([loc, dat])

    def WriteRaw(self, n):
        '''Write the list of 8-bit integers to the module in raw mode'''
        if self.Mode != 0:
            raise ValueError()
        if type(n) is int:
            print("please provide an tuple or list")

        for i in range(len(n)):
            self.WriteLocChar(i + 1, n[i])

    def WriteInt(self, n):
        ''' Write the integer n on the display, shifted left. If n is larger (smaller) than
        fits, an overflow is indicated by all dash.'''

        if self.Mode != 1:
            raise ValueError()

        if n > 99999999 or n < -9999999:  # Display overflow, --------
            for i in range(8):
                self.WriteLocChar(i + 1, 0x0A)
            return

        if n < 0:
            negative = True
            n = -n
        else:
            negative = False
        for i in range(8):
            n, d = divmod(n, 10)
            if n == 0 and d == 0:
                if i == 0:
                    self.WriteLocChar(i + 1, 0x0)  # 0
                else:
                    if negative:
                        self.WriteLocChar(i + 1, 0x0A)
                        negative = False
                    else:
                        self.WriteLocChar(i + 1, 0x0F)  # Blank
            else:
                self.WriteLocChar(i + 1, d)

    def WriteFloat(self, f, form='{:9.6f}'):
        '''Write a floating point number. Trying to use a reasonable format.
        You can specify the format with the form= argument, using the python
        style, to use with form="{:4.2f}" or form="{:8.4e}" '''

        if self.Mode != 1:
            raise ValueError()

        s = form.format(f)
        loc = 1
        highbit = 0
        rev = reversed(
            s[0:8 + s.count('.') +
              s.count('e')])  # Read the letters reversed, starting at the end.
        #        print("Trying to write [{}] len={}".format(s,len(s)))
        #        rev_test=""
        for c in rev:  # Get each of the numbers/symbols, starting with the rightmost.
            #            rev_test += c
            if c == '.':  # If it is the period, then set bit7 but don't count as a digit.
                highbit = 1
            else:
                if c.isdigit():  # It is a digit.
                    i = int(c)
                    i += highbit << 7
                    self.WriteLocChar(loc, i)
                    loc += 1
                    #print("L: {:1d} C: 0x{:2x}".format(loc,i))
                elif c == ' ':
                    self.WriteLocChar(loc, 0x0F)  # Write blank
                    loc += 1
                    #print("L: {:1d} C: 0x{:2x}".format(loc,0x0F))
                elif c == '+':
                    self.WriteLocChar(loc, 0x0B)  # Write E
                    loc += 1
                    #print("L: {:1d} C: 0x{:2x}".format(loc,0x0B))
                elif c == '-':
                    self.WriteLocChar(loc, 0x0A)  # Write -
                    loc += 1
                    #print("L: {:1d} C: 0x{:2x}".format(loc,0x0A))
                elif c == 'e' or c == 'E':  # Skip the E, E- too long.
                    pass
                else:
                    print("Bad char in string: ", c)
                highbit = 0
        while loc < 9:  # Fill the end with blanks
            self.WriteLocChar(loc, 0x0F)  # Write blank
            loc += 1

    def __str__(self):
        '''Write something comforting to the user :-) '''
        if self.DATA > 0:
            print(
                "MAX7219 driver interface. GPIO mode: DATA={} CS_bar={} CLK={}",
                self.DATA, self.CS_bar, self.CLK)
Exemple #8
0
class AMIS30543_Controller():
    def __init__(self, DO_DIRECTION_PIN, DO_RESET_PIN, DI_FAULT_PIN, ARGS):

        self.REG = {  # AMIS-30543 Registers
            'WR': 0x00,
            'CR0': 0x01,
            'CR1': 0x02,
            'CR2': 0x03,
            'CR3': 0x09,
            'SR0': 0x04,
            'SR1': 0x05,
            'SR2': 0x06,
            'SR3': 0x07,
            'SR4': 0x0A
        }

        self.CMD = {  # AMIS-30543 Command constants
            'READ': 0x00,
            'WRITE': 0x80
        }

        self.dirctrl = ARGS[0]
        self.pwmf = ARGS[1]
        self.pwmj = ARGS[2]
        self.sm = ARGS[3]
        self.mult = ARGS[4]
        self.dist = ARGS[5]
        self.step = ARGS[6]

        self.VAL = {
            'WR': 0b00000000,  # no watchdog
            'CR0': 0b00010111 | self.sm,  # & 2.7 A current limit
            'CR1': 0b00000000 | self.dirctrl | self.pwmf
            | self.pwmj,  # & step on rising edge & fast slopes
            'CR2':
            0b00000000,  # motor off & no sleep & SLA gain @ 0.5 & SLA no transparent
            'CR3':
            0b00000000  #,                                         # no extended step mode
            #'dist': self.dist,
            #'step': self.step
        }

        # InitGPIO

        PWM.setup(5, 0)  # 5 us pulse_incr, 0 delay_hw
        PWM.init_channel(0, 3000)  # DMA channel 0, 3000 us subcycle time

        self.DO_RESET = gpiozero.DigitalOutputDevice(DO_RESET_PIN)
        self.DO_DIRECTION = gpiozero.DigitalOutputDevice(DO_DIRECTION_PIN)
        self.DI_NO_FAULT = gpiozero.DigitalInputDevice(DI_FAULT_PIN)

        self.spi = SpiDev()
        self.spi.open(0, 0)
        self.spi.max_speed_hz = 1000000

        self.RegisterSet()

    def __del__(self):
        self.spi.close()

    def ResetStepper(self):
        self.DO_RESET.off()  # must be off for AMIS to see reset
        time.sleep(0.11)
        self.DO_RESET.on()
        time.sleep(0.11)
        self.DO_RESET.off()

    def RegisterDump(self):  # to check stepper status
        print("\nAMIS-30543 Registers:")
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['WR'], 0])
        print(" WR = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['CR0'], 0])
        print("CR0 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['CR1'], 0])
        print("CR1 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['CR2'], 0])
        print("CR2 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['CR3'], 0])
        print("CR3 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['SR0'], 0])
        print("SR0 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['SR1'], 0])
        print("SR1 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['SR2'], 0])
        print("SR2 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['SR3'], 0])
        print("SR3 = ", bin(resp[1]), " ", str(resp[1]))
        resp = self.spi.xfer2([self.CMD['READ'] | self.REG['SR4'], 0])
        print("SR4 = ", bin(resp[1]), " ", str(resp[1]))
        print("")

    def RegisterSet(self):
        self.ResetStepper()

        self.spi.writebytes(
            [self.CMD['WRITE'] | self.REG['WR'], self.VAL['WR']])
        self.spi.writebytes(
            [self.CMD['WRITE'] | self.REG['CR0'], self.VAL['CR0']])
        self.spi.writebytes(
            [self.CMD['WRITE'] | self.REG['CR1'], self.VAL['CR1']])
        self.spi.writebytes(
            [self.CMD['WRITE'] | self.REG['CR2'], self.VAL['CR2']])
        self.spi.writebytes(
            [self.CMD['WRITE'] | self.REG['CR3'], self.VAL['CR3']])

        if self.spi.xfer2([self.CMD['READ'] | self.REG['WR'], 0
                           ])[1] != self.VAL['WR']:
            print(
                "Writing or reading self.REG['WR'] failed; driver power might be off."
            )
            return False
        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR0'], 0
                           ])[1] != self.VAL['CR0']:
            print(
                "Writing or reading self.REG['CR0'] failed; driver power might be off."
            )
            return False
        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR1'], 0
                           ])[1] != self.VAL['CR1']:
            print(
                "Writing or reading self.REG['CR1'] failed; driver power might be off."
            )
            return False
        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR2'], 0
                           ])[1] != self.VAL['CR2']:
            print(
                "Writing or reading self.REG['CR2'] failed; driver power might be off."
            )
            return False
        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR3'], 0
                           ])[1] != self.VAL['CR3']:
            print(
                "Writing or reading self.REG['CR3'] failed; driver power might be off."
            )
            return False

        #self.RegisterDump()
        #print("RegisterSet Ok\n")
        return True

    def SetMotorEnable(self):

        self.spi.writebytes([
            self.CMD['WRITE'] | self.REG['CR2'], self.VAL['CR2'] | 0b10000000
        ])

        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR2'], 0
                           ])[1] != self.VAL['CR2'] | 0b10000000:
            print(
                "Writing or reading self.REG['CR2'] failed; driver power might be off."
            )
            return False

    def SetMotorDisable(self):

        self.spi.writebytes([
            self.CMD['WRITE'] | self.REG['CR2'], self.VAL['CR2'] & 0b01111111
        ])

        if self.spi.xfer2([self.CMD['READ'] | self.REG['CR2'], 0
                           ])[1] != self.VAL['CR2'] & 0b01111111:
            print(
                "Writing or reading self.REG['CR2'] failed; driver power might be off."
            )
            return False
Exemple #9
0
class spi(bitbang):
    """
    Wraps an `SPI <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
    (Serial Peripheral Interface) bus to provide :py:func:`data` and
    :py:func:`command` methods.

    :param port: SPI port, usually 0 (default) or 1.
    :type port: int
    :param device: SPI device, usually 0 (default) or 1.
    :type device: int
    :param bus_speed_hz: SPI bus speed, defaults to 8MHz.
    :type bus_speed_hz: int
    :param transfer_size: Maximum amount of bytes to transfer in one go. Some implementations
        only support a maximum of 64 or 128 bytes, whereas RPi/py-spidev supports
        4096 (default).
    :type transfer_size: int
    :param gpio_DC: The GPIO pin to connect data/command select (DC) to (defaults to 24).
    :type gpio_DC: int
    :param gpio_RST: The GPIO pin to connect reset (RES / RST) to (defaults to 25).
    :type gpio_RST: int
    :param spi_mode: SPI mode as two bit pattern of clock polarity and phase [CPOL|CPHA], 0-3 (default:None)
    :type spi_mode: int
    :param reset_hold_time: The number of seconds to hold reset active. Some devices may require
        a duration of 100ms or more to fully reset the display (default:0)
    :type reset_hold_time: float
    :param reset_release_time: The number of seconds to delay afer reset. Some devices may require
        a duration of 150ms or more after reset was triggered before the device can accept the
        initialization sequence (default:0)
    :type reset_release_time: float
    :raises luma.core.error.DeviceNotFoundError: SPI device could not be found.
    :raises luma.core.error.UnsupportedPlatform: GPIO access not available.
    """
    def __init__(self,
                 port=0,
                 device=0,
                 bus_speed_hz=8000000,
                 transfer_size=4096,
                 gpio_DC=24,
                 gpio_RST=25,
                 spi_mode=None,
                 reset_hold_time=0,
                 reset_release_time=0,
                 **kwargs):
        assert bus_speed_hz in [
            mhz * 1000000 for mhz in
            [0.5, 1, 2, 4, 8, 16, 20, 24, 28, 32, 36, 40, 44, 48, 50, 52]
        ]

        bitbang.__init__(
            self,
            transfer_size,
            reset_hold_time,
            reset_release_time,
            DC=gpio_DC,
            RST=gpio_RST,
        )

        try:
            self._spi = SpiDev()
            self._spi.open(port, device)
            if spi_mode:
                self._spi.mode = spi_mode
            if "cs_high" in kwargs:
                import warnings

                warnings.warn(
                    "SPI cs_high is no longer supported in kernel 5.4.51 and beyond, so setting parameter cs_high is now ignored!",
                    RuntimeWarning,
                )
        except (IOError, OSError) as e:
            if e.errno == errno.ENOENT:
                raise DeviceNotFoundError("SPI device not found")
            else:  # pragma: no cover
                raise

        self._spi.max_speed_hz = bus_speed_hz

    def _write_bytes(self, data):
        self._spi.writebytes(data)

    def cleanup(self):
        """Clean up SPI & GPIO resources."""
        self._spi.close()
        super(spi, self).cleanup()
Exemple #10
0
class EpdKernelPort:
    """e-Ink Waveshare 2.9" monochrome display screen SPI driver
    """

    # GPIO assignment on RPi (zero W) to GPIO lines
    DC_PIN = 5  # Data/Command: pin 29
    RESET_PIN = 6  # HW Reset: pin 31
    BUSY_PIN = 12  # Busy: pin 32

    def __init__(self, debug=False):
        self._debug = debug
        self._spi_port = None

    def open(self):
        """Open an SPI connection to a slave"""
        self._spi_port = SpiDev()
        self._spi_port.open(0, 0)
        self._spi_port.max_speed_hz = int(3E6)
        self._spi_port.mode = 0b00
        GPIO.setup(self.DC_PIN, GPIO.OUT)
        GPIO.setup(self.RESET_PIN, GPIO.OUT)
        GPIO.setup(self.BUSY_PIN, GPIO.IN)

    def close(self):
        """Close the SPI connection"""
        if self._spi_port:
            self._spi_port.close()

    def reset(self):
        """Hardware reset the eInk screen"""
        GPIO.output(self.RESET_PIN, True)
        sleep(0.02)
        GPIO.output(self.RESET_PIN, False)
        sleep(0.02)
        GPIO.output(self.RESET_PIN, True)
        sleep(0.02)

    def write_command(self, data):
        """Write a command byte sequence to the display"""
        GPIO.output(self.DC_PIN, False)
        if isinstance(data, int):
            # accept single byte as an integer
            self._spi_port.writebytes([data])
        else:
            self._spi_port.writebytes(list(data))

    def write_data(self, data):
        """Write a data byte sequence to the display"""
        GPIO.output(self.DC_PIN, True)
        if isinstance(data, int):
            # accept single byte as an integer
            data = bytes([data])
        while data:
            # SPI driver does not accept SPI exchange larger than an MMU
            # small page (FTDI backend accepts up to 64K)
            buf, data = data[:4096], data[4096:]
            self._spi_port.writebytes(list(buf))

    def wait_ready(self):
        """Busy polling waiting for e-Ink readyness"""
        start = now()
        while GPIO.input(self.BUSY_PIN):
            sleep(0.05)
        # return the actual time spent waiting
        return now() - start
Exemple #11
0
import time
import sys
from spidev import SpiDev

dev = SpiDev(0, 0)
dev.max_speed_hz = 10

try:
    while True:
        dev.writebytes([1, 2, 4, 8, 16, 32, 64, 128])
        time.sleep(0.001)
except KeyboardInterrupt:
    sys.exit(0)