From 0c447df7b04b9382040352ad5f528fccc5f393c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?King=20K=C3=A9vin?= Date: Mon, 24 Aug 2015 16:17:58 +0200 Subject: [PATCH] add script to dump and flash NXP LPC 1313 over UART ISP --- lpc-uart-isp.rb | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100755 lpc-uart-isp.rb diff --git a/lpc-uart-isp.rb b/lpc-uart-isp.rb new file mode 100755 index 0000000..4698be8 --- /dev/null +++ b/lpc-uart-isp.rb @@ -0,0 +1,149 @@ +#!/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"