diff options
68 files changed, 2220 insertions, 601 deletions
| diff --git a/altosui/AltosDebug.java b/altoslib/AltosDebug.java index c69369ef..4d8e3ae7 100644 --- a/altosui/AltosDebug.java +++ b/altoslib/AltosDebug.java @@ -15,12 +15,11 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altoslib_1;  import java.io.*; -import org.altusmetrum.altosuilib_1.*; -public class AltosDebug extends AltosSerial { +public class AltosDebug {  	public static final byte WR_CONFIG =		0x1d;  	public static final byte RD_CONFIG =		0x24; @@ -53,13 +52,15 @@ public class AltosDebug extends AltosSerial {  	public static final byte GET_CHIP_ID =		0x68; +	AltosLink	link; +  	boolean	debug_mode;  	void ensure_debug_mode() {  		if (!debug_mode) { -			printf("D\n"); +			link.printf("D\n");  			try { -				flush_input(); +				link.flush_input();  			} catch (InterruptedException ie) {  			}  			debug_mode = true; @@ -79,15 +80,19 @@ public class AltosDebug extends AltosSerial {  		System.out.printf("\n");  	} +	public void close() { +		link.close(); +	} +  	/*  	 * Write target memory  	 */  	public void write_memory(int address, byte[] bytes, int start, int len) {  		ensure_debug_mode();  //		dump_memory("write_memory", address, bytes, start, len); -		printf("O %x %x\n", len, address); +		link.printf("O %x %x\n", len, address);  		for (int i = 0; i < len; i++) -			printf("%02x", bytes[start + i]); +			link.printf("%02x", bytes[start + i]);  	}  	public void write_memory(int address, byte[] bytes) { @@ -101,21 +106,21 @@ public class AltosDebug extends AltosSerial {  		throws IOException, InterruptedException {  		byte[]	data = new byte[length]; -		flush_input(); +		link.flush_input();  		ensure_debug_mode(); -		printf("I %x %x\n", length, address); +		link.printf("I %x %x\n", length, address);  		int i = 0;  		int start = 0;  		while (i < length) { -			String	line = get_reply().trim(); -			if (!Altos.ishex(line) || line.length() % 2 != 0) +			String	line = link.get_reply().trim(); +			if (!AltosLib.ishex(line) || line.length() % 2 != 0)  				throw new IOException(  					String.format  					("Invalid reply \"%s\"", line));  			int this_time = line.length() / 2;  			for (int j = 0; j < this_time; j++) -				data[start + j] = (byte) ((Altos.fromhex(line.charAt(j*2)) << 4) + -						  Altos.fromhex(line.charAt(j*2+1))); +				data[start + j] = (byte) ((AltosLib.fromhex(line.charAt(j*2)) << 4) + +						  AltosLib.fromhex(line.charAt(j*2+1)));  			start += this_time;  			i += this_time;  		} @@ -134,10 +139,10 @@ public class AltosDebug extends AltosSerial {  			int this_time = bytes.length - i;  			if (this_time > 8)  				this_time = 0; -			printf("P"); +			link.printf("P");  			for (int j = 0; j < this_time; j++) -				printf(" %02x", bytes[i+j]); -			printf("\n"); +				link.printf(" %02x", bytes[i+j]); +			link.printf("\n");  			i += this_time;  		}  	} @@ -153,20 +158,20 @@ public class AltosDebug extends AltosSerial {  	public byte[] read_bytes(int length)  		throws IOException, InterruptedException { -		flush_input(); +		link.flush_input();  		ensure_debug_mode(); -		printf("G %x\n", length); +		link.printf("G %x\n", length);  		int i = 0;  		byte[] data = new byte[length];  		while (i < length) { -			String line = get_reply(); +			String line = link.get_reply();  			if (line == null)  				throw new IOException("Timeout in read_bytes");  			line = line.trim();  			String tokens[] = line.split("\\s+");  			for (int j = 0; j < tokens.length; j++) { -				if (!Altos.ishex(tokens[j]) || +				if (!AltosLib.ishex(tokens[j]) ||  				    tokens[j].length() != 2)  					throw new IOException(  						String.format @@ -266,10 +271,10 @@ public class AltosDebug extends AltosSerial {  	 * Reset target  	 */  	public void reset() { -		printf ("R\n"); +		link.printf ("R\n");  	} -	public AltosDebug (AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException { -		super(in_device); +	public AltosDebug (AltosLink link) { +		this.link = link;  	}  }
\ No newline at end of file diff --git a/altosui/AltosFlash.java b/altoslib/AltosFlash.java index 239d4dd7..010274b9 100644 --- a/altosui/AltosFlash.java +++ b/altoslib/AltosFlash.java @@ -15,23 +15,19 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altoslib_1; -import java.awt.event.*; -import javax.swing.*;  import java.io.*; -import org.altusmetrum.altosuilib_1.*;  public class AltosFlash { -	File		file; -	FileInputStream	input; -	AltosHexfile	image; -	JFrame		frame; -	AltosDevice	debug_dongle; -	AltosDebug	debug; -	AltosRomconfig	rom_config; -	ActionListener	listener; -	boolean		aborted; +	File			file; +	FileInputStream		input; +	AltosHexfile		image; +	AltosLink		link; +	AltosDebug		debug; +	AltosRomconfig		rom_config; +	boolean			aborted; +	AltosFlashListener	listener;  	static final byte MOV_direct_data	= (byte) 0x75;  	static final byte MOV_DPTR_data16	= (byte) 0x90; @@ -205,22 +201,9 @@ public class AltosFlash {  		}  	} -	void action(String in_s, int in_percent) { -		final String s = in_s; -		final int percent = in_percent; -		if (listener != null && !aborted) { -			Runnable r = new Runnable() { -					public void run() { -						try { -							listener.actionPerformed(new ActionEvent(this, -												 percent, -												 s)); -						} catch (Exception ex) { -						} -					} -				}; -			SwingUtilities.invokeLater(r); -		} +	void action(String s, int percent) { +		if (listener != null && !aborted) +			listener.position(s, percent);  	}  	void action(int part, int total) { @@ -335,10 +318,6 @@ public class AltosFlash {  		close();  	} -	public void addActionListener(ActionListener l) { -		listener = l; -	} -  	public boolean check_rom_config() {  		if (debug == null)  			return true; @@ -357,12 +336,13 @@ public class AltosFlash {  		return rom_config;  	} -	public AltosFlash(File in_file, AltosDevice in_debug_dongle) -		throws IOException, FileNotFoundException, AltosSerialInUseException, InterruptedException { -		file = in_file; -		debug_dongle = in_debug_dongle; -		if (debug_dongle != null) -			debug = new AltosDebug(in_debug_dongle); +	public AltosFlash(File file, AltosLink link, AltosFlashListener listener) +		throws IOException, FileNotFoundException, InterruptedException { +		this.file = file; +		this.link = link; +		this.listener = listener; +		if (link != null) +			debug = new AltosDebug(link);  		input = new FileInputStream(file);  		image = new AltosHexfile(input);  		if (debug != null && !debug.check_connection()) { diff --git a/altoslib/AltosFlashListener.java b/altoslib/AltosFlashListener.java new file mode 100644 index 00000000..ab50b74a --- /dev/null +++ b/altoslib/AltosFlashListener.java @@ -0,0 +1,22 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +package org.altusmetrum.altoslib_1; + +public interface AltosFlashListener { +	public void position(String label, int percent); +} diff --git a/altosui/AltosHexfile.java b/altoslib/AltosHexfile.java index 56875f53..68f42f14 100644 --- a/altosui/AltosHexfile.java +++ b/altoslib/AltosHexfile.java @@ -15,7 +15,7 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altoslib_1;  import java.io.*;  import java.util.LinkedList; @@ -228,21 +228,70 @@ public class AltosHexfile {  			else  				record_list.add(record);  		} -		HexRecord[] records  = record_list.toArray(new HexRecord[0]); -		Arrays.sort(records); -		if (records.length > 0) { -			int	base = records[0].address; -			int	bound = records[records.length-1].address + -				records[records.length-1].data.length; - -			data = new byte[bound - base]; -			address = base; -			Arrays.fill(data, (byte) 0xff); - -			/* Paint the records into the new array */ -			for (int i = 0; i < records.length; i++) { -				for (int j = 0; j < records[i].data.length; j++) -					data[records[i].address - base + j] = records[i].data[j]; + +		long	extended_addr = 0; +		long	base = 0xffffffff; +		long	bound = 0x00000000; +		for (HexRecord record : record_list) { +			switch (record.type) { +			case 0: +				long addr = extended_addr + record.address; +				long r_bound = addr + record.data.length; +				if (addr < base) +					base = addr; +				if (r_bound > bound) +					bound = r_bound; +				break; +			case 1: +				break; +			case 2: +				if (record.data.length != 2) +					throw new IOException("invalid extended segment address record"); +				extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; +				break; +			case 4: +				if (record.data.length != 2) +					throw new IOException("invalid extended segment address record"); +				extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; +				break; +			default: +				throw new IOException ("invalid hex record type"); +			} +		} + +		if (base >= bound) +			throw new IOException("invalid hex file"); + +		if (bound - base > 4 * 1024 * 1024) +			throw new IOException("hex file too large"); + +		data = new byte[(int) (bound - base)]; +		address = (int) base; +		Arrays.fill(data, (byte) 0xff); + +		/* Paint the records into the new array */ +		for (HexRecord record : record_list) { +			switch (record.type) { +			case 0: +				long addr = extended_addr + record.address; +				long r_bound = addr + record.data.length; +				for (int j = 0; j < record.data.length; j++) +					data[(int) (addr - base) + j] = record.data[j]; +				break; +			case 1: +				break; +			case 2: +				if (record.data.length != 2) +					throw new IOException("invalid extended segment address record"); +				extended_addr = ((record.data[0] << 8) + (record.data[1])) << 4; +				break; +			case 4: +				if (record.data.length != 2) +					throw new IOException("invalid extended segment address record"); +				extended_addr = ((record.data[0] << 8) + (record.data[1])) << 16; +				break; +			default: +				throw new IOException ("invalid hex record type");  			}  		}  	} diff --git a/altosui/AltosRomconfig.java b/altoslib/AltosRomconfig.java index 55056b5e..0800a2c4 100644 --- a/altosui/AltosRomconfig.java +++ b/altoslib/AltosRomconfig.java @@ -15,7 +15,8 @@   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.   */ -package altosui; +package org.altusmetrum.altoslib_1; +  import java.io.*;  public class AltosRomconfig { diff --git a/altoslib/Makefile.am b/altoslib/Makefile.am index 30a9d954..18b028d6 100644 --- a/altoslib/Makefile.am +++ b/altoslib/Makefile.am @@ -16,6 +16,7 @@ altoslib_JAVA = \  	AltosConfigValues.java \  	AltosConvert.java \  	AltosCRCException.java \ +	AltosDebug.java \  	AltosEepromChunk.java \  	AltosEepromIterable.java \  	AltosEepromLog.java \ @@ -24,12 +25,15 @@ altoslib_JAVA = \  	AltosEepromRecord.java \  	AltosEepromTeleScience.java \  	AltosFile.java \ +	AltosFlash.java \ +	AltosFlashListener.java \  	AltosFlightReader.java \  	AltosFrequency.java \  	AltosGPS.java \  	AltosGPSQuery.java \  	AltosGPSSat.java \  	AltosGreatCircle.java \ +	AltosHexfile.java \  	AltosIdleMonitor.java \  	AltosIdleMonitorListener.java \  	AltosIgnite.java \ @@ -53,6 +57,7 @@ altoslib_JAVA = \  	AltosRecordTM.java \  	AltosRecordMM.java \  	AltosReplayReader.java \ +	AltosRomconfig.java \  	AltosSensorMM.java \  	AltosSensorTM.java \  	AltosState.java \ diff --git a/altosui/AltosFlashUI.java b/altosui/AltosFlashUI.java index f26a3916..f4e52218 100644 --- a/altosui/AltosFlashUI.java +++ b/altosui/AltosFlashUI.java @@ -23,6 +23,7 @@ import javax.swing.*;  import javax.swing.filechooser.FileNameExtensionFilter;  import java.io.*;  import java.util.concurrent.*; +import org.altusmetrum.altoslib_1.*;  import org.altusmetrum.altosuilib_1.*;  public class AltosFlashUI @@ -214,15 +215,30 @@ public class AltosFlashUI  		}  	} -	class flash_task implements Runnable { +	class flash_task implements Runnable, AltosFlashListener {  		AltosFlashUI	ui;  		Thread		t;  		AltosFlash	flash; +		public void position(String in_s, int in_percent) { +			final String s = in_s; +			final int percent = in_percent; +			Runnable r = new Runnable() { +					public void run() { +						try { +							ui.actionPerformed(new ActionEvent(this, +											   percent, +											   s)); +						} catch (Exception ex) { +						} +					} +				}; +			SwingUtilities.invokeLater(r); +		} +  		public void run () {  			try { -				flash = new AltosFlash(ui.file, ui.debug_dongle); -				flash.addActionListener(ui); +				flash = new AltosFlash(ui.file, new AltosSerial(ui.debug_dongle), this);  				final AltosRomconfig	current_config = flash.romconfig(); diff --git a/altosui/AltosRomconfigUI.java b/altosui/AltosRomconfigUI.java index cf4658af..909e72a0 100644 --- a/altosui/AltosRomconfigUI.java +++ b/altosui/AltosRomconfigUI.java @@ -20,6 +20,7 @@ package altosui;  import java.awt.*;  import java.awt.event.*;  import javax.swing.*; +import org.altusmetrum.altoslib_1.*;  import org.altusmetrum.altosuilib_1.*;  public class AltosRomconfigUI diff --git a/altosui/Makefile.am b/altosui/Makefile.am index 4bfef47c..d59e3082 100644 --- a/altosui/Makefile.am +++ b/altosui/Makefile.am @@ -30,7 +30,6 @@ altosui_JAVA = \  	AltosConfigTDUI.java \  	AltosCSV.java \  	AltosCSVUI.java \ -	AltosDebug.java \  	AltosDescent.java \  	AltosDeviceUIDialog.java \  	AltosDisplayThread.java \ @@ -40,7 +39,6 @@ altosui_JAVA = \  	AltosEepromManage.java \  	AltosEepromMonitor.java \  	AltosEepromSelect.java \ -	AltosFlash.java \  	AltosFlashUI.java \  	AltosFlightDisplay.java \  	AltosFlightInfoTableModel.java \ @@ -50,7 +48,6 @@ altosui_JAVA = \  	AltosFlightStatusUpdate.java \  	AltosFlightUI.java \  	AltosFreqList.java \ -	AltosHexfile.java \  	Altos.java \  	AltosIdleMonitorUI.java \  	AltosIgniteUI.java \ @@ -63,7 +60,6 @@ altosui_JAVA = \  	AltosLights.java \  	AltosPad.java \  	AltosUIPreferencesBackend.java \ -	AltosRomconfig.java \  	AltosRomconfigUI.java \  	AltosScanUI.java \  	AltosSerial.java \ diff --git a/ao-tools/ao-stmload/Makefile.am b/ao-tools/ao-stmload/Makefile.am index 5aea7db4..4eaf699c 100644 --- a/ao-tools/ao-stmload/Makefile.am +++ b/ao-tools/ao-stmload/Makefile.am @@ -4,11 +4,14 @@ bin_PROGRAMS=ao-stmload  LIBSTLINKDIR=/local/src/stlink -AM_CFLAGS=$(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) -I../lib +AM_CFLAGS=-I$(top_srcdir)/ao-tools/lib $(LIBSTLINK_CFLAGS) $(LIBUSB_CFLAGS) +AO_STMLOAD_LIBS=$(top_builddir)/ao-tools/lib/libao-tools.a -ao_stmload_LDADD=$(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf +ao_stmload_DEPENDENCIES = $(AO_STMLOAD_LIBS) -ao_stmload_SOURCES=ao-stmload.c +ao_stmload_LDADD=$(AO_STMLOAD_LIBS) $(LIBSTLINK_LIBS) $(LIBUSB_LIBS) -lelf + +ao_stmload_SOURCES=ao-stmload.c ao-elf.c ao-stmload.h ao-selfload.c  man_MANS = ao-stmload.1 diff --git a/ao-tools/ao-stmload/ao-elf.c b/ao-tools/ao-stmload/ao-elf.c new file mode 100644 index 00000000..dad8fb80 --- /dev/null +++ b/ao-tools/ao-stmload/ao-elf.c @@ -0,0 +1,303 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao-elf.h" +#include <err.h> +#include <gelf.h> +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "ccdbg.h" +#include "ao-stmload.h" + +/* + * Look through the Elf file for the AltOS symbols + * that can be adjusted before the image is written + * to the device + */ +static int +find_symbols (Elf *e) +{ +	Elf_Scn 	*scn; +	Elf_Data	*symbol_data = NULL; +	GElf_Shdr	shdr; +	GElf_Sym       	sym; +	int		i, symbol_count, s; +	int		required = 0; +	char		*symbol_name; +	char		*section_name; +	size_t		shstrndx; + +	if (elf_getshdrstrndx(e, &shstrndx) < 0) +		return 0; + +	/* +	 * Find the symbols +	 */ + +	scn = NULL; +	while ((scn = elf_nextscn(e, scn)) != NULL) { + +		if (gelf_getshdr(scn, &shdr) != &shdr) +			return 0; + +		if (shdr.sh_type == SHT_SYMTAB) { +			symbol_data = elf_getdata(scn, NULL); +			symbol_count = shdr.sh_size / shdr.sh_entsize; +			break; +		} +	} + +	if (!symbol_data) +		return 0; + +	for (i = 0; i < symbol_count; i++) { +		gelf_getsym(symbol_data, i, &sym); + +		symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name); + +		for (s = 0; s < ao_num_symbols; s++) +			if (!strcmp (ao_symbols[s].name, symbol_name)) { +				int	t; +				ao_symbols[s].addr = sym.st_value; +				if (ao_symbols[s].required) +					++required; +			} +	} + +	return required >= ao_num_required_symbols; +} + +uint32_t round4(uint32_t a) { +	return (a + 3) & ~3; +} + +struct hex_image * +new_load (uint32_t addr, uint32_t len) +{ +	struct hex_image *new; + +	len = round4(len); +	new = calloc (1, sizeof (struct hex_image) + len); +	if (!new) +		abort(); + +	new->address = addr; +	new->length = len; +	return new; +} + +void +load_paste(struct hex_image *into, struct hex_image *from) +{ +	if (from->address < into->address || into->address + into->length < from->address + from->length) +		abort(); + +	memcpy(into->data + from->address - into->address, from->data, from->length); +} + +/* + * Make a new load structure large enough to hold the old one and + * the new data + */ +struct hex_image * +expand_load(struct hex_image *from, uint32_t address, uint32_t length) +{ +	struct hex_image	*new; + +	if (from) { +		uint32_t	from_last = from->address + from->length; +		uint32_t	last = address + length; + +		if (address > from->address) +			address = from->address; +		if (last < from_last) +			last = from_last; + +		length = last - address; + +		if (address == from->address && length == from->length) +			return from; +	} +	new = new_load(address, length); +	if (from) { +		load_paste(new, from); +		free (from); +	} +	return new; +} + +/* + * Create a new load structure with data from the existing one + * and the new data + */ +struct hex_image * +load_write(struct hex_image *from, uint32_t address, uint32_t length, void *data) +{ +	struct hex_image	*new; + +	new = expand_load(from, address, length); +	memcpy(new->data + address - new->address, data, length); +	return new; +} + +/* + * Construct a large in-memory block for all + * of the loaded sections of the program + */ +static struct hex_image * +get_load(Elf *e) +{ +	Elf_Scn 	*scn; +	size_t		shstrndx; +	GElf_Shdr	shdr; +	Elf_Data	*data; +	char		*got_name; +	size_t		nphdr; +	size_t		p; +	GElf_Phdr	phdr; +	GElf_Addr	p_paddr; +	GElf_Off	p_offset; +	GElf_Addr	sh_paddr; +	struct hex_image	*load = NULL; +	char		*section_name; +	size_t		nshdr; +	size_t		s; +	 +	if (elf_getshdrstrndx(e, &shstrndx) < 0) +		return 0; + +	if (elf_getphdrnum(e, &nphdr) < 0) +		return 0; + +	if (elf_getshdrnum(e, &nshdr) < 0) +		return 0; + +	/* +	 * As far as I can tell, all of the phdr sections should +	 * be flashed to memory +	 */ +	for (p = 0; p < nphdr; p++) { + +		/* Find this phdr */ +		gelf_getphdr(e, p, &phdr); + +		if (phdr.p_type != PT_LOAD) +			continue; + +		p_offset = phdr.p_offset; +		/* Get the associated file section */ + +#if 0 +		printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", +			(uint32_t) phdr.p_offset, +			(uint32_t) phdr.p_vaddr, +			(uint32_t) phdr.p_paddr, +			(uint32_t) phdr.p_filesz, +			(uint32_t) phdr.p_memsz); +#endif +		 +		for (s = 0; s < nshdr; s++) { +			scn = elf_getscn(e, s); + +			if (!scn) { +				printf ("getscn failed\n"); +				abort(); +			} +			if (gelf_getshdr(scn, &shdr) != &shdr) { +				printf ("gelf_getshdr failed\n"); +				abort(); +			} + +			section_name = elf_strptr(e, shstrndx, shdr.sh_name); + +			if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) { +					 +				if (shdr.sh_size == 0) +					continue; + +				sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset; + +				printf ("\tsize %08x rom %08x exec %08x %s\n", +					(uint32_t) shdr.sh_size, +					(uint32_t) sh_paddr, +					(uint32_t) shdr.sh_addr, +					section_name); + +				data = elf_getdata(scn, NULL); + +				/* Write the section data into the memory block */ +				load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf); +			} +		} +	} +	return load; +} + +/* + * Open the specified ELF file and + * check for the symbols we need + */ + +struct hex_image * +ao_load_elf(char *name) +{ +	int		fd; +	Elf		*e; +	Elf_Scn 	*scn; +	Elf_Data	*symbol_data = NULL; +	GElf_Shdr	shdr; +	GElf_Sym       	sym; +	size_t		n, shstrndx, sz; +	int		i, symbol_count, s; +	int		required = 0; +	struct hex_image	*image; + +	if (elf_version(EV_CURRENT) == EV_NONE) +		return NULL; + +	fd = open(name, O_RDONLY, 0); + +	if (fd < 0) +		return NULL; + +	e = elf_begin(fd, ELF_C_READ, NULL); + +	if (!e) +		return NULL; + +	if (elf_kind(e) != ELF_K_ELF) +		return NULL; + +	if (elf_getshdrstrndx(e, &shstrndx) != 0) +		return NULL; + +	if (!find_symbols(e)) { +		fprintf (stderr, "Cannot find required symbols\n"); +		return NULL; +	} + +	image = get_load(e); +	if (!image) { +		fprintf (stderr, "Cannot create memory image from file\n"); +		return NULL; +	} + +	return image; +} diff --git a/ao-tools/ao-stmload/ao-elf.h b/ao-tools/ao-stmload/ao-elf.h new file mode 100644 index 00000000..4303d5ca --- /dev/null +++ b/ao-tools/ao-stmload/ao-elf.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_ELF_H_ +#define _AO_ELF_H_ + +struct hex_image * +ao_load_elf(char *name); + +#endif diff --git a/ao-tools/ao-stmload/ao-selfload.c b/ao-tools/ao-stmload/ao-selfload.c new file mode 100644 index 00000000..95667dca --- /dev/null +++ b/ao-tools/ao-stmload/ao-selfload.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <sysexits.h> +#include <unistd.h> +#include <string.h> +#include "cc.h" +#include "cc-usb.h" +#include "ccdbg.h" +#include "ao-stmload.h" + +int	ao_self_verbose; + +#define TRACE(...) if (ao_self_verbose) printf (__VA_ARGS__) + +void +ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]) +{ +	int			byte; +	cc_usb_sync(cc); +	cc_usb_printf(cc, "R %x\n", address); +	for (byte = 0; byte < 0x100; byte++) { +		block[byte] = cc_usb_getchar(cc); +	} +	TRACE ("\nread %08x\n", address); +	for (byte = 0; byte < 0x100; byte++) { +		TRACE (" %02x", block[byte]); +		if ((byte & 0xf) == 0xf) +			TRACE ("\n"); +	} +} + +void +ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]) +{ +	int			byte; +	cc_usb_sync(cc); +	cc_usb_printf(cc, "W %x\n", address); +	TRACE ("write %08x\n", address); +	for (byte = 0; byte < 0x100; byte++) { +		TRACE (" %02x", block[byte]); +		if ((byte & 0xf) == 0xf) +			TRACE ("\n"); +	} +	for (byte = 0; byte < 0x100; byte++) { +		cc_usb_printf(cc, "%c", block[byte]); +	} +} + +struct hex_image * +ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length) +{ +	struct hex_image	*image; +	int			pages; +	int			page; +	uint32_t		base = address & ~0xff; +	uint32_t		bound = (address + length + 0xff) & ~0xff; + +	image = calloc(sizeof (struct hex_image) + (bound - base), 1); +	image->address = base; +	image->length = bound - base; +	pages = image->length / 0x100; +	for (page = 0; page < pages; page++) +		ao_self_block_read(cc, image->address + page * 0x100, image->data + page * 0x100); +	return image; +} + +int +ao_self_write(struct cc_usb *cc, struct hex_image *image) +{ +	uint8_t		block[256]; +	uint8_t		check[256]; +	uint32_t	base, bound, length, address; +	uint32_t	pages; +	uint32_t	page; + +	base = image->address & ~0xff; +	bound = (image->address + image->length + 0xff) & ~0xff; + +	address = base; +	length = bound - base; + +	pages = length / 0x100; +	printf ("Write %08x %d pages: ", address, length/0x100); fflush(stdout); +	for (page = 0; page < pages; page++) { +		uint32_t	start, stop; +		address = base + page * 0x100; + +		if (address < image->address || address + 0x100 > image->address + image->length) { +			ao_self_block_read(cc, address, block); +		} +		start = address; +		stop = address + 0x100; +		if (start < image->address) +			start = image->address; +		if (stop > image->address + image->length) +			stop = image->address + image->length; +		memcpy(block + start - address, image->data + start - image->address, stop - start); +		ao_self_block_write(cc, address, block); +		ao_self_block_read(cc, address, check); +		if (memcmp(block, check, 0x100) != 0) { +			fprintf(stderr, "Block at 0x%08x doesn't match\n", address); +			return 0; +		} +		putchar('.'); fflush(stdout); +	} +	printf("done\n"); +	cc_usb_printf(cc,"a\n"); +	return 1; +} diff --git a/ao-tools/ao-stmload/ao-stmload.c b/ao-tools/ao-stmload/ao-stmload.c index 89b818da..dd25f07f 100644 --- a/ao-tools/ao-stmload/ao-stmload.c +++ b/ao-tools/ao-stmload/ao-stmload.c @@ -26,365 +26,107 @@  #include <getopt.h>  #include <string.h>  #include "stlink-common.h" +#include "ao-elf.h" +#include "ccdbg.h" +#include "cc-usb.h" +#include "cc.h" +#include "ao-stmload.h"  #define AO_USB_DESC_STRING		3 -struct sym { -	unsigned	addr; -	char		*name; -	int		required; -} ao_symbols[] = { +struct sym ao_symbols[] = { -	{ 0,	"ao_romconfig_version",	1 }, +	{ 0, AO_BOOT_APPLICATION_BASE + 0x100,	"ao_romconfig_version",	1 },  #define AO_ROMCONFIG_VERSION	(ao_symbols[0].addr) -	{ 0,	"ao_romconfig_check",	1 }, +	{ 0, AO_BOOT_APPLICATION_BASE + 0x102,	"ao_romconfig_check",	1 },  #define AO_ROMCONFIG_CHECK	(ao_symbols[1].addr) -	{ 0,	"ao_serial_number", 1 }, +	{ 0, AO_BOOT_APPLICATION_BASE + 0x104,	"ao_serial_number", 1 },  #define AO_SERIAL_NUMBER	(ao_symbols[2].addr) -	{ 0,	"ao_usb_descriptors", 0 }, -#define AO_USB_DESCRIPTORS	(ao_symbols[3].addr) +	{ 0, AO_BOOT_APPLICATION_BASE + 0x108,	"ao_radio_cal", 0 }, +#define AO_RADIO_CAL		(ao_symbols[3].addr) -	{ 0,	"ao_radio_cal", 0 }, -#define AO_RADIO_CAL		(ao_symbols[4].addr) +	{ 0, AO_BOOT_APPLICATION_BASE + 0x10c,	"ao_usb_descriptors", 0 }, +#define AO_USB_DESCRIPTORS	(ao_symbols[4].addr)  };  #define NUM_SYMBOLS		5  #define NUM_REQUIRED_SYMBOLS	3 -/* - * Look through the Elf file for the AltOS symbols - * that can be adjusted before the image is written - * to the device - */ -static int -find_symbols (Elf *e) -{ -	Elf_Scn 	*scn; -	Elf_Data	*symbol_data = NULL; -	GElf_Shdr	shdr; -	GElf_Sym       	sym; -	int		i, symbol_count, s; -	int		required = 0; -	char		*symbol_name; -	char		*section_name; -	size_t		shstrndx; - -	if (elf_getshdrstrndx(e, &shstrndx) < 0) -		return 0; - -	/* -	 * Find the symbols -	 */ - -	scn = NULL; -	while ((scn = elf_nextscn(e, scn)) != NULL) { - -		if (gelf_getshdr(scn, &shdr) != &shdr) -			return 0; - -#if 0 -		section_name = elf_strptr(e, shstrndx, shdr.sh_name); - -		printf ("name %s\n", section_name); - -		if (shdr.sh_type == SHT_PROGBITS) -		{ -			printf ("\ttype %lx\n", shdr.sh_type); -			printf ("\tflags %lx\n", shdr.sh_flags); -			printf ("\taddr %lx\n", shdr.sh_addr); -			printf ("\toffset %lx\n", shdr.sh_offset); -			printf ("\tsize %lx\n", shdr.sh_size); -			printf ("\tlink %lx\n", shdr.sh_link); -			printf ("\tinfo %lx\n", shdr.sh_info); -			printf ("\taddralign %lx\n", shdr.sh_addralign); -			printf ("\tentsize %lx\n", shdr.sh_entsize); -		} -#endif - -		if (shdr.sh_type == SHT_SYMTAB) { -			symbol_data = elf_getdata(scn, NULL); -			symbol_count = shdr.sh_size / shdr.sh_entsize; -			break; -		} -	} - -	if (!symbol_data) -		return 0; - -	for (i = 0; i < symbol_count; i++) { -		gelf_getsym(symbol_data, i, &sym); - -		symbol_name = elf_strptr(e, shdr.sh_link, sym.st_name); - -		for (s = 0; s < NUM_SYMBOLS; s++) -			if (!strcmp (ao_symbols[s].name, symbol_name)) { -				int	t; -				ao_symbols[s].addr = sym.st_value; -				if (ao_symbols[s].required) -					++required; -			} -	} - -	return required >= NUM_REQUIRED_SYMBOLS; -} - -struct load { -	uint32_t	addr; -	uint32_t	len; -	uint8_t		buf[0]; -}; - -uint32_t round4(uint32_t a) { -	return (a + 3) & ~3; -} - -struct load * -new_load (uint32_t addr, uint32_t len) -{ -	struct load *new; - -	len = round4(len); -	new = calloc (1, sizeof (struct load) + len); -	if (!new) -		abort(); - -	new->addr = addr; -	new->len = len; -	return new; -} - -void -load_paste(struct load *into, struct load *from) -{ -	if (from->addr < into->addr || into->addr + into->len < from->addr + from->len) -		abort(); - -	memcpy(into->buf + from->addr - into->addr, from->buf, from->len); -} - -/* - * Make a new load structure large enough to hold the old one and - * the new data - */ -struct load * -expand_load(struct load *from, uint32_t addr, uint32_t len) -{ -	struct load	*new; - -	if (from) { -		uint32_t	from_last = from->addr + from->len; -		uint32_t	last = addr + len; - -		if (addr > from->addr) -			addr = from->addr; -		if (last < from_last) -			last = from_last; - -		len = last - addr; - -		if (addr == from->addr && len == from->len) -			return from; -	} -	new = new_load(addr, len); -	if (from) { -		load_paste(new, from); -		free (from); -	} -	return new; -} - -/* - * Create a new load structure with data from the existing one - * and the new data - */ -struct load * -load_write(struct load *from, uint32_t addr, uint32_t len, void *data) -{ -	struct load	*new; - -	new = expand_load(from, addr, len); -	memcpy(new->buf + addr - new->addr, data, len); -	return new; -} - -/* - * Construct a large in-memory block for all - * of the loaded sections of the program - */ -static struct load * -get_load(Elf *e) -{ -	Elf_Scn 	*scn; -	size_t		shstrndx; -	GElf_Shdr	shdr; -	Elf_Data	*data; -	uint8_t		*buf; -	char		*got_name; -	size_t		nphdr; -	size_t		p; -	GElf_Phdr	phdr; -	GElf_Addr	p_paddr; -	GElf_Off	p_offset; -	GElf_Addr	sh_paddr; -	struct load	*load = NULL; -	char		*section_name; -	size_t		nshdr; -	size_t		s; -	 -	if (elf_getshdrstrndx(e, &shstrndx) < 0) -		return 0; - -	if (elf_getphdrnum(e, &nphdr) < 0) -		return 0; - -	if (elf_getshdrnum(e, &nshdr) < 0) -		return 0; - -	/* -	 * As far as I can tell, all of the phdr sections should -	 * be flashed to memory -	 */ -	for (p = 0; p < nphdr; p++) { - -		/* Find this phdr */ -		gelf_getphdr(e, p, &phdr); - -		if (phdr.p_type != PT_LOAD) -			continue; - -		p_offset = phdr.p_offset; -		/* Get the associated file section */ - -#if 0 -		printf ("offset %08x vaddr %08x paddr %08x filesz %08x memsz %08x\n", -			(uint32_t) phdr.p_offset, -			(uint32_t) phdr.p_vaddr, -			(uint32_t) phdr.p_paddr, -			(uint32_t) phdr.p_filesz, -			(uint32_t) phdr.p_memsz); -#endif -		 -		for (s = 0; s < nshdr; s++) { -			scn = elf_getscn(e, s); - -			if (!scn) { -				printf ("getscn failed\n"); -				abort(); -			} -			if (gelf_getshdr(scn, &shdr) != &shdr) { -				printf ("gelf_getshdr failed\n"); -				abort(); -			} - -			section_name = elf_strptr(e, shstrndx, shdr.sh_name); - -			if (phdr.p_offset <= shdr.sh_offset && shdr.sh_offset < phdr.p_offset + phdr.p_filesz) { -					 -				if (shdr.sh_size == 0) -					continue; - -				sh_paddr = phdr.p_paddr + shdr.sh_offset - phdr.p_offset; - -				printf ("\tsize %08x rom %08x exec %08x %s\n", -					(uint32_t) shdr.sh_size, -					(uint32_t) sh_paddr, -					(uint32_t) shdr.sh_addr, -					section_name); - -				data = elf_getdata(scn, NULL); - -				/* Write the section data into the memory block */ -				load = load_write(load, sh_paddr, shdr.sh_size, data->d_buf); -			} -		} -	} -	return load; -} +int ao_num_symbols = NUM_SYMBOLS; +int ao_num_required_symbols = NUM_REQUIRED_SYMBOLS;  /*   * Edit the to-be-written memory block   */  static int -rewrite(struct load *load, unsigned addr, uint8_t *data, int len) +rewrite(struct hex_image *load, unsigned address, uint8_t *data, int length)  {  	int 		i; -	if (addr < load->addr || load->addr + load->len < addr + len) +	if (address < load->address || load->address + load->length < address + length)  		return 0; -	printf("rewrite %04x:", addr); -	for (i = 0; i < len; i++) -		printf (" %02x", load->buf[addr - load->addr + i]); +	printf("rewrite %04x:", address); +	for (i = 0; i < length; i++) +		printf (" %02x", load->data[address - load->address + i]);  	printf(" ->"); -	for (i = 0; i < len; i++) +	for (i = 0; i < length; i++)  		printf (" %02x", data[i]);  	printf("\n"); -	memcpy(load->buf + addr - load->addr, data, len); +	memcpy(load->data + address - load->address, data, length);  }  /* - * Open the specified ELF file and - * check for the symbols we need + * Read a 16-bit value from the USB target   */ -Elf * -ao_open_elf(char *name) +static uint16_t +get_uint16_cc(struct cc_usb *cc, uint32_t addr)  { -	int		fd; -	Elf		*e; -	Elf_Scn 	*scn; -	Elf_Data	*symbol_data = NULL; -	GElf_Shdr	shdr; -	GElf_Sym       	sym; -	size_t		n, shstrndx, sz; -	int		i, symbol_count, s; -	int		required = 0; - -	if (elf_version(EV_CURRENT) == EV_NONE) -		return NULL; +	struct hex_image	*hex = ao_self_read(cc, addr, 2); +	uint16_t		v; +	uint8_t			*data; -	fd = open(name, O_RDONLY, 0); - -	if (fd < 0) -		return NULL; - -	e = elf_begin(fd, ELF_C_READ, NULL); - -	if (!e) -		return NULL; - -	if (elf_kind(e) != ELF_K_ELF) -		return NULL; - -	if (elf_getshdrstrndx(e, &shstrndx) != 0) -		return NULL; +	if (!hex) +		return 0; +	data = hex->data + addr - hex->address; +	v = data[0] | (data[1] << 8); +	free(hex); +	return v; +} -	if (!find_symbols(e)) { -		fprintf (stderr, "Cannot find required symbols\n"); -		return NULL; -	} +static uint32_t +get_uint32_cc(struct cc_usb *cc, uint32_t addr) +{ +	struct hex_image	*hex = ao_self_read(cc, addr, 4); +	uint32_t		v; +	uint8_t			*data; -	return e; +	if (!hex) +		return 0; +	data = hex->data + addr - hex->address; +	v = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); +	free(hex); +	return v;  }  /* - * Read a 32-bit value from the target device with arbitrary + * Read a 16-bit value from the target device with arbitrary   * alignment   */ -static uint32_t -get_uint32(stlink_t *sl, uint32_t addr) +static uint16_t +get_uint16_sl(stlink_t *sl, uint32_t addr)  {  	const 		uint8_t *data = sl->q_buf;  	uint32_t	actual_addr;  	int		off; -	uint32_t	result; +	uint16_t	result;  	sl->q_len = 0; -	printf ("read 0x%x\n", addr);  	actual_addr = addr & ~3; @@ -394,25 +136,37 @@ get_uint32(stlink_t *sl, uint32_t addr)  		abort();  	off = addr & 3; -	result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24); -	printf ("read 0x%08x = 0x%08x\n", addr, result); +	result = data[off] | (data[off + 1] << 8); +	return result; +} + +static uint16_t +get_uint16(stlink_t *sl, struct cc_usb *cc, uint32_t addr) +{ +	uint16_t	result; +	if (cc) +		result = get_uint16_cc(cc, addr); +	else +		result = get_uint16_sl(sl, addr); +	printf ("read 0x%08x = 0x%04x\n", addr, result);  	return result;  }  /* - * Read a 16-bit value from the target device with arbitrary + * Read a 32-bit value from the target device with arbitrary   * alignment   */ -static uint16_t -get_uint16(stlink_t *sl, uint32_t addr) +static uint32_t +get_uint32_sl(stlink_t *sl, uint32_t addr)  {  	const 		uint8_t *data = sl->q_buf;  	uint32_t	actual_addr;  	int		off; -	uint16_t	result; +	uint32_t	result;  	sl->q_len = 0; +	printf ("read 0x%x\n", addr);  	actual_addr = addr & ~3; @@ -422,8 +176,24 @@ get_uint16(stlink_t *sl, uint32_t addr)  		abort();  	off = addr & 3; -	result = data[off] | (data[off + 1] << 8); -	printf ("read 0x%08x = 0x%04x\n", addr, result); +	result = data[off] | (data[off + 1] << 8) | (data[off+2] << 16) | (data[off+3] << 24); +	return result; +} + +/* + * Read a 32-bit value from the target device with arbitrary + * alignment + */ +static uint32_t +get_uint32(stlink_t *sl, struct cc_usb *cc, uint32_t addr) +{ +	uint32_t	result; + +	if (cc) +		result = get_uint32_cc(cc, addr); +	else +		result = get_uint32_sl(sl, addr); +	printf ("read 0x%08x = 0x%08x\n", addr, result);  	return result;  } @@ -436,10 +206,10 @@ get_uint16(stlink_t *sl, uint32_t addr)   * places this at 0x100 from the start of the rom section   */  static int -check_flashed(stlink_t *sl) +check_flashed(stlink_t *sl, struct cc_usb *cc)  { -	uint16_t	romconfig_version = get_uint16(sl, AO_ROMCONFIG_VERSION); -	uint16_t	romconfig_check = get_uint16(sl, AO_ROMCONFIG_CHECK); +	uint16_t	romconfig_version = get_uint16(sl, cc, AO_ROMCONFIG_VERSION); +	uint16_t	romconfig_check = get_uint16(sl, cc, AO_ROMCONFIG_CHECK);  	if (romconfig_version != (uint16_t) ~romconfig_check) {  		fprintf (stderr, "Device has not been flashed before\n"); @@ -449,21 +219,28 @@ check_flashed(stlink_t *sl)  }  static const struct option options[] = { +	{ .name = "stlink", .has_arg = 0, .val = 'S' }, +	{ .name = "tty", .has_arg = 1, .val = 'T' },  	{ .name = "device", .has_arg = 1, .val = 'D' },  	{ .name = "cal", .has_arg = 1, .val = 'c' },  	{ .name = "serial", .has_arg = 1, .val = 's' }, +	{ .name = "verbose", .has_arg = 0, .val = 'v' },  	{ 0, 0, 0, 0},  };  static void usage(char *program)  { -	fprintf(stderr, "usage: %s [--cal=<radio-cal>] [--serial=<serial>] file.elf\n", program); +	fprintf(stderr, "usage: %s [--stlink] [--verbose] [--device=<device>] [-tty=<tty>] [--cal=<radio-cal>] [--serial=<serial>] file.{elf,ihx}\n", program);  	exit(1);  }  void -done(stlink_t *sl, int code) +done(stlink_t *sl, struct cc_usb *cc, int code)  { +	if (cc) { +/*		cc_usb_printf(cc, "a\n"); */ +		cc_usb_close(cc); +	}  	if (sl) {  		stlink_reset(sl);  		stlink_run(sl); @@ -473,6 +250,17 @@ done(stlink_t *sl, int code)  	exit (code);  } +static int +ends_with(char *whole, char *suffix) +{ +	int whole_len = strlen(whole); +	int suffix_len = strlen(suffix); + +	if (suffix_len > whole_len) +		return 0; +	return strcmp(whole + whole_len - suffix_len, suffix) == 0; +} +  int  main (int argc, char **argv)  { @@ -491,13 +279,21 @@ main (int argc, char **argv)  	char			cal_int[4];  	char			*cal_end;  	int			c; -	stlink_t		*sl; +	stlink_t		*sl = NULL;  	int			was_flashed = 0; -	struct load		*load; +	struct hex_image	*load;  	int			tries; +	struct cc_usb		*cc = NULL; +	int			use_stlink = 0; +	char			*tty = NULL; +	int			success; +	int			verbose = 0; -	while ((c = getopt_long(argc, argv, "D:c:s:", options, NULL)) != -1) { +	while ((c = getopt_long(argc, argv, "T:D:c:s:Sv", options, NULL)) != -1) {  		switch (c) { +		case 'T': +			tty = optarg; +			break;  		case 'D':  			device = optarg;  			break; @@ -511,101 +307,168 @@ main (int argc, char **argv)  			if (serial_end == optarg || *serial_end != '\0')  				usage(argv[0]);  			break; +		case 'S': +			use_stlink = 1; +			break; +		case 'v': +			verbose++; +			break;  		default:  			usage(argv[0]);  			break;  		}  	} +	ao_self_verbose = verbose; + +	if (verbose > 1) +		ccdbg_add_debug(CC_DEBUG_BITBANG); +  	filename = argv[optind];  	if (filename == NULL)  		usage(argv[0]); -	/* -	 * Open the source file and load the symbols and -	 * flash data -	 */ -	 -	e = ao_open_elf(filename); -	if (!e) { -		fprintf(stderr, "Cannot open file \"%s\"\n", filename); -		exit(1); -	} - -	if (!find_symbols(e)) { -		fprintf(stderr, "Cannot find symbols in \"%s\"\n", filename); -		exit(1); -	} +	if (ends_with (filename, ".elf")) { +		load = ao_load_elf(filename); +	} else if (ends_with (filename, ".ihx")) { +		int	i; +		load = ccdbg_hex_load(filename); +		for (i = 0; i < ao_num_symbols; i++) +			ao_symbols[i].addr = ao_symbols[i].default_addr; +	} else +		usage(argv[0]); -	if (!(load = get_load(e))) { -		fprintf(stderr, "Cannot find program data in \"%s\"\n", filename); -		exit(1); -	} -		 -	/* Connect to the programming dongle -	 */ +	if (use_stlink) { +		/* Connect to the programming dongle +		 */ -	for (tries = 0; tries < 3; tries++) { -		if (device) { -			sl = stlink_v1_open(50); -		} else { -			sl = stlink_open_usb(50); +		for (tries = 0; tries < 3; tries++) { +			if (device) { +				sl = stlink_v1_open(50); +			} else { +				sl = stlink_open_usb(50); +			} +			if (!sl) { +				fprintf (stderr, "No STLink devices present\n"); +				done (sl, NULL, 1); +			} + +			if (sl->chip_id != 0) +				break; +			stlink_reset(sl); +			stlink_close(sl); +			sl = NULL;  		}  		if (!sl) { -			fprintf (stderr, "No STLink devices present\n"); -			done (sl, 1); +			fprintf (stderr, "Debugger connection failed\n"); +			exit(1);  		} -		if (sl->chip_id != 0) -			break; -		stlink_reset(sl); -		stlink_close(sl); -	} -	if (sl->chip_id == 0) { -		fprintf (stderr, "Debugger connection failed\n"); -		done(sl, 1); -	} +		/* Verify that the loaded image fits entirely within device flash +		 */ +		if (load->address < sl->flash_base || +		    sl->flash_base + sl->flash_size < load->address + load->length) { +			fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename, +				 load->address, load->address + load->length); +			done(sl, NULL, 1); +		} -	/* Verify that the loaded image fits entirely within device flash -	 */ -	if (load->addr < sl->flash_base || -	    sl->flash_base + sl->flash_size < load->addr + load->len) { -		fprintf (stderr, "\%s\": Invalid memory range 0x%08x - 0x%08x\n", filename, -			 load->addr, load->addr + load->len); -		done(sl, 1); +		/* Enter debugging mode +		 */ +		if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) +			stlink_exit_dfu_mode(sl); + +		if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) +			stlink_enter_swd_mode(sl); +	} else { +		int	is_loader; +		int	tries; + +		for (tries = 0; tries < 3; tries++) { +			char	*this_tty = tty; +			if (!this_tty) +				this_tty = cc_usbdevs_find_by_arg(device, "AltosFlash"); +			if (!this_tty) +				this_tty = cc_usbdevs_find_by_arg(device, "MegaMetrum"); +			if (!this_tty) +				this_tty = getenv("ALTOS_TTY"); +			if (!this_tty) +				this_tty="/dev/ttyACM0"; + +			cc = cc_usb_open(this_tty); + +			if (!cc) +				exit(1); +			cc_usb_printf(cc, "v\n"); +			is_loader = 0; +			for (;;) { +				char	line[256]; +				cc_usb_getline(cc, line, sizeof(line)); +				if (!strncmp(line, "altos-loader", 12)) +					is_loader = 1; +				if (!strncmp(line, "software-version", 16)) +					break; +			} +			if (is_loader) +				break; +			printf ("rebooting to loader\n"); +			cc_usb_printf(cc, "X\n"); +			cc_usb_close(cc); +			sleep(1); +			cc = NULL; +		} +		if (!is_loader) { +			fprintf(stderr, "Cannot switch to boot loader\n"); +			exit(1); +		} +#if 0 +		{ +			uint8_t	check[256]; +			int	i = 0; + +			ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, check); +			for (;;) { +				uint8_t block[256]; +				putchar ('.'); +				if (++i == 40) { +					putchar('\n'); +					i = 0; +				} +				fflush(stdout); +				ao_self_block_write(cc, AO_BOOT_APPLICATION_BASE, block); +				ao_self_block_read(cc, AO_BOOT_APPLICATION_BASE, block); +				if (memcmp(block, check, 256) != 0) { +					fprintf (stderr, "read differed\n"); +					exit(1); +				} +			} +		} +#endif  	} -	/* Enter debugging mode -	 */ -	if (stlink_current_mode(sl) == STLINK_DEV_DFU_MODE) -		stlink_exit_dfu_mode(sl); - -	if (stlink_current_mode(sl) != STLINK_DEV_DEBUG_MODE) -		stlink_enter_swd_mode(sl); -  	/* Go fetch existing config values  	 * if available  	 */ -	was_flashed = check_flashed(sl); +	was_flashed = check_flashed(sl, cc);  	if (!serial) {  		if (!was_flashed) {  			fprintf (stderr, "Must provide serial number\n"); -			done(sl, 1); +			done(sl, cc, 1);  		} -		serial = get_uint16(sl, AO_SERIAL_NUMBER); +		serial = get_uint16(sl, cc, AO_SERIAL_NUMBER);  		if (!serial || serial == 0xffff) {  			fprintf (stderr, "Invalid existing serial %d\n", serial); -			done(sl, 1); +			done(sl, cc, 1);  		}  	}  	if (!cal && AO_RADIO_CAL && was_flashed) { -		cal = get_uint32(sl, AO_RADIO_CAL); +		cal = get_uint32(sl, cc, AO_RADIO_CAL);  		if (!cal || cal == 0xffffffff) {  			fprintf (stderr, "Invalid existing rf cal %d\n", cal); -			done(sl, 1); +			done(sl, cc, 1);  		}  	} @@ -618,32 +481,31 @@ main (int argc, char **argv)  	if (!rewrite(load, AO_SERIAL_NUMBER, serial_int, sizeof (serial_int))) {  		fprintf(stderr, "Cannot rewrite serial integer at %08x\n",  			AO_SERIAL_NUMBER); -		done(sl, 1); +		done(sl, cc, 1);  	}  	if (AO_USB_DESCRIPTORS) { -		unsigned	usb_descriptors; -		usb_descriptors = AO_USB_DESCRIPTORS - load->addr; +		uint32_t	usb_descriptors = AO_USB_DESCRIPTORS - load->address;  		string_num = 0; -		while (load->buf[usb_descriptors] != 0 && usb_descriptors < load->len) { -			if (load->buf[usb_descriptors+1] == AO_USB_DESC_STRING) { +		while (load->data[usb_descriptors] != 0 && usb_descriptors < load->length) { +			if (load->data[usb_descriptors+1] == AO_USB_DESC_STRING) {  				++string_num;  				if (string_num == 4)  					break;  			} -			usb_descriptors += load->buf[usb_descriptors]; +			usb_descriptors += load->data[usb_descriptors];  		} -		if (usb_descriptors >= load->len || load->buf[usb_descriptors] == 0 ) { +		if (usb_descriptors >= load->length || load->data[usb_descriptors] == 0 ) {  			fprintf(stderr, "Cannot rewrite serial string at %08x\n", AO_USB_DESCRIPTORS); -			done(sl, 1); +			done(sl, cc, 1);  		} -		serial_ucs2_len = load->buf[usb_descriptors] - 2; +		serial_ucs2_len = load->data[usb_descriptors] - 2;  		serial_ucs2 = malloc(serial_ucs2_len);  		if (!serial_ucs2) {  			fprintf(stderr, "Malloc(%d) failed\n", serial_ucs2_len); -			done(sl, 1); +			done(sl, cc, 1);  		}  		s = serial;  		for (i = serial_ucs2_len / 2; i; i--) { @@ -651,9 +513,9 @@ main (int argc, char **argv)  			serial_ucs2[i * 2 - 2] = (s % 10) + '0';  			s /= 10;  		} -		if (!rewrite(load, usb_descriptors + 2 + load->addr, serial_ucs2, serial_ucs2_len)) { +		if (!rewrite(load, usb_descriptors + 2 + load->address, serial_ucs2, serial_ucs2_len)) {  			fprintf (stderr, "Cannot rewrite USB descriptor at %08x\n", AO_USB_DESCRIPTORS); -			done(sl, 1); +			done(sl, cc, 1);  		}  	} @@ -671,10 +533,15 @@ main (int argc, char **argv)  	/* And flash the resulting image to the device  	 */ -	if (stlink_write_flash(sl, load->addr, load->buf, load->len) < 0) { +	if (cc) +		success = ao_self_write(cc, load); +	else +		success = (stlink_write_flash(sl, load->address, load->data, load->length) >= 0); +		 +	if (!success) {  		fprintf (stderr, "\"%s\": Write failed\n", filename); -		done(sl, 1); +		done(sl, cc, 1);  	} -	done(sl, 0); +	done(sl, cc, 0);  } diff --git a/ao-tools/ao-stmload/ao-stmload.h b/ao-tools/ao-stmload/ao-stmload.h new file mode 100644 index 00000000..98884535 --- /dev/null +++ b/ao-tools/ao-stmload/ao-stmload.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_STMLOAD_H_ +#define _AO_STMLOAD_H_ + +struct sym { +	unsigned	addr; +	unsigned	default_addr; +	char		*name; +	int		required; +}; + +#define AO_BOOT_APPLICATION_BASE	0x08001000 + +extern struct sym ao_symbols[]; + +extern int ao_num_symbols; +extern int ao_num_required_symbols; + +void +ao_self_block_read(struct cc_usb *cc, uint32_t address, uint8_t block[256]); + +void +ao_self_block_write(struct cc_usb *cc, uint32_t address, uint8_t block[256]); + +struct hex_image * +ao_self_read(struct cc_usb *cc, uint32_t address, uint32_t length); + +int +ao_self_write(struct cc_usb *cc, struct hex_image *image); + +extern int ao_self_verbose; + +#endif /* _AO_STMLOAD_H_ */ diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c index 485583f9..d7ac138c 100644 --- a/ao-tools/lib/cc-usb.c +++ b/ao-tools/lib/cc-usb.c @@ -123,9 +123,10 @@ cc_handle_hex_read(struct cc_usb *cc)  static void  cc_usb_dbg(int indent, uint8_t *bytes, int len)  { -	int	eol = 1; +	static int	eol = 1;  	int	i;  	uint8_t	c; +	ccdbg_debug(CC_DEBUG_BITBANG, "<<<%d bytes>>>", len);  	while (len--) {  		c = *bytes++;  		if (eol) { @@ -135,10 +136,12 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len)  		}  		switch (c) {  		case '\r': -			ccdbg_debug(CC_DEBUG_BITBANG, "^M"); +			ccdbg_debug(CC_DEBUG_BITBANG, "\\r");  			break;  		case '\n':  			eol = 1; +			ccdbg_debug(CC_DEBUG_BITBANG, "\\n\n"); +			break;  		default:  			if (c < ' ' || c > '~')  				ccdbg_debug(CC_DEBUG_BITBANG, "\\%02x", c); @@ -193,7 +196,6 @@ _cc_usb_sync(struct cc_usb *cc, int wait_for_input)  			ret = read(cc->fd, cc->in_buf + cc->in_count,  				   CC_IN_BUF - cc->in_count);  			if (ret > 0) { -				int i;  				cc_usb_dbg(24, cc->in_buf + cc->in_count, ret);  				cc->in_count += ret;  				if (cc->hex_count) diff --git a/ao-tools/lib/ccdbg-hex.c b/ao-tools/lib/ccdbg-hex.c index dfea9156..184b4e3b 100644 --- a/ao-tools/lib/ccdbg-hex.c +++ b/ao-tools/lib/ccdbg-hex.c @@ -233,15 +233,6 @@ ccdbg_hex_file_free(struct hex_file *hex)  	free(hex);  } -static int -ccdbg_hex_record_compar(const void *av, const void *bv) -{ -	const struct hex_record *a = *(struct hex_record **) av; -	const struct hex_record *b = *(struct hex_record **) bv; - -	return (int) a->address - (int) b->address; -} -  struct hex_file *  ccdbg_hex_file_read(FILE *file, char *name)  { @@ -272,11 +263,6 @@ ccdbg_hex_file_read(FILE *file, char *name)  		if (record->type == HEX_RECORD_EOF)  			done = 1;  	} -	/* -	 * Sort them into increasing addresses, except for EOF -	 */ -	qsort(hex->records, hex->nrecord - 1, sizeof (struct hex_record *), -	      ccdbg_hex_record_compar);  	return hex;  bail: @@ -288,16 +274,45 @@ struct hex_image *  ccdbg_hex_image_create(struct hex_file *hex)  {  	struct hex_image *image; -	struct hex_record *first, *last, *record; +	struct hex_record *record;  	int i; +	uint32_t addr;  	uint32_t base, bound;  	uint32_t offset; +	uint32_t extended_addr; +  	int length; -	first = hex->records[0]; -	last = hex->records[hex->nrecord - 2];	/* skip EOF */ -	base = (uint32_t) first->address; -	bound = (uint32_t) last->address + (uint32_t) last->length; +	base = 0xffffffff; +	bound = 0x0; +	extended_addr = 0; +	for (i = 0; i < hex->nrecord; i++) { +		uint32_t r_bound; +		record = hex->records[i]; +		switch (record->type) { +		case 0: +			addr = extended_addr + record->address; +			r_bound = addr + record->length; +			if (addr < base) +				base = addr; +			if (r_bound > bound) +				bound = r_bound; +			break; +		case 1: +			break; +		case 2: +			if (record->length != 2) +				return NULL; +			extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; +			break; +		case 4: +			if (record->length != 2) +				return NULL; +			extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; +			break; +		} + +	}  	length = bound - base;  	image = calloc(sizeof(struct hex_image) + length, 1);  	if (!image) @@ -305,10 +320,24 @@ ccdbg_hex_image_create(struct hex_file *hex)  	image->address = base;  	image->length = length;  	memset(image->data, 0xff, length); -	for (i = 0; i < hex->nrecord - 1; i++) { +	extended_addr = 0; +	for (i = 0; i < hex->nrecord; i++) {  		record = hex->records[i]; -		offset = record->address - base; -		memcpy(image->data + offset, record->data, record->length); +		switch (record->type) { +		case 0: +			addr = extended_addr + record->address; +			offset = addr - base; +			memcpy(image->data + offset, record->data, record->length); +			break; +		case 1: +			break; +		case 2: +			extended_addr = ((record->data[0] << 8) | record->data[1]) << 4; +			break; +		case 4: +			extended_addr = ((record->data[0] << 8) | record->data[1]) << 16; +			break; +		}  	}  	return image;  } @@ -328,3 +357,25 @@ ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b)  		return 0;  	return 1;  } + +struct hex_image * +ccdbg_hex_load(char *filename) +{ +	FILE *file; +	struct hex_file	*hex_file; +	struct hex_image *hex_image; + +	file = fopen (filename, "r"); +	if (!file) +		return 0; +	 +	hex_file = ccdbg_hex_file_read(file, filename); +	fclose(file); +	if (!hex_file) +		return 0; +	hex_image = ccdbg_hex_image_create(hex_file); +	if (!hex_image) +		return 0; +	ccdbg_hex_file_free(hex_file); +	return hex_image; +} diff --git a/ao-tools/lib/ccdbg.h b/ao-tools/lib/ccdbg.h index ca596143..a27ff5d1 100644 --- a/ao-tools/lib/ccdbg.h +++ b/ao-tools/lib/ccdbg.h @@ -122,8 +122,8 @@ struct hex_file {  };  struct hex_image { -	uint16_t	address; -	uint16_t	length; +	uint32_t	address; +	uint32_t	length;  	uint8_t		data[0];  }; @@ -253,6 +253,9 @@ ccdbg_hex_image_create(struct hex_file *hex);  void  ccdbg_hex_image_free(struct hex_image *image); +struct hex_image * +ccdbg_hex_load(char *filename); +  int  ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); diff --git a/src/Makefile b/src/Makefile index 90a74166..5ae61a00 100644 --- a/src/Makefile +++ b/src/Makefile @@ -29,7 +29,12 @@ AVRDIRS=\  	telescience-v0.1 telescience-pwm telepyro-v0.1 micropeak  ARMDIRS=\ -	telemega-v0.1 telemega-v0.3 megadongle-v0.1 stm-bringup stm-demo telelco-v0.1 \ +	telemega-v0.1 telemega-v0.1/flash-loader \ +	telemega-v0.3 telemega-v0.3/flash-loader \ +	megadongle-v0.1 megadongle-v0.1/flash-loader \ +	telegps-v0.1 telegps-v0.1/flash-loader \ +	stm-bringup stm-demo telelco-v0.1 \ +	telelco-v0.2 telelco-v0.2/flash-loader \  	telescience-v0.2  ifneq ($(shell which sdcc),) diff --git a/src/attiny/ao_arch.h b/src/attiny/ao_arch.h index 52bed981..8140dd30 100644 --- a/src/attiny/ao_arch.h +++ b/src/attiny/ao_arch.h @@ -55,7 +55,7 @@  #define putchar(c)	ao_putchar(c)  #define getchar		ao_getchar -#define ao_arch_cpu_idle() do {			\ +#define ao_arch_wait_interrupt() do {		\  		sleep_enable();			\  		sei();				\  		sleep_cpu();			\ diff --git a/src/avr/ao_avr_stdio.c b/src/avr/ao_avr_stdio.c index 2765853a..f9c0f88c 100644 --- a/src/avr/ao_avr_stdio.c +++ b/src/avr/ao_avr_stdio.c @@ -20,16 +20,7 @@  int  stdio_put(char c, FILE *stream)  { -	if (ao_cur_task && ao_num_stdios) -		putchar(c); -	else -	{ -		if (c == '\n') -			stdio_put('\r', stream); -		loop_until_bit_is_set(UCSR1A, UDRE1); -		UDR1 = c; -	} - +	putchar(c);  	return 0;  } diff --git a/src/core/ao.h b/src/core/ao.h index 6bcb3664..0ad3e4aa 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -45,6 +45,8 @@  #if HAS_TASK  #include <ao_task.h> +#else +#include <ao_notask.h>  #endif  /* diff --git a/src/core/ao_cmd.c b/src/core/ao_cmd.c index 6eed08d9..188b8bb4 100644 --- a/src/core/ao_cmd.c +++ b/src/core/ao_cmd.c @@ -16,6 +16,7 @@   */  #include "ao.h" +#include "ao_task.h"  __pdata uint16_t ao_cmd_lex_i;  __pdata uint32_t ao_cmd_lex_u32; @@ -262,6 +263,11 @@ ao_reboot(void)  	ao_panic(AO_PANIC_REBOOT);  } +#ifndef HAS_VERSION +#define HAS_VERSION 1 +#endif + +#if HAS_VERSION  static void  version(void)  { @@ -289,6 +295,7 @@ version(void)  #endif  	printf("software-version %s\n", ao_version);  } +#endif  #ifndef NUM_CMDS  #define NUM_CMDS	11 @@ -378,14 +385,33 @@ ao_cmd(void)  	}  } +#if HAS_BOOT_LOADER + +#include <ao_boot.h> + +static void +ao_loader(void) +{ +	flush(); +	ao_boot_loader(); +} +#endif +  __xdata struct ao_task ao_cmd_task;  __code struct ao_cmds	ao_base_cmds[] = {  	{ help,		"?\0Help" }, +#if HAS_TASK_INFO  	{ ao_task_info,	"T\0Tasks" }, +#endif  	{ echo,		"E <0 off, 1 on>\0Echo" },  	{ ao_reboot,	"r eboot\0Reboot" }, +#if HAS_VERSION  	{ version,	"v\0Version" }, +#endif +#if HAS_BOOT_LOADER +	{ ao_loader,	"X\0Switch to boot loader" }, +#endif  	{ 0,	NULL },  }; diff --git a/src/micropeak/ao_notask.c b/src/core/ao_notask.c index 0aef9cf3..a41712d2 100644 --- a/src/micropeak/ao_notask.c +++ b/src/core/ao_notask.c @@ -24,7 +24,7 @@ ao_sleep(__xdata void *wchan)  {  #if 1  	ao_wchan = wchan; -	ao_arch_cpu_idle(); +	ao_arch_wait_interrupt();  #else  	uint8_t	sreg; diff --git a/src/core/ao_notask.h b/src/core/ao_notask.h new file mode 100644 index 00000000..6b6b5bb8 --- /dev/null +++ b/src/core/ao_notask.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_NOTASK_H_ +#define _AO_NOTASK_H_ + +uint8_t +ao_sleep(__xdata void *wchan); + +void +ao_wakeup(__xdata void *wchan); + +#endif /* _AO_NOTASK_H_ */ diff --git a/src/core/ao_stdio.c b/src/core/ao_stdio.c index 977d74b1..cd144d6b 100644 --- a/src/core/ao_stdio.c +++ b/src/core/ao_stdio.c @@ -66,8 +66,15 @@  #define AO_NUM_STDIOS	(HAS_USB + PACKET_HAS_SLAVE + USE_SERIAL_STDIN)  __xdata struct ao_stdio ao_stdios[AO_NUM_STDIOS]; + +#if AO_NUM_STDIOS > 1  __pdata int8_t ao_cur_stdio;  __pdata int8_t ao_num_stdios; +#else +__pdata int8_t ao_cur_stdio; +#define ao_cur_stdio	0 +#define ao_num_stdios	0 +#endif  void  putchar(char c) @@ -107,12 +114,16 @@ getchar(void) __reentrant  		c = ao_stdios[stdio]._pollchar();  		if (c != AO_READ_AGAIN)  			break; +#if AO_NUM_STDIOS > 1  		if (++stdio == ao_num_stdios)  			stdio = 0;  		if (stdio == ao_cur_stdio) +#endif  			ao_sleep(&ao_stdin_ready);  	} +#if AO_NUM_STDIOS > 1  	ao_cur_stdio = stdio; +#endif  	ao_arch_release_interrupts();  	return c;  } @@ -128,11 +139,17 @@ ao_add_stdio(int (*_pollchar)(void),  	     void (*putchar)(char),  	     void (*flush)(void)) __reentrant  { +#if AO_NUM_STDIOS > 1  	if (ao_num_stdios == AO_NUM_STDIOS)  		ao_panic(AO_PANIC_STDIO); +#endif  	ao_stdios[ao_num_stdios]._pollchar = _pollchar;  	ao_stdios[ao_num_stdios].putchar = putchar;  	ao_stdios[ao_num_stdios].flush = flush;  	ao_stdios[ao_num_stdios].echo = 1; +#if AO_NUM_STDIOS > 1  	return ao_num_stdios++; +#else +	return 0; +#endif  } diff --git a/src/core/ao_task.c b/src/core/ao_task.c index c24c9929..0aad6508 100644 --- a/src/core/ao_task.c +++ b/src/core/ao_task.c @@ -512,6 +512,7 @@ ao_exit(void)  	/* we'll never get back here */  } +#if HAS_TASK_INFO  void  ao_task_info(void)  { @@ -528,6 +529,7 @@ ao_task_info(void)  	ao_task_validate();  #endif  } +#endif  void  ao_start_scheduler(void) diff --git a/src/core/ao_task.h b/src/core/ao_task.h index 50bfb220..1a4b5b6b 100644 --- a/src/core/ao_task.h +++ b/src/core/ao_task.h @@ -21,6 +21,10 @@  #include <ao_list.h>  #endif +#ifndef HAS_TASK_INFO +#define HAS_TASK_INFO 1 +#endif +  /* An AltOS task */  struct ao_task {  	__xdata void *wchan;		/* current wait channel (NULL if running) */ diff --git a/src/megadongle-v0.1/Makefile b/src/megadongle-v0.1/Makefile index fe392ce1..7f12963f 100644 --- a/src/megadongle-v0.1/Makefile +++ b/src/megadongle-v0.1/Makefile @@ -28,6 +28,7 @@ INC = \  #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ diff --git a/src/megadongle-v0.1/flash-loader/Makefile b/src/megadongle-v0.1/flash-loader/Makefile new file mode 100644 index 00000000..adea5786 --- /dev/null +++ b/src/megadongle-v0.1/flash-loader/Makefile @@ -0,0 +1,7 @@ +# +# AltOS flash loader build +# + +TOPDIR=../.. +HARDWARE=megadongle-v0.1 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/megadongle-v0.1/flash-loader/ao_pins.h b/src/megadongle-v0.1/flash-loader/ao_pins.h new file mode 100644 index 00000000..1af92f13 --- /dev/null +++ b/src/megadongle-v0.1/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Companion port cs_companion0 PD0 */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiod +#define AO_BOOT_APPLICATION_PIN		0 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/product/ao_flash_pins.h b/src/product/ao_flash_pins.h new file mode 100644 index 00000000..b774df6d --- /dev/null +++ b/src/product/ao_flash_pins.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_FLASH_PINS_H_ +#define _AO_FLASH_PINS_H_ + +/* Common definitions for the USB flash loader */ + +#define HAS_TASK_QUEUE		0 + +#define HAS_USB			1 +#define USE_USB_STDIO		0 +#define HAS_BEEP		0 +#define HAS_TASK		0 +#define HAS_ECHO		0 +#define HAS_TICK		0 + +#define PACKET_HAS_SLAVE	0 + +#define HAS_TASK_INFO		0 +#define HAS_VERSION		0 + +#define AO_BOOT_CHAIN		1 +#define AO_BOOT_PIN		1 + +#endif /* _AO_FLASH_PINS_H_ */ diff --git a/src/stm-flash/ao_stm_flash.c b/src/product/ao_flash_task.c index df466d85..fdc4d0aa 100644 --- a/src/stm-flash/ao_stm_flash.c +++ b/src/product/ao_flash_task.c @@ -1,5 +1,5 @@  /* - * Copyright © 2011 Keith Packard <keithp@keithp.com> + * Copyright © 2013 Keith Packard <keithp@keithp.com>   *   * This program is free software; you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -18,54 +18,70 @@  #include "ao.h"  #include <ao_exti.h>  #include <ao_boot.h> -#include <ao_flash_stm.h> +#include <ao_flash.h> +#include <ao_flash_task.h>  void  ao_panic(uint8_t reason)  { -	for (;;);  }  void +ao_put_string(__code char *s) +{ +	char	c; +	while ((c = *s++)) { +		if (c == '\n') +			ao_usb_putchar('\r'); +		ao_usb_putchar(c); +	} +} + +static void  ao_application(void)  {  	ao_boot_reboot(AO_BOOT_APPLICATION_BASE);  }  static uint32_t -ao_cmd_hex32(void) +ao_get_hex32(void)  { -	__pdata uint8_t	r = ao_cmd_lex_error;  	int8_t	n;  	uint32_t v = 0; -	ao_cmd_white(); +	for (;;) { +		n = ao_usb_getchar(); +		if (n != ' ') +			break; +	}  	for(;;) { -		n = ao_cmd_hexchar(ao_cmd_lex_c); -		if (n < 0) +		if ('0' <= n && n <= '9') +			n = n - '0'; +		else if ('a' <= n && n <= 'f') +			n = n - ('a' - 10); +		else if ('A' <= n && n <= 'F') +			n = n - ('A' - 10); +		else  			break;  		v = (v << 4) | n; -		r = ao_cmd_success; -		ao_cmd_lex(); +		n = ao_usb_getchar();  	} -	if (r != ao_cmd_success) -		ao_cmd_status = r;  	return v;  } -void +static void  ao_block_erase(void)  { -	uint32_t	addr = ao_cmd_hex32(); +	uint32_t	addr = ao_get_hex32();  	uint32_t	*p = (uint32_t *) addr;  	ao_flash_erase_page(p);  } -void +static void  ao_block_write(void)  { -	uint32_t	addr = ao_cmd_hex32(); +	uint32_t	addr = ao_get_hex32();  	uint32_t	*p = (uint32_t *) addr;  	union {  		uint8_t		data8[256]; @@ -73,65 +89,49 @@ ao_block_write(void)  	} u;  	uint16_t	i; -	if (addr < 0x08002000 || 0x08200000 <= addr) { -		puts("Invalid address"); +	if (addr < (uint32_t) AO_BOOT_APPLICATION_BASE) { +		ao_put_string("Invalid address\n");  		return;  	}  	for (i = 0; i < 256; i++) -		u.data8[i] = i; +		u.data8[i] = ao_usb_getchar();  	ao_flash_page(p, u.data32);  }  static void -puthex(uint8_t c) -{ -	c &= 0xf; -	if (c < 10) -		c += '0'; -	else -		c += 'a' - 10; -	putchar (c); -} - -void  ao_block_read(void)  { -	uint32_t	addr = ao_cmd_hex32(); +	uint32_t	addr = ao_get_hex32();  	uint8_t		*p = (uint8_t *) addr;  	uint16_t	i;  	uint8_t		c;  	for (i = 0; i < 256; i++) {  		c = *p++; -		puthex(c); -		puthex(c>>4); -		if ((i & 0xf) == 0xf) -			putchar('\n'); +		ao_usb_putchar(c);  	}  } -__code struct ao_cmds ao_flash_cmds[] = { -	{ ao_application, "a\0Switch to application" }, -	{ ao_block_erase, "e <addr>\0Erase block." }, -	{ ao_block_write, "W <addr>\0Write block. 256 binary bytes follow newline" }, -	{ ao_block_read, "R <addr>\0Read block. Returns 256 bytes" }, -	{ 0, NULL }, -}; - -int -main(void) +static void +ao_show_version(void)  { -	ao_clock_init(); - -	ao_task_init(); - -	ao_timer_init(); -//	ao_dma_init(); -	ao_cmd_init(); -//	ao_exti_init(); -	ao_usb_init(); +	ao_put_string("altos-loader"); +	ao_put_string("\nmanufacturer     "); ao_put_string(ao_manufacturer); +	ao_put_string("\nproduct          "); ao_put_string(ao_product); +	ao_put_string("\nsoftware-version "); ao_put_string(ao_version); +	ao_put_string("\n"); +} -	ao_cmd_register(&ao_flash_cmds[0]); -	ao_start_scheduler(); -	return 0; +void +ao_flash_task(void) { +	for (;;) { +		ao_usb_flush(); +		switch (ao_usb_getchar()) { +		case 'v': ao_show_version(); break; +		case 'a': ao_application(); break; +		case 'X': ao_block_erase(); break; +		case 'W': ao_block_write(); break; +		case 'R': ao_block_read(); break; +		} +	}  } diff --git a/src/product/ao_flash_task.h b/src/product/ao_flash_task.h new file mode 100644 index 00000000..0a2fbb35 --- /dev/null +++ b/src/product/ao_flash_task.h @@ -0,0 +1,24 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_FLASH_TASK_H_ +#define _AO_FLASH_TASK_H_ + +void +ao_flash_task(void); + +#endif /* _AO_FLASH_TASK_H_ */ diff --git a/src/stm-bringup/ao.h b/src/stm-bringup/ao.h index 27204fae..2c7d5282 100644 --- a/src/stm-bringup/ao.h +++ b/src/stm-bringup/ao.h @@ -16,3 +16,5 @@   */  #define ao_panic(n)	for(;;); + +#define AO_BOOT_LOADER_BASE               ((uint32_t *) 0x0) diff --git a/src/stm-demo/Makefile b/src/stm-demo/Makefile index 3b1b671b..d1f825db 100644 --- a/src/stm-demo/Makefile +++ b/src/stm-demo/Makefile @@ -17,6 +17,7 @@ INC = \  #  ALTOS_SRC = \  	ao_interrupt.c \ +	ao_boot_chain.c \  	ao_product.c \  	ao_romconfig.c \  	ao_cmd.c \ @@ -46,17 +47,19 @@ IDPRODUCT=0x000a  CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os -PROG=stm-demo +PROG=stm-demo-$(VERSION) +ELF=$(PROG).elf +IHX=$(PROG).ihx  SRC=$(ALTOS_SRC) ao_demo.c  OBJ=$(SRC:.c=.o) -all: $(PROG) +all: $(ELF) $(IHX)  LDFLAGS=-L../stm -Wl,-Taltos.ld -$(PROG): Makefile $(OBJ) -	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc +$(ELF): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $@ $(OBJ) $(SAT_CLIB) -lgcc  ao_product.h: ao-make-product.5c ../Version  	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ diff --git a/src/stm-demo/ao_demo.c b/src/stm-demo/ao_demo.c index 9ee0be03..5677cdf4 100644 --- a/src/stm-demo/ao_demo.c +++ b/src/stm-demo/ao_demo.c @@ -20,6 +20,7 @@  #include <ao_event.h>  #include <ao_quadrature.h>  #include <ao_button.h> +#include <ao_boot.h>  struct ao_task demo_task; diff --git a/src/stm-demo/ao_pins.h b/src/stm-demo/ao_pins.h index 07b4a19d..40e48a36 100644 --- a/src/stm-demo/ao_pins.h +++ b/src/stm-demo/ao_pins.h @@ -68,6 +68,8 @@  #define HAS_BEEP		0  #define PACKET_HAS_SLAVE	0 +#define AO_BOOT_CHAIN		1 +  #define LOW_LEVEL_DEBUG		1  #define LED_PORT_ENABLE		STM_RCC_AHBENR_GPIOBEN diff --git a/src/stm-flash/Makefile b/src/stm-flash/Makefile new file mode 100644 index 00000000..1ea35581 --- /dev/null +++ b/src/stm-flash/Makefile @@ -0,0 +1,59 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pins.h \ +	ao_product.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ +	ao_interrupt.c \ +	ao_boot_chain.c \ +	ao_boot_pin.c \ +	ao_product.c \ +	ao_notask.c \ +	ao_timer.c \ +	ao_usb_stm.c \ +	ao_flash_stm.c + +PRODUCT=AltosFlash-$(VERSION) +PRODUCT_DEF=-DALTOS_FLASH +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os + +PROG=altos-flash-$(VERSION).elf + +SRC=$(ALTOS_SRC) ao_stm_flash.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) + +LDFLAGS=-L../stm -Wl,-Taltos-loader.ld + +$(PROG): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean:	clean + +clean: +	rm -f *.o $(PROG) +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stm-flash/ao_pins.h b/src/stm-flash/ao_pins.h new file mode 100644 index 00000000..d6c72653 --- /dev/null +++ b/src/stm-flash/ao_pins.h @@ -0,0 +1,79 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		0 + +/* Bridge SB17 on the board and use the MCO from the other chip */ +#define AO_HSE		8000000 +#define AO_HSE_BYPASS		1 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHZ (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER	1 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER      	1 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +#define HAS_USB			1 +#define USE_USB_STDIO		0 +#define HAS_BEEP		0 +#define HAS_TASK		0 +#define HAS_ECHO		0 +#define HAS_TICK		0 + +#define PACKET_HAS_SLAVE	0 + +#define LED_PORT_ENABLE		STM_RCC_AHBENR_GPIOCEN +#define LED_PORT		(&stm_gpiob) +#define LED_PIN_RED		6 +#define LED_PIN_GREEN		7 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_GREEN) + +#define AO_TICK_TYPE		uint32_t +#define AO_TICK_SIGNED		int32_t + +#define HAS_TASK_INFO		0 +#define HAS_VERSION		0 + +#define AO_BOOT_CHAIN		1 +#define AO_BOOT_PIN		1 + +#define AO_BOOT_APPLICATION_GPIO	stm_gpiod +#define AO_BOOT_APPLICATION_PIN		2 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/stm/Makefile-flash.defs b/src/stm/Makefile-flash.defs new file mode 100644 index 00000000..016bb7e7 --- /dev/null +++ b/src/stm/Makefile-flash.defs @@ -0,0 +1,92 @@ +vpath % $(TOPDIR)/stm:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/core:$(TOPDIR)/util:$(TOPDIR) +vpath ao-make-product.5c $(TOPDIR)/util + +.SUFFIXES: .elf .ihx + +.elf.ihx: +	objcopy -O ihex $*.elf $@ + +CC=arm-none-eabi-gcc +SAT=/opt/cortex +SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a +SAT_CFLAGS=-I$(SAT)/include + +ifndef VERSION +include $(TOPDIR)/Version +endif + +AO_CFLAGS=-I. -I$(TOPDIR)/stm -I$(TOPDIR)/core -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) +STM_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS) + +LDFLAGS=-L$(TOPDIR)/stm -Wl,-Taltos-loader.ld + +NICKLE=nickle + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf "  $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +.c.o: +	$(call quiet,CC) -c $(CFLAGS) -o $@ $< + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_flash_pins.h \ +	ao_flash_stm_pins.h \ +	ao_flash_task.h \ +	ao_pins.h \ +	ao_product.h \ +	Makefile + +# +# Common AltOS sources +# +SRC = \ +	ao_interrupt.c \ +	ao_romconfig.c \ +	ao_boot_chain.c \ +	ao_boot_pin.c \ +	ao_product.c \ +	ao_notask.c \ +	ao_timer.c \ +	ao_usb_stm.c \ +	ao_flash_stm.c \ +	ao_flash_task.c \ +	ao_flash_loader_stm.c + +OBJ=$(SRC:.c=.o) + +PRODUCT=AltosFlash-$(VERSION) +PRODUCT_DEF=-DALTOS_FLASH +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -g -Os + +PROGNAME=altos-flash +PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf + +$(PROG): Makefile $(OBJ) altos-loader.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(SAT_CLIB) -lgcc + +ao_product.h: ao-make-product.5c $(TOPDIR)/Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +all: $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROG) +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stm/Makefile.defs b/src/stm/Makefile.defs index 1480f0b3..c8bb7d70 100644 --- a/src/stm/Makefile.defs +++ b/src/stm/Makefile.defs @@ -7,6 +7,11 @@ vpath load_csv.5c ../kalman  vpath matrix.5c ../kalman  vpath ao-make-product.5c ../util +.SUFFIXES: .elf .ihx + +.elf.ihx: +	objcopy -O ihex $*.elf $@ +  CC=arm-none-eabi-gcc  SAT=/opt/cortex  SAT_CLIB=$(SAT)/lib/pdclib-cortex-m3.a diff --git a/src/stm/altos-loader.ld b/src/stm/altos-loader.ld new file mode 100644 index 00000000..2be964f2 --- /dev/null +++ b/src/stm/altos-loader.ld @@ -0,0 +1,94 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +MEMORY { +	rom : ORIGIN = 0x08000000, LENGTH = 4K +	ram : ORIGIN = 0x20000000, LENGTH = 16K +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.text : { +		__text_start__ = .; +		*(.interrupt)	/* Interrupt vectors */ + +		. = ORIGIN(rom) + 0x100; + +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) +		*(.text)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ +		__text_end__ = .; +	} > rom + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		__boot_end__ = .; +	} >ram + +	/* Functions placed in RAM (required for flashing) +	 * +	 * Align to 8 bytes as that's what the ARM likes text +	 * segment alignments to be, and if we don't, then +	 * we end up with a mismatch between the location in +	 * ROM and the desired location in RAM. I don't +	 * entirely understand this, but at least this appears +	 * to work... +	 */ + +	.textram BLOCK(8): { +		__data_start__ = .; +		__text_ram_start__ = .; +		*(.text.ram) +		__text_ram_end = .; +	} >ram AT>rom + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		*(.data)	/* initialized data */ +		__data_end__ = .; +	} >ram AT>rom + + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		__bss_end__ = .; +	} >ram + +	PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram)); +	PROVIDE(end = .); +} + +ENTRY(start); + + diff --git a/src/stm/altos.ld b/src/stm/altos.ld index d218e992..3106cc3b 100644 --- a/src/stm/altos.ld +++ b/src/stm/altos.ld @@ -16,7 +16,7 @@   */  MEMORY { -	rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K +	rom (rx) : ORIGIN = 0x08001000, LENGTH = 124K  	ram (!w) : ORIGIN = 0x20000000, LENGTH = 15872  	stack (!w) : ORIGIN = 0x20003e00, LENGTH = 512  } @@ -36,9 +36,19 @@ SECTIONS {  		. = ORIGIN(rom) + 0x100; + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */  		ao_romconfig.o(.romconfig*)  		ao_product.o(.romconfig*) -  		*(.text*)	/* Executable code */  		*(.rodata*)	/* Constants */ @@ -46,21 +56,34 @@ SECTIONS {  	.ARM.exidx : {  		*(.ARM.exidx* .gnu.linkonce.armexidx.*) -		__text_end__ = .;  	} > rom +	__text_end__ = .; + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram  	/* Data -- relocated to RAM, but written to ROM  	 */ -	.data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) { +	.data : {  		__data_start__ = .;  		*(.data)	/* initialized data */ +		. = ALIGN(4);  		__data_end__ = .; -		__bss_start__ = .; -	} >ram +	} >ram AT>rom  	.bss : { +		__bss_start__ = .;  		*(.bss)  		*(COMMON) +		. = ALIGN(4);  		__bss_end__ = .;  	} >ram diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index 27a942f2..adc288c3 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -88,6 +88,10 @@ extern const uint32_t ao_radio_cal;   * For now, we're running at a weird frequency   */ +#ifndef AO_HSE +#error High speed frequency undefined +#endif +  #if AO_HSE  #define AO_PLLSRC	AO_HSE  #else @@ -129,5 +133,10 @@ extern const uint32_t	ao_radio_cal;  void  ao_adc_init(); +#define AO_BOOT_APPLICATION_BASE	((uint32_t *) 0x08001000) +#define AO_BOOT_LOADER_BASE		((uint32_t *) 0x0) +#define HAS_BOOT_LOADER			1 +  #endif /* _AO_ARCH_H_ */ + diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index f3d68202..1e78cabc 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -113,6 +113,19 @@ ao_spi_init(void);  			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN); \  	} while (0) +#define ao_disable_port(port) do {					\ +		if ((port) == &stm_gpioa)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_GPIOAEN); \ +		else if ((port) == &stm_gpiob)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_GPIOBEN); \ +		else if ((port) == &stm_gpioc)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_GPIOCEN); \ +		else if ((port) == &stm_gpiod)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_GPIODEN); \ +		else if ((port) == &stm_gpioe)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_GPIOEEN); \ +	} while (0) +  #define ao_gpio_set(port, bit, pin, v) stm_gpio_set(port, bit, v) @@ -124,9 +137,7 @@ ao_spi_init(void);  		stm_moder_set(port, bit, STM_MODER_OUTPUT);\  	} while (0) -#define ao_enable_input(port,bit,mode) do {				\ -		ao_enable_port(port);					\ -		stm_moder_set(port, bit, STM_MODER_INPUT);		\ +#define ao_gpio_set_mode(port,bit,mode) do {				\  		if (mode == AO_EXTI_MODE_PULL_UP)			\  			stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP);	\  		else if (mode == AO_EXTI_MODE_PULL_DOWN)		\ @@ -134,6 +145,12 @@ ao_spi_init(void);  		else							\  			stm_pupdr_set(port, bit, STM_PUPDR_NONE);	\  	} while (0) +	 +#define ao_enable_input(port,bit,mode) do {				\ +		ao_enable_port(port);					\ +		stm_moder_set(port, bit, STM_MODER_INPUT);		\ +		ao_gpio_set_mode(port, bit, mode);			\ +	} while (0)  #define ao_enable_cs(port,bit) do {				\  		stm_gpio_set((port), bit, 1);			\ @@ -250,6 +267,7 @@ ao_arch_memory_barrier() {  	asm volatile("" ::: "memory");  } +#if HAS_TASK  static inline void  ao_arch_init_stack(struct ao_task *task, void *start)  { @@ -332,6 +350,8 @@ static inline void ao_arch_start_scheduler(void) {  #define ao_arch_isr_stack() +#endif +  #define ao_arch_wait_interrupt() do {			\  		asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");	\  		ao_arch_release_interrupts();				\ diff --git a/src/stm/ao_boot.h b/src/stm/ao_boot.h new file mode 100644 index 00000000..e0ed4de7 --- /dev/null +++ b/src/stm/ao_boot.h @@ -0,0 +1,39 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_BOOT_H_ +#define _AO_BOOT_H_ + +void +ao_boot_chain(uint32_t *base); + +void +ao_boot_check_pin(void); + +/* Return true to switch to application (if present) */ +int +ao_boot_check_chain(void); + +void +ao_boot_reboot(uint32_t *base); + +static inline void +ao_boot_loader(void) { +	ao_boot_reboot(AO_BOOT_LOADER_BASE); +} + +#endif /* _AO_BOOT_H_ */ diff --git a/src/stm/ao_boot_chain.c b/src/stm/ao_boot_chain.c new file mode 100644 index 00000000..6a3864a7 --- /dev/null +++ b/src/stm/ao_boot_chain.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_boot.h> + +void +ao_boot_chain(uint32_t *base) +{ +	uint32_t	sp; +	uint32_t	pc; + +	sp = base[0]; +	pc = base[1]; +	if (0x08000100 <= pc && pc <= 0x08200000 && (pc & 1) == 1) { +		asm ("mov sp, %0" : : "r" (sp)); +		asm ("mov lr, %0" : : "r" (pc)); +		asm ("bx lr"); +	} +} + +#define AO_BOOT_SIGNAL	0x5a5aa5a5 +#define AO_BOOT_CHECK	0xc3c33c3c + +struct ao_boot { +	uint32_t	*base; +	uint32_t	signal; +	uint32_t	check; +}; + +static struct ao_boot __attribute__ ((section(".boot"))) ao_boot; +	 +int +ao_boot_check_chain(void) +{ +	if (ao_boot.signal == AO_BOOT_SIGNAL && ao_boot.check == AO_BOOT_CHECK) { +		ao_boot.signal = 0; +		ao_boot.check = 0; +		if (ao_boot.base == 0) +			return 0; +		ao_boot_chain(ao_boot.base); +	} +	return 1; +} + +void +ao_boot_reboot(uint32_t *base) +{ +	ao_boot.base = base; +	ao_boot.signal = AO_BOOT_SIGNAL; +	ao_boot.check = AO_BOOT_CHECK; +	ao_arch_reboot(); +} diff --git a/src/stm/ao_boot_pin.c b/src/stm/ao_boot_pin.c new file mode 100644 index 00000000..1000a65a --- /dev/null +++ b/src/stm/ao_boot_pin.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_boot.h> +#include <ao_exti.h> + +void +ao_boot_check_pin(void) +{ +	uint16_t v; + +	/* Enable power interface clock */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); +	 +	/* Enable the input pin */ +	ao_enable_input(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, +			AO_BOOT_APPLICATION_MODE); + +	for (v = 0; v < 100; v++) +		ao_arch_nop(); + +	/* Read the value */ +	v = stm_gpio_get(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN); + +	/* Reset the chip to turn off the port and the power interface clock */ +	ao_gpio_set_mode(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0); +	ao_disable_port(&AO_BOOT_APPLICATION_GPIO); +	stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN); +	if (v == AO_BOOT_APPLICATION_VALUE) +		ao_boot_chain(AO_BOOT_APPLICATION_BASE); +} diff --git a/src/stm/ao_flash.h b/src/stm/ao_flash.h new file mode 100644 index 00000000..09ca5ac1 --- /dev/null +++ b/src/stm/ao_flash.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_FLASH_STM_H_ +#define _AO_FLASH_STM_H_ + +void +ao_flash_erase_page(uint32_t *page); + +void +ao_flash_page(uint32_t *page, uint32_t *src); + +#endif /* _AO_FLASH_STM_H_ */ diff --git a/src/stm/ao_flash_loader_stm.c b/src/stm/ao_flash_loader_stm.c new file mode 100644 index 00000000..2ab548cf --- /dev/null +++ b/src/stm/ao_flash_loader_stm.c @@ -0,0 +1,32 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include <ao_exti.h> +#include <ao_boot.h> +#include <ao_flash_task.h> + +int +main(void) +{ +	ao_clock_init(); + +	ao_usb_init(); + +	ao_flash_task(); +	return 0; +} diff --git a/src/stm/ao_flash_stm.c b/src/stm/ao_flash_stm.c new file mode 100644 index 00000000..d7a85582 --- /dev/null +++ b/src/stm/ao_flash_stm.c @@ -0,0 +1,127 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include <ao.h> +#include <ao_flash.h> + +static uint8_t +ao_flash_pecr_is_locked(void) +{ +	return (stm_flash.pecr & (1 << STM_FLASH_PECR_PELOCK)) != 0; +} + +static uint8_t +ao_flash_pgr_is_locked(void) +{ +	return (stm_flash.pecr & (1 << STM_FLASH_PECR_PRGLOCK)) != 0; +} + +static void +ao_flash_pecr_unlock(void) +{ +	if (!ao_flash_pecr_is_locked()) +		return; + +	/* Unlock Data EEPROM and FLASH_PECR register */ +	stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY1; +	stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY2; +	if (ao_flash_pecr_is_locked()) +		ao_panic(AO_PANIC_FLASH); +} + +static void +ao_flash_pgr_unlock(void) +{ +	if (!ao_flash_pgr_is_locked()) +		return; + +	/* Unlock program memory */ +	stm_flash.prgkeyr = STM_FLASH_PRGKEYR_PRGKEY1; +	stm_flash.prgkeyr = STM_FLASH_PRGKEYR_PRGKEY2; +	if (ao_flash_pgr_is_locked()) +		ao_panic(AO_PANIC_FLASH); +} + +static void +ao_flash_lock(void) +{ +	stm_flash.pecr |= (1 << STM_FLASH_PECR_OPTLOCK) | (1 << STM_FLASH_PECR_PRGLOCK) | (1 << STM_FLASH_PECR_PELOCK); +} + +static void +ao_flash_wait_bsy(void) +{ +	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) +		; +} + +static void __attribute__ ((section(".text.ram"),noinline)) +_ao_flash_erase_page(uint32_t *page) +{ +	stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG); +	 +	*page = 0x00000000; + +	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) +		; +} + +void +ao_flash_erase_page(uint32_t *page) +{ +	ao_flash_pecr_unlock(); +	ao_flash_pgr_unlock(); + +	_ao_flash_erase_page(page); + +	ao_flash_lock(); +} + +static void __attribute__ ((section(".text.ram"), noinline)) +_ao_flash_half_page(uint32_t *dst, uint32_t *src) +{ +	uint8_t		i; + +	stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG); +	stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG); +	 +	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) +		; + +	for (i = 0; i < 32; i++) { +		*dst++ = *src++; +	} + +	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) +		; +} + +void +ao_flash_page(uint32_t *page, uint32_t *src) +{ +	uint8_t		h; + +	ao_flash_erase_page(page); +	ao_flash_pecr_unlock(); +	ao_flash_pgr_unlock(); +	for (h = 0; h < 2; h++) { +		_ao_flash_half_page(page, src); +		page += 32; +		src += 32; +	} +	ao_flash_lock(); +} diff --git a/src/stm/ao_flash_stm_pins.h b/src/stm/ao_flash_stm_pins.h new file mode 100644 index 00000000..d157a226 --- /dev/null +++ b/src/stm/ao_flash_stm_pins.h @@ -0,0 +1,43 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_FLASH_STM_PINS_H_ +#define _AO_FLASH_STM_PINS_H_ + +#include <ao_flash_pins.h> + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHZ (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at HCLK/1 */ +#define AO_APB1_PRESCALER	1 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +/* Run APB2 at HCLK/1 */ +#define AO_APB2_PRESCALER      	1 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_1 + +#endif /* _AO_FLASH_STM_PINS_H_ */ diff --git a/src/stm/ao_interrupt.c b/src/stm/ao_interrupt.c index a423d8b1..969e6a0f 100644 --- a/src/stm/ao_interrupt.c +++ b/src/stm/ao_interrupt.c @@ -18,6 +18,7 @@  #include <ao.h>  #include "stm32l.h"  #include <string.h> +#include <ao_boot.h>  extern void main(void);  extern char __stack__; @@ -36,7 +37,19 @@ void stm_ignore_isr(void)  {  } -void start(void) { +const void *stm_interrupt_vector[]; + +void start(void) +{ +#ifdef AO_BOOT_CHAIN +	if (ao_boot_check_chain()) { +#ifdef AO_BOOT_PIN +		ao_boot_check_pin(); +#endif +	} +#endif +	/* Set interrupt vector table offset */ +	stm_nvic.vto = (uint32_t) &stm_interrupt_vector;  	memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);  	memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);  	main(); diff --git a/src/stm/ao_timer.c b/src/stm/ao_timer.c index 5976eb3f..daf2f400 100644 --- a/src/stm/ao_timer.c +++ b/src/stm/ao_timer.c @@ -18,6 +18,11 @@  #include "ao.h"  #include <ao_task.h> +#ifndef HAS_TICK +#define HAS_TICK 1 +#endif + +#if HAS_TICK  volatile AO_TICK_TYPE ao_tick_count;  AO_TICK_TYPE @@ -88,6 +93,8 @@ ao_timer_init(void)  			   (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE));  } +#endif +  void  ao_clock_init(void)  { diff --git a/src/stm/ao_usb_stm.c b/src/stm/ao_usb_stm.c index e484cd22..11dde92e 100644 --- a/src/stm/ao_usb_stm.c +++ b/src/stm/ao_usb_stm.c @@ -23,6 +23,16 @@  #define USB_DEBUG_DATA	0  #define USB_ECHO	0 +#ifndef USE_USB_STDIO +#define USE_USB_STDIO	1 +#endif + +#if USE_USB_STDIO +#define AO_USB_OUT_SLEEP_ADDR	(&ao_stdin_ready) +#else +#define AO_USB_OUT_SLEEP_ADDR	(&ao_usb_out_avail) +#endif +  #if USB_DEBUG  #define debug(format, args...)	printf(format, ## args);  #else @@ -770,7 +780,7 @@ stm_usb_lp_isr(void)  				_rx_dbg1("RX ISR", epr);  				ao_usb_out_avail = 1;  				_rx_dbg0("out avail set"); -				ao_wakeup(&ao_stdin_ready); +				ao_wakeup(AO_USB_OUT_SLEEP_ADDR);  				_rx_dbg0("stdin awoken");  			}  			break; @@ -936,7 +946,7 @@ ao_usb_getchar(void)  	ao_arch_block_interrupts();  	while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) -		ao_sleep(&ao_stdin_ready); +		ao_sleep(AO_USB_OUT_SLEEP_ADDR);  	ao_arch_release_interrupts();  	return c;  } @@ -1064,8 +1074,10 @@ ao_usb_init(void)  	ao_cmd_register(&ao_usb_cmds[0]);  #endif  #if !USB_ECHO +#if USE_USB_STDIO  	ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);  #endif +#endif  }  #if TX_DBG || RX_DBG diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 5c0748a6..63bde0f8 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -435,6 +435,9 @@ extern struct stm_flash	stm_flash;  #define STM_FLASH_PEKEYR_PEKEY1	0x89ABCDEF  #define STM_FLASH_PEKEYR_PEKEY2 0x02030405 +#define STM_FLASH_PRGKEYR_PRGKEY1 0x8C9DAEBF +#define STM_FLASH_PRGKEYR_PRGKEY2 0x13141516 +  struct stm_rcc {  	vuint32_t	cr;  	vuint32_t	icscr; diff --git a/src/telegps-v0.1/Makefile b/src/telegps-v0.1/Makefile index aae37660..2c41235b 100644 --- a/src/telegps-v0.1/Makefile +++ b/src/telegps-v0.1/Makefile @@ -33,6 +33,7 @@ INC = \  #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ diff --git a/src/telegps-v0.1/flash-loader/Makefile b/src/telegps-v0.1/flash-loader/Makefile new file mode 100644 index 00000000..efc98d14 --- /dev/null +++ b/src/telegps-v0.1/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telegps-v0.1 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telegps-v0.1/flash-loader/ao_pins.h b/src/telegps-v0.1/flash-loader/ao_pins.h new file mode 100644 index 00000000..564e84de --- /dev/null +++ b/src/telegps-v0.1/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Telemetry TX pin PB6 */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiob +#define AO_BOOT_APPLICATION_PIN		6 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telelco-v0.1/Makefile b/src/telelco-v0.1/Makefile index a4a83d02..24083308 100644 --- a/src/telelco-v0.1/Makefile +++ b/src/telelco-v0.1/Makefile @@ -30,6 +30,7 @@ INC = \  #PROFILE_DEF=-DAO_PROFILE=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ diff --git a/src/telemega-v0.1/Makefile b/src/telemega-v0.1/Makefile index 16393ea0..a72d08f2 100644 --- a/src/telemega-v0.1/Makefile +++ b/src/telemega-v0.1/Makefile @@ -45,6 +45,7 @@ INC = \  #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ diff --git a/src/telemega-v0.1/flash-loader/Makefile b/src/telemega-v0.1/flash-loader/Makefile new file mode 100644 index 00000000..7aa8549f --- /dev/null +++ b/src/telemega-v0.1/flash-loader/Makefile @@ -0,0 +1,7 @@ +# +# AltOS flash loader build +# + +TOPDIR=../.. +HARDWARE=telemega-v0.1 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telemega-v0.1/flash-loader/ao_pins.h b/src/telemega-v0.1/flash-loader/ao_pins.h new file mode 100644 index 00000000..1af92f13 --- /dev/null +++ b/src/telemega-v0.1/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Companion port cs_companion0 PD0 */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiod +#define AO_BOOT_APPLICATION_PIN		0 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telemega-v0.3/Makefile b/src/telemega-v0.3/Makefile index 42ea53fc..a5fdd86b 100644 --- a/src/telemega-v0.3/Makefile +++ b/src/telemega-v0.3/Makefile @@ -45,6 +45,7 @@ INC = \  #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ diff --git a/src/telemega-v0.3/flash-loader/Makefile b/src/telemega-v0.3/flash-loader/Makefile new file mode 100644 index 00000000..8fda18cd --- /dev/null +++ b/src/telemega-v0.3/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telemega-v0.3 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telemega-v0.3/flash-loader/ao_pins.h b/src/telemega-v0.3/flash-loader/ao_pins.h new file mode 100644 index 00000000..1af92f13 --- /dev/null +++ b/src/telemega-v0.3/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Companion port cs_companion0 PD0 */ + +#define AO_BOOT_PIN		1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpiod +#define AO_BOOT_APPLICATION_PIN		0 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#endif /* _AO_PINS_H_ */ diff --git a/src/telescience-v0.2/Makefile b/src/telescience-v0.2/Makefile index fbeeb75c..f16ef268 100644 --- a/src/telescience-v0.2/Makefile +++ b/src/telescience-v0.2/Makefile @@ -28,6 +28,7 @@ INC = \  #STACK_GUARD_DEF=-DHAS_STACK_GUARD=1  ALTOS_SRC = \ +	ao_boot_chain.c \  	ao_interrupt.c \  	ao_product.c \  	ao_romconfig.c \ | 
