class Sd

Constants

Cmds

Public Class Methods

new(hash={}) click to toggle source
# File lib/sd.rb, line 26
def initialize(hash={})
  hash[:blklen] = 512 if not hash[:blklen]
  hash[:do] = 10 if not hash[:do]
  hash[:di] = 9  if not hash[:di]
  hash[:clk]= 11 if not hash[:clk]
  hash[:cs] = 22 if not hash[:cs]
  @blklen=hash[:blklen]
  @options=hash
  @cs =PiPiper::Pin.new(:pin => hash[:cs], :direction => :out)
  @do =PiPiper::Pin.new(:pin => hash[:do], :direction => :out)
  @clk=PiPiper::Pin.new(:pin => hash[:clk],:direction => :out)
  @di =PiPiper::Pin.new(:pin => hash[:di], :direction => :in,:pull => :down)
  @cs.on
  @clk.off
  @do.off
  @SPI_CLOCK=2500000
end

Public Instance Methods

bdump(l) click to toggle source
# File lib/sd.rb, line 127
def bdump l
  print "["
  l.each do |b|
    printf "%08d ", b.to_s(2)
  end
  print "]\n"
end
boot() click to toggle source
# File lib/sd.rb, line 189
def boot
  loop do
    ret=outbytes nil,[0x40, 0, 0, 0, 0,0x95]
    if ret[0]==0x01
      break
    end
  end
  loop do
    ret=cmd :send_op_cond
    if ret[0]==0x00
      break
    end
  end
end
cmd(cmd,val=0,retlen=nil) click to toggle source
# File lib/sd.rb, line 99
def cmd cmd,val=0,retlen=nil
  if not Cmds[cmd]
    puts "Error: Unknown Command to SD: #{cmd}"
  end
  c=Cmds[cmd][:op]
  retlen=Cmds[cmd][:retlen] if not retlen
  l=[c|0x40]
  l+=[val].pack("N").unpack("CCCC")
  l<<1
  data=outbytes Cmds[cmd],l,retlen
  if @options[:verbose]
    printf("%20.20s (%2d %08X): ",cmd,c,val)
    data.each_with_index do |b,i|
      printf("%02X ",b)# if i<30
    end
    puts ""
  end
  data
end
erase(from=0,till=0) click to toggle source
# File lib/sd.rb, line 228
def erase from=0,till=0
  return  if till<=from
  cmd :erase_start,from*@blklen
  cmd :erase_end,till*@blklen
  cmd :erase
end
hdump(l) click to toggle source
# File lib/sd.rb, line 119
def hdump l
  print "["
  l.each do |b|
    printf "%02X ", b
  end
  print "]\n"
end
ident() click to toggle source
# File lib/sd.rb, line 162
def ident
  info={}
  ret=cmd :send_cid
  if ret and ret!=[]
    serno=""
    ret[8...8+5].each do |b|
      serno+=sprintf("%02X",b)
    end
    info=info.merge({
      mid: ret[0].to_s(16),
      oem:ret[1...1+2].pack("c*"),
      pnm:ret[3...3+5].pack("c*"),
      rev: ret[7],
      serno: serno,
      date: sprintf("%d/%d",2000+ret[14]/0x10,ret[14]&0xf),
    })
  end
  ret=cmd :send_csd
  if ret and ret!=[]
    info[:block_size]=2**(pickbits ret[0..-3],83,80)
    info[:block_count]=pickbits ret[0..-3],73,62
    info[:capacity]=info[:block_count]*524288
    info[:capacity_gb]=sprintf("%.1f",info[:block_count]*524288/(1000.0**3.0))
  end
  info
end
init() click to toggle source
# File lib/sd.rb, line 204
def init
  tries=0
  ret=false
  loop do
    ret=cmd :read_ocr
    if ret==[0,0,0,0,0]
      if tries>10
        puts "Error: Cannot Init SD Card"
        ret=false
        break
      end
      boot
      sleep 0.01
    else
      break
    end
    tries+=1
  end
  if ret
     cmd :set_blocklen,@blklen
  end
  ret
end
outbytes(c,l,retlen=1) click to toggle source
# File lib/sd.rb, line 44
def outbytes c,l,retlen=1
  ret=[]
  data=[]
  cmd_data=[]
  @cs.off
  PiPiper::Spi.begin do
    clock(2500000)
    l.each do |b|
      cmd_data << write(b)
    end
    write(0xff)
    retlen.times do
      data << write(0xff)
    end
    if c and c[:data] == :busy
      tries=0
      while (start=write(0xff))==0 do
        if tries>10000
          puts "Error: busy stuck (#{c},#{l})"
          break
        end
        tries+=1
        sleep 0.01
      end
      #puts "took #{tries} to unbusy"
    elsif c and c[:data] == :read
      data=[]
      tries=0
      while (start=write(0xff))!=0xfe do
        if tries>1000
          puts "Error: data read stuck with [0x#{start.to_s(16)}] (#{c},#{l}) tried #{tries}"
          break
        end
        tries+=1
        sleep 0.001
      end
      if start==0xfe
        if c[:datalen]
          c[:datalen].times do
            data << write(0xff)
          end
        else
          (@blklen).times do
            data << write(0xff)
          end
        end
        write(0xff)
        write(0xff)
      end
    end
  end
  @cs.on
  data
end
pickbits(l,so,eo) click to toggle source
# File lib/sd.rb, line 135
def pickbits l,so,eo
  sz=l.size*8
  b=[]
  s=sz-so-1
  e=sz-eo-1
  (s .. e).each do |bit|
    byte=bit/8
    oset=bit%8
    bval= 1<<oset
    v=(l[byte]&bval)==bval
    if v
      b=[1]+b
    else
      b=[0]+b
    end
  end
  val=0
  b.each do |bit|
    val*=2
    if bit==1
      val|=1
    end
  end
  #printf "%d:%d 0x%X (%d)\n",so,eo,val,val
  val
end
write(addr=0,data=[]) click to toggle source
# File lib/sd.rb, line 234
def write addr=0,data=[]
  return if not data or data==[]
  buf=[0xfe]
  buf+=data
  buf << 0 #crc 2 bytes
  buf << 0
  buf << 0 #this will shift data response

  cmd :write_block,addr
  outbytes({data: :busy},buf)
end