diff options
| author | Keith Packard <keithp@keithp.com> | 2010-08-23 22:02:21 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2010-08-23 22:02:21 -0700 | 
| commit | 4c0c099716197ef7539be0cf55bbb164f6804958 (patch) | |
| tree | 39a55cf2d4604f199195b120924e4edbd9985e26 | |
| parent | bd2b44ddd61fadd8bf8ee6bf783ce019b1be7cc0 (diff) | |
altosui: Finish device programming code
Altosui can now reprogram Altusmetrum devices.
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | ao-tools/altosui/AltosFlash.java | 263 | ||||
| -rw-r--r-- | ao-tools/altosui/AltosFlashUI.java | 115 | 
2 files changed, 376 insertions, 2 deletions
diff --git a/ao-tools/altosui/AltosFlash.java b/ao-tools/altosui/AltosFlash.java index bab60c1f..0f92d6e7 100644 --- a/ao-tools/altosui/AltosFlash.java +++ b/ao-tools/altosui/AltosFlash.java @@ -33,17 +33,274 @@ import altosui.AltosHexfile;  public class AltosFlash {  	File		file;  	FileInputStream	input; -	Thread		thread;  	AltosHexfile	image;  	JFrame		frame;  	AltosDevice	debug_dongle;  	AltosDebug	debug;  	AltosRomconfig	rom_config; +	ActionListener	listener; +	boolean		aborted; + +	static final byte MOV_direct_data	= (byte) 0x75; +	static final byte MOV_DPTR_data16	= (byte) 0x90; +	static final byte MOV_A_data		= (byte) 0x74; +	static final byte MOVX_atDPTR_A		= (byte) 0xf0; +	static final byte MOVX_A_atDPTR	        = (byte) 0xe0; +	static final byte INC_DPTR		= (byte) 0xa3; +	static final byte TRAP			= (byte) 0xa5; + +	static final byte JB			= (byte) 0x20; + +	static final byte MOV_A_direct		= (byte) 0xe5; +	static final byte MOV_direct1_direct2	= (byte) 0x85; +	static final byte MOV_direct_A		= (byte) 0xf5; +	static final byte MOV_R0_data		= (byte) (0x78 | 0); +	static final byte MOV_R1_data		= (byte) (0x78 | 1); +	static final byte MOV_R2_data		= (byte) (0x78 | 2); +	static final byte MOV_R3_data		= (byte) (0x78 | 3); +	static final byte MOV_R4_data		= (byte) (0x78 | 4); +	static final byte MOV_R5_data		= (byte) (0x78 | 5); +	static final byte MOV_R6_data		= (byte) (0x78 | 6); +	static final byte MOV_R7_data		= (byte) (0x78 | 7); +	static final byte DJNZ_R0_rel		= (byte) (0xd8 | 0); +	static final byte DJNZ_R1_rel		= (byte) (0xd8 | 1); +	static final byte DJNZ_R2_rel		= (byte) (0xd8 | 2); +	static final byte DJNZ_R3_rel		= (byte) (0xd8 | 3); +	static final byte DJNZ_R4_rel		= (byte) (0xd8 | 4); +	static final byte DJNZ_R5_rel		= (byte) (0xd8 | 5); +	static final byte DJNZ_R6_rel		= (byte) (0xd8 | 6); +	static final byte DJNZ_R7_rel		= (byte) (0xd8 | 7); + +	static final byte P1DIR			= (byte) 0xFE; +	static final byte P1			= (byte) 0x90; + +	/* flash controller */ +	static final byte FWT			= (byte) 0xAB; +	static final byte FADDRL		= (byte) 0xAC; +	static final byte FADDRH		= (byte) 0xAD; +	static final byte FCTL			= (byte) 0xAE; +	static final byte FCTL_BUSY		= (byte) 0x80; +	static final byte FCTL_BUSY_BIT		= (byte) 7; +	static final byte FCTL_SWBSY		= (byte) 0x40; +	static final byte FCTL_SWBSY_BIT	= (byte) 6; +	static final byte FCTL_CONTRD		= (byte) 0x10; +	static final byte FCTL_WRITE		= (byte) 0x02; +	static final byte FCTL_ERASE		= (byte) 0x01; +	static final byte FWDATA		= (byte) 0xAF; + +	static final byte ACC			= (byte) 0xE0; + +	/* offsets within the flash_page program */ +	static final int FLASH_ADDR_HIGH	= 8; +	static final int FLASH_ADDR_LOW		= 11; +	static final int RAM_ADDR_HIGH		= 13; +	static final int RAM_ADDR_LOW		= 14; +	static final int FLASH_WORDS_HIGH	= 16; +	static final int FLASH_WORDS_LOW	= 18; +	static final int FLASH_TIMING		= 21; + +	/* sleep mode control */ +	static final int SLEEP			= (byte) 0xbe; +	static final int  SLEEP_USB_EN		= (byte) 0x80; +	static final int  SLEEP_XOSC_STB	= (byte) 0x40; +	static final int  SLEEP_HFRC_STB	= (byte) 0x20; +	static final int  SLEEP_RST_MASK	= (byte) 0x18; +	static final int   SLEEP_RST_POWERON	= (byte) 0x00; +	static final int   SLEEP_RST_EXTERNAL	= (byte) 0x10; +	static final int   SLEEP_RST_WATCHDOG	= (byte) 0x08; +	static final int  SLEEP_OSC_PD		= (byte) 0x04; +	static final int  SLEEP_MODE_MASK	= (byte) 0x03; +	static final int   SLEEP_MODE_PM0	= (byte) 0x00; +	static final int   SLEEP_MODE_PM1	= (byte) 0x01; +	static final int   SLEEP_MODE_PM2	= (byte) 0x02; +	static final int   SLEEP_MODE_PM3	= (byte) 0x03; + +	/* clock controller */ +	static final byte CLKCON		= (byte) 0xC6; +	static final byte  CLKCON_OSC32K	= (byte) 0x80; +	static final byte  CLKCON_OSC		= (byte) 0x40; +	static final byte  CLKCON_TICKSPD	= (byte) 0x38; +	static final byte  CLKCON_CLKSPD	= (byte) 0x07; + +	static final byte[] flash_page_proto = { + +		MOV_direct_data, P1DIR, (byte) 0x02, +		MOV_direct_data, P1,	(byte) 0xFF, + +		MOV_direct_data, FADDRH, 0,	/* FLASH_ADDR_HIGH */ + +		MOV_direct_data, FADDRL, 0,	/* FLASH_ADDR_LOW */ + +		MOV_DPTR_data16, 0, 0,		/* RAM_ADDR_HIGH, RAM_ADDR_LOW */ + +		MOV_R7_data, 0,			/* FLASH_WORDS_HIGH */ + +		MOV_R6_data, 0,			/* FLASH_WORDS_LOW */ + + +		MOV_direct_data, FWT, 0x20,	/* FLASH_TIMING */ + +		MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ +		MOV_A_direct,		FCTL, +		JB, ACC|FCTL_BUSY_BIT, (byte) 0xfb, + +		MOV_direct_data, P1, (byte) 0xfd, + +		MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ +		MOV_R5_data, 2, +/* writeWordLoop: */ +		MOVX_A_atDPTR, +		INC_DPTR, +		MOV_direct_A, FWDATA, +		DJNZ_R5_rel, (byte) 0xfa,		/* writeWordLoop */ +/* writeWaitLoop: */ +		MOV_A_direct, FCTL, +		JB, ACC|FCTL_SWBSY_BIT, (byte) 0xfb,	/* writeWaitLoop */ +		DJNZ_R6_rel, (byte) 0xf1,		/* writeLoop */ +		DJNZ_R7_rel, (byte) 0xef,			/* writeLoop */ + +		MOV_direct_data, P1DIR, (byte) 0x00, +		MOV_direct_data, P1,	(byte) 0xFF, +		TRAP, +	}; + +	public byte[] make_flash_page(int flash_addr, int ram_addr, int byte_count) { +		int flash_word_addr = flash_addr >> 1; +		int flash_word_count = ((byte_count + 1) >> 1); + +		byte[] flash_page = new byte[flash_page_proto.length]; +		for (int i = 0; i < flash_page.length; i++) +			flash_page[i] = flash_page_proto[i]; + +		flash_page[FLASH_ADDR_HIGH]  = (byte) (flash_word_addr >> 8); +		flash_page[FLASH_ADDR_LOW]   = (byte) (flash_word_addr); +		flash_page[RAM_ADDR_HIGH]    = (byte) (ram_addr >> 8); +		flash_page[RAM_ADDR_LOW]     = (byte) (ram_addr); + +		byte flash_words_low = (byte) (flash_word_count); +		byte flash_words_high = (byte) (flash_word_count >> 8); +		/* the flashing code has a minor 'bug' */ +		if (flash_words_low != 0) +			flash_words_high++; + +		flash_page[FLASH_WORDS_HIGH] = (byte) flash_words_high; +		flash_page[FLASH_WORDS_LOW]  = (byte) flash_words_low; +		return flash_page; +	} + +	static byte[] set_clkcon_fast = { +		MOV_direct_data, CLKCON, 0x00 +	}; + +	static byte[] get_sleep = { +		MOV_A_direct, SLEEP +	}; + +	public void clock_init() throws IOException, InterruptedException { +		debug.debug_instr(set_clkcon_fast); + +		byte	status; +		do { +			status = debug.debug_instr(get_sleep); +		} while ((status & SLEEP_XOSC_STB) == 0); +	} + +	void action(String s, int percent) { +		if (listener != null && !aborted) +			listener.actionPerformed(new ActionEvent(this, +								 percent, +								 s)); +	} + +	void action(int part, int total) { +		int percent = 100 * part / total; +		action(String.format("%d/%d (%d%%)", +				     part, total, percent), +		       percent); +	}  	public void flash() throws IOException, FileNotFoundException, InterruptedException {  		if (!check_rom_config())  			throw new IOException("Invalid rom config settings"); +		if (image.address + image.data.length > 0x8000) +			throw new IOException(String.format("Flash image too long %d", +							    image.address + +							    image.data.length)); +		if ((image.address & 0x3ff) != 0) +			throw new IOException(String.format("Flash image must start on page boundary (is 0x%x)", +							    image.address)); +		int ram_address = 0xf000; +		int flash_prog = 0xf400; + +		/* +		 * Store desired config values into image +		 */  		rom_config.write(image); +		/* +		 * Bring up the clock +		 */ +		clock_init(); + +		int remain = image.data.length; +		int flash_addr = image.address; +		int image_start = 0; + +		action(0, image.data.length); +		while (remain > 0 && !aborted) { +			int this_time = remain; +			if (this_time > 0x400) +				this_time = 0x400; + +			/* write the data */ +			debug.write_memory(ram_address, image.data, +					   image_start, this_time); + +			/* write the flash program */ +			byte[] flash_page = make_flash_page(flash_addr, +							    ram_address, +							    this_time); +			debug.write_memory(flash_prog, flash_page); + +			debug.set_pc(flash_prog); +			int pc = debug.get_pc(); +			debug.resume(); +			Thread.sleep(100); +			for (int times = 0; times < 10; times++) { +				byte status = debug.read_status(); +				if ((status & AltosDebug.STATUS_CPU_HALTED) != 0) +					break; +				Thread.sleep(100); +			} + +			byte[] check = debug.read_memory(flash_addr, this_time); +			for (int i = 0; i < this_time; i++) +				if (check[i] != image.data[image_start + i]) +					throw new IOException(String.format("Flash write failed at 0x%x (%02x != %02x)", +									    image.address + image_start + i, +									    check[i], image.data[image_start + i])); +			remain -= this_time; +			flash_addr += this_time; +			image_start += this_time; + +			action(image.data.length - remain, image.data.length); +		} +		if (!aborted) { +			action("done", 100); +			debug.set_pc(image.address); +			debug.resume(); +		} +		debug.close(); +	} + +	public void abort() { +		aborted = true; +		debug.close(); +	} + +	public void addActionListener(ActionListener l) { +		listener = l;  	}  	public boolean check_rom_config() { @@ -56,6 +313,10 @@ public class AltosFlash {  		rom_config = romconfig;  	} +	public AltosRomconfig romconfig() { +		return rom_config; +	} +  	public void open() throws IOException, FileNotFoundException, InterruptedException {  		input = new FileInputStream(file);  		image = new AltosHexfile(input); diff --git a/ao-tools/altosui/AltosFlashUI.java b/ao-tools/altosui/AltosFlashUI.java index 5cae4756..0c2041e3 100644 --- a/ao-tools/altosui/AltosFlashUI.java +++ b/ao-tools/altosui/AltosFlashUI.java @@ -31,15 +31,43 @@ import java.util.concurrent.LinkedBlockingQueue;  import altosui.AltosHexfile;  import altosui.AltosFlash; -public class AltosFlashUI implements Runnable { +public class AltosFlashUI +	extends JDialog +	implements Runnable, ActionListener +{ +	Container	pane; +	Box		box; +	JLabel		serial_label; +	JLabel		serial_value; +	JLabel		file_label; +	JLabel		file_value; +	JProgressBar	pbar; +	JButton		cancel; +  	File		file;  	Thread		thread;  	JFrame		frame;  	AltosDevice	debug_dongle;  	AltosFlash	flash; +	public void actionPerformed(ActionEvent e) { +		if (e.getSource() == cancel) { +			abort(); +			dispose(); +		} else { +			String	cmd = e.getActionCommand(); +			if (cmd.equals("done")) +				dispose(); +			else { +				pbar.setValue(e.getID()); +				pbar.setString(cmd); +			} +		} +	} +  	public void run() {  		flash = new AltosFlash(file, debug_dongle); +		flash.addActionListener(this);  		try {  			flash.open();  			if (!flash.check_rom_config()) { @@ -50,6 +78,10 @@ public class AltosFlashUI implements Runnable {  					return;  				flash.set_romconfig(romconfig);  			} +			serial_value.setText(String.format("%d", +							   flash.romconfig().serial_number)); +			file_value.setText(file.toString()); +			setVisible(true);  			flash.flash();  		} catch (FileNotFoundException ee) {  			JOptionPane.showMessageDialog(frame, @@ -67,9 +99,90 @@ public class AltosFlashUI implements Runnable {  		}  	} +	public void abort() { +		if (flash != null) +			flash.abort(); +	} + +	public void build_dialog() { +		GridBagConstraints c; +		Insets il = new Insets(4,4,4,4); +		Insets ir = new Insets(4,4,4,4); + +		pane = getContentPane(); +		pane.setLayout(new GridBagLayout()); + +		c = new GridBagConstraints(); +		c.gridx = 0; c.gridy = 0; +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		serial_label = new JLabel("Serial:"); +		pane.add(serial_label, c); + +		c = new GridBagConstraints(); +		c.gridx = 1; c.gridy = 0; +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		serial_value = new JLabel(""); +		pane.add(serial_value, c); + +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.NONE; +		c.gridx = 0; c.gridy = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = il; +		file_label = new JLabel("File:"); +		pane.add(file_label, c); + +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.HORIZONTAL; +		c.weightx = 1; +		c.gridx = 1; c.gridy = 1; +		c.anchor = GridBagConstraints.LINE_START; +		c.insets = ir; +		file_value = new JLabel(""); +		pane.add(file_value, c); + +		pbar = new JProgressBar(); +		pbar.setMinimum(0); +		pbar.setMaximum(100); +		pbar.setValue(0); +		pbar.setString(""); +		pbar.setStringPainted(true); +		pbar.setPreferredSize(new Dimension(600, 20)); +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.HORIZONTAL; +		c.anchor = GridBagConstraints.CENTER; +		c.gridx = 0; c.gridy = 2; +		c.gridwidth = GridBagConstraints.REMAINDER; +		Insets ib = new Insets(4,4,4,4); +		c.insets = ib; +		pane.add(pbar, c); + +		cancel = new JButton("Cancel"); +		c = new GridBagConstraints(); +		c.fill = GridBagConstraints.NONE; +		c.anchor = GridBagConstraints.CENTER; +		c.gridx = 0; c.gridy = 3; +		c.gridwidth = GridBagConstraints.REMAINDER; +		Insets ic = new Insets(4,4,4,4); +		c.insets = ic; +		pane.add(cancel, c); +		cancel.addActionListener(this); +		pack(); +		setLocationRelativeTo(frame); +	} +  	public AltosFlashUI(JFrame in_frame) { +		super(in_frame, "Program Altusmetrum Device", false); +  		frame = in_frame; +		build_dialog(); +  		debug_dongle = AltosDeviceDialog.show(frame, AltosDevice.Any);  		if (debug_dongle == null)  | 
