sd 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/sd-util.rb +77 -0
- data/lib/sd.rb +246 -0
- metadata +49 -0
data/bin/sd-util.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: UTF-8
|
3
|
+
|
4
|
+
require 'optparse'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
lib="sd"
|
8
|
+
if File.file? "./lib/#{lib}.rb"
|
9
|
+
require "./lib/#{lib}.rb"
|
10
|
+
puts "using local #{lib}"
|
11
|
+
local=true
|
12
|
+
else
|
13
|
+
require lib
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
options={}
|
18
|
+
|
19
|
+
|
20
|
+
$sd=Sd.new options
|
21
|
+
|
22
|
+
if not $sd.init
|
23
|
+
exit -1
|
24
|
+
else
|
25
|
+
pp $sd.ident
|
26
|
+
end
|
27
|
+
#cmd :send_status
|
28
|
+
|
29
|
+
b=4
|
30
|
+
|
31
|
+
if false
|
32
|
+
tb=1000
|
33
|
+
mul=5000
|
34
|
+
erase 0,tb*mul
|
35
|
+
|
36
|
+
rers=wers=0
|
37
|
+
start=Time.now.to_f
|
38
|
+
(0..tb).each do |j|
|
39
|
+
start2=Time.now.to_f
|
40
|
+
buf=[]
|
41
|
+
$blklen.times do |i|
|
42
|
+
buf << ((i+j)&0xff)
|
43
|
+
end
|
44
|
+
a=$blklen*j*mul
|
45
|
+
printf "%08X (%.3fMb) [%d]",a,a/1000000.0,j*mul
|
46
|
+
write a,buf
|
47
|
+
d=cmd :read_single_block,a
|
48
|
+
now=Time.now.to_f
|
49
|
+
if buf==d
|
50
|
+
printf "OK %.2f %.2f\n",now-start,now-start2
|
51
|
+
else
|
52
|
+
puts "ER"
|
53
|
+
wers+=1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
puts "Verify:"
|
57
|
+
start=Time.now.to_f
|
58
|
+
(0..tb).each do |j|
|
59
|
+
start2=Time.now.to_f
|
60
|
+
buf=[]
|
61
|
+
$blklen.times do |i|
|
62
|
+
buf << ((i+j)&0xff)
|
63
|
+
end
|
64
|
+
a=$blklen*j*mul
|
65
|
+
printf "%08X ",a
|
66
|
+
d=cmd :read_single_block,a
|
67
|
+
now=Time.now.to_f
|
68
|
+
if buf==d
|
69
|
+
printf "OK %.2f %.2f\n",now-start,now-start2
|
70
|
+
else
|
71
|
+
puts "ER"
|
72
|
+
rers+=1
|
73
|
+
end
|
74
|
+
end
|
75
|
+
puts "Write Errs: #{wers}, Read Errs: #{rers}"
|
76
|
+
end
|
77
|
+
|
data/lib/sd.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#encoding: UTF-8
|
3
|
+
|
4
|
+
require 'pp'
|
5
|
+
require 'time'
|
6
|
+
require 'pi_piper'
|
7
|
+
include PiPiper
|
8
|
+
|
9
|
+
class Sd
|
10
|
+
Cmds={
|
11
|
+
send_op_cond: {op: 1, retlen: 1},
|
12
|
+
send_csd: {op: 9, retlen: 1, data: :read, datalen:18},
|
13
|
+
send_cid: {op: 10, retlen: 1, data: :read, datalen:18},
|
14
|
+
send_status: {op: 13, retlen: 2},
|
15
|
+
set_blocklen: {op: 16, retlen: 1},
|
16
|
+
read_single_block: {op: 17, retlen: 1, data: :read},
|
17
|
+
write_block: {op: 24, retlen: 1, data: :write},
|
18
|
+
erase_start: {op: 32, retlen: 1},
|
19
|
+
erase_end: {op: 33, retlen: 1},
|
20
|
+
erase: {op: 38, retlen: 1, data: :busy},
|
21
|
+
send_scr: {op: 51, retlen: 1, data: :read, datalen:10},
|
22
|
+
app_cmd: {op: 55, retlen: 1},
|
23
|
+
read_ocr: {op: 58, retlen: 5},
|
24
|
+
}
|
25
|
+
|
26
|
+
def initialize(hash={})
|
27
|
+
hash[:blklen] = 512 if not hash[:blklen]
|
28
|
+
hash[:do] = 10 if not hash[:do]
|
29
|
+
hash[:di] = 9 if not hash[:di]
|
30
|
+
hash[:clk]= 11 if not hash[:clk]
|
31
|
+
hash[:cs] = 22 if not hash[:cs]
|
32
|
+
@blklen=hash[:blklen]
|
33
|
+
@options=hash
|
34
|
+
@cs =PiPiper::Pin.new(:pin => hash[:cs], :direction => :out)
|
35
|
+
@do =PiPiper::Pin.new(:pin => hash[:do], :direction => :out)
|
36
|
+
@clk=PiPiper::Pin.new(:pin => hash[:clk],:direction => :out)
|
37
|
+
@di =PiPiper::Pin.new(:pin => hash[:di], :direction => :in,:pull => :down)
|
38
|
+
@cs.on
|
39
|
+
@clk.off
|
40
|
+
@do.off
|
41
|
+
@SPI_CLOCK=2500000
|
42
|
+
end
|
43
|
+
|
44
|
+
def outbytes c,l,retlen=1
|
45
|
+
ret=[]
|
46
|
+
data=[]
|
47
|
+
cmd_data=[]
|
48
|
+
@cs.off
|
49
|
+
PiPiper::Spi.begin do
|
50
|
+
clock(2500000)
|
51
|
+
l.each do |b|
|
52
|
+
cmd_data << write(b)
|
53
|
+
end
|
54
|
+
write(0xff)
|
55
|
+
retlen.times do
|
56
|
+
data << write(0xff)
|
57
|
+
end
|
58
|
+
if c and c[:data] == :busy
|
59
|
+
tries=0
|
60
|
+
while (start=write(0xff))==0 do
|
61
|
+
if tries>10000
|
62
|
+
puts "Error: busy stuck (#{c},#{l})"
|
63
|
+
break
|
64
|
+
end
|
65
|
+
tries+=1
|
66
|
+
sleep 0.01
|
67
|
+
end
|
68
|
+
#puts "took #{tries} to unbusy"
|
69
|
+
elsif c and c[:data] == :read
|
70
|
+
data=[]
|
71
|
+
tries=0
|
72
|
+
while (start=write(0xff))!=0xfe do
|
73
|
+
if tries>1000
|
74
|
+
puts "Error: data read stuck with [0x#{start.to_s(16)}] (#{c},#{l}) tried #{tries}"
|
75
|
+
break
|
76
|
+
end
|
77
|
+
tries+=1
|
78
|
+
sleep 0.001
|
79
|
+
end
|
80
|
+
if start==0xfe
|
81
|
+
if c[:datalen]
|
82
|
+
c[:datalen].times do
|
83
|
+
data << write(0xff)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
(@blklen).times do
|
87
|
+
data << write(0xff)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
write(0xff)
|
91
|
+
write(0xff)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
@cs.on
|
96
|
+
data
|
97
|
+
end
|
98
|
+
|
99
|
+
def cmd cmd,val=0,retlen=nil
|
100
|
+
if not Cmds[cmd]
|
101
|
+
puts "Error: Unknown Command to SD: #{cmd}"
|
102
|
+
end
|
103
|
+
c=Cmds[cmd][:op]
|
104
|
+
retlen=Cmds[cmd][:retlen] if not retlen
|
105
|
+
l=[c|0x40]
|
106
|
+
l+=[val].pack("N").unpack("CCCC")
|
107
|
+
l<<1
|
108
|
+
data=outbytes Cmds[cmd],l,retlen
|
109
|
+
if @options[:verbose]
|
110
|
+
printf("%20.20s (%2d %08X): ",cmd,c,val)
|
111
|
+
data.each_with_index do |b,i|
|
112
|
+
printf("%02X ",b)# if i<30
|
113
|
+
end
|
114
|
+
puts ""
|
115
|
+
end
|
116
|
+
data
|
117
|
+
end
|
118
|
+
|
119
|
+
def hdump l
|
120
|
+
print "["
|
121
|
+
l.each do |b|
|
122
|
+
printf "%02X ", b
|
123
|
+
end
|
124
|
+
print "]\n"
|
125
|
+
end
|
126
|
+
|
127
|
+
def bdump l
|
128
|
+
print "["
|
129
|
+
l.each do |b|
|
130
|
+
printf "%08d ", b.to_s(2)
|
131
|
+
end
|
132
|
+
print "]\n"
|
133
|
+
end
|
134
|
+
|
135
|
+
def pickbits l,so,eo
|
136
|
+
sz=l.size*8
|
137
|
+
b=[]
|
138
|
+
s=sz-so-1
|
139
|
+
e=sz-eo-1
|
140
|
+
(s .. e).each do |bit|
|
141
|
+
byte=bit/8
|
142
|
+
oset=bit%8
|
143
|
+
bval= 1<<oset
|
144
|
+
v=(l[byte]&bval)==bval
|
145
|
+
if v
|
146
|
+
b=[1]+b
|
147
|
+
else
|
148
|
+
b=[0]+b
|
149
|
+
end
|
150
|
+
end
|
151
|
+
val=0
|
152
|
+
b.each do |bit|
|
153
|
+
val*=2
|
154
|
+
if bit==1
|
155
|
+
val|=1
|
156
|
+
end
|
157
|
+
end
|
158
|
+
#printf "%d:%d 0x%X (%d)\n",so,eo,val,val
|
159
|
+
val
|
160
|
+
end
|
161
|
+
|
162
|
+
def ident
|
163
|
+
info={}
|
164
|
+
ret=cmd :send_cid
|
165
|
+
if ret and ret!=[]
|
166
|
+
serno=""
|
167
|
+
ret[8...8+5].each do |b|
|
168
|
+
serno+=sprintf("%02X",b)
|
169
|
+
end
|
170
|
+
info=info.merge({
|
171
|
+
mid: ret[0].to_s(16),
|
172
|
+
oem:ret[1...1+2].pack("c*"),
|
173
|
+
pnm:ret[3...3+5].pack("c*"),
|
174
|
+
rev: ret[7],
|
175
|
+
serno: serno,
|
176
|
+
date: sprintf("%d/%d",2000+ret[14]/0x10,ret[14]&0xf),
|
177
|
+
})
|
178
|
+
end
|
179
|
+
ret=cmd :send_csd
|
180
|
+
if ret and ret!=[]
|
181
|
+
info[:block_size]=2**(pickbits ret[0..-3],83,80)
|
182
|
+
info[:block_count]=pickbits ret[0..-3],73,62
|
183
|
+
info[:capacity]=info[:block_count]*524288
|
184
|
+
info[:capacity_gb]=sprintf("%.1f",info[:block_count]*524288/(1000.0**3.0))
|
185
|
+
end
|
186
|
+
info
|
187
|
+
end
|
188
|
+
|
189
|
+
def boot
|
190
|
+
loop do
|
191
|
+
ret=outbytes nil,[0x40, 0, 0, 0, 0,0x95]
|
192
|
+
if ret[0]==0x01
|
193
|
+
break
|
194
|
+
end
|
195
|
+
end
|
196
|
+
loop do
|
197
|
+
ret=cmd :send_op_cond
|
198
|
+
if ret[0]==0x00
|
199
|
+
break
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def init
|
205
|
+
tries=0
|
206
|
+
ret=false
|
207
|
+
loop do
|
208
|
+
ret=cmd :read_ocr
|
209
|
+
if ret==[0,0,0,0,0]
|
210
|
+
if tries>10
|
211
|
+
puts "Error: Cannot Init SD Card"
|
212
|
+
ret=false
|
213
|
+
break
|
214
|
+
end
|
215
|
+
boot
|
216
|
+
sleep 0.01
|
217
|
+
else
|
218
|
+
break
|
219
|
+
end
|
220
|
+
tries+=1
|
221
|
+
end
|
222
|
+
if ret
|
223
|
+
cmd :set_blocklen,@blklen
|
224
|
+
end
|
225
|
+
ret
|
226
|
+
end
|
227
|
+
|
228
|
+
def erase from=0,till=0
|
229
|
+
return if till<=from
|
230
|
+
cmd :erase_start,from*@blklen
|
231
|
+
cmd :erase_end,till*@blklen
|
232
|
+
cmd :erase
|
233
|
+
end
|
234
|
+
def write addr=0,data=[]
|
235
|
+
return if not data or data==[]
|
236
|
+
buf=[0xfe]
|
237
|
+
buf+=data
|
238
|
+
buf << 0 #crc 2 bytes
|
239
|
+
buf << 0
|
240
|
+
buf << 0 #this will shift data response
|
241
|
+
|
242
|
+
cmd :write_block,addr
|
243
|
+
outbytes({data: :busy},buf)
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Ari Siitonen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-01-04 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Sd-card library for RPi in pure Ruby, supports SDHC via SPI, tested on
|
15
|
+
Raspberry Pi
|
16
|
+
email: jalopuuverstas@gmail.com
|
17
|
+
executables:
|
18
|
+
- sd-util.rb
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- lib/sd.rb
|
23
|
+
- bin/sd-util.rb
|
24
|
+
homepage: https://github.com/arisi/sd
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
post_install_message:
|
28
|
+
rdoc_options: []
|
29
|
+
require_paths:
|
30
|
+
- lib
|
31
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
32
|
+
none: false
|
33
|
+
requirements:
|
34
|
+
- - ! '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ! '>='
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '0'
|
43
|
+
requirements: []
|
44
|
+
rubyforge_project:
|
45
|
+
rubygems_version: 1.8.23
|
46
|
+
signing_key:
|
47
|
+
specification_version: 3
|
48
|
+
summary: sd-card library for RPi in pure Ruby
|
49
|
+
test_files: []
|