ea-ps_2084-03b/lpc-uart-isp.rb

150 lines
4.5 KiB
Ruby
Executable File

#!/usr/bin/env ruby
# encoding: utf-8
# ruby: 1.9.1
# this script will use the LPC1300 UART ISP protocol to read/write memory
# the protocol is specified in AN11229
require 'serialport'
DEBUG = false
# open serial port
@serial = SerialPort.open("/dev/ttyUSB0",{ baud: 9600, databits: 8, parity: SerialPort::NONE, stop_bit: 1, flow_control: SerialPort::SOFT})
$/ = "\r\n"
# send a non ISP command
# used for configuring ISP
# returns response
def simple_command(command)
puts "< "+command if DEBUG
@serial.puts command
line = @serial.gets.chomp
if line.start_with? command then
line = line[(command.length)..-1]
line.gsub!(/^\r?\n?/,'')
end
puts "> "+line if DEBUG
return line
end
# send ISP command
# returns return code
def isp_command(command)
rc = simple_command(command).to_i
return rc
end
# read memory (size byte at address)
# returns raw memory
# does not support multiple line
def read_memory(address,size)
return nil if size>44 # maximal 44 bytes (1 line) supported
raise "reading memory failed" unless isp_command("R #{address} #{size}")==0
data = @serial.gets.chomp.unpack("u*")[0] # memory read, UU encoded
checksum = @serial.gets.chomp.to_i # checksum, addition
sum = 0
data.bytes {|b| sum += b }
#puts data.bytes.to_a.collect {|b| "%02x" % b }*" "
raise "wrong checksum" unless checksum==sum
@serial.puts "OK"
return data
end
# write one page (256 bytes) of raw data to flash at address
def write_flash_page(address,data)
raise "data size is not one page (256 bytes): #{data.bytesize}" unless data.bytesize==256
raise "address #{address} is not page aligned (256 bytes)" unless address%256==0
ram_addr = 0x10001000 # where to copy in RAM
rc = isp_command("W #{ram_addr} #{data.bytesize}")
raise "can't write to RAM (error: #{rc})" unless rc==0
(256/32).times do |i|
@serial.puts [data.byteslice(i*32,32)].pack("u*")
end
checksum = 0
data.bytes.to_a.each {|b| checksum += b }
@serial.puts checksum.to_s
line = @serial.gets.chomp
raise "writing flash failed (error: #{line})" unless line=="OK"
raise "preparing memory failed" unless isp_command("P 0 7")==0
rc = isp_command("C #{address} #{ram_addr} #{data.bytesize}")
raise "copying RAM to flash failed (error: #{rc})" unless rc==0
end
# test for ISP
raise "ISP not detected" unless simple_command("?")=="Synchronized"
raise "ISP not detected" unless simple_command("Synchronized")=="OK"
puts "ISP detected"
# set internal frequency
raise "can't set frequency" unless simple_command("12000")=="OK"
# disable echo
raise "can't disable echo" unless isp_command("A 0")==0
# read part ID
parts = {}
parts["742543403"] = "LPC1311FHN33"
parts["742395947"] = "LPC1313FHN33"
parts["742395947"] = "LPC1313FBD48"
parts["1023492139"] = "LPC1342FHN33"
parts["1023492139"] = "LPC1342FBD48"
parts["1023410219"] = "LPC1343FHN33"
parts["1023410219"] = "LPC1343FBD48"
parts["404131883"] = "LPC1311FHN33/01"
parts["405803051"] = "LPC1313FHN33/01"
parts["405803051"] = "LPC1313FBD48/01"
raise "reading part ID failed" unless isp_command("J")==0
id = @serial.gets.chomp
part = parts[id]
if part then
puts "part: #{part}"
else
puts "part ID: #{id} (unknown part)"
end
# read boot code version
raise "reading boot version failed" unless isp_command("K")==0
version1 = @serial.gets.chomp
version2 = @serial.gets.chomp
puts "boot version: #{version2}.#{version1}"
# read UID
raise "reading UID failed" unless isp_command("N")==0
uid1 = @serial.gets.chomp
uid2 = @serial.gets.chomp
uid3 = @serial.gets.chomp
uid4 = @serial.gets.chomp
puts "UID: #{uid1} #{uid2} #{uid3} #{uid4}"
# read memory
puts "dumping flash"
file = File.open("lpcdump.raw","w")
size = 32 # number of byte to read (1 UU line can hold 61 char = 45 bytes, every 20 lines on checksum is sent)
(32*1024/size).times do |offset|
data = read_memory(offset*size,size)
file.write data
end
file.close
puts "dumped in #{file.path}"
# unlock firmware to write flash
raise "unlocking failed" unless isp_command("U 23130")==0
puts "erasing sector"
rc = isp_command("P 0 1")
raise "preparing failed (error: #{rc})" unless rc==0
rc = isp_command("E 0 1")
raise "erasing failed (error: #{rc})" unless rc==0
# write firmware
puts "flashing"
file = File.open("firmware/PS2000/96230036_PS2000_P2R_212.bin","r")
size = 256 # page size (number of byte to write)
(file.size/size).times do |i|
write_flash_page(i*size,file.read(size))
end
rest = file.size%size
if rest>0 then
write_flash_page(file.size-rest,file.read(rest)+("\xff".force_encoding("ASCII-8BIT")*(size-rest)))
end
puts "wrote #{file.size} bytes"