#!/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"