class I2CDevice::Driver::GPIO

Generic software I2C Driver based on /sys/class/gpio. THIS MODULE WORKS WITH VERY SLOW SPEED ABOUT JUST 1kHz (normaly 100kHz).

Attributes

scl[R]

Pin-number of SCL

sda[R]

Pin-number of SDA

speed[R]

Clock speed in kHz

Public Class Methods

new(opts={}) click to toggle source
opts[:sda]
Integer

Pin-number of SDA

opts[:scl]
Integer

Pin-number of SCL

[ opts[:speed] = 1 ]
Integer

Clock speed in kHz

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 90
def initialize(opts={})
        @sda = opts[:sda] or raise "opts[:sda] = [gpio pin number] is required"
        @scl = opts[:scl] or raise "opts[:scl] = [gpio pin number] is required"
        @speed = opts[:speed] || 1 # kHz but insane
        @clock = 1.0 / (@speed * 1000)

        begin
                GPIO.export(@sda)
                GPIO.export(@scl)
        rescue Errno::EBUSY => e
        end
        ObjectSpace.define_finalizer(self, self.class.finalizer([@scl, @sda]))
        begin
                GPIO.direction(@sda, :high)
                GPIO.direction(@scl, :high)
                GPIO.direction(@sda, :in)
                GPIO.direction(@scl, :in)
        rescue Errno::EACCES => e # writing to gpio after export is failed in a while
                retry
        end
end

Public Instance Methods

i2cget(address, param, length=1) click to toggle source

Interface of I2CDevice::Driver

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 113
def i2cget(address, param, length=1)
        ret = ""
        start_condition
        unless write( (address << 1) + 0)
                raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
        end
        write(param)
        stop_condition # AVR stucked with SCL low without this (Does not AVR support Sr condition?)
        start_condition
        unless write( (address << 1) + 1)
                raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
        end
        length.times do |n|
                ret << read(n != length - 1).chr
        end
        ret
ensure
        stop_condition
end
i2cset(address, *data) click to toggle source

Interface of I2CDevice::Driver

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 134
def i2cset(address, *data)
        sent = 0
        start_condition
        unless write( (address << 1) + 0)
                raise I2CDevice::I2CIOError, "Unknown slave device (address:#{address})"
        end
        data.each do |c|
                unless write(c)
                        break
                end
                sent += 1
        end
        sent
ensure
        stop_condition
end

Private Instance Methods

read(ack=true) click to toggle source

Read one byte from BUS.

ack
true|flase

Send ack for this read.

Returns
Integer

Byte

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 218
def read(ack=true)
        p [:read, ack] if @@DEBUG
        ret = 0

        GPIO.direction(@scl, :low)
        sleep @clock
        GPIO.direction(@sda, :in)

        8.times do
                GPIO.direction(@scl, :in)
                sleep @clock / 2
                ret = (ret << 1) | GPIO.read(@sda)
                sleep @clock / 2
                GPIO.direction(@scl, :low)
                sleep @clock
        end

        GPIO.direction(@sda, ack ? :low : :high)

        GPIO.write(@scl, true)
        sleep @clock
        GPIO.write(@scl, false)
        sleep @clock
        ret
end
start_condition() click to toggle source

Send start condition (or repeated start condition) raise I2CDevice::I2CBUSBusy if SCL line is low

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 155
def start_condition
        p :start_condition if @@DEBUG
        sleep @clock
        GPIO.direction(@sda, :in)
        GPIO.direction(@scl, :in)
        if GPIO.read(@scl) == 0
                raise I2CDevice::I2CBUSBusy, "BUS is busy"
        end

        sleep @clock / 2
        GPIO.direction(@scl, :high)
        sleep @clock / 2
        GPIO.direction(@sda, :low)
        sleep @clock
end
stop_condition() click to toggle source

Send stop condition.

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 172
def stop_condition
        p :stop_condition if @@DEBUG
        GPIO.direction(@scl, :low)
        sleep @clock / 2
        GPIO.direction(@sda, :low)
        sleep @clock / 2
        GPIO.direction(@scl, :in)
        sleep @clock / 2
        GPIO.direction(@sda, :in)
        sleep @clock / 2
end
write(byte) click to toggle source

Write one byte to BUS.

# File lib/templates/grove_pi/i2c/driver/gpio.rb, line 185
def write(byte)
        p [:write, byte] if @@DEBUG
        GPIO.direction(@scl, :low)
        sleep @clock

        7.downto(0) do |n|
                GPIO.direction(@sda, byte[n] == 1 ? :high : :low)
                GPIO.direction(@scl, :in)
                until GPIO.read(@scl) == 1
                        # clock streching
                        sleep @clock
                end
                sleep @clock
                GPIO.direction(@scl, :low)
                GPIO.write(@sda, false)
                sleep @clock
        end

        GPIO.direction(@sda, :in)
        GPIO.direction(@scl, :in)
        sleep @clock / 2
        ack = GPIO.read(@sda) == 0
        sleep @clock / 2
        while GPIO.read(@scl) == 0
                sleep @clock
        end
        GPIO.direction(@scl, :low)
        ack
end