Class: PiPiper::Spi

Inherits:
Object
  • Object
show all
Defined in:
lib/pi_piper/spi.rb

Overview

class for SPI interfaces on the Raspberry Pi

Constant Summary collapse

LSBFIRST =

Least signifigant bit first, e.g. 4 = 0b001

0
MSBFIRST =

Most signifigant bit first, e.g. 4 = 0b100

1
CHIP_SELECT_0 =

Select Chip 0

0
CHIP_SELECT_1 =

Select Chip 1

1
CHIP_SELECT_BOTH =

Select both chips (ie pins CS1 and CS2 are asserted)

2
CHIP_SELECT_NONE =

No CS, control it yourself

3
SPI_MODE0 =

SPI Modes

0
SPI_MODE1 =
1
SPI_MODE2 =
2
SPI_MODE3 =
3

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.begin(chip = nil, &block) ⇒ Object

Begin an SPI block. All SPI communications should be wrapped in a block.


34
35
36
37
38
39
40
41
42
43
44
# File 'lib/pi_piper/spi.rb', line 34

def self.begin(chip=nil, &block)
  Platform.driver.spi_begin
  chip = CHIP_SELECT_0 if !chip && block_given?
  spi = new(chip)

  if block.arity > 0
    block.call spi
  else  
    spi.instance_exec &block
  end
end

.endObject

Not needed when #begin is called with a block


47
48
49
# File 'lib/pi_piper/spi.rb', line 47

def self.end
  Platform.driver.spi_end
end

.set_mode(cpol, cpha) ⇒ Object

Sets the SPI mode. Defaults to mode (0,0).


25
26
27
28
29
30
31
# File 'lib/pi_piper/spi.rb', line 25

def self.set_mode(cpol, cpha)
  mode = SPI_MODE0 #default
  mode = SPI_MODE1 if cpol == 0 and cpha == 1
  mode = SPI_MODE2 if cpol == 1 and cpha == 0
  mode = SPI_MODE3 if cpol == 1 and cpha == 1
  Platform.driver.spi_set_data_mode mode
end

.spidev_out(array) ⇒ Object

Uses /dev/spidev0.0 to write to the SPI NOTE: Requires that you have /dev/spidev0.0

see: http://learn.adafruit.com/adafruit-raspberry-pi-educational-linux-distro/overview
most likely requires `chmod 666 /dev/spidev0.0`

Examples:

Writing red, green, blue to a string of WS2801 pixels

PiPiper::Spi.spidev_out([255,0,0,0,255,0,0,0,255])

59
60
61
# File 'lib/pi_piper/spi.rb', line 59

def self.spidev_out(array)
  Platform.driver.spidev_out(array)
end

Instance Method Details

#bit_order(order = MSBFIRST) ⇒ Object


83
84
85
86
87
88
89
90
91
92
93
# File 'lib/pi_piper/spi.rb', line 83

def bit_order(order=MSBFIRST)
  if order.is_a?(Range)  
    if order.begin < order.end
      order = LSBFIRST
    else
      order = MSBFIRST
    end
  end

  Platform.driver.spi_bit_order(order)
end

#chip_select(chip = CHIP_SELECT_0) { ... } ⇒ Object

Activate a specific chip so that communication can begin

When a block is provided, the chip is automatically deactivated after the block completes. When a block is not provided, the user is responsible for calling chip_select(CHIP_SELECT_NONE)

Examples:

With block (preferred)

spi.chip_select do
  spi.write(0xFF)
end

Without block

spi.chip_select(CHIP_SELECT_0)
spi.write(0xFF)
spi.write(0x22)
spi.chip_select(CHIP_SELECT_NONE)

Parameters:

  • chip (optional, CHIP_SELECT_*) (defaults to: CHIP_SELECT_0)

    the chip select line options

Yields:


113
114
115
116
117
118
119
120
121
122
123
# File 'lib/pi_piper/spi.rb', line 113

def chip_select(chip=CHIP_SELECT_0)
  chip = @chip if @chip
  Platform.driver.spi_chip_select(chip) 
  if block_given?
    begin
      yield
    ensure
      Platform.driver.spi_chip_select(CHIP_SELECT_NONE)
    end
  end
end

#chip_select_active_low(active_low, chip = nil) ⇒ Object

Configure the active state of the chip select line

The default state for most chips is active low.

“active low” means the clock line is kept high during idle, and goes low when communicating.

“active high” means the clock line is kept low during idle, and goes high when communicating.

Parameters:

  • active_low (Boolean)

    true for active low, false for active high

  • chip (optional, CHIP_SELECT_*) (defaults to: nil)

    one of CHIP_SELECT_*


135
136
137
138
139
140
# File 'lib/pi_piper/spi.rb', line 135

def chip_select_active_low(active_low, chip=nil)
  chip = @chip if @chip
  chip = CHIP_SELECT_0 unless chip

  Platform.driver.spi_chip_select_polarity(chip, active_low ? 0 : 1)
end

#clock(frequency) ⇒ Object

Sets the SPI clock frequency


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/pi_piper/spi.rb', line 64

def clock(frequency)
  options = {4000     => 0,      #4 kHz
             8000     => 32768,  #8 kHz
             15625    => 16384,  #15.625 kHz
             31250    => 8192,   #31.25 kHz
             62500    => 4096,   #62.5 kHz
             125000   => 2048,   #125 kHz
             250000   => 1024,   #250 kHz
             500000   => 512,    #500 kHz
             1000000  => 256,    #1 MHz
             2000000  => 128,    #2 MHz
             4000000  => 64,     #4 MHz
             8000000  => 32,     #8 MHz
             20000000 => 16      #20 MHz
           }
  divider = options[frequency]
  Platform.driver.spi_clock(divider)
end

#read(count = nil) ⇒ Number|Array

Read from the bus

Examples:

Read a single byte

byte = spi.read

Read array of bytes

array = spi.read(3)

Parameters:

  • count (optional, Number) (defaults to: nil)

    the number of bytes to read. When count is provided, an array is returned. When count is nil, a single byte is returned.

Returns:

  • (Number|Array)

    data that was read from the bus


155
156
157
158
159
160
161
# File 'lib/pi_piper/spi.rb', line 155

def read(count=nil)
  if count
    write([0xFF] * count)
  else
    enable { Platform.driver.spi_transfer(0) }
  end
end

#write(*args) ⇒ Number|Array

Write to the bus

Examples:

Write a single byte

spi.write(0x22)

Write multiple bytes

spi.write(0x22, 0x33, 0x44)

Returns:

  • (Number|Array)

    data that came out of MISO during write


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/pi_piper/spi.rb', line 172

def write(*args)
  case args.count
    when 0
      raise ArgumentError.new("missing arguments")
    when 1
      data = args.first
    else
      data = args
  end

  enable do
    case data
    when Numeric
      Platform.driver.spi_transfer(data)
    when Enumerable
      Platform.driver.spi_transfer_bytes(data)
    else
      raise ArgumentError.new("#{data.class} is not valid data. Use Numeric or an Enumerable of numbers")
    end
  end
end