stm32 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/bin/stm32_cli.rb +177 -0
  3. data/lib/stm32.rb +417 -0
  4. metadata +86 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 069d773b51764deb1d1f3e16dfc7c44efa9c42f0
4
+ data.tar.gz: 715b55b8a41a363284ceca662418f4c43c9c7b86
5
+ SHA512:
6
+ metadata.gz: 97b5432c8983db33acdcc1c87e26c5906b4865bac5d97d24b6ad021031a65877ff4d136e54f063dd39f9aa3c4999e82c9b6aeba544e0bc0a0f166beff9d83a0d
7
+ data.tar.gz: 342295cacada68c8f24a3bf707e89928e8c41c4924aa3991579a5fc14e0d93c43aa8cf7d594b9abffdf23badea8751be2d1e3be2fcbee3318ad5924bf5ab4c84
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+
4
+ require 'optparse'
5
+ require 'yaml'
6
+ require 'pp'
7
+
8
+ require 'io/wait'
9
+
10
+ local=false
11
+ require 'srec'
12
+
13
+ if File.file? './lib/stm32.rb'
14
+ require './lib/stm32.rb'
15
+ puts "using local lib"
16
+ local=true
17
+ else
18
+ require 'stm32'
19
+ end
20
+
21
+ def isprint(c)
22
+ /[[:print:]]/ === c.chr
23
+ end
24
+
25
+
26
+ options = {}
27
+ CONF_FILE='/etc/stm32.conf'
28
+
29
+ options=options.merge YAML::load_file(CONF_FILE) if File.exist?(CONF_FILE)
30
+ options=options.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
31
+
32
+ options[:dev] = "/dev/ttyUSB0" if not options[:dev]
33
+ OptionParser.new do |opts|
34
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
35
+
36
+ opts.on("-v", "--[no-]verbose", "Run verbosely; creates protocol log on console (false)") do |v|
37
+ options[:verbose] = v
38
+ end
39
+ opts.on("-d", "--[no-]debug", "Produce Debug dump on verbose log (false)") do |v|
40
+ options[:debug] = v
41
+ end
42
+
43
+ opts.on("--dev dev", "serial device to use (/dev/ttyUSB0)") do |v|
44
+ options[:dev] = v
45
+ end
46
+ end.parse!
47
+
48
+ #pp options
49
+
50
+ stm=Stm32.new options
51
+
52
+ stm.get_port()
53
+ if stm.boot
54
+ stm.get_info
55
+ printf "BOOTED OK!\r\n>"
56
+ else
57
+ puts "Error: Boot failed! retry!\r\n"
58
+ end
59
+
60
+ #pp stm.run
61
+ port=stm.get_port
62
+ $stdout.sync = true
63
+ oldstate=:unknown
64
+ oldaddr=0x08000000
65
+ begin
66
+ state = `stty -g`
67
+ loop do
68
+ curstate=stm.get_state
69
+ if oldstate!=curstate
70
+ if curstate==:running
71
+ system("stty raw -echo -icanon isig") # turn raw input on
72
+ else
73
+ system "stty #{state}" # turn raw input off
74
+ end
75
+ oldstate=curstate
76
+ end
77
+ if port.ready_for_read?
78
+ ch = port.readbyte
79
+ if ch==0x0a and stm.get_state==:running
80
+ printf "\n\r"
81
+ elsif ch==0x0d and stm.get_state==:running
82
+
83
+ elsif ch>0x1f and stm.get_state==:running
84
+ printf "%c",ch
85
+ else
86
+ printf "[%02x]",ch
87
+ end
88
+ elsif $stdin.ready?
89
+ if curstate==:running #terminal mode
90
+ c = $stdin.getc
91
+ if c.ord==0x02
92
+ system "stty #{state}" # turn raw input off
93
+ if stm.boot
94
+ printf "BOOTED OK!\r\n>"
95
+ else
96
+ puts "Error: Boot failed! retry!\r\n"
97
+ end
98
+ #system("stty raw -echo -icanon isig") # turn raw input on
99
+ else
100
+ port.write c
101
+ end
102
+ else #debugger
103
+ c = $stdin.gets.chop
104
+ a=c.split " "
105
+ if a[0]=="g"
106
+ if stm.run
107
+ puts "RUN OK!\r\n"
108
+ else
109
+ puts "Error: Run failed! retry!\r\n"
110
+ end
111
+ #system("stty raw -echo -icanon isig") # turn raw input on
112
+ elsif a[0]=="i"
113
+ stm.get_info
114
+ elsif a[0]=="e"
115
+ if a[1]
116
+ b=a[1].hex
117
+ else
118
+ b=0
119
+ end
120
+ stm.erase [b]
121
+ elsif a[0]=="w" or a[0]=="wf"
122
+ if a[1]
123
+ addr=a[1].hex
124
+ else
125
+ addr=oldaddr
126
+ end
127
+ if a[2]
128
+ data=[a[2].to_i,0x11,0x22,0x33]
129
+ else
130
+ data=[1,2,3,4]
131
+ end
132
+ addr |= 0x08000000 if a[0]=="wf"
133
+ stm.write addr,data
134
+ oldaddr=addr
135
+ elsif a[0]=="f"
136
+ stm.flash("/home/arisi/projects/mygit/arisi/ctex/bin/sol_STM32L_mg11.srec")
137
+ elsif a[0]=="q"
138
+ break
139
+ elsif a[0]=="r" or a[0]=="rf"
140
+ if a[1]
141
+ addr=a[1].hex
142
+ else
143
+ addr=oldaddr
144
+ end
145
+ addr |= 0x08000000 if a[0]=="rf"
146
+ if a[2]
147
+ len=a[2].hex
148
+ else
149
+ len=0x100
150
+ end
151
+ buf=stm.read addr,len
152
+ #printf "0x%08X:",addr
153
+ if not buf
154
+ puts "Illegal address!"
155
+ else
156
+ buf.each_with_index do |b,i|
157
+ if i&0xf==0x0
158
+ printf "\n0x%08X: ",addr+i
159
+ end
160
+ printf "%02X ",b
161
+ end
162
+ printf "\n";
163
+ oldaddr=addr
164
+ end
165
+ #system("stty raw -echo -icanon isig") # turn raw input on
166
+ else
167
+ puts "Commands: g(o), i(d), w(rite), r(ead), e(rase), q(uit)"
168
+ end
169
+ printf "\r\n>"
170
+ end
171
+ else
172
+ sleep 0.01
173
+ end
174
+ end
175
+ ensure
176
+ system "stty #{state}" # turn raw input off
177
+ end
@@ -0,0 +1,417 @@
1
+ #!/usr/bin/env ruby
2
+ #encoding: UTF-8
3
+
4
+ require 'json'
5
+ require 'serialport'
6
+ #require 'srec'
7
+
8
+ class IO
9
+ def ready_for_read?
10
+ result = IO.select([self], nil, nil, 0)
11
+ result && (result.first.first == self)
12
+ end
13
+ end
14
+
15
+
16
+ class Stm32
17
+ @port=nil
18
+ @dev=nil
19
+ @state=nil
20
+ @cpu_info={}
21
+ @debug=true
22
+ @@Clist_def=[0x00,0x01,0x02,0x11,0x21,0x31,0x44,0x63,0x73,0x82,0x92]
23
+ @@Commands={
24
+ get: {index:0},
25
+ getver: {index:1},
26
+ getid: {index:2},
27
+ read: {index:3},
28
+ go: {index:4},
29
+ write: {index:5},
30
+ erase: {index:6},
31
+ }
32
+ @@Cpu_ids={
33
+ 0x416 => {
34
+ family: :L1,
35
+ ram_s:0x20000800,
36
+ ram_e:0x20004000,
37
+ flash_s:0x8000000,
38
+ flash_e:0x08020000,
39
+ flash_bsize:0x100,
40
+ serno:0x1ff80050,
41
+ flash_initial:0
42
+ },
43
+ 0x413 => {family: :F4,ram_s:0x20002000,ram_e:0x20020000,flash_s:0x8000000,flash_e:0x08100000,flash_blk:16384,serno:0x1fff7a10,flash_initial:0xff},
44
+ }
45
+
46
+ def initialize(hash={})
47
+ @clist=@@Clist_def
48
+ @debug=hash[:debug]
49
+ if not hash[:dev]
50
+ puts "Error: No serial Device??"
51
+ return nil
52
+ end
53
+ if not File.chardev? hash[:dev]
54
+ puts "Error: '#{hash[:dev]}'' is not serial Device??"
55
+ return nil
56
+ end
57
+ begin
58
+ @port = SerialPort.new hash[:dev],115200,8,1,SerialPort::NONE
59
+ #$sp.read_timeout = 100
60
+ @port.flow_control= SerialPort::NONE
61
+ @port.binmode
62
+ @port.sync = true
63
+ rescue => e
64
+ puts "Error: Cannot open serial device: #{e}"
65
+ pp e.backtrace
66
+ return nil
67
+ end
68
+ @dev=hash[:dev]
69
+ puts "Open Serial OK!" if @debug
70
+ end
71
+ def get_port()
72
+ @port
73
+ end
74
+ def get_dev()
75
+ @dev
76
+ end
77
+ def get_state()
78
+ @state
79
+ end
80
+ def get_cpu(k)
81
+ @cpu_info[k]
82
+ end
83
+
84
+ def flush_chars tout=0.1
85
+ while ch=wait_char(tout) do
86
+ puts "\nWarning: Flushed #{ch.to_s(16)}\n"
87
+ end
88
+ end
89
+
90
+ def send_cmd cmd,ack=true
91
+ if not @@Commands[cmd] or not @@Commands[cmd][:index]
92
+ puts "Error: Unknown command #{cmd}"
93
+ end
94
+ if not c=@clist[@@Commands[cmd][:index]]
95
+ puts "Error: Unsupported command #{cmd}"
96
+ end
97
+ retries=0
98
+ flush_chars 0.001
99
+ while retries<2 do
100
+ ch=send_buf [c,0xff-c],ack
101
+ if ack
102
+ if not ch
103
+ return :tout
104
+ elsif ch== :nack
105
+ printf("SYNC\r\n") if @debug
106
+ send_buf [32],false #synch!
107
+ flush_chars 0.1
108
+ else
109
+ return ch
110
+ end
111
+ else
112
+ return :ack
113
+ end
114
+ end
115
+ :nack
116
+ end
117
+
118
+ def send_addr a,ack=true
119
+ buf=[0,0,0,0]
120
+ check=0
121
+ 4.times do |i|
122
+ c=a&0xff
123
+ a>>=8
124
+ buf[3-i] = c
125
+ check ^=c
126
+ end
127
+ buf << check
128
+ send_buf buf,ack
129
+ end
130
+
131
+ def send_buf_with_check buf,tout=0.1
132
+ check=0
133
+ buf.each do |b|
134
+ check ^=b
135
+ end
136
+ buf << check
137
+ send_buf buf,true,tout
138
+ end
139
+
140
+ def send_buf buf,ack=false,tout=0.1
141
+ bytes=buf.pack("c*")
142
+ printf "> " if @debug
143
+ bytes.split("").each do |ch|
144
+ @port.write ch
145
+ printf("%02X ",ch.ord) if @debug
146
+ sleep 0.0001
147
+ end
148
+ puts "" if @debug
149
+ if ack
150
+ ch=wait_char tout
151
+ if ch
152
+ if ch==0x1f
153
+ printf("< NACK: %02X\n",ch) if @debug
154
+ return nil
155
+ else
156
+ printf("< ACK: %02X\n",ch) if @debug
157
+ return :ack
158
+ end
159
+ return ch
160
+ else
161
+ puts "< TOUT"
162
+ return nil
163
+ end
164
+ end
165
+ return true
166
+ end
167
+
168
+ def wait_char tout=1
169
+ cnt=0
170
+ while cnt<tout*100
171
+ if @port.ready_for_read?
172
+ return @port.readbyte
173
+ end
174
+ sleep 0.01
175
+ cnt+=1
176
+ end
177
+ return nil
178
+ end
179
+
180
+ def boot
181
+ retries=0
182
+ delay=0.001
183
+ while retries<10
184
+ #$sp.rts=1 #if retries>5 #power off --really cold boot
185
+ #sleep 0.5
186
+ @port.rts=0 #if retries>5 #power off --really cold boot
187
+ @port.dtr=0
188
+ sleep delay
189
+ @port.flush_input
190
+ @port.flush_output
191
+ @port.rts=0 #power on
192
+ sleep delay
193
+ @port.dtr=1 #reset up -> start to run
194
+ ch=wait_char delay
195
+
196
+ if ch and ch==0
197
+ printf("OK: [%02x]", ch ) if @debug
198
+ sleep delay
199
+ end
200
+ send_buf [0x7f]
201
+ if ch=wait_char
202
+ if ch==0x79
203
+ puts "Booted OK, retries=#{retries}\n" if @debug
204
+ @state=:booted
205
+ return true
206
+ else
207
+ printf "Error:got strange ack: %02X '%c'\n",ch,ch
208
+ end
209
+ else
210
+ puts "Error: no cmd ack"
211
+ end
212
+ retries+=1
213
+ delay*=2
214
+ end
215
+ puts "Error:not booted, gave up\n"
216
+ return false
217
+ end
218
+
219
+ def wait_chars len,tout=0.1
220
+ ret=[]
221
+ len.times do
222
+ if ch=wait_char(tout)
223
+ ret << ch
224
+ else
225
+ puts "Warning: Short Data! #{ret}"
226
+ return nil
227
+ end
228
+ end
229
+ return ret
230
+ end
231
+
232
+ def cmd c
233
+ boot if @state!=:booted
234
+ puts "cmd: #{c}" if @debug
235
+ send_cmd c
236
+ if c==:write #no reply expected
237
+ return
238
+ end
239
+ if len=wait_char
240
+ len+=1
241
+ if buf=wait_chars(len)
242
+ if @debug
243
+ printf "len=#{len}:"
244
+ buf.each do |b|
245
+ printf "%02X ",b
246
+ end
247
+ printf "\n"
248
+ end
249
+ if ack=wait_char
250
+ if ack==0x79
251
+ return buf
252
+ else
253
+ puts "Error: no ack for cmd #{c} #{ack}"
254
+ end
255
+ else
256
+ puts "Error: tout at ack for #{c}"
257
+ end
258
+ else
259
+ puts "Error: timeout for #{c}"
260
+ end
261
+ end
262
+ end
263
+
264
+
265
+ def get_info
266
+ if buf=cmd(:get)
267
+ puts "BL ver: #{buf[0].to_s(16)}"
268
+ @clist=buf[1..-1]
269
+ #puts "Command list updated to #{@clist}"
270
+ end
271
+ if buf=cmd(:getid)
272
+ @cpu=buf[0]*0x100 + buf[1]
273
+ puts "Cpu ID: #{@cpu.to_s(16)}"
274
+ if @@Cpu_ids[@cpu]
275
+ @cpu_info=@@Cpu_ids[@cpu]
276
+ printf "Family: %s\n", @cpu_info[:family]
277
+ printf "Ram: %08X .. %08X %5.1fk\n", @cpu_info[:ram_s],@cpu_info[:ram_e],(@cpu_info[:ram_e]-@cpu_info[:ram_s])/1024.0
278
+ printf "Flash: %08X .. %08X %5.1fk\n", @cpu_info[:flash_s],@cpu_info[:flash_e],(@cpu_info[:flash_e]-@cpu_info[:flash_s])/1024.0
279
+ addr=@cpu_info[:serno]
280
+ base=addr&(0xffffff00)
281
+ oset=addr&(0xff)
282
+ buf=read base,oset+0x10
283
+ serno=""
284
+ 10.times do |i|
285
+ serno += sprintf("%02X",buf[oset+i])
286
+ end
287
+ @serno=serno
288
+ puts "Serno: '#{serno}'."
289
+ end
290
+ end
291
+ end
292
+
293
+ def read addr,len
294
+ if send_cmd(:read)
295
+ if send_addr addr
296
+ ch=send_buf [(len-1),0xff - (len-1)],true
297
+ if buf=wait_chars(len,0.1)
298
+ if @debug
299
+ printf "len=#{len}:"
300
+ buf.each do |b|
301
+ printf "%02X ",b
302
+ end
303
+ printf "\n"
304
+ end
305
+ return buf
306
+ end
307
+ end
308
+ end
309
+ return nil
310
+ end
311
+
312
+ def write addr,data
313
+ return(nil) if not data or data==[]
314
+ len=data.length
315
+ if len>0x100
316
+ puts "Too big block to write #{len}"
317
+ return nil
318
+ end
319
+ if send_cmd(:write)
320
+ if send_addr addr
321
+ list=[data.length-1]
322
+ list+=data
323
+ if ack=send_buf_with_check(list,3)
324
+ #puts "Write Result: #{ack}"
325
+ return ack
326
+ end
327
+ end
328
+ end
329
+ puts "Error: Write fails!"
330
+ flush_chars # failed write may have produced some nacks
331
+ return nil
332
+ end
333
+
334
+ def erase blocks
335
+ return if not blocks or blocks==[]
336
+ list=[blocks.length-1].pack("n").unpack("cc")
337
+ blocks.each do |b|
338
+ list+=[b].pack("n").unpack("cc")
339
+ end
340
+ if send_cmd(:erase)
341
+ if ack=send_buf_with_check(list,3)
342
+ #puts "Erase #{list.size} Pages Result: #{ack}"
343
+ return ack
344
+ end
345
+ end
346
+ return nil
347
+ end
348
+
349
+ def run addr=0x08000000
350
+ printf "try to Run @ %x",addr
351
+ if @state!=:booted
352
+ if not boot
353
+ puts "Error: Cannot run, as cannot get booted"
354
+ return nil
355
+ end
356
+ end
357
+ retries=0
358
+ while retries<4 do
359
+ if send_cmd :go
360
+ if send_addr addr
361
+ if ch=wait_char
362
+ puts "Started Running, retries: #{retries} got #{ch}\n" if @debug
363
+ if ch==0
364
+ @state=:running
365
+ return true
366
+ end
367
+ else
368
+ puts "Started Running???, retries: #{retries} -- no start char\n"
369
+ end
370
+ end
371
+ end
372
+ puts "run failed, retry boot and run"
373
+ if not boot
374
+ puts "Error: Cannot run, as cannot get booted"
375
+ return nil
376
+ end
377
+ retries+=1
378
+ end
379
+ boot #return to bootstrap mode
380
+ return false
381
+ end
382
+
383
+ def flash fn
384
+ s=Srec.new file: fn
385
+ bsize=get_cpu(:flash_bsize)
386
+ fs=get_cpu(:flash_s)
387
+ fe=get_cpu(:flash_e)
388
+ b= s.to_blocks fs,fe,bsize
389
+ puts "#{b.size} blocks of #{bsize} bytes"
390
+ list=[]
391
+ b.each do |blk,data|
392
+ list << blk
393
+ end
394
+ start=Time.now.to_i
395
+ if erase list
396
+ dur=Time.now.to_i-start
397
+ puts "Erased in #{dur}s"
398
+ cnt=0
399
+ start=Time.now.to_i
400
+ b.each do |blk,data|
401
+ addr=blk*bsize+fs
402
+ if write addr,data
403
+ printf("\r#{cnt}/#{b.length} %.0f%%",100.0*cnt/b.length) if cnt%10==0
404
+ else
405
+ puts "Error: Write fails at #{addr}"
406
+ break
407
+ end
408
+ cnt+=1
409
+ end
410
+ dur=Time.now.to_i-start
411
+ puts "\nFlashed in #{dur}s"
412
+ else
413
+ puts "Error: Erase failed"
414
+ end
415
+ end
416
+
417
+ end
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stm32
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ari Siitonen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: srec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.0.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: minimal-http-ruby
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '0.0'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 0.0.3
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '0.0'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 0.0.3
53
+ description: Pure Ruby Driver and Flash programmer for stm32 bootstrap -- cli included
54
+ email: jalopuuverstas@gmail.com
55
+ executables:
56
+ - stm32_cli.rb
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - bin/stm32_cli.rb
61
+ - lib/stm32.rb
62
+ homepage: https://github.com/arisi/stm32
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.2.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Pure Ruby Driver and Flash programmer for stm32 bootstrap
86
+ test_files: []