class ChipGPIO::HardwareSPI

Constants

SPI_CPHA
SPI_CPOL
SPI_IOC_MESSAGE_1
SPI_IOC_RD_BITS_PER_WORD
SPI_IOC_RD_LSB_FIRST
SPI_IOC_RD_MAX_SPEED_HZ
SPI_IOC_RD_MODE
SPI_IOC_RD_MODE32
SPI_IOC_WR_BITS_PER_WORD
SPI_IOC_WR_LSB_FIRST
SPI_IOC_WR_MAX_SPEED_HZ
SPI_IOC_WR_MODE
SPI_IOC_WR_MODE32
SPI_MAX_CHUNK_BYTES

Attributes

lsb_first[R]
mode[R]
phase[R]
polarity[R]
speed_hz[R]
word_size[R]

Public Class Methods

new(polarity: 0, phase: 0, word_size: 8, lsb_first: false) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 28
def initialize(polarity: 0, phase: 0, word_size: 8, lsb_first: false)
  @polarity = polarity
  @phase = phase
  @word_size = word_size
  @lsb_first = lsb_first
  @speed_hz = 1000000 #TODO Configurable parameter

  @device = open("/dev/spidev32766.0", File::RDWR)      

  @mode = 0
  @mode = @mode | 0x01 if (phase == 1)
  @mode = @mode | 0x02 if (polarity == 1)

  write_u8(SPI_IOC_WR_MODE, @mode)
  write_u8(SPI_IOC_WR_LSB_FIRST, (@lsb_first ? 1 : 0))
  write_u32(SPI_IOC_WR_MAX_SPEED_HZ, @speed_hz) 

end

Public Instance Methods

break_words_into_nibbles(words: []) { |w, ((w >> (i * 4)) & 0xf)| ... } click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 73
def break_words_into_nibbles(words: [])
  nibbles_per_word = @word_size / 4

  #for each word, output each nibble individually
  #(shifting by 4 each time since a nibble is 4 bits)
  words.each do |w|
    
    #this is basically the reverse of nibbles_per_word.times
    #we reverse it because we want to start at the most-significant nibble
    #which will be shifted the most times
    #
    #since we want to end up at 0, subtract one from nibbles_per_word
    #so we don't get an extra
    (nibbles_per_word - 1).downto(0).each do |i|
      yield w, ((w >> (i * 4)) & 0xf)
    end
  end
end
close() click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 47
def close()
  @device.close()
end
pack_words_into_bytes(words: []) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 92
def pack_words_into_bytes(words: [])
  nibbles_per_word = @word_size / 4

  bytes = []
  current_byte = 0
  new_byte = true 

  break_words_into_nibbles(words: words) do |current_word, current_nibble|
    if new_byte
      new_byte = false 
      current_byte = current_byte | (current_nibble << 4)
    else
      current_byte = current_byte | current_nibble
      
      bytes << current_byte
      current_byte = 0
      new_byte = true
    end
  end

  return bytes
end
read_u32(msg) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 62
def read_u32(msg)
  value_packed = [0].pack("L")
  @device.ioctl(msg, value_packed)
  return value_packed.unpack("L")[0]
end
read_u8(msg) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 51
def read_u8(msg)
  value_packed = [0].pack("C")
  @device.ioctl(msg, value_packed)
  return value_packed.unpack("C")[0]
end
test() click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 159
def test()
  words = []
  24.times { |i| words << 0 }

  transfer_data(words: words)
end
to_s() click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 166
def to_s
  return "\#<ChipGPIO:HardwareSPI mode=#{@mode} device=#{@device.path} word_size=#{@word_size} lsb_first=#{@lsb_first}>"
end
transfer_bytes(bytes: []) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 115
def transfer_bytes(bytes: [])
  # http://stackoverflow.com/questions/11949538/pointers-to-buffer-in-ioctl-call
  raise "Too many bytes sent to transfer_bytes" if bytes.size > SPI_MAX_CHUNK_BYTES
  
  #begin spi_ioc_transfer struct (cat /usr/include/linux/spi/spidev.h)
  tx_buff = bytes.pack("C*")        
  rx_buff = (Array.new(bytes.size) { 0 }).pack("C*")       
  
  tx_buff_pointer = [tx_buff].pack("P").unpack("L!")[0]   #u64 (zero-extended pointer)
  rx_buff_pointer = [rx_buff].pack("P").unpack("L!")[0]   #u64 (zero-extended pointer)

  
  buff_len = bytes.size                                   #u32
  speed_hz = @speed_hz                                    #u32

  delay_usecs = 0                                         #u16
  bits_per_word = 8                                       #u8
  cs_change = 0                                           #u8
  tx_nbits = 0                                            #u8
  rx_nbits = 0                                            #u8
  pad = 0                                                 #u16

  struct_array = [tx_buff_pointer, rx_buff_pointer, buff_len, speed_hz, delay_usecs, bits_per_word, cs_change, tx_nbits, rx_nbits, pad]
  struct_packed = struct_array.pack("QQLLSCCCCS")
  #end spi_ioc_transfer struct

  @device.ioctl(SPI_IOC_MESSAGE_1, struct_packed)

  return rx_buff.unpack("C*")
end
transfer_data(words: []) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 146
def transfer_data(words: [])
  
  bytes_to_transfer = pack_words_into_bytes(words: words)

  result = []

  bytes_to_transfer.each_slice(SPI_MAX_CHUNK_BYTES) do |chunk_bytes|
    result = result + transfer_bytes(bytes: chunk_bytes)
  end

  return result
end
write_u32(msg, value) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 68
def write_u32(msg, value)
  value_packed = [value].pack("L")
  @device.ioctl(msg, value_packed)
end
write_u8(msg, value) click to toggle source
# File lib/chip-gpio/HardwareSpi.rb, line 57
def write_u8(msg, value)
  value_packed = [value].pack("C")
  @device.ioctl(msg, value_packed)
end