Merge branch 'lpc'
authorKeith Packard <keithp@keithp.com>
Tue, 21 May 2013 18:16:54 +0000 (11:16 -0700)
committerKeith Packard <keithp@keithp.com>
Tue, 21 May 2013 18:16:54 +0000 (11:16 -0700)
53 files changed:
altoslib/AltosEepromMini.java [new file with mode: 0644]
altoslib/AltosEepromMiniIterable.java [new file with mode: 0644]
altoslib/AltosLib.java
altoslib/AltosOrderedMiniRecord.java [new file with mode: 0644]
altoslib/AltosRecordMini.java [new file with mode: 0644]
altoslib/Makefile.am
altosui/AltosDataChooser.java
altosui/AltosEepromDownload.java
altosui/AltosLanded.java
altosui/AltosUI.java
src/Makefile
src/attiny/ao_arch_funcs.h
src/attiny/ao_exti.h
src/core/ao.h
src/core/ao_adc.h
src/core/ao_data.c [new file with mode: 0644]
src/core/ao_data.h
src/core/ao_flight.c
src/core/ao_log.h
src/core/ao_log_mini.c [new file with mode: 0644]
src/core/ao_log_tiny.c
src/core/ao_usb.h
src/drivers/ao_m25.c
src/drivers/ao_ms5607.c
src/easymini-v0.1/.gitignore [new file with mode: 0644]
src/easymini-v0.1/Makefile [new file with mode: 0644]
src/easymini-v0.1/ao_easymini.c [new file with mode: 0644]
src/easymini-v0.1/ao_pins.h [new file with mode: 0644]
src/lpc/Makefile.defs [new file with mode: 0644]
src/lpc/altos.ld [new file with mode: 0644]
src/lpc/ao_adc_lpc.c [new file with mode: 0644]
src/lpc/ao_arch.h [new file with mode: 0644]
src/lpc/ao_arch_funcs.h [new file with mode: 0644]
src/lpc/ao_beep_lpc.c [new file with mode: 0644]
src/lpc/ao_exti.h [new file with mode: 0644]
src/lpc/ao_exti_lpc.c [new file with mode: 0644]
src/lpc/ao_interrupt.c [new file with mode: 0644]
src/lpc/ao_led_lpc.c [new file with mode: 0644]
src/lpc/ao_romconfig.c [new file with mode: 0644]
src/lpc/ao_serial_lpc.c [new file with mode: 0644]
src/lpc/ao_spi_lpc.c [new file with mode: 0644]
src/lpc/ao_timer_lpc.c [new file with mode: 0644]
src/lpc/ao_usb_lpc.c [new file with mode: 0644]
src/lpc/baud_rate [new file with mode: 0644]
src/lpc/figure-checksum [new file with mode: 0755]
src/lpc/lpc.h [new file with mode: 0644]
src/lpc/registers.ld [new file with mode: 0644]
src/lpcxpresso/Makefile [new file with mode: 0644]
src/lpcxpresso/ao_demo.c [new file with mode: 0644]
src/lpcxpresso/ao_pins.h [new file with mode: 0644]
src/stm/ao_data.c [deleted file]
src/stm/ao_exti.h
src/stm/ao_exti_stm.c

diff --git a/altoslib/AltosEepromMini.java b/altoslib/AltosEepromMini.java
new file mode 100644 (file)
index 0000000..215cd3d
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright © 2011 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;
+
+import java.text.*;
+
+public class AltosEepromMini {
+       public int      cmd;
+       public int      tick;
+       public boolean  valid;
+       public String   data;
+       public int      config_a, config_b;
+
+       public int      data8[];
+
+       public static final int record_length = 16;
+       static final int        header_length = 4;
+       static final int        data_length = record_length - header_length;
+
+       public int data8(int i) {
+               return data8[i];
+       }
+
+       public int data16(int i) {
+               return ((data8[i] | (data8[i+1] << 8)) << 16) >> 16;
+       }
+
+       public int data24(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16);
+       }
+
+       public int data32(int i) {
+               return data8[i] | (data8[i+1] << 8) | (data8[i+2] << 16) | (data8[i+3] << 24);
+       }
+
+       /* AO_LOG_FLIGHT elements */
+       public int flight() { return data16(0); }
+       public int ground_pres() { return data32(4); }
+
+       /* AO_LOG_STATE elements */
+       public int state() { return data16(0); }
+       public int reason() { return data16(2); }
+
+       /* AO_LOG_SENSOR elements */
+       public int pres() { return data24(0); }
+       public int temp() { return data24(3); }
+       public int sense_a() { return data16(6); }
+       public int sense_m() { return data16(8); }
+       public int v_batt() { return data16(10); }
+
+       public AltosEepromMini (AltosEepromChunk chunk, int start) throws ParseException {
+               cmd = chunk.data(start);
+
+               valid = !chunk.erased(start, record_length);
+               if (valid) {
+                       if (AltosConvert.checksum(chunk.data, start, record_length) != 0)
+                               throw new ParseException(String.format("invalid checksum at 0x%x",
+                                                                      chunk.address + start), 0);
+               } else {
+                       cmd = AltosLib.AO_LOG_INVALID;
+               }
+
+               tick = chunk.data16(start+2);
+
+               data8 = new int[data_length];
+               for (int i = 0; i < data_length; i++)
+                       data8[i] = chunk.data(start + header_length + i);
+       }
+
+       public AltosEepromMini (String line) {
+               valid = false;
+               tick = 0;
+
+               if (line == null) {
+                       cmd = AltosLib.AO_LOG_INVALID;
+                       line = "";
+               } else {
+                       try {
+                               String[] tokens = line.split("\\s+");
+
+                               if (tokens[0].length() == 1) {
+                                       if (tokens.length != 2 + data_length) {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                               data = line;
+                                       } else {
+                                               cmd = tokens[0].codePointAt(0);
+                                               tick = Integer.parseInt(tokens[1],16);
+                                               valid = true;
+                                               data8 = new int[data_length];
+                                               for (int i = 0; i < data_length; i++)
+                                                       data8[i] = Integer.parseInt(tokens[2 + i],16);
+                                       }
+                               } else if (tokens[0].equals("Config") && tokens[1].equals("version:")) {
+                                       cmd = AltosLib.AO_LOG_CONFIG_VERSION;
+                                       data = tokens[2];
+                               } else if (tokens[0].equals("Main") && tokens[1].equals("deploy:")) {
+                                       cmd = AltosLib.AO_LOG_MAIN_DEPLOY;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Apogee") && tokens[1].equals("delay:")) {
+                                       cmd = AltosLib.AO_LOG_APOGEE_DELAY;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("channel:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CHANNEL;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Callsign:")) {
+                                       cmd = AltosLib.AO_LOG_CALLSIGN;
+                                       data = tokens[1].replaceAll("\"","");
+                               } else if (tokens[0].equals("Accel") && tokens[1].equals("cal")) {
+                                       cmd = AltosLib.AO_LOG_ACCEL_CAL;
+                                       config_a = Integer.parseInt(tokens[3]);
+                                       config_b = Integer.parseInt(tokens[5]);
+                               } else if (tokens[0].equals("Radio") && tokens[1].equals("cal:")) {
+                                       cmd = AltosLib.AO_LOG_RADIO_CAL;
+                                       config_a = Integer.parseInt(tokens[2]);
+                               } else if (tokens[0].equals("Max") && tokens[1].equals("flight") && tokens[2].equals("log:")) {
+                                       cmd = AltosLib.AO_LOG_MAX_FLIGHT_LOG;
+                                       config_a = Integer.parseInt(tokens[3]);
+                               } else if (tokens[0].equals("manufacturer")) {
+                                       cmd = AltosLib.AO_LOG_MANUFACTURER;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("product")) {
+                                       cmd = AltosLib.AO_LOG_PRODUCT;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("serial-number")) {
+                                       cmd = AltosLib.AO_LOG_SERIAL_NUMBER;
+                                       config_a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("log-format")) {
+                                       cmd = AltosLib.AO_LOG_LOG_FORMAT;
+                                       config_a = Integer.parseInt(tokens[1]);
+                               } else if (tokens[0].equals("software-version")) {
+                                       cmd = AltosLib.AO_LOG_SOFTWARE_VERSION;
+                                       data = tokens[1];
+                               } else if (tokens[0].equals("ms5607")) {
+                                       if (tokens[1].equals("reserved:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_RESERVED;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("sens:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_SENS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("off:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_OFF;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tcs:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TCS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tco:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TCO;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tref:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TREF;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("tempsens:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_TEMPSENS;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else if (tokens[1].equals("crc:")) {
+                                               cmd = AltosLib.AO_LOG_BARO_CRC;
+                                               config_a = Integer.parseInt(tokens[2]);
+                                       } else {
+                                               cmd = AltosLib.AO_LOG_INVALID;
+                                               data = line;
+                                       }
+                               } else {
+                                       cmd = AltosLib.AO_LOG_INVALID;
+                                       data = line;
+                               }
+                       } catch (NumberFormatException ne) {
+                               cmd = AltosLib.AO_LOG_INVALID;
+                               data = line;
+                       }
+               }
+       }
+
+       public AltosEepromMini(int in_cmd, int in_tick) {
+               cmd = in_cmd;
+               tick = in_tick;
+               valid = true;
+       }
+}
diff --git a/altoslib/AltosEepromMiniIterable.java b/altoslib/AltosEepromMiniIterable.java
new file mode 100644 (file)
index 0000000..1f22118
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * Copyright © 2010 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;
+
+import java.io.*;
+import java.util.*;
+import java.text.*;
+
+public class AltosEepromMiniIterable extends AltosRecordIterable {
+
+       static final int        seen_flight = 1;
+       static final int        seen_sensor = 2;
+
+       static final int        seen_basic = seen_flight|seen_sensor;
+
+       boolean                 has_accel;
+       boolean                 has_gps;
+       boolean                 has_ignite;
+
+       AltosEepromMini flight_record;
+
+       TreeSet<AltosOrderedMiniRecord> records;
+
+       AltosMs5607             baro;
+
+       LinkedList<AltosRecord> list;
+
+       class EepromState {
+               int     seen;
+               int     n_pad_samples;
+               double  ground_pres;
+               int     boost_tick;
+               int     sensor_tick;
+
+               EepromState() {
+                       seen = 0;
+                       n_pad_samples = 0;
+                       ground_pres = 0.0;
+               }
+       }
+
+       void update_state(AltosRecordMini state, AltosEepromMini record, EepromState eeprom) {
+               state.tick = record.tick;
+               switch (record.cmd) {
+               case AltosLib.AO_LOG_FLIGHT:
+                       eeprom.seen |= seen_flight;
+                       state.ground_pres = record.ground_pres();
+                       state.flight_pres = state.ground_pres;
+                       state.flight = record.data16(0);
+                       eeprom.boost_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_SENSOR:
+                       baro.set(record.pres(), record.temp());
+                       state.pres = baro.pa;
+                       state.temp = baro.cc;
+                       state.sense_m = record.sense_m();
+                       state.sense_a = record.sense_a();
+                       state.v_batt = record.v_batt();
+                       if (state.state < AltosLib.ao_flight_boost) {
+                               eeprom.n_pad_samples++;
+                               eeprom.ground_pres += state.pres;
+                               state.ground_pres = (int) (eeprom.ground_pres / eeprom.n_pad_samples);
+                               state.flight_pres = state.ground_pres;
+                       } else {
+                               state.flight_pres = (state.flight_pres * 15 + state.pres) / 16;
+                       }
+                       if ((eeprom.seen & seen_sensor) == 0)
+                               eeprom.sensor_tick = record.tick - 1;
+                       eeprom.seen |= seen_sensor;
+                       eeprom.sensor_tick = record.tick;
+                       break;
+               case AltosLib.AO_LOG_STATE:
+                       state.state = record.state();
+                       break;
+               case AltosLib.AO_LOG_CONFIG_VERSION:
+                       break;
+               case AltosLib.AO_LOG_MAIN_DEPLOY:
+                       break;
+               case AltosLib.AO_LOG_APOGEE_DELAY:
+                       break;
+               case AltosLib.AO_LOG_RADIO_CHANNEL:
+                       break;
+               case AltosLib.AO_LOG_CALLSIGN:
+                       state.callsign = record.data;
+                       break;
+               case AltosLib.AO_LOG_RADIO_CAL:
+                       break;
+               case AltosLib.AO_LOG_MANUFACTURER:
+                       break;
+               case AltosLib.AO_LOG_PRODUCT:
+                       break;
+               case AltosLib.AO_LOG_SERIAL_NUMBER:
+                       state.serial = record.config_a;
+                       break;
+               case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                       break;
+               case AltosLib.AO_LOG_BARO_RESERVED:
+                       baro.reserved = record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_SENS:
+                       baro.sens =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_OFF:
+                       baro.off =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCS:
+                       baro.tcs =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TCO:
+                       baro.tco =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TREF:
+                       baro.tref =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_TEMPSENS:
+                       baro.tempsens =record.config_a;
+                       break;
+               case AltosLib.AO_LOG_BARO_CRC:
+                       baro.crc =record.config_a;
+                       break;
+               }
+               state.seen |= eeprom.seen;
+       }
+
+       LinkedList<AltosRecord> make_list() {
+               LinkedList<AltosRecord>         list = new LinkedList<AltosRecord>();
+               Iterator<AltosOrderedMiniRecord> iterator = records.iterator();
+               AltosOrderedMiniRecord          record = null;
+               AltosRecordMini                 state = new AltosRecordMini();
+               //boolean                       last_reported = false;
+               EepromState                     eeprom = new EepromState();
+
+               state.state = AltosLib.ao_flight_pad;
+
+               /* Pull in static data from the flight records */
+               if (flight_record != null)
+                       update_state(state, flight_record, eeprom);
+
+               while (iterator.hasNext()) {
+                       record = iterator.next();
+                       if ((eeprom.seen & seen_basic) == seen_basic && record.tick != state.tick) {
+                               AltosRecordMini r = state.clone();
+                               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+                               list.add(r);
+                       }
+                       update_state(state, record, eeprom);
+               }
+               AltosRecordMini r = state.clone();
+               r.time = (r.tick - eeprom.boost_tick) / 100.0;
+               list.add(r);
+               return list;
+       }
+
+       public Iterator<AltosRecord> iterator() {
+               if (list == null)
+                       list = make_list();
+               return list.iterator();
+       }
+
+       public boolean has_gps() { return has_gps; }
+       public boolean has_accel() { return has_accel; }
+       public boolean has_ignite() { return has_ignite; }
+
+       public void write_comments(PrintStream out) {
+               Iterator<AltosOrderedMiniRecord>        iterator = records.iterator();
+               out.printf("# Comments\n");
+               while (iterator.hasNext()) {
+                       AltosOrderedMiniRecord  record = iterator.next();
+                       switch (record.cmd) {
+                       case AltosLib.AO_LOG_CONFIG_VERSION:
+                               out.printf("# Config version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_MAIN_DEPLOY:
+                               out.printf("# Main deploy: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_APOGEE_DELAY:
+                               out.printf("# Apogee delay: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CHANNEL:
+                               out.printf("# Radio channel: %s\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_CALLSIGN:
+                               out.printf("# Callsign: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_ACCEL_CAL:
+                               out.printf ("# Accel cal: %d %d\n", record.config_a, record.config_b);
+                               break;
+                       case AltosLib.AO_LOG_RADIO_CAL:
+                               out.printf ("# Radio cal: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_MAX_FLIGHT_LOG:
+                               out.printf ("# Max flight log: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_MANUFACTURER:
+                               out.printf ("# Manufacturer: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_PRODUCT:
+                               out.printf ("# Product: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_SERIAL_NUMBER:
+                               out.printf ("# Serial number: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_SOFTWARE_VERSION:
+                               out.printf ("# Software version: %s\n", record.data);
+                               break;
+                       case AltosLib.AO_LOG_BARO_RESERVED:
+                               out.printf ("# Baro reserved: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_SENS:
+                               out.printf ("# Baro sens: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_OFF:
+                               out.printf ("# Baro off: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCS:
+                               out.printf ("# Baro tcs: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TCO:
+                               out.printf ("# Baro tco: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TREF:
+                               out.printf ("# Baro tref: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_TEMPSENS:
+                               out.printf ("# Baro tempsens: %d\n", record.config_a);
+                               break;
+                       case AltosLib.AO_LOG_BARO_CRC:
+                               out.printf ("# Baro crc: %d\n", record.config_a);
+                               break;
+                       }
+               }
+       }
+
+       /*
+        * Read the whole file, dumping records into a RB tree so
+        * we can enumerate them in time order -- the eeprom data
+        * are sometimes out of order
+        */
+       public AltosEepromMiniIterable (FileInputStream input) {
+               records = new TreeSet<AltosOrderedMiniRecord>();
+
+               AltosOrderedMiniRecord last_gps_time = null;
+
+               baro = new AltosMs5607();
+
+               int index = 0;
+               int prev_tick = 0;
+               boolean prev_tick_valid = false;
+               boolean missing_time = false;
+
+               try {
+                       for (;;) {
+                               String line = AltosLib.gets(input);
+                               if (line == null)
+                                       break;
+                               AltosOrderedMiniRecord record = new AltosOrderedMiniRecord(line, index++, prev_tick, prev_tick_valid);
+                               if (record.cmd == AltosLib.AO_LOG_INVALID)
+                                       continue;
+                               prev_tick = record.tick;
+                               if (record.cmd < AltosLib.AO_LOG_CONFIG_VERSION)
+                                       prev_tick_valid = true;
+                               if (record.cmd == AltosLib.AO_LOG_FLIGHT) {
+                                       flight_record = record;
+                                       continue;
+                               }
+
+                               records.add(record);
+
+                               /* Bail after reading the 'landed' record; we're all done */
+                               if (record.cmd == AltosLib.AO_LOG_STATE &&
+                                   record.state() == AltosLib.ao_flight_landed)
+                                       break;
+                       }
+               } catch (IOException io) {
+               } catch (ParseException pe) {
+               }
+               try {
+                       input.close();
+               } catch (IOException ie) {
+               }
+       }
+}
index 25d17e726bf01727c2720d6aba01c1e6772eb722..a629260bb50d2e0fd844bf8361f31c2cfe43cd1a 100644 (file)
@@ -216,6 +216,7 @@ public class AltosLib {
        public static final int AO_LOG_FORMAT_TELEMETRY = 3;
        public static final int AO_LOG_FORMAT_TELESCIENCE = 4;
        public static final int AO_LOG_FORMAT_TELEMEGA = 5;
+       public static final int AO_LOG_FORMAT_MINI = 6;
        public static final int AO_LOG_FORMAT_NONE = 127;
 
        public static boolean isspace(int c) {
diff --git a/altoslib/AltosOrderedMiniRecord.java b/altoslib/AltosOrderedMiniRecord.java
new file mode 100644 (file)
index 0000000..9688894
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright © 2010 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;
+
+import java.text.ParseException;
+
+/*
+ * AltosRecords with an index field so they can be sorted by tick while preserving
+ * the original ordering for elements with matching ticks
+ */
+class AltosOrderedMiniRecord extends AltosEepromMini implements Comparable<AltosOrderedMiniRecord> {
+
+       public int      index;
+
+       public AltosOrderedMiniRecord(String line, int in_index, int prev_tick, boolean prev_tick_valid)
+               throws ParseException {
+               super(line);
+               if (prev_tick_valid) {
+                       tick |= (prev_tick & ~0xffff);
+                       if (tick < prev_tick) {
+                               if (prev_tick - tick > 0x8000)
+                                       tick += 0x10000;
+                       } else {
+                               if (tick - prev_tick > 0x8000)
+                                       tick -= 0x10000;
+                       }
+               }
+               index = in_index;
+       }
+
+       public int compareTo(AltosOrderedMiniRecord o) {
+               int     tick_diff = tick - o.tick;
+               if (tick_diff != 0)
+                       return tick_diff;
+               return index - o.index;
+       }
+}
diff --git a/altoslib/AltosRecordMini.java b/altoslib/AltosRecordMini.java
new file mode 100644 (file)
index 0000000..253f380
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+package org.altusmetrum.altoslib_1;
+
+public class AltosRecordMini extends AltosRecord {
+
+       /* Sensor values */
+       public int      pres;
+       public int      temp;
+       
+       public int      sense_a;
+       public int      sense_m;
+       public int      v_batt;
+
+       public int      ground_pres;
+
+       public int      flight_accel;
+       public int      flight_vel;
+       public int      flight_pres;
+
+       static double adc(int raw) {
+               return raw / 4095.0;
+       }
+
+       public double pressure() {
+               if (pres != MISSING)
+                       return pres;
+               return MISSING;
+       }
+
+       public double temperature() {
+               if (temp != MISSING)
+                       return temp;
+               return MISSING;
+       }
+
+       public double ground_pressure() {
+               if (ground_pres != MISSING)
+                       return ground_pres;
+               return MISSING;
+       }
+
+       public double battery_voltage() {
+               if (v_batt != MISSING)
+                       return 3.3 * adc(v_batt) * (15.0 + 27.0) / 27.0;
+               return MISSING;
+       }
+
+       static double pyro(int raw) {
+               if (raw != MISSING)
+                       return 3.3 * adc(raw) * (100.0 + 27.0) / 27.0;
+               return MISSING;
+       }
+
+       public double main_voltage() {
+               return pyro(sense_m);
+       }
+
+       public double apogee_voltage() {
+               return pyro(sense_a);
+       }
+
+       public void copy (AltosRecordMini old) {
+               super.copy(old);
+
+               pres = old.pres;
+               temp = old.temp;
+
+               sense_a = old.sense_a;
+               sense_m = old.sense_m;
+               v_batt = old.v_batt;
+
+               ground_pres = old.ground_pres;
+               
+               flight_accel = old.flight_accel;
+               flight_vel = old.flight_vel;
+               flight_pres = old.flight_pres;
+       }
+
+
+
+       public AltosRecordMini clone() {
+               return new AltosRecordMini(this);
+       }
+
+       void make_missing() {
+
+               pres = MISSING;
+
+               sense_a = MISSING;
+               sense_m = MISSING;
+               v_batt = MISSING;
+
+               ground_pres = MISSING;
+
+               flight_accel = 0;
+               flight_vel = 0;
+               flight_pres = 0;
+       }
+
+       public AltosRecordMini(AltosRecord old) {
+               super.copy(old);
+               make_missing();
+       }
+
+       public AltosRecordMini(AltosRecordMini old) {
+               copy(old);
+       }
+
+       public AltosRecordMini() {
+               super();
+               make_missing();
+       }
+}
index 18b028d628776652ef2243e30ba8eb50ce22fc80..8c1cf2add83c615b6899d4a147a199ed797b559e 100644 (file)
@@ -24,6 +24,8 @@ altoslib_JAVA = \
        AltosEepromMegaIterable.java \
        AltosEepromRecord.java \
        AltosEepromTeleScience.java \
+       AltosEepromMini.java \
+       AltosEepromMiniIterable.java \
        AltosFile.java \
        AltosFlash.java \
        AltosFlashListener.java \
@@ -47,6 +49,7 @@ altoslib_JAVA = \
        AltosMs5607Query.java \
        AltosOrderedRecord.java \
        AltosOrderedMegaRecord.java \
+       AltosOrderedMiniRecord.java \
        AltosParse.java \
        AltosPreferences.java \
        AltosPreferencesBackend.java \
@@ -56,6 +59,7 @@ altoslib_JAVA = \
        AltosRecordNone.java \
        AltosRecordTM.java \
        AltosRecordMM.java \
+       AltosRecordMini.java \
        AltosReplayReader.java \
        AltosRomconfig.java \
        AltosSensorMM.java \
index f914f138f2fe7d2e2d116744a343910283ad8cc9..c7b561d5a809c5eda48f5045a1234c438fe02079 100644 (file)
@@ -55,6 +55,9 @@ public class AltosDataChooser extends JFileChooser {
                                } else if (filename.endsWith("mega")) {
                                        FileInputStream in = new FileInputStream(file);
                                        return new AltosEepromMegaIterable(in);
+                               } else if (filename.endsWith("mini")) {
+                                       FileInputStream in = new FileInputStream(file);
+                                       return new AltosEepromMiniIterable(in);
                                } else {
                                        throw new FileNotFoundException();
                                }
@@ -77,8 +80,10 @@ public class AltosDataChooser extends JFileChooser {
                                                          "telem"));
                setFileFilter(new FileNameExtensionFilter("TeleMega eeprom file",
                                                          "mega"));
+               setFileFilter(new FileNameExtensionFilter("EasyMini eeprom file",
+                                                         "mini"));
                setFileFilter(new FileNameExtensionFilter("Flight data file",
-                                                         "telem", "eeprom", "mega"));
+                                                         "telem", "eeprom", "mega", "mini"));
                setCurrentDirectory(AltosUIPreferences.logdir());
        }
 }
index a0523b58a2c00ea8734c614479994a617ef6249d..53d5433f0146e45aa19756f4ae13b1a5ebe2526f 100644 (file)
@@ -302,6 +302,53 @@ public class AltosEepromDownload implements Runnable {
                CheckFile(false);
        }
        
+       void LogMini(AltosEepromMini r) throws IOException {
+               if (r.cmd != Altos.AO_LOG_INVALID) {
+                       String log_line = String.format("%c %4x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                                                       r.cmd, r.tick,
+                                                       r.data8[0], r.data8[1], r.data8[2], r.data8[3],
+                                                       r.data8[4], r.data8[5], r.data8[6], r.data8[7],
+                                                       r.data8[8], r.data8[9], r.data8[10], r.data8[11]);
+                       if (eeprom_file != null)
+                               eeprom_file.write(log_line);
+                       else
+                               eeprom_pending.add(log_line);
+               }
+       }
+
+       void CaptureMini(AltosEepromChunk eechunk) throws IOException {
+               boolean any_valid = false;
+
+               extension = "mini";
+               set_serial(flights.config_data.serial);
+               for (int i = 0; i < AltosEepromChunk.chunk_size && !done; i += AltosEepromMini.record_length) {
+                       try {
+                               AltosEepromMini r = new AltosEepromMini(eechunk, i);
+                               if (r.cmd == Altos.AO_LOG_FLIGHT)
+                                       set_flight(r.data16(0));
+
+                               /* Monitor state transitions to update display */
+                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) <= Altos.ao_flight_landed) {
+                                       state = r.data16(0);
+                                       if (state > Altos.ao_flight_pad)
+                                               want_file = true;
+                               }
+
+                               if (r.cmd == Altos.AO_LOG_STATE && r.data16(0) == Altos.ao_flight_landed)
+                                       done = true;
+                               any_valid = true;
+                               LogMini(r);
+                       } catch (ParseException pe) {
+                               if (parse_exception == null)
+                                       parse_exception = pe;
+                       }
+               }
+               if (!any_valid)
+                       done = true;
+
+               CheckFile(false);
+       }
+       
        void CaptureTelemetry(AltosEepromChunk eechunk) throws IOException {
                
        }
@@ -369,6 +416,9 @@ public class AltosEepromDownload implements Runnable {
                        case AltosLib.AO_LOG_FORMAT_TELEMEGA:
                                extension = "mega";
                                CaptureMega(eechunk);
+                       case AltosLib.AO_LOG_FORMAT_MINI:
+                               extension = "mini";
+                               CaptureMini(eechunk);
                        }
                }
                CheckFile(true);
index 1d209bda8ccaa493371d104126efb2d1c6ca21c2..9dab52c436098b8ea0f2a8a90bd5a8829d9276d3 100644 (file)
@@ -253,6 +253,9 @@ public class AltosLanded extends JComponent implements AltosFlightDisplay, Actio
                                        } else if (filename.endsWith("mega")) {
                                                FileInputStream in = new FileInputStream(file);
                                                records = new AltosEepromMegaIterable(in);
+                                       } else if (filename.endsWith("mini")) {
+                                               FileInputStream in = new FileInputStream(file);
+                                               records = new AltosEepromMiniIterable(in);
                                        } else {
                                                throw new FileNotFoundException(filename);
                                        }
index 9f8f6ddac4285a0bee154d6267b52e429ec01d54..4362e36c88e1575ee5167790a0d3c26427dcfa09 100644 (file)
@@ -354,6 +354,8 @@ public class AltosUI extends AltosUIFrame {
                                return new AltosEepromIterable(in);
                        else if (file.getName().endsWith("mega"))
                                return new AltosEepromMegaIterable(in);
+                       else if (file.getName().endsWith("mini"))
+                               return new AltosEepromMiniIterable(in);
                        else
                                return new AltosTelemetryIterable(in);
                } catch (FileNotFoundException fe) {
@@ -441,6 +443,8 @@ public class AltosUI extends AltosUIFrame {
                        recs = new AltosEepromIterable(in);
                } else if (file.getName().endsWith("mega")) {
                        recs = new AltosEepromMegaIterable(in);
+               } else if (file.getName().endsWith("mini")) {
+                       recs = new AltosEepromMiniIterable(in);
                } else {
                        recs = new AltosTelemetryIterable(in);
                }
index c35964989cfb498c0c831100862aab621c612431..5851b2a8905247df0b215b2e973d451e0ac54388 100644 (file)
@@ -35,7 +35,8 @@ ARMDIRS=\
        telegps-v0.1 telegps-v0.1/flash-loader \
        stm-bringup stm-demo \
        telelco-v0.2 telelco-v0.2/flash-loader \
-       telescience-v0.2 telescience-v0.2/flash-loader
+       telescience-v0.2 telescience-v0.2/flash-loader \
+       easymini-v0.1
 
 ifneq ($(shell which sdcc),)
        SUBDIRS += $(SDCCDIRS)
index 8c9d1ae69a6dbe81135cf606c2c12ba738effb57..76dc7820a0d2460d583b74696a28d993bd1e8079 100644 (file)
  */
 
 #define ao_spi_get_mask(reg,mask,bus,speed) do {       \
-               (reg) &= ~(mask);               \
+               (reg) &= ~(mask);                       \
        } while (0)
 
 #define ao_spi_put_mask(reg,mask,bus) do {     \
                (reg) |= (mask);                \
        } while (0)
 
-#define ao_spi_get_bit(reg,bit,pin,bus,speed) do {     \
-               (pin) = 0;                      \
-       } while (0)
-
-#define ao_spi_put_bit(reg,bit,pin,bus) do {   \
-               (pin) = 1;                      \
-       } while (0)
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<(bit)),bus,speed)
 
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<(bit)),bus)
 
 #define ao_gpio_token_paster(x,y)              x ## y
 #define ao_gpio_token_evaluator(x,y)   ao_gpio_token_paster(x,y)
index 2ea4f47d33421e112e5d0d0bfacdd5db7c62387f..85bb2fbabc939eb39b3ad0e31205f287668a6dff 100644 (file)
@@ -30,5 +30,6 @@ ao_exti_setup_port(uint8_t pin, uint8_t mode, void (*callback)(void));
 #define ao_exti_init()
 
 #define AO_EXTI_MODE_RISING    1
+#define AO_EXTI_PIN_NOCONFIGURE        0
 
 #endif /* _AO_EXTI_H_ */
index 71bfb6a1f880d36988788b8e4a99e36fcf8c1ed6..7f344736b8f0a7bd19c5d204b09be34a0b2f62a7 100644 (file)
 #define HAS_TASK       1
 #endif
 
+#ifndef AO_PORT_TYPE
+#define AO_PORT_TYPE uint8_t
+#endif
+
+typedef AO_PORT_TYPE ao_port_t;
+
 #if HAS_TASK
 #include <ao_task.h>
 #else
@@ -68,6 +74,7 @@
 #define AO_PANIC_SPI           13      /* SPI communication failure */
 #define AO_PANIC_CRASH         14      /* Processor crashed */
 #define AO_PANIC_BUFIO         15      /* Mis-using bufio API */
+#define AO_PANIC_EXTI          16      /* Mis-using exti API */
 #define AO_PANIC_SELF_TEST_CC1120      0x40 | 1        /* Self test failure */
 #define AO_PANIC_SELF_TEST_HMC5883     0x40 | 2        /* Self test failure */
 #define AO_PANIC_SELF_TEST_MPU6000     0x40 | 3        /* Self test failure */
index 0dd87080037686a1c099c11bc024aaa0039ea06f..373db1c4794ccf81ad5f4496e3ba997c59d29860 100644 (file)
@@ -28,10 +28,6 @@ ao_adc_poll(void);
 void
 ao_adc_sleep(void);
 
-/* Get a copy of the last complete sample set */
-void
-ao_data_get(__xdata struct ao_data *packet);
-
 /* Initialize the A/D converter */
 void
 ao_adc_init(void);
diff --git a/src/core/ao_data.c b/src/core/ao_data.c
new file mode 100644 (file)
index 0000000..38d2f7f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_data.h>
+
+volatile __xdata struct ao_data        ao_data_ring[AO_DATA_RING];
+volatile __data uint8_t                ao_data_head;
+volatile __data uint8_t                ao_data_present;
+
+void
+ao_data_get(__xdata struct ao_data *packet)
+{
+#if HAS_FLIGHT
+       uint8_t i = ao_data_ring_prev(ao_sample_data);
+#else
+       uint8_t i = ao_data_ring_prev(ao_data_head);
+#endif
+       memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
+}
index 7e2f85d8fb569894c09a75672f57f046df048007..b0f086f867285cf111d865b48bd0a684d0fd41d6 100644 (file)
@@ -82,6 +82,10 @@ struct ao_data {
 #define ao_data_ring_next(n)   (((n) + 1) & (AO_DATA_RING - 1))
 #define ao_data_ring_prev(n)   (((n) - 1) & (AO_DATA_RING - 1))
 
+/* Get a copy of the last complete sample set */
+void
+ao_data_get(__xdata struct ao_data *packet);
+
 extern volatile __xdata struct ao_data ao_data_ring[AO_DATA_RING];
 extern volatile __data uint8_t         ao_data_head;
 extern volatile __data uint8_t         ao_data_present;
index 9d9d4c6e0b3ddea72a724b1b3eacee94dbb9f76c..782e22744c434dc28e9356d60708ef728f7e9380 100644 (file)
@@ -124,7 +124,7 @@ ao_flight(void)
                                ao_usb_disable();
 #endif
 
-#if !HAS_ACCEL
+#if !HAS_ACCEL && PACKET_HAS_SLAVE
                                /* Disable packet mode in pad state on TeleMini */
                                ao_packet_slave_stop();
 #endif
index a68a40dddc0f4f8370c7edc7cd109408a1579af6..95b3764991c47554669132244cc27b0c3a24a9e9 100644 (file)
@@ -44,6 +44,7 @@ extern __pdata enum ao_flight_state ao_log_state;
 #define AO_LOG_FORMAT_TELEMETRY                3       /* 32 byte ao_telemetry records */
 #define AO_LOG_FORMAT_TELESCIENCE      4       /* 32 byte typed telescience records */
 #define AO_LOG_FORMAT_TELEMEGA         5       /* 32 byte typed telemega records */
+#define AO_LOG_FORMAT_MINI             6       /* 16-byte MS5607 baro only */
 #define AO_LOG_FORMAT_NONE             127     /* No log at all */
 
 extern __code uint8_t ao_log_format;
@@ -261,6 +262,40 @@ struct ao_log_mega {
        } u;
 };
 
+struct ao_log_mini {
+       char            type;                           /* 0 */
+       uint8_t         csum;                           /* 1 */
+       uint16_t        tick;                           /* 2 */
+       union {                                         /* 4 */
+               /* AO_LOG_FLIGHT */
+               struct {
+                       uint16_t        flight;         /* 4 */
+                       uint16_t        r6;
+                       uint32_t        ground_pres;    /* 8 */
+               } flight;
+               /* AO_LOG_STATE */
+               struct {
+                       uint16_t        state;          /* 4 */
+                       uint16_t        reason;         /* 6 */
+               } state;
+               /* AO_LOG_SENSOR */
+               struct {
+                       uint8_t         pres[3];        /* 4 */
+                       uint8_t         temp[3];        /* 7 */
+                       int16_t         sense_a;        /* 10 */
+                       int16_t         sense_m;        /* 12 */
+                       int16_t         v_batt;         /* 14 */
+               } sensor;                               /* 16 */
+       } u;                                            /* 16 */
+};                                                     /* 16 */
+
+static inline void
+ao_log_pack24(uint8_t *dst, uint32_t value) {
+       dst[0] = value;
+       dst[1] = value >> 8;
+       dst[2] = value >> 16;
+}
+
 /* Write a record to the eeprom log */
 uint8_t
 ao_log_data(__xdata struct ao_log_record *log) __reentrant;
@@ -268,6 +303,9 @@ ao_log_data(__xdata struct ao_log_record *log) __reentrant;
 uint8_t
 ao_log_mega(__xdata struct ao_log_mega *log) __reentrant;
 
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant;
+
 void
 ao_log_flush(void);
 
diff --git a/src/core/ao_log_mini.c b/src/core/ao_log_mini.c
new file mode 100644 (file)
index 0000000..1273b0e
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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.
+ */
+
+#include "ao.h"
+#include <ao_log.h>
+#include <ao_data.h>
+#include <ao_flight.h>
+
+static __xdata uint8_t ao_log_mutex;
+static __xdata struct ao_log_mini log;
+
+__code uint8_t ao_log_format = AO_LOG_FORMAT_MINI;
+
+static uint8_t
+ao_log_csum(__xdata uint8_t *b) __reentrant
+{
+       uint8_t sum = 0x5a;
+       uint8_t i;
+
+       for (i = 0; i < sizeof (struct ao_log_mini); i++)
+               sum += *b++;
+       return -sum;
+}
+
+uint8_t
+ao_log_mini(__xdata struct ao_log_mini *log) __reentrant
+{
+       uint8_t wrote = 0;
+       /* set checksum */
+       log->csum = 0;
+       log->csum = ao_log_csum((__xdata uint8_t *) log);
+       ao_mutex_get(&ao_log_mutex); {
+               if (ao_log_current_pos >= ao_log_end_pos && ao_log_running)
+                       ao_log_stop();
+               if (ao_log_running) {
+                       wrote = 1;
+                       ao_storage_write(ao_log_current_pos,
+                                        log,
+                                        sizeof (struct ao_log_mini));
+                       ao_log_current_pos += sizeof (struct ao_log_mini);
+               }
+       } ao_mutex_put(&ao_log_mutex);
+       return wrote;
+}
+
+static uint8_t
+ao_log_dump_check_data(void)
+{
+       if (ao_log_csum((uint8_t *) &log) != 0)
+               return 0;
+       return 1;
+}
+
+static __data uint8_t  ao_log_data_pos;
+
+/* a hack to make sure that ao_log_minis fill the eeprom block in even units */
+typedef uint8_t check_log_size[1-(256 % sizeof(struct ao_log_mini))] ;
+
+#ifndef AO_SENSOR_INTERVAL_ASCENT
+#define AO_SENSOR_INTERVAL_ASCENT      1
+#define AO_SENSOR_INTERVAL_DESCENT     10
+#endif
+
+void
+ao_log(void)
+{
+       __pdata uint16_t        next_sensor, next_other;
+       uint8_t                 i;
+
+       ao_storage_setup();
+
+       ao_log_scan();
+
+       while (!ao_log_running)
+               ao_sleep(&ao_log_running);
+
+#if HAS_FLIGHT
+       log.type = AO_LOG_FLIGHT;
+       log.tick = ao_sample_tick;
+       log.u.flight.flight = ao_flight_number;
+       log.u.flight.ground_pres = ao_ground_pres;
+       ao_log_mini(&log);
+#endif
+
+       /* Write the whole contents of the ring to the log
+        * when starting up.
+        */
+       ao_log_data_pos = ao_data_ring_next(ao_data_head);
+       next_other = next_sensor = ao_data_ring[ao_log_data_pos].tick;
+       ao_log_state = ao_flight_startup;
+       for (;;) {
+               /* Write samples to EEPROM */
+               while (ao_log_data_pos != ao_data_head) {
+                       log.tick = ao_data_ring[ao_log_data_pos].tick;
+                       if ((int16_t) (log.tick - next_sensor) >= 0) {
+                               log.type = AO_LOG_SENSOR;
+                               ao_log_pack24(log.u.sensor.pres,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.pres);
+                               ao_log_pack24(log.u.sensor.temp,
+                                             ao_data_ring[ao_log_data_pos].ms5607_raw.temp);
+                               log.u.sensor.sense_a = ao_data_ring[ao_log_data_pos].adc.sense_a;
+                               log.u.sensor.sense_m = ao_data_ring[ao_log_data_pos].adc.sense_m;
+                               log.u.sensor.v_batt = ao_data_ring[ao_log_data_pos].adc.v_batt;
+                               ao_log_mini(&log);
+                               if (ao_log_state <= ao_flight_coast)
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_ASCENT;
+                               else
+                                       next_sensor = log.tick + AO_SENSOR_INTERVAL_DESCENT;
+                       }
+                       ao_log_data_pos = ao_data_ring_next(ao_log_data_pos);
+               }
+#if HAS_FLIGHT
+               /* Write state change to EEPROM */
+               if (ao_flight_state != ao_log_state) {
+                       ao_log_state = ao_flight_state;
+                       log.type = AO_LOG_STATE;
+                       log.tick = ao_time();
+                       log.u.state.state = ao_log_state;
+                       log.u.state.reason = 0;
+                       ao_log_mini(&log);
+
+                       if (ao_log_state == ao_flight_landed)
+                               ao_log_stop();
+               }
+#endif
+
+               ao_log_flush();
+
+               /* Wait for a while */
+               ao_delay(AO_MS_TO_TICKS(100));
+
+               /* Stop logging when told to */
+               while (!ao_log_running)
+                       ao_sleep(&ao_log_running);
+       }
+}
+
+uint16_t
+ao_log_flight(uint8_t slot)
+{
+       if (!ao_storage_read(ao_log_pos(slot),
+                            &log,
+                            sizeof (struct ao_log_mini)))
+               return 0;
+
+       if (ao_log_dump_check_data() && log.type == AO_LOG_FLIGHT)
+               return log.u.flight.flight;
+       return 0;
+}
index 492658ea2d05502aaebe2606ae4a843678964190..67767dc9ce285c88aeaa0510889be3aa906e8557 100644 (file)
@@ -105,7 +105,7 @@ ao_log(void)
                 */
                ao_sleep(DATA_TO_XDATA(&ao_sample_data));
                while (ao_log_data != ao_sample_data) {
-                       sum += ao_data_ring[ao_log_data].adc.pres;
+                       sum += ao_data_pres(&ao_data_ring[ao_log_data]);
                        count++;
                        ao_log_data = ao_data_ring_next(ao_log_data);
                }
index 6bc77608ef331a8782b6be051c948deab9cdcc52..35e64e655d92297c72fd36b070c59fb351621621 100644 (file)
@@ -102,8 +102,11 @@ extern __code __at (0x00aa) uint8_t ao_usb_descriptors [];
 #define AO_USB_INT_EP          1
 #define AO_USB_INT_SIZE                8
 
+#ifndef AO_USB_OUT_EP
 #define AO_USB_OUT_EP          4
 #define AO_USB_IN_EP           5
+#endif
+
 /*
  * USB bulk packets can only come in 8, 16, 32 and 64
  * byte sizes, so we'll use 64 for everything
index 390637d7fd116b5c39889b4ed65df295d6d6e1b5..9b768012a06b03b633fccb45f9b3b3fa9742422e 100644 (file)
@@ -82,7 +82,7 @@ __pdata uint16_t      ao_storage_unit;
 
 #if M25_MAX_CHIPS > 1
 static uint8_t ao_m25_size[M25_MAX_CHIPS];     /* number of sectors in each chip */
-static uint8_t ao_m25_pin[M25_MAX_CHIPS];      /* chip select pin for each chip */
+static ao_port_t ao_m25_pin[M25_MAX_CHIPS];    /* chip select pin for each chip */
 static uint8_t ao_m25_numchips;                        /* number of chips detected */
 #endif
 static uint8_t ao_m25_total;                   /* total sectors available */
@@ -112,7 +112,7 @@ static __xdata uint8_t      ao_m25_instruction[4];
  * Block until the specified chip is done writing
  */
 static void
-ao_m25_wait_wip(uint8_t cs)
+ao_m25_wait_wip(ao_port_t cs)
 {
        if (ao_m25_wip & cs) {
                M25_SELECT(cs);
@@ -132,7 +132,7 @@ ao_m25_wait_wip(uint8_t cs)
  * so that future operations will block until the WIP bit goes off
  */
 static void
-ao_m25_write_enable(uint8_t cs)
+ao_m25_write_enable(ao_port_t cs)
 {
        M25_SELECT(cs);
        ao_m25_instruction[0] = M25_WREN;
@@ -146,7 +146,7 @@ ao_m25_write_enable(uint8_t cs)
  * Returns the number of 64kB sectors
  */
 static uint8_t
-ao_m25_read_capacity(uint8_t cs)
+ao_m25_read_capacity(ao_port_t cs)
 {
        uint8_t capacity;
        M25_SELECT(cs);
@@ -166,12 +166,13 @@ ao_m25_read_capacity(uint8_t cs)
        return 1 << (capacity - 0x10);
 }
 
-static uint8_t
+static ao_port_t
 ao_m25_set_address(uint32_t pos)
 {
-       uint8_t chip;
+       ao_port_t       mask;
 #if M25_MAX_CHIPS > 1
        uint8_t size;
+       uint8_t         chip;
 
        for (chip = 0; chip < ao_m25_numchips; chip++) {
                size = ao_m25_size[chip];
@@ -182,16 +183,16 @@ ao_m25_set_address(uint32_t pos)
        if (chip == ao_m25_numchips)
                return 0xff;
 
-       chip = ao_m25_pin[chip];
+       mask = ao_m25_pin[chip];
 #else
-       chip = AO_M25_SPI_CS_MASK;
+       mask = AO_M25_SPI_CS_MASK;
 #endif
-       ao_m25_wait_wip(chip);
+       ao_m25_wait_wip(mask);
 
        ao_m25_instruction[1] = pos >> 16;
        ao_m25_instruction[2] = pos >> 8;
        ao_m25_instruction[3] = pos;
-       return chip;
+       return mask;
 }
 
 /*
@@ -239,7 +240,7 @@ ao_m25_scan(void)
 uint8_t
 ao_storage_erase(uint32_t pos) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + ao_storage_block > ao_storage_total)
                return 0;
@@ -268,7 +269,7 @@ ao_storage_erase(uint32_t pos) __reentrant
 uint8_t
 ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + len > ao_storage_total)
                return 0;
@@ -295,7 +296,7 @@ ao_storage_device_write(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 uint8_t
 ao_storage_device_read(uint32_t pos, __xdata void *d, uint16_t len) __reentrant
 {
-       uint8_t cs;
+       ao_port_t       cs;
 
        if (pos >= ao_storage_total || pos + len > ao_storage_total)
                return 0;
@@ -332,7 +333,7 @@ void
 ao_storage_device_info(void) __reentrant
 {
 #if M25_DEBUG
-       uint8_t cs;
+       ao_port_t       cs;
 #endif
 #if M25_MAX_CHIPS > 1
        uint8_t chip;
index bd57400e94690524170ae6ddaa203f3103eff0b2..8f1dcbe1688b268c00d5f6b526a2cc8f9a62cd5e 100644 (file)
@@ -26,14 +26,12 @@ static uint8_t                      ms5607_configured;
 
 static void
 ao_ms5607_start(void) {
-       ao_spi_get(AO_MS5607_SPI_INDEX,AO_SPI_SPEED_FAST);
-       ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 0);
+       ao_spi_get_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX, AO_SPI_SPEED_FAST);
 }
 
 static void
 ao_ms5607_stop(void) {
-       ao_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, 1);
-       ao_spi_put(AO_MS5607_SPI_INDEX);
+       ao_spi_put_bit(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, AO_MS5607_CS, AO_MS5607_SPI_INDEX);
 }
 
 static void
@@ -249,17 +247,9 @@ ao_ms5607_init(void)
         */
        ao_exti_setup(AO_MS5607_MISO_PORT,
                      AO_MS5607_MISO_PIN,
-                     AO_EXTI_MODE_RISING,
+                     AO_EXTI_MODE_RISING|
+                     AO_EXTI_PIN_NOCONFIGURE,
                      ao_ms5607_isr);
-
-#ifdef STM_MODER_ALTERNATE
-       /* Reset the pin from INPUT to ALTERNATE so that SPI works
-        * This needs an abstraction at some point...
-        */
-       stm_moder_set(AO_MS5607_MISO_PORT,
-                     AO_MS5607_MISO_PIN,
-                     STM_MODER_ALTERNATE);
-#endif
 }
 
 #endif
diff --git a/src/easymini-v0.1/.gitignore b/src/easymini-v0.1/.gitignore
new file mode 100644 (file)
index 0000000..e5f7d58
--- /dev/null
@@ -0,0 +1,2 @@
+ao_product.h
+*.elf
diff --git a/src/easymini-v0.1/Makefile b/src/easymini-v0.1/Makefile
new file mode 100644 (file)
index 0000000..612cc47
--- /dev/null
@@ -0,0 +1,85 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       lpc.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+       ao_interrupt.c \
+       ao_romconfig.c \
+       ao_product.c \
+       ao_mutex.c \
+       ao_panic.c \
+       ao_stdio.c \
+       ao_storage.c \
+       ao_report.c \
+       ao_ignite.c \
+       ao_flight.c \
+       ao_kalman.c \
+       ao_sample.c \
+       ao_data.c \
+       ao_convert_pa.c \
+       ao_led_lpc.c \
+       ao_task.c \
+       ao_log.c \
+       ao_log_mini.c \
+       ao_cmd.c \
+       ao_config.c \
+       ao_timer_lpc.c \
+       ao_exti_lpc.c \
+       ao_serial_lpc.c \
+       ao_usb_lpc.c \
+       ao_spi_lpc.c \
+       ao_adc_lpc.c \
+       ao_beep_lpc.c \
+       ao_m25.c \
+       ao_ms5607.c
+
+PRODUCT=EasyMini-v0.1
+PRODUCT_DEF=-DEASYMINI_V_0_1
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROGNAME=easymini-v0.1
+PROG=$(PROGNAME)-$(VERSION).elf
+
+SRC=$(ALTOS_SRC) ao_easymini.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.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)
+
+load: $(PROG)
+       lpc-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROG)
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/easymini-v0.1/ao_easymini.c b/src/easymini-v0.1/ao_easymini.c
new file mode 100644 (file)
index 0000000..97230b6
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright © 2011 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>
+
+void
+main(void)
+{
+       ao_clock_init();
+       ao_task_init();
+       ao_timer_init();
+       ao_exti_init();
+
+       ao_beep_init();
+
+       ao_adc_init();
+       ao_spi_init();
+       ao_storage_init();
+
+       ao_usb_init();
+
+       ao_cmd_init();
+       ao_flight_init();
+       ao_ms5607_init();
+       ao_log_init();
+       ao_report_init();
+       ao_igniter_init();
+       ao_config_init();
+
+       ao_start_scheduler();
+}
diff --git a/src/easymini-v0.1/ao_pins.h b/src/easymini-v0.1/ao_pins.h
new file mode 100644 (file)
index 0000000..d4fbe7a
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#define HAS_BEEP       1
+#define        HAS_LED         1
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#define LED_PORT       0
+#define LED_PIN_RED    7
+
+#define AO_LED_RED     (1 << LED_PIN_RED)
+
+#define LEDS_AVAILABLE AO_LED_RED
+
+#define HAS_USB                1
+
+#define HAS_USB_CONNECT        0
+#define HAS_USB_VBUS   0
+
+#define PACKET_HAS_SLAVE       0
+
+/* USART */
+
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     1
+#define SERIAL_0_18_19         1
+#define SERIAL_0_14_15         0
+#define SERIAL_0_17_18         0
+#define SERIAL_0_26_27         0
+
+/* SPI */
+
+#define HAS_SPI_0              1
+#define SPI_SCK0_P0_6          1
+#define HAS_SPI_1              1
+#define SPI_SCK1_P1_15         1
+#define SPI_MISO1_P0_22                1
+#define SPI_MOSI1_P0_21                1
+
+/* M25 */
+
+#define M25_MAX_CHIPS          1
+#define AO_M25_SPI_CS_PORT     0
+#define AO_M25_SPI_CS_MASK     (1 << 23)
+#define AO_M25_SPI_BUS         1
+
+/* MS5607 */
+
+#define HAS_MS5607             1
+#define HAS_MS5611             0
+#define AO_MS5607_PRIVATE_PINS 0
+#define AO_MS5607_CS_PORT      0
+#define AO_MS5607_CS_PIN       7
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS_PIN)
+#define AO_MS5607_MISO_PORT    0
+#define AO_MS5607_MISO_PIN     8
+#define AO_MS5607_MISO_MASK    (1 << AO_MS5607_MISO_PIN)
+#define AO_MS5607_SPI_INDEX    0
+
+#define HAS_ACCEL              0
+#define HAS_GPS                        0
+#define HAS_RADIO              0
+#define HAS_FLIGHT             1
+#define HAS_EEPROM             1
+#define HAS_TELEMETRY          0
+#define HAS_APRS               0
+#define HAS_LOG                        1
+#define USE_INTERNAL_FLASH     0
+#define HAS_IGNITE             1
+#define HAS_IGNITE_REPORT      1
+
+#define AO_DATA_RING           16
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC                        1
+
+#define AO_NUM_ADC             3
+
+#define AO_ADC_0               1
+#define AO_ADC_1               1
+#define AO_ADC_2               1
+
+struct ao_adc {
+       int16_t         sense_a;
+       int16_t         sense_m;
+       int16_t         v_batt;
+};
+
+/*
+ * Igniter
+ */
+
+#define AO_IGNITER_CLOSED      400
+#define AO_IGNITER_OPEN                60
+
+#define AO_IGNITER_DROGUE_PORT 0
+#define AO_IGNITER_DROGUE_PIN  2
+#define AO_IGNITER_SET_DROGUE(v)       ao_gpio_set(AO_IGNITER_DROGUE_PORT, AO_IGNITER_DROGUE_PIN, AO_IGNITER_DROGUE, v)
+
+#define AO_IGNITER_MAIN_PORT   0
+#define AO_IGNITER_MAIN_PIN    3
+#define AO_IGNITER_SET_MAIN(v)         ao_gpio_set(AO_IGNITER_MAIN_PORT, AO_IGNITER_MAIN_PIN, AO_IGNITER_MAIN, v)
+
+#define AO_SENSE_DROGUE(p)     ((p)->adc.sense_a)
+#define AO_SENSE_MAIN(p)       ((p)->adc.sense_m)
+
+#define AO_ADC_DUMP(p) \
+       printf("tick: %5u apogee: %5d main: %5d batt: %5d\n", \
+              (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
diff --git a/src/lpc/Makefile.defs b/src/lpc/Makefile.defs
new file mode 100644 (file)
index 0000000..b63bdd1
--- /dev/null
@@ -0,0 +1,42 @@
+vpath % ../lpc:../product:../drivers:../core:../util:../kalman:../aes:..
+vpath make-altitude ../util
+vpath make-kalman ../util
+vpath kalman.5c ../kalman
+vpath kalman_filter.5c ../kalman
+vpath load_csv.5c ../kalman
+vpath matrix.5c ../kalman
+vpath ao-make-product.5c ../util
+
+CC=/usr/bin/arm-none-eabi-gcc
+SAT=/opt/cortex
+SAT_CLIB=$(SAT)/lib/pdclib-cortex-m0.a
+SAT_CFLAGS=-I$(SAT)/include
+
+ifndef VERSION
+include ../Version
+endif
+
+AO_CFLAGS=-I. -I../lpc -I../core -I../drivers -I..
+LPC_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb -ffreestanding -nostdlib $(AO_CFLAGS) $(SAT_CFLAGS)
+
+LDFLAGS=-L../stm -Wl,-Taltos.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 $@ $<
+
+ao_serial_lpc.h: ../lpc/baud_rate ao_pins.h
+       nickle ../lpc/baud_rate `awk '/AO_LPC_CLKOUT/{print $$3}' ao_pins.h` > $@
+
+ao_serial_lpc.o: ao_serial_lpc.h
+
+.DEFAULT_GOAL=all
diff --git a/src/lpc/altos.ld b/src/lpc/altos.ld
new file mode 100644 (file)
index 0000000..4d6f35a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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 (rx) : ORIGIN = 0x00000000, LENGTH = 32K
+       ram (!w) : ORIGIN = 0x10000000, LENGTH = 4K - 128
+       usb (!x) : ORIGIN = 0x20004000 + 2K - 256, LENGTH = 256
+       stack (!w) : ORIGIN = 0x10000000 + 4K - 128, LENGTH = 128
+}
+
+INCLUDE registers.ld
+
+EXTERN (lpc_interrupt_vector)
+
+SECTIONS {
+       /*
+        * Rom contents
+        */
+
+       .text ORIGIN(rom) : {
+               __text_start__ = .;
+               *(.interrupt)   /* Interrupt vectors */
+
+               . = ORIGIN(rom) + 0x100;
+
+               ao_romconfig.o(.romconfig*)
+               ao_product.o(.romconfig*)
+
+               *(.text*)       /* Executable code */
+               *(.rodata*)     /* Constants */
+
+       } > rom
+
+       .ARM.exidx : {
+               *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+               __text_end__ = .;
+       } > rom
+
+       /* Data -- relocated to RAM, but written to ROM
+        */
+       .data ORIGIN(ram) : AT (ADDR(.ARM.exidx) + SIZEOF (.ARM.exidx)) {
+               __data_start__ = .;
+               *(.data)        /* initialized data */
+               __data_end__ = .;
+               __bss_start__ = .;
+       } >ram
+
+       .bss : {
+               *(.bss)
+               *(COMMON)
+               __bss_end__ = .;
+       } >ram
+       PROVIDE(end = .);
+
+       PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack));
+}
+
+ENTRY(start);
+
+
diff --git a/src/lpc/ao_adc_lpc.c b/src/lpc/ao_adc_lpc.c
new file mode 100644 (file)
index 0000000..9ecc7c1
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_data.h>
+
+#ifndef AO_ADC_0
+#define AO_ADC_0       0
+#endif
+
+#ifndef AO_ADC_1
+#define AO_ADC_1       0
+#endif
+
+#ifndef AO_ADC_2
+#define AO_ADC_2       0
+#endif
+
+#ifndef AO_ADC_3
+#define AO_ADC_3       0
+#endif
+
+#ifndef AO_ADC_4
+#define AO_ADC_4       0
+#endif
+
+#ifndef AO_ADC_5
+#define AO_ADC_5       0
+#endif
+
+#ifndef AO_ADC_6
+#define AO_ADC_6       0
+#endif
+
+#ifndef AO_ADC_7
+#define AO_ADC_7       0
+#endif
+
+#if AO_ADC_7
+# define AO_ADC_LAST           7
+#else
+# if AO_ADC_6
+#  define AO_ADC_LAST          6
+# else
+#  if AO_ADC_5
+#   define AO_ADC_LAST         5
+#  else
+#   if AO_ADC_4
+#    define AO_ADC_LAST                4
+#   else
+#    if AO_ADC_3
+#     define AO_ADC_LAST       3
+#    else
+#     if AO_ADC_2
+#      define AO_ADC_LAST      2
+#     else
+#      if AO_ADC_1
+#       define AO_ADC_LAST     1
+#      else
+#       if AO_ADC_0
+#        define AO_ADC_LAST    0
+#       endif
+#      endif
+#     endif
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+static uint8_t                 ao_adc_ready;
+
+void  lpc_adc_isr(void)
+{
+       uint32_t        stat = lpc_adc.stat;
+       uint16_t        *out = (uint16_t *) &ao_data_ring[ao_data_head].adc;
+       vuint32_t       *in = &lpc_adc.dr[0];
+
+       lpc_adc.cr = 0;
+       lpc_adc.stat = 0;
+
+       /* Store converted values in packet */
+
+#if AO_ADC_0
+       *out++ = lpc_adc.dr[0] >> 1;
+#endif
+#if AO_ADC_1
+       *out++ = lpc_adc.dr[1] >> 1;
+#endif
+#if AO_ADC_2
+       *out++ = lpc_adc.dr[2] >> 1;
+#endif
+#if AO_ADC_3
+       *out++ = lpc_adc.dr[3] >> 1;
+#endif
+#if AO_ADC_4
+       *out++ = lpc_adc.dr[4] >> 1;
+#endif
+#if AO_ADC_5
+       *out++ = lpc_adc.dr[5] >> 1;
+#endif
+#if AO_ADC_6
+       *out++ = lpc_adc.dr[6] >> 1;
+#endif
+#if AO_ADC_7
+       *out++ = lpc_adc.dr[7] >> 1;
+#endif
+
+       AO_DATA_PRESENT(AO_DATA_ADC);
+       if (ao_data_present == AO_DATA_ALL) {
+#if HAS_MS5607
+               ao_data_ring[ao_data_head].ms5607_raw = ao_ms5607_current;
+#endif
+#if HAS_MMA655X
+               ao_data_ring[ao_data_head].mma655x = ao_mma655x_current;
+#endif
+#if HAS_HMC5883
+               ao_data_ring[ao_data_head].hmc5883 = ao_hmc5883_current;
+#endif
+#if HAS_MPU6000
+               ao_data_ring[ao_data_head].mpu6000 = ao_mpu6000_current;
+#endif
+               ao_data_ring[ao_data_head].tick = ao_tick_count;
+               ao_data_head = ao_data_ring_next(ao_data_head);
+               ao_wakeup((void *) &ao_data_head);
+       }
+       ao_adc_ready = 1;
+}
+
+#define AO_ADC_MASK    ((AO_ADC_0 << 0) |      \
+                        (AO_ADC_1 << 1) |      \
+                        (AO_ADC_2 << 2) |      \
+                        (AO_ADC_3 << 3) |      \
+                        (AO_ADC_4 << 4) |      \
+                        (AO_ADC_5 << 5) |      \
+                        (AO_ADC_6 << 6) |      \
+                        (AO_ADC_7 << 7))
+
+#define AO_ADC_CLKDIV  (AO_LPC_CLKOUT / 4500000)
+
+/*
+ * Start the ADC sequence using the DMA engine
+ */
+void
+ao_adc_poll(void)
+{
+       if (!ao_adc_ready)
+               return;
+       ao_adc_ready = 0;
+
+       lpc_adc.cr = ((AO_ADC_MASK << LPC_ADC_CR_SEL) |
+                     (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) |
+                     (1 << LPC_ADC_CR_BURST) |
+                     (LPC_ADC_CR_CLKS_11 << LPC_ADC_CR_CLKS));
+}
+
+static void
+ao_adc_dump(void) __reentrant
+{
+       struct ao_data  packet;
+       int16_t *d;
+       uint8_t i;
+
+       ao_data_get(&packet);
+#ifdef AO_ADC_DUMP
+       AO_ADC_DUMP(&packet);
+#else
+       printf("tick: %5u",  packet.tick);
+       d = (int16_t *) (&packet.adc);
+       for (i = 0; i < AO_NUM_ADC; i++)
+               printf (" %2d: %5d", i, d[i]);
+       printf("\n");
+#endif
+}
+
+__code struct ao_cmds ao_adc_cmds[] = {
+       { ao_adc_dump,  "a\0Display current ADC values" },
+       { 0, NULL },
+};
+
+void
+ao_adc_init(void)
+{
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC);
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD);
+
+       /* Enable interrupt when last channel is complete */
+       lpc_adc.inten = (1 << AO_ADC_LAST);
+
+       lpc_nvic_set_enable(LPC_ISR_ADC_POS);
+       lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY);
+#if AO_ADC_0
+       ao_enable_analog(0, 11);
+#endif
+#if AO_ADC_1
+       ao_enable_analog(0, 12);
+#endif
+#if AO_ADC_2
+       ao_enable_analog(0, 13);
+#endif
+#if AO_ADC_3
+       ao_enable_analog(0, 14);
+#endif
+#if AO_ADC_4
+       ao_enable_analog(0, 14);
+#endif
+#if AO_ADC_5
+       ao_enable_analog(0, 14);
+#endif
+#if AO_ADC_6
+       ao_enable_analog(0, 14);
+#endif
+#if AO_ADC_7
+       ao_enable_analog(0, 14);
+#endif
+       ao_cmd_register(&ao_adc_cmds[0]);
+
+       ao_adc_ready = 1;
+}
diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h
new file mode 100644 (file)
index 0000000..f605e3d
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ * 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_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <lpc.h>
+
+/*
+ * LPC11U14 definitions and code fragments for AltOS
+ */
+
+#define AO_STACK_SIZE  320
+
+#define AO_LED_TYPE    uint16_t
+
+#define AO_PORT_TYPE   uint32_t
+
+#ifndef AO_TICK_TYPE
+#define AO_TICK_TYPE   uint16_t
+#define AO_TICK_SIGNED int16_t
+#endif
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare  __attribute__((naked))
+#define ao_arch_naked_define
+#define __pdata
+#define __data
+#define __xdata
+#define __code const
+#define __reentrant
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() arm_scb.aircr = ((0x05fa << 16) |     \
+                                         (0 << 15) |           \
+                                         (1 << 2) |            \
+                                         (0 << 1))
+
+#define ao_arch_nop()          asm("nop")
+
+#define ao_arch_interrupt(n)   /* nothing */
+
+#undef putchar
+#undef getchar
+#define putchar(c)     ao_putchar(c)
+#define getchar                ao_getchar
+
+extern void putchar(char c);
+extern char getchar(void);
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_VERSION   2
+
+#define AO_ROMCONFIG_SYMBOL(a) __attribute__((section(".romconfig"))) const
+
+extern const uint16_t ao_romconfig_version;
+extern const uint16_t ao_romconfig_check;
+extern const uint16_t ao_serial_number;
+extern const uint32_t ao_radio_cal;
+
+#define ao_arch_task_members\
+       uint32_t *sp;                   /* saved stack pointer */
+
+#define ao_arch_block_interrupts()     asm("cpsid i")
+#define ao_arch_release_interrupts()   asm("cpsie i")
+
+/*
+ * For now, we're running at a weird frequency
+ */
+
+#if AO_HSE
+#define AO_PLLSRC      AO_HSE
+#else
+#define AO_PLLSRC      STM_HSI_FREQ
+#endif
+
+#define AO_PLLVCO      (AO_PLLSRC * AO_PLLMUL)
+#define AO_SYSCLK      (AO_PLLVCO / AO_PLLDIV)
+#define AO_HCLK                (AO_SYSCLK / AO_AHB_PRESCALER)
+#define AO_PCLK1       (AO_HCLK / AO_APB1_PRESCALER)
+#define AO_PCLK2       (AO_HCLK / AO_APB2_PRESCALER)
+
+#if AO_APB1_PRESCALER == 1
+#define AO_TIM23467_CLK                AO_PCLK1
+#else
+#define AO_TIM23467_CLK                (2 * AO_PCLK1)
+#endif
+
+#if AO_APB2_PRESCALER == 1
+#define AO_TIM91011_CLK                AO_PCLK2
+#else
+#define AO_TIM91011_CLK                (2 * AO_PCLK2)
+#endif
+
+#define AO_LPC_NVIC_HIGH_PRIORITY      0
+#define AO_LPC_NVIC_CLOCK_PRIORITY     1
+#define AO_LPC_NVIC_MED_PRIORITY       2
+#define AO_LPC_NVIC_LOW_PRIORITY       3
+
+void
+ao_adc_init(void);
+
+#define AO_USB_OUT_EP  2
+#define AO_USB_IN_EP   3
+
+void
+ao_serial_init(void);
+
+/* SPI definitions */
+
+#define AO_SPI_SPEED_12MHz             4
+#define AO_SPI_SPEED_6MHz              8
+#define AO_SPI_SPEED_4MHz              12
+#define AO_SPI_SPEED_2MHz              24
+#define AO_SPI_SPEED_1MHz              48
+#define AO_SPI_SPEED_500kHz            96
+#define AO_SPI_SPEED_250kHz            192
+
+#define AO_SPI_SPEED_FAST      AO_SPI_SPEED_12MHz
+
+#endif /* _AO_ARCH_H_ */
diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h
new file mode 100644 (file)
index 0000000..204d122
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+#define ao_enable_port(port) (lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO))
+
+#define lpc_all_bit(port,bit)  (((port) << 5) | (bit))
+
+#define ao_gpio_set(port, bit, pin, v) (lpc_gpio.byte[lpc_all_bit(port,bit)] = (v))
+
+#define ao_gpio_get(port, bit, pin)    (lpc_gpio_byte[lpc_all_bit(port,bit)])
+
+#define ao_enable_output(port,bit,pin,v) do {                  \
+               ao_enable_port(port);                           \
+               ao_gpio_set(port, bit, pin, v);                 \
+               lpc_gpio.dir[port] |= (1 << bit);               \
+       } while (0)
+
+#define ao_enable_input(port,bit,mode) do {                            \
+               vuint32_t *_ioconf = &lpc_ioconf.pio0_0 + ((port)*24+(bit)); \
+               vuint32_t _mode;                                        \
+               ao_enable_port(port);                                   \
+               lpc_gpio.dir[port] &= ~(1 << bit);                      \
+               if (mode == AO_EXTI_MODE_PULL_UP)                       \
+                       _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+               else if (mode == AO_EXTI_MODE_PULL_DOWN)                \
+                       _mode = LPC_IOCONF_MODE_PULL_UP << LPC_IOCONF_MODE; \
+               else                                                    \
+                       _mode = LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE; \
+               *_ioconf = ((*_ioconf & ~(LPC_IOCONF_MODE_MASK << LPC_IOCONF_MODE)) | \
+                           _mode |                                     \
+                           (1 << LPC_IOCONF_ADMODE));                  \
+       } while (0)
+
+#define ao_enable_analog(port,bit) do {                                        \
+               vuint32_t *_ioconf = &lpc_ioconf.pio0_0 + ((port)*24+(bit)); \
+               ao_enable_port(port);                                   \
+               lpc_gpio.dir[port] &= ~(1 << bit);                      \
+               *_ioconf = *_ioconf & ~((1 << LPC_IOCONF_ADMODE) |      \
+                                       (LPC_IOCONF_MODE_MASK << LPC_IOCONF_MODE)); \
+       } while (0)
+       
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+static inline uint32_t
+ao_arch_irqsave(void) {
+       uint32_t        primask;
+       asm("mrs %0,primask" : "=&r" (primask));
+       ao_arch_block_interrupts();
+       return primask;
+}
+
+static inline void
+ao_arch_irqrestore(uint32_t primask) {
+       asm("msr primask,%0" : : "r" (primask));
+}
+
+static inline void
+ao_arch_memory_barrier() {
+       asm volatile("" ::: "memory");
+}
+
+static inline void
+ao_arch_init_stack(struct ao_task *task, void *start)
+{
+       uint32_t        *sp = (uint32_t *) (task->stack + AO_STACK_SIZE);
+       uint32_t        a = (uint32_t) start;
+       int             i;
+
+       /* Return address (goes into LR) */
+       ARM_PUSH32(sp, a);
+
+       /* Clear register values r0-r7 */
+       i = 8;
+       while (i--)
+               ARM_PUSH32(sp, 0);
+
+       /* APSR */
+       ARM_PUSH32(sp, 0);
+
+       /* PRIMASK with interrupts enabled */
+       ARM_PUSH32(sp, 0);
+
+       task->sp = sp;
+}
+
+static inline void ao_arch_save_regs(void) {
+       /* Save general registers */
+       asm("push {r0-r7,lr}\n");
+
+       /* Save APSR */
+       asm("mrs r0,apsr");
+       asm("push {r0}");
+
+       /* Save PRIMASK */
+       asm("mrs r0,primask");
+       asm("push {r0}");
+}
+
+static inline void ao_arch_save_stack(void) {
+       uint32_t        *sp;
+       asm("mov %0,sp" : "=&r" (sp) );
+       ao_cur_task->sp = (sp);
+       if ((uint8_t *) sp < &ao_cur_task->stack[0])
+               ao_panic (AO_PANIC_STACK);
+}
+
+static inline void ao_arch_restore_stack(void) {
+       uint32_t        sp;
+       sp = (uint32_t) ao_cur_task->sp;
+
+       /* Switch stacks */
+       asm("mov sp, %0" : : "r" (sp) );
+
+       /* Restore PRIMASK */
+       asm("pop {r0}");
+       asm("msr primask,r0");
+
+       /* Restore APSR */
+       asm("pop {r0}");
+       asm("msr apsr_nczvq,r0");
+
+       /* Restore general registers and return */
+       asm("pop {r0-r7,pc}\n");
+}
+
+#define ao_arch_isr_stack()
+
+#define ao_arch_wait_interrupt() do {                  \
+               asm(".global ao_idle_loc\n\twfi\nao_idle_loc:");        \
+               ao_arch_release_interrupts();                           \
+               ao_arch_block_interrupts();                             \
+       } while (0)
+
+#define ao_arch_critical(b) do {                               \
+               ao_arch_block_interrupts();                     \
+               do { b } while (0);                             \
+               ao_arch_release_interrupts();                   \
+       } while (0)
+
+/*
+ * SPI
+ */
+
+#define ao_spi_set_cs(port,mask) (lpc_gpio.clr[port] = (mask))
+#define ao_spi_clr_cs(port,mask) (lpc_gpio.set[port] = (mask))
+
+#define ao_spi_get_mask(port,mask,bus,speed) do {      \
+               ao_spi_get(bus, speed);                 \
+               ao_spi_set_cs(port, mask);              \
+       } while (0)
+
+#define ao_spi_put_mask(reg,mask,bus) do {     \
+               ao_spi_clr_cs(reg,mask);        \
+               ao_spi_put(bus);                \
+       } while (0)
+
+#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index);
+
+extern uint16_t        ao_spi_speed[LPC_NUM_SPI];
+
+void
+ao_spi_init(void);
+
+#define ao_spi_init_cs(port, mask) do {                                        \
+               uint8_t __bit__;                                        \
+               for (__bit__ = 0; __bit__ < 32; __bit__++) {            \
+                       if (mask & (1 << __bit__))                      \
+                               ao_enable_output(port, __bit__, PIN, 1); \
+               }                                                       \
+       } while (0)
+
+#define HAS_ARCH_START_SCHEDULER       1
+
+static inline void ao_arch_start_scheduler(void) {
+       uint32_t        sp;
+       uint32_t        control;
+
+       asm("mrs %0,msp" : "=&r" (sp));
+       asm("msr psp,%0" : : "r" (sp));
+       asm("mrs %0,control" : "=&r" (control));
+       control |= (1 << 1);
+       asm("msr control,%0" : : "r" (control));
+}
+
+#endif /* _AO_ARCH_FUNCS_H_ */
diff --git a/src/lpc/ao_beep_lpc.c b/src/lpc/ao_beep_lpc.c
new file mode 100644 (file)
index 0000000..eb9132b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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"
+
+void
+ao_beep(uint8_t beep)
+{
+       if (beep == 0) {
+               lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+                                 (1 << LPC_CT32B_TCR_CRST));
+               lpc_scb.sysahbclkctrl &= ~(1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+       } else {
+               lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+               /* Set prescaler to match cc1111 clocks
+                */
+               lpc_ct32b1.pr = AO_LPC_SYSCLK / 750000 - 1;
+
+               /* Write the desired data in the match registers */
+
+               /* Reset after two time units */
+               lpc_ct32b1.mr[0] = beep << 1;
+
+               /* PWM width is half of that */
+               lpc_ct32b1.mr[1] = beep;
+
+               /* Flip output 1 on PWM match */
+               lpc_ct32b1.emr = (LPC_CT32B_EMR_EMC_TOGGLE << LPC_CT32B_EMR_EMC1);
+
+               /* Reset on match 0 */
+               lpc_ct32b1.mcr = (1 << LPC_CT32B_MCR_MR0R);
+
+               /* PWM on match 1 */
+               lpc_ct32b1.pwmc = (1 << LPC_CT32B_PWMC_PWMEN1);
+               
+               /* timer mode */
+               lpc_ct32b1.ctcr = 0;
+
+               /* And turn the timer on */
+               lpc_ct32b1.tcr = ((1 << LPC_CT32B_TCR_CEN) |
+                                 (0 << LPC_CT32B_TCR_CRST));
+       }
+}
+
+void
+ao_beep_for(uint8_t beep, uint16_t ticks) __reentrant
+{
+       ao_beep(beep);
+       ao_delay(ticks);
+       ao_beep(0);
+}
+
+void
+ao_beep_init(void)
+{
+       /* Our beeper is on c32b1_mat1
+        * which is on pin pio0_14
+        */
+
+       lpc_ioconf.pio0_14 = ((LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (1 << LPC_IOCONF_ADMODE) |
+                             (0 << LPC_IOCONF_OD));
+
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_CT32B1);
+
+       /* Disable the counter and reset the value */
+       lpc_ct32b1.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+                         (1 << LPC_CT32B_TCR_CRST));
+}
diff --git a/src/lpc/ao_exti.h b/src/lpc/ao_exti.h
new file mode 100644 (file)
index 0000000..e8599eb
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING    1
+#define AO_EXTI_MODE_FALLING   2
+#define AO_EXTI_MODE_PULL_UP   4
+#define AO_EXTI_MODE_PULL_DOWN 8
+#define AO_EXTI_PRIORITY_LOW   16
+#define AO_EXTI_PRIORITY_MED   0
+#define AO_EXTI_PRIORITY_HIGH  32
+#define AO_EXTI_PIN_NOCONFIGURE        64
+
+void
+ao_exti_setup(uint8_t gpio, uint8_t pin, uint8_t mode, void (*callback)());
+
+void
+ao_exti_set_mode(uint8_t gpio, uint8_t pin, uint8_t mode);
+
+void
+ao_exti_set_callback(uint8_t gpio, uint8_t pin, void (*callback)());
+
+void
+ao_exti_enable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_disable(uint8_t gpio, uint8_t pin);
+
+void
+ao_exti_init(void);
+
+#endif /* _AO_EXTI_H_ */
diff --git a/src/lpc/ao_exti_lpc.c b/src/lpc/ao_exti_lpc.c
new file mode 100644 (file)
index 0000000..588cf58
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+#define LPC_NUM_PINS   56
+#define LPC_NUM_PINT   8
+
+static void    (*ao_exti_callback[LPC_NUM_PINT])(void);
+
+static uint8_t ao_pint_map[LPC_NUM_PINS];
+static uint8_t ao_pint_mode[LPC_NUM_PINS];
+static uint8_t ao_pint_inuse;
+static uint8_t ao_pint_enabled;
+
+static void
+ao_exti_isr(uint8_t pint)
+{
+       uint8_t mask = 1 << pint;
+
+       if (lpc_gpio_pin.ist & mask) {
+               lpc_gpio_pin.ist = mask;
+               lpc_gpio_pin.rise = mask;
+               lpc_gpio_pin.fall = mask;
+
+               (*ao_exti_callback[pint]) ();
+       }
+}
+
+#define pin_isr(n)     void lpc_pin_int ## n ## _isr(void) { ao_exti_isr(n); }
+pin_isr(0)
+pin_isr(1)
+pin_isr(2)
+pin_isr(3)
+pin_isr(4)
+pin_isr(5)
+pin_isr(6)
+pin_isr(7)
+
+#define pin_id(port,pin)       ((port) * 24 + (pin));
+
+static void
+_ao_exti_set_enable(uint8_t pint)
+{
+       uint8_t         mask = 1 << pint;
+       uint8_t         mode;
+
+       if (ao_pint_enabled & mask)
+               mode = ao_pint_mode[pint];
+       else
+               mode = 0;
+
+       if (mode & AO_EXTI_MODE_RISING)
+               lpc_gpio_pin.sienr = mask;
+       else
+               lpc_gpio_pin.cienr = mask;
+               
+       if (mode & AO_EXTI_MODE_FALLING)
+               lpc_gpio_pin.sienf = mask;
+       else
+               lpc_gpio_pin.cienf = mask;
+       lpc_gpio_pin.rise = mask;
+       lpc_gpio_pin.fall = mask;
+}
+
+void
+ao_exti_setup (uint8_t port, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint;
+       uint32_t        mask;
+       uint8_t         prio;
+
+       for (pint = 0; pint < LPC_NUM_PINT; pint++)
+               if ((ao_pint_inuse & (1 << pint)) == 0)
+                       break;
+       if (pint == LPC_NUM_PINT)
+               ao_panic(AO_PANIC_EXTI);
+
+       if (!mode & AO_EXTI_PIN_NOCONFIGURE)
+               ao_enable_input(port, pin, mode);
+
+       ao_arch_block_interrupts();
+       mask = (1 << pint);
+       ao_pint_inuse |= mask;
+       ao_pint_enabled &= ~mask;
+       
+       ao_pint_map[id] = pint;
+       ao_exti_callback[pint] = callback;
+
+       /* configure gpio to interrupt routing */
+       lpc_scb.pintsel[pint] = id;
+
+       /* Set edge triggered */
+       lpc_gpio_pin.isel &= ~mask;
+
+       ao_pint_enabled &= ~mask;
+       ao_pint_mode[pint] = mode;
+       _ao_exti_set_enable(pint);
+
+       /* Set interrupt mask and rising/falling mode */
+
+       prio = AO_LPC_NVIC_MED_PRIORITY;
+       if (mode & AO_EXTI_PRIORITY_LOW)
+               prio = AO_LPC_NVIC_LOW_PRIORITY;
+       else if (mode & AO_EXTI_PRIORITY_HIGH)
+               prio = AO_LPC_NVIC_HIGH_PRIORITY;
+
+       /* Set priority and enable */
+       lpc_nvic_set_priority(LPC_ISR_PIN_INT0_POS + pint, prio);
+       lpc_nvic_set_enable(LPC_ISR_PIN_INT0_POS + pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_mode(uint8_t port, uint8_t pin, uint8_t mode)
+{
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+
+       ao_arch_block_interrupts();
+       ao_pint_mode[pint] = mode;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_set_callback(uint8_t port, uint8_t pin, void (*callback)()) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+
+       ao_exti_callback[pint] = callback;
+}
+
+void
+ao_exti_enable(uint8_t port, uint8_t pin)
+{
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+       uint8_t         mask = 1 << pint;
+
+       ao_arch_block_interrupts();
+       ao_pint_enabled |= mask;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_disable(uint8_t port, uint8_t pin) {
+       uint8_t         id = pin_id(port,pin);
+       uint8_t         pint = ao_pint_map[id];
+       uint8_t         mask = 1 << pint;
+
+       ao_arch_block_interrupts();
+       ao_pint_enabled &= ~mask;
+       _ao_exti_set_enable(pint);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_exti_init(void)
+{
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_PINT);
+}
diff --git a/src/lpc/ao_interrupt.c b/src/lpc/ao_interrupt.c
new file mode 100644 (file)
index 0000000..b5e6700
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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 <string.h>
+
+extern void main(void);
+extern char __stack__;
+extern char __text_start__, __text_end__;
+extern char __data_start__, __data_end__;
+extern char __bss_start__, __bss_end__;
+
+/* Interrupt functions */
+
+void lpc_halt_isr(void)
+{
+       ao_panic(AO_PANIC_CRASH);
+}
+
+void lpc_ignore_isr(void)
+{
+}
+
+int x;
+
+void start(void) {
+       x = 0;
+       memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__);
+       memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__);
+       main();
+}
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+       void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_ignore_isr))
+
+#define isr_halt(name) \
+       void __attribute__ ((weak)) lpc_ ## name ## _isr(void); \
+       _Pragma(STRINGIFY(weak lpc_ ## name ## _isr = lpc_halt_isr))
+
+isr(nmi)
+isr_halt(hardfault)
+isr_halt(memmanage)
+isr_halt(busfault)
+isr_halt(usagefault)
+isr(svc)
+isr(debugmon)
+isr(pendsv)
+isr(systick)
+
+isr(pin_int0)  /* IRQ0 */
+isr(pin_int1)
+isr(pin_int2)
+isr(pin_int3)
+isr(pin_int4)  /* IRQ4 */
+isr(pin_int5)
+isr(pin_int6)
+isr(pin_int7)
+
+isr(gint0)     /* IRQ8 */
+isr(gint1)
+isr(ssp1)
+isr(i2c)
+
+isr(ct16b0)    /* IRQ16 */
+isr(ct16b1)
+isr(ct32b0)
+isr(ct32b1)
+isr(ssp0)      /* IRQ20 */
+isr(usart)
+isr(usb_irq)
+isr(usb_fiq)
+
+isr(adc)       /* IRQ24 */
+isr(wwdt)
+isr(bod)
+isr(flash)
+
+isr(usb_wakeup)
+
+#define i(addr,name)   [(addr)/4] = lpc_ ## name ## _isr
+#define c(addr,value)  [(addr)/4] = (value)
+
+__attribute__ ((section(".interrupt")))
+const void *lpc_interrupt_vector[] = {
+       [0] = &__stack__,
+       [1] = start,
+       i(0x08, nmi),
+       i(0x0c, hardfault),
+       c(0x10, 0),
+       c(0x14, 0),
+       c(0x18, 0),
+       c(0x1c, 0),
+       c(0x20, 0),
+       c(0x24, 0),
+       c(0x28, 0),
+       i(0x2c, svc),
+       i(0x30, hardfault),
+       i(0x34, hardfault),
+       i(0x38, pendsv),
+       i(0x3c, systick),
+
+       i(0x40, pin_int0),      /* IRQ0 */
+       i(0x44, pin_int1),
+       i(0x48, pin_int2),
+       i(0x4c, pin_int3),
+       i(0x50, pin_int4),      /* IRQ4 */
+       i(0x54, pin_int5),
+       i(0x58, pin_int6),
+       i(0x5c, pin_int7),
+
+       i(0x60, gint0),         /* IRQ8 */
+       i(0x64, gint1),
+       i(0x68, hardfault),
+       i(0x6c, hardfault),
+       i(0x70, hardfault),     /* IRQ12 */
+       i(0x74, hardfault),
+       i(0x78, ssp1),
+       i(0x7c, i2c),
+
+       i(0x80, ct16b0),        /* IRQ16 */
+       i(0x84, ct16b1),
+       i(0x88, ct32b0),
+       i(0x8c, ct32b1),
+       i(0x90, ssp0),          /* IRQ20 */
+       i(0x94, usart),
+       i(0x98, usb_irq),
+       i(0x9c, usb_fiq),
+
+       i(0xa0, adc),           /* IRQ24 */
+       i(0xa4, wwdt),
+       i(0xa8, bod),
+       i(0xac, flash),
+
+       i(0xb0, hardfault),     /* IRQ28 */
+       i(0xb4, hardfault),
+       i(0xb8, usb_wakeup),
+       i(0xbc, hardfault),     
+};
diff --git a/src/lpc/ao_led_lpc.c b/src/lpc/ao_led_lpc.c
new file mode 100644 (file)
index 0000000..7bef51b
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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>
+
+__pdata uint16_t ao_led_enable;
+
+void
+ao_led_on(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] |= colors;
+}
+
+void
+ao_led_off(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] &= ~colors;
+}
+
+void
+ao_led_set(uint16_t colors)
+{
+       uint16_t        on = colors & ao_led_enable;
+       uint16_t        off = ~colors & ao_led_enable;
+
+       ao_led_off(off);
+       ao_led_on(on);
+}
+
+void
+ao_led_toggle(uint16_t colors)
+{
+       lpc_gpio.pin[LED_PORT] ^= colors;
+}
+
+void
+ao_led_for(uint16_t colors, uint16_t ticks) __reentrant
+{
+       ao_led_on(colors);
+       ao_delay(ticks);
+       ao_led_off(colors);
+}
+
+void
+ao_led_init(uint16_t enable)
+{
+       int     bit;
+
+       ao_led_enable = enable;
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO);
+       lpc_gpio.dir[LED_PORT] |= enable;
+}
diff --git a/src/lpc/ao_romconfig.c b/src/lpc/ao_romconfig.c
new file mode 100644 (file)
index 0000000..cbb922e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright © 2011 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"
+
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION;
+AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0;
+#ifdef AO_RADIO_CAL_DEFAULT
+AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT;
+#endif
diff --git a/src/lpc/ao_serial_lpc.c b/src/lpc/ao_serial_lpc.c
new file mode 100644 (file)
index 0000000..c042469
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * 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_serial.h>
+
+struct ao_fifo ao_usart_rx_fifo;
+struct ao_fifo ao_usart_tx_fifo;
+uint8_t                ao_usart_tx_avail;
+uint8_t                ao_usart_tx_avail_min;
+
+#define LPC_USART_TX_FIFO_SIZE 16
+
+void
+ao_debug_out(char c)
+{
+       if (c == '\n')
+               ao_debug_out('\r');
+       while (!(lpc_usart.lsr & (1 << LPC_USART_LSR_TEMT)))
+               ;
+       lpc_usart.rbr_thr = c;
+}
+
+static void
+_ao_serial_tx_start(void)
+{
+       if (!ao_fifo_empty(ao_usart_tx_fifo) && ao_usart_tx_avail) {
+               ao_usart_tx_avail--;
+               if (ao_usart_tx_avail < ao_usart_tx_avail_min)
+                       ao_usart_tx_avail_min = ao_usart_tx_avail;
+               ao_fifo_remove(ao_usart_tx_fifo, lpc_usart.rbr_thr);
+       }
+}
+
+void
+lpc_usart_isr(void)
+{
+       (void) lpc_usart.iir_fcr;
+
+       while (lpc_usart.lsr & (1 << LPC_USART_LSR_RDR)) {
+               char c = lpc_usart.rbr_thr;
+               if (!ao_fifo_full(ao_usart_rx_fifo))
+                       ao_fifo_insert(ao_usart_rx_fifo, c);
+               ao_wakeup(&ao_usart_rx_fifo);
+               if (stdin)
+                       ao_wakeup(&ao_stdin_ready);
+       }
+       if (lpc_usart.lsr & (1 << LPC_USART_LSR_THRE)) {
+               ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+               _ao_serial_tx_start();
+               ao_wakeup(&ao_usart_tx_fifo);
+       }
+}
+
+int
+_ao_serial_pollchar(void)
+{
+       int     c;
+       
+       if (ao_fifo_empty(ao_usart_rx_fifo))
+               c = AO_READ_AGAIN;
+       else {
+               uint8_t u;
+               ao_fifo_remove(ao_usart_rx_fifo,u);
+               c = u;
+       }
+       return c;
+}
+
+char
+ao_serial_getchar(void)
+{
+       int c;
+       ao_arch_block_interrupts();
+       while ((c = _ao_serial_pollchar()) == AO_READ_AGAIN)
+               ao_sleep(&ao_usart_rx_fifo);
+       ao_arch_release_interrupts();
+       return (char) c;
+}
+
+void
+ao_serial_putchar(char c)
+{
+       ao_arch_block_interrupts();
+       while (ao_fifo_full(ao_usart_tx_fifo))
+               ao_sleep(&ao_usart_tx_fifo);
+       ao_fifo_insert(ao_usart_tx_fifo, c);
+       _ao_serial_tx_start();
+       ao_arch_release_interrupts();
+}
+
+void
+ao_serial_drain(void)
+{
+       ao_arch_block_interrupts();
+       while (!ao_fifo_empty(ao_usart_tx_fifo))
+               ao_sleep(&ao_usart_tx_fifo);
+       ao_arch_release_interrupts();
+}
+
+#include "ao_serial_lpc.h"
+
+void
+ao_serial_set_speed(uint8_t speed)
+{
+       if (speed > AO_SERIAL_SPEED_115200)
+               return;
+
+       /* Flip to allow access to divisor latches */
+       lpc_usart.lcr |= (1 << LPC_USART_LCR_DLAB);
+
+       /* DL LSB */
+       lpc_usart.rbr_thr = ao_usart_speeds[speed].dl & 0xff;
+       
+       /* DL MSB */
+       lpc_usart.ier = (ao_usart_speeds[speed].dl >> 8) & 0xff;
+
+       lpc_usart.fdr = ((ao_usart_speeds[speed].divaddval << LPC_USART_FDR_DIVADDVAL) |
+                        (ao_usart_speeds[speed].mulval << LPC_USART_FDR_MULVAL));
+
+       /* Turn access to divisor latches back off */
+       lpc_usart.lcr &= ~(1 << LPC_USART_LCR_DLAB);
+}
+
+void
+ao_serial_init(void)
+{
+#if SERIAL_0_18_19
+       lpc_ioconf.pio0_18 = ((LPC_IOCONF_FUNC_PIO0_18_RXD << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (0 << LPC_IOCONF_OD));
+       lpc_ioconf.pio0_19 = ((LPC_IOCONF_FUNC_PIO0_19_TXD << LPC_IOCONF_FUNC) |
+                             (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                             (0 << LPC_IOCONF_HYS) |
+                             (0 << LPC_IOCONF_INV) |
+                             (0 << LPC_IOCONF_OD));
+#endif
+
+       /* Turn on the USART */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_USART);
+
+       /* Turn on the USART clock */
+       lpc_scb.uartclkdiv = AO_LPC_CLKOUT / AO_LPC_USARTCLK;
+
+       /* Configure USART */
+
+       /* Enable FIFOs, reset fifo contents, interrupt on 1 received char */
+       lpc_usart.iir_fcr = ((1 << LPC_USART_FCR_FIFOEN) |
+                        (1 << LPC_USART_FCR_RXFIFORES) |
+                        (1 << LPC_USART_FCR_TXFIFORES) |
+                        (LPC_USART_FCR_RXTL_1 << LPC_USART_FCR_RXTL));
+
+       ao_usart_tx_avail = LPC_USART_TX_FIFO_SIZE;
+       ao_usart_tx_avail_min = LPC_USART_TX_FIFO_SIZE;
+
+       /* 8 n 1 */
+       lpc_usart.lcr = ((LPC_USART_LCR_WLS_8 << LPC_USART_LCR_WLS) |
+                        (LPC_USART_LCR_SBS_1 << LPC_USART_LCR_SBS) |
+                        (0 << LPC_USART_LCR_PE) |
+                        (LPC_USART_LCR_PS_ODD << LPC_USART_LCR_PS) |
+                        (0 << LPC_USART_LCR_BC) |
+                        (0 << LPC_USART_LCR_DLAB));
+
+       /* Disable flow control */
+       lpc_usart.mcr = ((0 << LPC_USART_MCR_DTRCTRL) |
+                        (0 << LPC_USART_MCR_RTSCTRL) |
+                        (0 << LPC_USART_MCR_LMS) |
+                        (0 << LPC_USART_MCR_RTSEN) |
+                        (0 << LPC_USART_MCR_CTSEN));
+
+       /* 16x oversampling */
+       lpc_usart.osr = ((0 << LPC_USART_OSR_OSFRAC) |
+                        ((16 - 1) << LPC_USART_OSR_OSINT) |
+                        (0 << LPC_USART_OSR_FDINT));
+
+       /* Full duplex */
+       lpc_usart.hden = ((0 << LPC_USART_HDEN_HDEN));
+
+       /* Set baud rate */
+       ao_serial_set_speed(AO_SERIAL_SPEED_9600);
+
+       /* Enable interrupts */
+       lpc_usart.ier = ((1 << LPC_USART_IER_RBRINTEN) |
+                        (1 << LPC_USART_IER_THREINTEN));
+
+       lpc_nvic_set_enable(LPC_ISR_USART_POS);
+       lpc_nvic_set_priority(LPC_ISR_USART_POS, 0);
+#if USE_SERIAL_0_STDIN
+       ao_add_stdio(_ao_serial_pollchar,
+                    ao_serial_putchar,
+                    NULL);
+#endif
+}
diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c
new file mode 100644 (file)
index 0000000..c358769
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * 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>
+
+static uint8_t         ao_spi_mutex[LPC_NUM_SPI];
+
+static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
+
+static uint8_t spi_dev_null;
+
+#define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF)
+#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE)
+
+#define spi_loop(len, put, get) do {                                   \
+               while (len--) {                                         \
+                       /* Wait for space in the fifo */                \
+                       while (tx_busy(lpc_ssp))                        \
+                               ;                                       \
+                                                                       \
+                       /* send a byte */                               \
+                       lpc_ssp->dr = put;                              \
+                                                                       \
+                       /* Wait for byte to appear in the fifo */       \
+                       while (rx_busy(lpc_ssp))                        \
+                               ;                                       \
+                                                                       \
+                       /* recv a byte */                               \
+                       get lpc_ssp->dr;                                \
+               }                                                       \
+       } while (0);
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t id)
+{
+       uint8_t *b = block;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, *b++, (void));
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
+{
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, value, (void));
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t id)
+{
+       uint8_t *b = block;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, 0xff, *b++ =);
+}
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id)
+{
+       uint8_t *o = out;
+       uint8_t *i = in;
+       struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
+
+       spi_loop(len, *o++, *i++ =);
+}
+
+void
+ao_spi_get(uint8_t id, uint32_t speed)
+{
+       struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
+
+       ao_mutex_get(&ao_spi_mutex[id]);
+       
+       /* Set the clock prescale */
+       lpc_ssp->cpsr = speed;
+}
+
+void
+ao_spi_put(uint8_t id)
+{
+       ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t id)
+{
+       struct lpc_ssp  *lpc_ssp = ao_lpc_ssp[id];
+       uint8_t d;
+
+       lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
+                       (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
+                       (0 << LPC_SSP_CR0_CPOL) |
+                       (0 << LPC_SSP_CR0_CPHA) |
+                       (0 << LPC_SSP_CR0_SCR));
+
+       /* Enable the device */
+       lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
+                       (1 << LPC_SSP_CR1_SSE) |
+                       (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
+                       (0 << LPC_SSP_CR1_SOD));
+
+       /* Drain the receive fifo */
+       for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
+               (void) lpc_ssp->dr;
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_0
+       /* Configure pins */
+#if SPI_SCK0_P0_6
+       lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P0_10
+       lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
+#define HAS_SCK0
+#endif
+#if SPI_SCK0_P1_29
+       lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
+#define HAS_SCK0
+#endif
+#ifndef HAS_SCK0
+#error "No pin specified for SCK0"
+#endif
+       lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
+       lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
+
+       /* Enable the device */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP0);
+
+       /* Turn on the clock */
+       lpc_scb.ssp0clkdiv = 1;
+
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+       lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
+       ao_spi_channel_init(0);
+#endif                    
+
+#if HAS_SPI_1
+
+#if SPI_SCK1_P1_15
+       lpc_ioconf.pio1_15 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_15_SCK1);
+#define HAS_SCK1
+#endif
+#if SPI_SCK1_P1_20
+       lpc_ioconf.pio1_20 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_20_SCK1);
+#define HAS_SCK1
+#endif
+#ifndef HAS_SCK1
+#error "No pin specified for SCK1"
+#endif
+
+#if SPI_MISO1_P0_22
+       lpc_ioconf.pio0_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_22_MISO1);
+#define HAS_MISO1
+#endif
+#if SPI_MISO1_P1_21
+       lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_21_MISO1);
+#define HAS_MISO1
+#endif
+#ifndef HAS_MISO1
+#error "No pin specified for MISO1"
+#endif
+
+#if SPI_MOSI1_P0_21
+       lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
+#define HAS_MOSI1
+#endif
+#if SPI_MOSI1_P1_22
+       lpc_ioconf.pio1_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_22_MOSI1);
+#define HAS_MOSI1
+#endif
+#ifndef HAS_MOSI1
+#error "No pin specified for MOSI1"
+#endif
+               
+       /* Enable the device */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
+
+       /* Turn on the clock */
+       lpc_scb.ssp1clkdiv = 1;
+
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+       lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
+       ao_spi_channel_init(1);
+#endif /* HAS_SPI_1 */
+}
diff --git a/src/lpc/ao_timer_lpc.c b/src/lpc/ao_timer_lpc.c
new file mode 100644 (file)
index 0000000..51835ba
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * 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>
+
+volatile __data AO_TICK_TYPE ao_tick_count;
+
+uint16_t
+ao_time(void)
+{
+       return ao_tick_count;
+}
+
+#if AO_DATA_ALL
+volatile __data uint8_t        ao_data_interval = 1;
+volatile __data uint8_t        ao_data_count;
+#endif
+
+void lpc_systick_isr(void)
+{
+       if (lpc_systick.csr & (1 << LPC_SYSTICK_CSR_COUNTFLAG)) {
+               ++ao_tick_count;
+#if HAS_TASK_QUEUE
+               if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0)
+                       ao_task_check_alarm((uint16_t) ao_tick_count);
+#endif
+#if AO_DATA_ALL
+               if (++ao_data_count == ao_data_interval) {
+                       ao_data_count = 0;
+                       ao_adc_poll();
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+                       ao_wakeup((void *) &ao_data_count);
+#endif
+               }
+#endif
+       }
+}
+
+#if HAS_ADC
+void
+ao_timer_set_adc_interval(uint8_t interval)
+{
+       ao_arch_critical(
+               ao_data_interval = interval;
+               ao_data_count = 0;
+               );
+}
+#endif
+
+#define SYSTICK_RELOAD ((AO_LPC_SYSCLK / 2) / 100 - 1)
+
+/* Initialize our 100Hz clock */
+void
+ao_timer_init(void)
+{
+       lpc_systick.rvr = SYSTICK_RELOAD;
+       lpc_systick.cvr = 0;
+       lpc_systick.csr = ((1 << LPC_SYSTICK_CSR_ENABLE) |
+                          (1 << LPC_SYSTICK_CSR_TICKINT) |
+                          (LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2 << LPC_SYSTICK_CSR_CLKSOURCE));
+}
+
+#define AO_LPC_M       ((AO_LPC_CLKOUT / AO_LPC_CLKIN) - 1)
+
+#define AO_LPC_FCCO_MIN        156000000
+
+static void
+ao_clock_delay(void)
+{
+       uint32_t        i;
+       for (i = 0; i < 200; i++)
+               ao_arch_nop();
+}
+
+void
+ao_clock_init(void)
+{
+       uint8_t         p;
+       uint32_t        i;
+
+       /* Turn off all perhipherals except for GPIO configuration */
+       lpc_scb.sysahbclkctrl = ((1 << LPC_SCB_SYSAHBCLKCTRL_SYS) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_ROM) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_RAM0) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO) |
+                                (1 << LPC_SCB_SYSAHBCLKCTRL_IOCON));
+                                
+       /* Turn the IRC clock back on */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_IRC_PD);
+       ao_clock_delay();
+       
+       /* Switch to the IRC clock */
+       lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_IRC << LPC_SCB_MAINCLKSEL_SEL;
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+               ;
+       
+       /* Find a PLL post divider ratio that gets the FCCO in range */
+       for (p = 0; p < 4; p++)
+               if (AO_LPC_CLKOUT << (1 + p) >= AO_LPC_FCCO_MIN)
+                       break;
+
+       if (p == 4)
+               ao_panic(AO_PANIC_CRASH);
+
+       /* Power down the PLL before touching the registers */
+       lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+       ao_clock_delay();
+
+       /* Set PLL divider values */
+       lpc_scb.syspllctrl = ((AO_LPC_M << LPC_SCB_SYSPLLCTRL_MSEL) |
+                             (p << LPC_SCB_SYSPLLCTRL_PSEL));
+
+       /* Turn off the external crystal clock */
+       lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+       ao_clock_delay();
+
+       /* Configure the crystal clock */
+       lpc_scb.sysoscctrl = ((0 << LPC_SCB_SYSOSCCTRL_BYPASS) |                           /* using a crystal */
+                             ((AO_LPC_CLKIN > 15000000) << LPC_SCB_SYSOSCCTRL_FREQRANGE));/* set range */
+
+       /* Turn on the external crystal clock */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSOSC_PD);
+       ao_clock_delay();
+
+       /* Select crystal as PLL input */
+
+       lpc_scb.syspllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+       lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       lpc_scb.syspllclkuen = (0 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       lpc_scb.syspllclkuen = (1 << LPC_SCB_SYSPLLCLKUEN_ENA);
+       while (!(lpc_scb.syspllclkuen & (1 << LPC_SCB_SYSPLLCLKUEN_ENA)))
+               ;
+       
+       /* Turn on the PLL */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_SYSPLL_PD);
+
+       /* Wait for it to lock */
+       
+       for (i = 0; i < 20000; i++)
+               if (lpc_scb.syspllstat & (1 << LPC_SCB_SYSPLLSTAT_LOCK))
+                       break;
+       if (i == 20000)
+               ao_panic(AO_PANIC_CRASH);
+
+       /* Switch to the PLL */
+       lpc_scb.mainclksel = LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT << LPC_SCB_MAINCLKSEL_SEL;
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (0 << LPC_SCB_MAINCLKUEN_ENA);
+       lpc_scb.mainclkuen = (1 << LPC_SCB_MAINCLKUEN_ENA);
+       while (!(lpc_scb.mainclkuen & (1 << LPC_SCB_MAINCLKUEN_ENA)))
+               ;
+
+       /* Set system clock divider */
+       lpc_scb.sysahbclkdiv = AO_LPC_CLKOUT / AO_LPC_SYSCLK;
+
+       /* Shut down perhipheral clocks (enabled as needed) */
+       lpc_scb.ssp0clkdiv = 0;
+       lpc_scb.uartclkdiv = 0;
+       lpc_scb.ssp1clkdiv = 0;
+       lpc_scb.usbclkdiv = 0;
+       lpc_scb.clkoutdiv = 0;
+}
diff --git a/src/lpc/ao_usb_lpc.c b/src/lpc/ao_usb_lpc.c
new file mode 100644 (file)
index 0000000..aac0df0
--- /dev/null
@@ -0,0 +1,1025 @@
+/*
+ * 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.
+ */
+
+#include "ao.h"
+#include "ao_usb.h"
+#include "ao_product.h"
+
+#define USB_DEBUG      0
+#define USB_DEBUG_DATA 0
+#define USB_ECHO       0
+
+#if USB_DEBUG
+#define debug(format, args...) printf(format, ## args);
+#else
+#define debug(format, args...)
+#endif
+
+#if USB_DEBUG_DATA
+#define debug_data(format, args...)    printf(format, ## args);
+#else
+#define debug_data(format, args...)
+#endif
+
+struct ao_task ao_usb_task;
+
+struct ao_usb_setup {
+       uint8_t         dir_type_recip;
+       uint8_t         request;
+       uint16_t        value;
+       uint16_t        index;
+       uint16_t        length;
+} ao_usb_setup;
+
+static uint8_t         ao_usb_ep0_state;
+
+/* Pending EP0 IN data */
+static const uint8_t   *ao_usb_ep0_in_data;    /* Remaining data */
+static uint8_t                 ao_usb_ep0_in_len;      /* Remaining amount */
+
+/* Temp buffer for smaller EP0 in data */
+static uint8_t ao_usb_ep0_in_buf[2];
+
+/* Pending EP0 OUT data */
+static uint8_t *ao_usb_ep0_out_data;
+static uint8_t         ao_usb_ep0_out_len;
+
+/*
+ * Objects allocated in special USB memory
+ */
+
+/* USB address of end of allocated storage */
+static uint8_t *ao_usb_sram;
+
+/* Pointer to ep0 tx/rx buffers in USB memory */
+static uint8_t *ao_usb_ep0_tx_buffer;
+static uint8_t *ao_usb_ep0_setup_buffer;
+static uint8_t *ao_usb_ep0_rx_buffer;
+
+/* Pointer to bulk data tx/rx buffers in USB memory */
+static uint8_t *ao_usb_in_tx_buffer;
+static uint8_t *ao_usb_out_rx_buffer;
+
+/* Our data buffers */
+static uint8_t ao_usb_tx_buffer[AO_USB_IN_SIZE];
+static uint8_t ao_usb_tx_count;
+
+static uint8_t ao_usb_rx_buffer[AO_USB_OUT_SIZE];
+static uint8_t ao_usb_rx_count, ao_usb_rx_pos;
+
+extern struct lpc_usb_endpoint lpc_usb_endpoint;
+
+/* Marks when we don't need to send an IN packet.
+ * This happens only when the last IN packet is not full,
+ * otherwise the host will expect to keep seeing packets.
+ * Send a zero-length packet as required
+ */
+static uint8_t ao_usb_in_flushed;
+
+/* Marks when we have delivered an IN packet to the hardware
+ * and it has not been received yet. ao_sleep on this address
+ * to wait for it to be delivered.
+ */
+static uint8_t ao_usb_in_pending;
+
+/* Marks when an OUT packet has been received by the hardware
+ * but not pulled to the shadow buffer.
+ */
+static uint8_t ao_usb_out_avail;
+static uint8_t ao_usb_running;
+static uint8_t ao_usb_configuration;
+static uint8_t ueienx_0;
+
+#define AO_USB_EP0_GOT_RESET   1
+#define AO_USB_EP0_GOT_SETUP   2
+#define AO_USB_EP0_GOT_RX_DATA 4
+#define AO_USB_EP0_GOT_TX_ACK  8
+
+static uint8_t ao_usb_ep0_receive;
+static uint8_t ao_usb_address;
+static uint8_t ao_usb_address_pending;
+
+static inline uint32_t set_toggle(uint32_t     current_value,
+                                  uint32_t     mask,
+                                  uint32_t     desired_value)
+{
+       return (current_value ^ desired_value) & mask;
+}
+
+/*
+ * Set current device address and mark the
+ * interface as active
+ */
+void
+ao_usb_set_address(uint8_t address)
+{
+       debug("ao_usb_set_address %02x\n", address);
+       lpc_usb.devcmdstat = ((address << LPC_USB_DEVCMDSTAT_DEV_ADDR) |
+                             (1 << LPC_USB_DEVCMDSTAT_DEV_EN) |
+                             (0 << LPC_USB_DEVCMDSTAT_SETUP) |
+                             (0 << LPC_USB_DEVCMDSTAT_PLL_ON) |
+                             (0 << LPC_USB_DEVCMDSTAT_LPM_SUP) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AO) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_AI) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CO) |
+                             (0 << LPC_USB_DEVCMDSTAT_INTONNAK_CI) |
+                             (1 << LPC_USB_DEVCMDSTAT_DCON) |
+                             (0 << LPC_USB_DEVCMDSTAT_DSUS) |
+                             (0 << LPC_USB_DEVCMDSTAT_DCON_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_DSUS_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_DRES_C) |
+                             (0 << LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED));
+       ao_usb_address_pending = 0;
+}
+
+#define TX_DBG 0
+#define RX_DBG 0
+
+#if TX_DBG
+#define _tx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _tx_dbg0(msg)
+#define _tx_dbg1(msg,value)
+#endif
+
+#if RX_DBG
+#define _rx_dbg0(msg) _dbg(__LINE__,msg,0)
+#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value)
+#else
+#define _rx_dbg0(msg)
+#define _rx_dbg1(msg,value)
+#endif
+
+#if TX_DBG || RX_DBG
+static void _dbg(int line, char *msg, uint32_t value);
+#endif
+
+/*
+ * Set just endpoint 0, for use during startup
+ */
+
+static uint8_t *
+ao_usb_alloc_sram(uint16_t size)
+{
+       uint8_t *addr = ao_usb_sram;
+
+       ao_usb_sram += (size + 63) & ~63;
+       return addr;
+}
+
+static uint16_t
+ao_usb_sram_offset(uint8_t *addr)
+{
+       return (uint16_t) ((intptr_t) addr >> 6);
+}
+
+static void
+ao_usb_set_ep(vuint32_t *ep, uint8_t *addr, uint16_t nbytes)
+{
+       *ep = ((ao_usb_sram_offset(addr) << LPC_USB_EP_OFFSET) |
+              (nbytes << LPC_USB_EP_NBYTES) |
+              (0 << LPC_USB_EP_ENDPOINT_ISO) |
+              (0 << LPC_USB_EP_RATE_FEEDBACK) |
+              (0 << LPC_USB_EP_TOGGLE_RESET) |
+              (0 << LPC_USB_EP_STALL) |
+              (0 << LPC_USB_EP_DISABLED) |
+              (1 << LPC_USB_EP_ACTIVE));
+}
+
+static inline uint16_t
+ao_usb_ep_count(vuint32_t *ep)
+{
+       return (*ep >> LPC_USB_EP_NBYTES) & LPC_USB_EP_NBYTES_MASK;
+}
+
+static inline uint8_t
+ao_usb_ep_stall(vuint32_t *ep)
+{
+       return (*ep >> LPC_USB_EP_STALL) & 1;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_out(void)
+{
+       return &lpc_usb_endpoint.ep0_out;
+}
+
+static inline vuint32_t *
+ao_usb_ep0_in(void)
+{
+       return &lpc_usb_endpoint.ep0_in;
+}
+
+static inline vuint32_t *
+ao_usb_epn_out(uint8_t n)
+{
+       return &lpc_usb_endpoint.epn[n-1].out[0];
+}
+
+static inline vuint32_t *
+ao_usb_epn_in(uint8_t n)
+{
+       return &lpc_usb_endpoint.epn[n-1].in[0];
+}
+
+static void
+ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+       ao_usb_set_ep(ao_usb_epn_in(n), addr, nbytes);
+}
+
+static void
+ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes)
+{
+       ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes);
+}
+
+static inline uint16_t
+ao_usb_epn_out_count(uint8_t n)
+{
+       return ao_usb_ep_count(ao_usb_epn_out(n));
+}
+
+static inline uint16_t
+ao_usb_epn_in_count(uint8_t n)
+{
+       return ao_usb_ep_count(ao_usb_epn_in(n));
+}
+
+static uint8_t *
+ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes)
+{
+       uint8_t *addr = ao_usb_alloc_sram(nbytes);
+       
+       ao_usb_set_ep(ep, addr, set_nbytes);
+       return addr;
+}
+
+static void
+ao_usb_disable_ep(vuint32_t *ep)
+{
+       *ep = ((0 << LPC_USB_EP_OFFSET) |
+              (0 << LPC_USB_EP_NBYTES) |
+              (0 << LPC_USB_EP_ENDPOINT_ISO) |
+              (0 << LPC_USB_EP_RATE_FEEDBACK) |
+              (0 << LPC_USB_EP_TOGGLE_RESET) |
+              (0 << LPC_USB_EP_STALL) |
+              (1 << LPC_USB_EP_DISABLED) |
+              (0 << LPC_USB_EP_ACTIVE));
+}
+
+static void
+ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr)
+{
+       uint8_t *addr;
+
+       addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes);
+       if (out_addr)
+               *out_addr = addr;
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+
+       addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0);
+       if (in_addr)
+               *in_addr = addr;
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_disable_epn(uint8_t n)
+{
+       ao_usb_disable_ep(ao_usb_epn_out(n));
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]);
+       ao_usb_disable_ep(ao_usb_epn_in(n));
+       ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]);
+}
+
+static void
+ao_usb_set_ep0(void)
+{
+       int                     e;
+
+       /* Everything is single buffered for now */
+       lpc_usb.epbufcfg = 0;
+       lpc_usb.epinuse = 0;
+       lpc_usb.epskip = 0xffffffff;
+
+       ao_usb_set_address(0);
+       lpc_usb.intstat = 0xc00003ff;
+
+       ao_usb_configuration = 0;
+
+       ao_usb_sram = lpc_usb_sram;
+
+       lpc_usb.epliststart = (uint32_t) (intptr_t) &lpc_usb_endpoint;
+       lpc_usb.databufstart = ((uint32_t) (intptr_t) ao_usb_sram) & 0xffc00000;
+
+       /* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */
+
+       ao_usb_ep0_rx_buffer = ao_usb_enable_ep(ao_usb_ep0_out(), AO_USB_CONTROL_SIZE, AO_USB_CONTROL_SIZE);
+       ao_usb_ep0_setup_buffer = ao_usb_alloc_sram(AO_USB_CONTROL_SIZE);
+       lpc_usb_endpoint.setup = ao_usb_sram_offset(ao_usb_ep0_setup_buffer);
+       ao_usb_ep0_tx_buffer = ao_usb_enable_ep(ao_usb_ep0_in(), AO_USB_CONTROL_SIZE, 0);
+
+       /* Clear all of the other endpoints */
+       for (e = 1; e <= 4; e++)
+               ao_usb_disable_epn(e);
+
+}
+
+static void
+ao_usb_set_configuration(void)
+{
+       debug ("ao_usb_set_configuration\n");
+
+       /* Set up the INT end point */
+       ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL);
+       
+       /* Set up the OUT end point */
+       ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL);
+
+       /* Set up the IN end point */
+       ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer);
+
+       ao_usb_running = 1;
+}
+
+/* Send an IN data packet */
+static void
+ao_usb_ep0_flush(void)
+{
+       uint8_t this_len;
+
+       this_len = ao_usb_ep0_in_len;
+       if (this_len > AO_USB_CONTROL_SIZE)
+               this_len = AO_USB_CONTROL_SIZE;
+
+       if (this_len < AO_USB_CONTROL_SIZE)
+               ao_usb_ep0_state = AO_USB_EP0_IDLE;
+
+       ao_usb_ep0_in_len -= this_len;
+
+       debug_data ("Flush EP0 len %d:", this_len);
+       memcpy(ao_usb_ep0_tx_buffer, ao_usb_ep0_in_data, this_len);
+       debug_data ("\n");
+       ao_usb_ep0_in_data += this_len;
+
+       /* Mark the endpoint as TX valid to send the packet */
+       ao_usb_set_ep(ao_usb_ep0_in(), ao_usb_ep0_tx_buffer, this_len);
+       debug ("queue tx.  0 now %08x\n", *ao_usb_ep0_in());
+}
+
+/* Read data from the ep0 OUT fifo */
+static void
+ao_usb_ep0_fill(void)
+{
+       uint16_t        len;
+       uint8_t         *rx_buffer;
+
+       /* Pull all of the data out of the packet */
+       if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP)) {
+               rx_buffer = ao_usb_ep0_setup_buffer;
+               len = 8;
+       } else {
+               rx_buffer = ao_usb_ep0_rx_buffer;
+               len = AO_USB_CONTROL_SIZE - ao_usb_ep_count(ao_usb_ep0_out());
+       }
+
+       if (len > ao_usb_ep0_out_len)
+               len = ao_usb_ep0_out_len;
+       ao_usb_ep0_out_len -= len;
+
+       debug_data ("Fill EP0 len %d:", len);
+       memcpy(ao_usb_ep0_out_data, rx_buffer, len);
+       debug_data ("\n");
+       ao_usb_ep0_out_data += len;
+
+       /* ACK the packet */
+       ao_usb_set_ep(ao_usb_ep0_out(), ao_usb_ep0_rx_buffer, AO_USB_CONTROL_SIZE);
+       lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_SETUP);
+}
+
+static void
+ao_usb_ep0_in_reset(void)
+{
+       ao_usb_ep0_in_data = ao_usb_ep0_in_buf;
+       ao_usb_ep0_in_len = 0;
+}
+
+static void
+ao_usb_ep0_in_queue_byte(uint8_t a)
+{
+       if (ao_usb_ep0_in_len < sizeof (ao_usb_ep0_in_buf))
+               ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a;
+}
+
+static void
+ao_usb_ep0_in_set(const uint8_t *data, uint8_t len)
+{
+       ao_usb_ep0_in_data = data;
+       ao_usb_ep0_in_len = len;
+}
+
+static void
+ao_usb_ep0_out_set(uint8_t *data, uint8_t len)
+{
+       ao_usb_ep0_out_data = data;
+       ao_usb_ep0_out_len = len;
+}
+
+static void
+ao_usb_ep0_in_start(uint8_t max)
+{
+       /* Don't send more than asked for */
+       if (ao_usb_ep0_in_len > max)
+               ao_usb_ep0_in_len = max;
+       ao_usb_ep0_flush();
+}
+
+static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8};
+
+/* Walk through the list of descriptors and find a match
+ */
+static void
+ao_usb_get_descriptor(uint16_t value)
+{
+       const uint8_t           *descriptor;
+       uint8_t         type = value >> 8;
+       uint8_t         index = value;
+
+       descriptor = ao_usb_descriptors;
+       while (descriptor[0] != 0) {
+               if (descriptor[1] == type && index-- == 0) {
+                       uint8_t len;
+                       if (type == AO_USB_DESC_CONFIGURATION)
+                               len = descriptor[2];
+                       else
+                               len = descriptor[0];
+                       ao_usb_ep0_in_set(descriptor, len);
+                       break;
+               }
+               descriptor += descriptor[0];
+       }
+}
+
+static void
+ao_usb_ep0_setup(void)
+{
+       /* Pull the setup packet out of the fifo */
+       ao_usb_ep0_out_set((uint8_t *) &ao_usb_setup, 8);
+       ao_usb_ep0_fill();
+       if (ao_usb_ep0_out_len != 0) {
+               debug ("invalid setup packet length\n");
+               return;
+       }
+
+       if ((ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) || ao_usb_setup.length == 0)
+               ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+       else
+               ao_usb_ep0_state = AO_USB_EP0_DATA_OUT;
+
+       ao_usb_ep0_in_reset();
+
+       switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) {
+       case AO_USB_TYPE_STANDARD:
+               debug ("Standard setup packet\n");
+               switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) {
+               case AO_USB_RECIP_DEVICE:
+                       debug ("Device setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               debug ("get status\n");
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_SET_ADDRESS:
+                               debug ("set address %d\n", ao_usb_setup.value);
+                               ao_usb_address = ao_usb_setup.value;
+                               ao_usb_address_pending = 1;
+                               break;
+                       case AO_USB_REQ_GET_DESCRIPTOR:
+                               debug ("get descriptor %d\n", ao_usb_setup.value);
+                               ao_usb_get_descriptor(ao_usb_setup.value);
+                               break;
+                       case AO_USB_REQ_GET_CONFIGURATION:
+                               debug ("get configuration %d\n", ao_usb_configuration);
+                               ao_usb_ep0_in_queue_byte(ao_usb_configuration);
+                               break;
+                       case AO_USB_REQ_SET_CONFIGURATION:
+                               ao_usb_configuration = ao_usb_setup.value;
+                               debug ("set configuration %d\n", ao_usb_configuration);
+                               ao_usb_set_configuration();
+                               break;
+                       }
+                       break;
+               case AO_USB_RECIP_INTERFACE:
+                       debug ("Interface setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_GET_INTERFACE:
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       case AO_USB_REQ_SET_INTERFACE:
+                               break;
+                       }
+                       break;
+               case AO_USB_RECIP_ENDPOINT:
+                       debug ("Endpoint setup packet\n");
+                       switch(ao_usb_setup.request) {
+                       case AO_USB_REQ_GET_STATUS:
+                               ao_usb_ep0_in_queue_byte(0);
+                               ao_usb_ep0_in_queue_byte(0);
+                               break;
+                       }
+                       break;
+               }
+               break;
+       case AO_USB_TYPE_CLASS:
+               debug ("Class setup packet\n");
+               switch (ao_usb_setup.request) {
+               case AO_USB_SET_LINE_CODING:
+                       debug ("set line coding\n");
+                       ao_usb_ep0_out_set((uint8_t *) &ao_usb_line_coding, 7);
+                       break;
+               case AO_USB_GET_LINE_CODING:
+                       debug ("get line coding\n");
+                       ao_usb_ep0_in_set((const uint8_t *) &ao_usb_line_coding, 7);
+                       break;
+               case AO_USB_SET_CONTROL_LINE_STATE:
+                       break;
+               }
+               break;
+       }
+
+       /* If we're not waiting to receive data from the host,
+        * queue an IN response
+        */
+       if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+               ao_usb_ep0_in_start(ao_usb_setup.length);
+}
+
+static void
+ao_usb_ep0_handle(uint8_t receive)
+{
+       ao_usb_ep0_receive = 0;
+
+       if (receive & AO_USB_EP0_GOT_RESET) {
+               debug ("\treset\n");
+               ao_usb_set_ep0();
+               return;
+       }
+       if (receive & AO_USB_EP0_GOT_SETUP) {
+               debug ("\tsetup\n");
+               ao_usb_ep0_setup();
+       }
+       if (receive & AO_USB_EP0_GOT_RX_DATA) {
+               debug ("\tgot rx data\n");
+               if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) {
+                       ao_usb_ep0_fill();
+                       if (ao_usb_ep0_out_len == 0) {
+                               ao_usb_ep0_state = AO_USB_EP0_DATA_IN;
+                               ao_usb_ep0_in_start(0);
+                       }
+               }
+       }
+       if (receive & AO_USB_EP0_GOT_TX_ACK) {
+               debug ("\tgot tx ack\n");
+
+               /* Wait until the IN packet is received from addr 0
+                * before assigning our local address
+                */
+               if (ao_usb_address_pending) {
+#if HAS_FLIGHT
+                       /* Go to idle mode if USB is connected
+                        */
+                       ao_flight_force_idle = 1;
+#endif
+                       ao_usb_set_address(ao_usb_address);
+               }
+               if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN)
+                       ao_usb_ep0_flush();
+       }
+}
+
+static uint16_t        control_count;
+static uint16_t int_count;
+static uint16_t        in_count;
+static uint16_t        out_count;
+static uint16_t        reset_count;
+
+void
+lpc_usb_irq_isr(void)
+{
+       uint32_t        intstat = lpc_usb.intstat & lpc_usb.inten;
+
+       lpc_usb.intstat = intstat;
+       /* Handle EP0 OUT packets */
+       if (intstat & (1 << LPC_USB_INT_EPOUT(0))) {
+               if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_SETUP))
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP;
+               else
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA;
+
+               ao_usb_ep0_handle(ao_usb_ep0_receive);
+       }
+
+       /* Handle EP0 IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(0))) {
+               ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK;
+
+               ao_usb_ep0_handle(ao_usb_ep0_receive);
+       }
+
+
+       /* Handle OUT packets */
+       if (intstat & (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP))) {
+               ++out_count;
+               _rx_dbg1("RX ISR", *ao_usb_epn_out(AO_USB_OUT_EP));
+               ao_usb_out_avail = 1;
+               _rx_dbg0("out avail set");
+               ao_wakeup(&ao_stdin_ready);
+               _rx_dbg0("stdin awoken");
+       }
+
+       /* Handle IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP))) {
+               ++in_count;
+               _tx_dbg1("TX ISR", *ao_usb_epn_in(AO_USB_IN_EP));
+               ao_usb_in_pending = 0;
+               ao_wakeup(&ao_usb_in_pending);
+       }
+
+       /* NAK all INT EP IN packets */
+       if (intstat & (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP))) {
+               ;
+       }
+
+       /* Check for reset */
+       if (intstat & (1 << LPC_USB_INT_DEV)) {
+               if (lpc_usb.devcmdstat & (1 << LPC_USB_DEVCMDSTAT_DRES_C))
+               {
+                       lpc_usb.devcmdstat |= (1 << LPC_USB_DEVCMDSTAT_DRES_C);
+                       ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET;
+                       ao_usb_ep0_handle(ao_usb_ep0_receive);
+               }
+       }
+}
+
+
+
+/* Queue the current IN buffer for transmission */
+static void
+_ao_usb_in_send(void)
+{
+       _tx_dbg0("in_send start");
+       debug ("send %d\n", ao_usb_tx_count);
+       while (ao_usb_in_pending)
+               ao_sleep(&ao_usb_in_pending);
+       ao_usb_in_pending = 1;
+       if (ao_usb_tx_count != AO_USB_IN_SIZE)
+               ao_usb_in_flushed = 1;
+       memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count);
+       ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count);
+       ao_usb_tx_count = 0;
+       _tx_dbg0("in_send end");
+}
+
+/* Wait for a free IN buffer. Interrupts are blocked */
+static void
+_ao_usb_in_wait(void)
+{
+       for (;;) {
+               /* Check if the current buffer is writable */
+               if (ao_usb_tx_count < AO_USB_IN_SIZE)
+                       break;
+
+               _tx_dbg0("in_wait top");
+               /* Wait for an IN buffer to be ready */
+               while (ao_usb_in_pending)
+                       ao_sleep(&ao_usb_in_pending);
+               _tx_dbg0("in_wait bottom");
+       }
+}
+
+void
+ao_usb_flush(void)
+{
+       if (!ao_usb_running)
+               return;
+
+       /* Anytime we've sent a character since
+        * the last time we flushed, we'll need
+        * to send a packet -- the only other time
+        * we would send a packet is when that
+        * packet was full, in which case we now
+        * want to send an empty packet
+        */
+       ao_arch_block_interrupts();
+       while (!ao_usb_in_flushed) {
+               _tx_dbg0("flush top");
+               _ao_usb_in_send();
+               _tx_dbg0("flush end");
+       }
+       ao_arch_release_interrupts();
+}
+
+void
+ao_usb_putchar(char c)
+{
+       if (!ao_usb_running)
+               return;
+
+       ao_arch_block_interrupts();
+       _ao_usb_in_wait();
+
+       ao_usb_in_flushed = 0;
+       ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c;
+
+       /* Send the packet when full */
+       if (ao_usb_tx_count == AO_USB_IN_SIZE) {
+               _tx_dbg0("putchar full");
+               _ao_usb_in_send();
+               _tx_dbg0("putchar flushed");
+       }
+       ao_arch_release_interrupts();
+}
+
+static void
+_ao_usb_out_recv(void)
+{
+       _rx_dbg0("out_recv top");
+       ao_usb_out_avail = 0;
+
+       ao_usb_rx_count = AO_USB_OUT_SIZE - ao_usb_epn_out_count(AO_USB_OUT_EP);
+
+       _rx_dbg1("out_recv count", ao_usb_rx_count);
+       debug ("recv %d\n", ao_usb_rx_count);
+       debug_data("Fill OUT len %d:", ao_usb_rx_count);
+       memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count);
+       debug_data("\n");
+       ao_usb_rx_pos = 0;
+
+       /* ACK the packet */
+       ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE);
+}
+
+int
+_ao_usb_pollchar(void)
+{
+       uint8_t c;
+
+       if (!ao_usb_running)
+               return AO_READ_AGAIN;
+
+       for (;;) {
+               if (ao_usb_rx_pos != ao_usb_rx_count)
+                       break;
+
+               _rx_dbg0("poll check");
+               /* Check to see if a packet has arrived */
+               if (!ao_usb_out_avail) {
+                       _rx_dbg0("poll none");
+                       return AO_READ_AGAIN;
+               }
+               _ao_usb_out_recv();
+       }
+
+       /* Pull a character out of the fifo */
+       c = ao_usb_rx_buffer[ao_usb_rx_pos++];
+       return c;
+}
+
+char
+ao_usb_getchar(void)
+{
+       int     c;
+
+       ao_arch_block_interrupts();
+       while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN)
+               ao_sleep(&ao_stdin_ready);
+       ao_arch_release_interrupts();
+       return c;
+}
+
+void
+ao_usb_disable(void)
+{
+       ao_arch_block_interrupts();
+
+       /* Disable interrupts */
+       lpc_usb.inten = 0;
+
+       lpc_nvic_clear_enable(LPC_ISR_USB_IRQ_POS);
+
+       /* Disable the device */
+       lpc_usb.devcmdstat = 0;
+
+       /* Turn off USB clock */
+       lpc_scb.usbclkdiv = 0;
+
+       /* Disable USB PHY */
+       lpc_scb.pdruncfg |= (1 << LPC_SCB_PDRUNCFG_USBPAD_PD);
+
+       /* Disable USB registers and RAM */
+       lpc_scb.sysahbclkctrl &= ~((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+                                  (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+       ao_arch_release_interrupts();
+}
+
+void
+ao_usb_enable(void)
+{
+       int     t;
+
+       /* Enable USB pins */
+#if HAS_USB_CONNECT
+       lpc_ioconf.pio0_6 = ((LPC_IOCONF_FUNC_USB_CONNECT << LPC_IOCONF_FUNC) |
+                            (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                            (0 << LPC_IOCONF_HYS) |
+                            (0 << LPC_IOCONF_INV) |
+                            (0 << LPC_IOCONF_OD) |
+                            0x80);
+#endif
+#if HAS_USB_VBUS
+       lpc_ioconf.pio0_3 = ((LPC_IOCONF_FUNC_USB_VBUS << LPC_IOCONF_FUNC) |
+                            (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
+                            (0 << LPC_IOCONF_HYS) |
+                            (0 << LPC_IOCONF_INV) |
+                            (0 << LPC_IOCONF_OD) |
+                            0x80);
+#endif
+       /* Enable USB registers and RAM */
+       lpc_scb.sysahbclkctrl |= ((1 << LPC_SCB_SYSAHBCLKCTRL_USB) |
+                                 (1 << LPC_SCB_SYSAHBCLKCTRL_USBRAM));
+
+       /* Enable USB PHY */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD);
+       
+       /* Turn on USB PLL */
+       lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD);
+
+       lpc_scb.usbpllclksel = (LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC << LPC_SCB_SYSPLLCLKSEL_SEL);
+       lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+       lpc_scb.usbpllclkuen = (0 << LPC_SCB_USBPLLCLKUEN_ENA);
+       lpc_scb.usbpllclkuen = (1 << LPC_SCB_USBPLLCLKUEN_ENA);
+       while (!(lpc_scb.usbpllclkuen & (1 << LPC_SCB_USBPLLCLKUEN_ENA)))
+               ;
+       lpc_scb.usbpllctrl = 0x23;
+       while (!(lpc_scb.usbpllstat & 1))
+               ;
+
+       lpc_scb.usbclksel = 0;
+
+       /* Turn on USB clock, use 48MHz clock unchanged */
+       lpc_scb.usbclkdiv = 1;
+
+       /* Configure interrupts */
+       ao_arch_block_interrupts();
+
+       /* Route all interrupts to the main isr */
+       lpc_usb.introuting = 0;
+
+       /* Configure NVIC */
+
+       lpc_nvic_set_enable(LPC_ISR_USB_IRQ_POS);
+       lpc_nvic_set_priority(LPC_ISR_USB_IRQ_POS, 0);
+
+       /* Clear any spurious interrupts */
+       lpc_usb.intstat = 0xffffffff;
+
+       debug ("ao_usb_enable\n");
+
+       /* Enable interrupts */
+       lpc_usb.inten = ((1 << LPC_USB_INT_EPOUT(0)) |
+                        (1 << LPC_USB_INT_EPIN(0)) |
+                        (1 << LPC_USB_INT_EPIN(AO_USB_INT_EP)) |
+                        (1 << LPC_USB_INT_EPOUT(AO_USB_OUT_EP)) |
+                        (1 << LPC_USB_INT_EPIN(AO_USB_IN_EP)) |
+                        (1 << LPC_USB_INT_DEV));
+
+       ao_arch_release_interrupts();
+
+       lpc_usb.devcmdstat = 0;
+       for (t = 0; t < 1000; t++)
+               ao_arch_nop();
+
+       ao_usb_set_ep0();
+}
+
+#if USB_ECHO
+struct ao_task ao_usb_echo_task;
+
+static void
+ao_usb_echo(void)
+{
+       char    c;
+
+       for (;;) {
+               c = ao_usb_getchar();
+               ao_usb_putchar(c);
+               ao_usb_flush();
+       }
+}
+#endif
+
+#if USB_DEBUG
+static void
+ao_usb_irq(void)
+{
+       printf ("control: %d out: %d in: %d int: %d reset: %d\n",
+               control_count, out_count, in_count, int_count, reset_count);
+}
+
+__code struct ao_cmds ao_usb_cmds[] = {
+       { ao_usb_irq, "I\0Show USB interrupt counts" },
+       { 0, NULL }
+};
+#endif
+
+void
+ao_usb_init(void)
+{
+       ao_usb_enable();
+
+       debug ("ao_usb_init\n");
+#if USB_ECHO
+       ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo");
+#endif
+#if USB_DEBUG
+       ao_cmd_register(&ao_usb_cmds[0]);
+#endif
+#if !USB_ECHO
+       ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush);
+#endif
+}
+
+#if TX_DBG || RX_DBG
+
+struct ao_usb_dbg {
+       int             line;
+       char            *msg;
+       uint32_t        value;
+       uint32_t        primask;
+#if TX_DBG
+       uint16_t        in_count;
+       uint32_t        in_ep;
+       uint32_t        in_pending;
+       uint32_t        tx_count;
+       uint32_t        in_flushed;
+#endif
+#if RX_DBG
+       uint8_t         rx_count;
+       uint8_t         rx_pos;
+       uint8_t         out_avail;
+       uint32_t        out_ep;
+#endif
+};
+
+#define NUM_USB_DBG    8
+
+static struct ao_usb_dbg dbg[NUM_USB_DBG];
+static int dbg_i;
+
+static void _dbg(int line, char *msg, uint32_t value)
+{
+       uint32_t        primask;
+       dbg[dbg_i].line = line;
+       dbg[dbg_i].msg = msg;
+       dbg[dbg_i].value = value;
+       asm("mrs %0,primask" : "=&r" (primask));
+       dbg[dbg_i].primask = primask;
+#if TX_DBG
+       dbg[dbg_i].in_count = in_count;
+       dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP);
+       dbg[dbg_i].in_pending = ao_usb_in_pending;
+       dbg[dbg_i].tx_count = ao_usb_tx_count;
+       dbg[dbg_i].in_flushed = ao_usb_in_flushed;
+#endif
+#if RX_DBG
+       dbg[dbg_i].rx_count = ao_usb_rx_count;
+       dbg[dbg_i].rx_pos = ao_usb_rx_pos;
+       dbg[dbg_i].out_avail = ao_usb_out_avail;
+       dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP);
+#endif
+       if (++dbg_i == NUM_USB_DBG)
+               dbg_i = 0;
+}
+#endif
diff --git a/src/lpc/baud_rate b/src/lpc/baud_rate
new file mode 100644 (file)
index 0000000..2bfbf30
--- /dev/null
@@ -0,0 +1,131 @@
+#!/usr/bin/env nickle
+
+/*
+ * Given a main clock frequency,
+ * compute USART clock freq and a table
+ * of USART config parameters for our target baud rates
+ */
+
+real main_clock = 0;
+real usart_clock = 0;
+
+real[] baud_rates = { 4800, 9600, 19200, 57600, 115200 };
+
+void
+compute_baud_rate(real rate) {
+       int     divaddval;
+       int     mulval;
+
+       real    dl_est = usart_clock / (16 * rate);
+
+       if (dl_est == floor(dl_est)) {
+               divaddval = 0;
+               mulval = 1;
+       } else {
+               if (false) {
+
+                       /* This is how the docs suggest doing it; this
+                        * generates a rate which is reasonably close
+                        */
+
+                       real fr_est = 1.5;
+
+                       /* Compute fractional estimate */
+                       do {
+                               dl_est = floor(usart_clock / (16 * rate * fr_est) + 0.5);
+                               fr_est = usart_clock / (16 * rate * dl_est);
+                       } while (fr_est <= 1.1 || 1.9 <= fr_est);
+
+                       /* Given fractional estimate, compute divaddval/mulvals that work best */
+
+                       real best_dist = 1000;
+                       for (int tmp_divaddval = 1; tmp_divaddval < 15; tmp_divaddval++) {
+                               for (int tmp_mulval = 1; tmp_mulval < 16; tmp_mulval++) {
+                                       real fr = 1 + tmp_divaddval / tmp_mulval;
+                                       real dist = abs(fr - fr_est);
+                                       if (dist < best_dist) {
+                                               divaddval = tmp_divaddval;
+                                               mulval = tmp_mulval;
+                                               best_dist = dist;
+                                       }
+                               }
+                       }
+               } else {
+
+                       /* This exhaustively searches for the best match */
+
+                       real my_best_dist = 1e20;
+                       int my_best_dl;
+                       int my_best_divaddval;
+                       int my_best_mulval;
+                       for (int my_dl = 1; my_dl < 1024; my_dl++) {
+                               for (int my_mulval = 1; my_mulval < 16; my_mulval++) {
+                                       for (int my_divaddval = 0; my_divaddval < my_mulval; my_divaddval++) {
+                                               real my_rate = usart_clock / ((16 * my_dl) * (1 + my_divaddval/my_mulval));
+
+                                               real my_dist = abs(rate - my_rate);
+
+                                               if (my_dist == 0 && my_divaddval == 0) {
+                                                       my_dist = -1;
+                                               }
+
+                                               if (my_dist < my_best_dist) {
+                                                       my_best_dl = my_dl;
+                                                       my_best_divaddval = my_divaddval;
+                                                       my_best_mulval = my_mulval;
+                                                       my_best_dist = my_dist;
+                                               }
+                                       }
+                               }
+                       }
+
+                       dl_est = my_best_dl;
+                       divaddval = my_best_divaddval;
+                       mulval = my_best_mulval;
+               }
+       }
+
+       int dl = floor (dl_est);        
+
+       real actual = usart_clock / ((16 * dl) * (1 + divaddval/mulval));
+
+       printf("\t[AO_SERIAL_SPEED_%d] = { /* actual = %8.2f */\n", floor(rate), actual);
+       printf("\t\t.dl = %d,\n", dl);
+       printf("\t\t.divaddval = %d,\n", divaddval);
+       printf("\t\t.mulval = %d\n", mulval);
+       printf("\t},\n");
+}
+
+void
+main() {
+       if (dim(argv) < 2) {
+               printf ("usage: %s <main-clock>\n", argv[0]);
+               exit(1);
+       }
+       main_clock = string_to_real(argv[1]);
+
+       for (int div = 0; div < 4; div++) {
+               if (main_clock / (1 << div) <= 12000000) {
+                       usart_clock = main_clock / (1 << div);
+                       break;
+               }
+       }
+
+       if (usart_clock == 0) {
+               printf ("can't get usart clock in range\n");
+               exit(1);
+       }
+
+       printf ("#define AO_LPC_USARTCLK %d\n\n", floor(usart_clock));
+       printf("static const struct {\n");
+       printf("\tuint16_t dl;\n");
+       printf("\tuint8_t divaddval;\n");
+       printf("\tuint8_t mulval;\n");
+       printf("} ao_usart_speeds[] = {\n");
+       for (int i = 0; i < dim(baud_rates); i++) {
+               compute_baud_rate(baud_rates[i]);
+       }
+       printf ("};\n");
+}
+
+main();
diff --git a/src/lpc/figure-checksum b/src/lpc/figure-checksum
new file mode 100755 (executable)
index 0000000..0b1de57
--- /dev/null
@@ -0,0 +1,39 @@
+#!/usr/bin/env nickle
+
+autoimport Process;
+
+int byteflip(int x) {
+       return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | ((x << 24) & 0xff000000);
+}
+
+void main () {
+       file    input = popen(popen_direction.read, true, "objdump",
+                             "objdump", "-j", ".text",
+                             "--start-address=0",
+                             "--stop-address=0x20",
+                             "-s", argv[1]);
+       int sum = 0;
+
+       void add_in(int addr, int value) {
+               if (addr < 0x1c) {
+                       sum += value;
+               } else if (addr == 0x1c) {
+                       printf ("-DCKSUM=0x%08x\n", -sum & 0xffffffff);
+                       exit(0);
+               }
+       }
+       while (!File::end(input)) {
+               string line = File::fgets(input);
+               string[] words = String::wordsplit(line, " ");
+
+               if (dim(words) < 5)
+                   continue;
+               if (words[0] == "0000" || words[0] == "0010") {
+                       int addr = string_to_integer(words[0], 16);
+                       for (int i = 0; i < 4; i++)
+                               add_in(addr + i * 4, byteflip(string_to_integer(words[i+1], 16)));
+               }
+       }
+}
+
+main();
diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h
new file mode 100644 (file)
index 0000000..49034c1
--- /dev/null
@@ -0,0 +1,1225 @@
+/*
+ * 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 _LPC_H_
+#define _LPC_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t      vuint32_t;
+typedef volatile uint16_t      vuint16_t;
+typedef volatile uint8_t       vuint8_t;
+typedef volatile void *                vvoid_t;
+
+struct lpc_ioconf {
+       vuint32_t       pio0_0;
+       vuint32_t       pio0_1;
+       vuint32_t       pio0_2;
+       vuint32_t       pio0_3;
+
+       vuint32_t       pio0_4;
+       vuint32_t       pio0_5;
+       vuint32_t       pio0_6;
+       vuint32_t       pio0_7;
+
+       vuint32_t       pio0_8;
+       vuint32_t       pio0_9;
+       vuint32_t       pio0_10;
+       vuint32_t       pio0_11;
+
+       vuint32_t       pio0_12;
+       vuint32_t       pio0_13;
+       vuint32_t       pio0_14;
+       vuint32_t       pio0_15;
+
+       vuint32_t       pio0_16;
+       vuint32_t       pio0_17;
+       vuint32_t       pio0_18;
+       vuint32_t       pio0_19;
+
+       vuint32_t       pio0_20;
+       vuint32_t       pio0_21;
+       vuint32_t       pio0_22;
+       vuint32_t       pio0_23;
+
+       vuint32_t       pio1_0;         /* 0x60 */
+       vuint32_t       pio1_1;
+       vuint32_t       pio1_2;
+       vuint32_t       pio1_3;
+
+       vuint32_t       pio1_4;
+       vuint32_t       pio1_5;
+       vuint32_t       pio1_6;
+       vuint32_t       pio1_7;
+
+       vuint32_t       pio1_8;         /* 0x80 */
+       vuint32_t       pio1_9;
+       vuint32_t       pio1_10;
+       vuint32_t       pio1_11;
+
+       vuint32_t       pio1_12;
+       vuint32_t       pio1_13;
+       vuint32_t       pio1_14;
+       vuint32_t       pio1_15;
+
+       vuint32_t       pio1_16;        /* 0xa0 */
+       vuint32_t       pio1_17;
+       vuint32_t       pio1_18;
+       vuint32_t       pio1_19;
+
+       vuint32_t       pio1_20;
+       vuint32_t       pio1_21;
+       vuint32_t       pio1_22;
+       vuint32_t       pio1_23;
+
+       vuint32_t       pio1_24;        /* 0xc0 */
+       vuint32_t       pio1_25;
+       vuint32_t       pio1_26;
+       vuint32_t       pio1_27;
+
+       vuint32_t       pio1_28;
+       vuint32_t       pio1_29;
+       vuint32_t       pio1_30;
+       vuint32_t       pio1_31;
+};
+
+extern struct lpc_ioconf lpc_ioconf;
+
+#define LPC_IOCONF_FUNC                0
+
+/* PIO0_0 */
+#define  LPC_IOCONF_FUNC_RESET         0
+#define  LPC_IOCONF_FUNC_PIO0_0                1
+
+/* PIO0_1 */
+#define  LPC_IOCONF_FUNC_PIO0_1                0
+#define  LPC_IOCONF_FUNC_CLKOUT                1
+#define  LPC_IOCONF_FUNC_CT32B0_MAT2   2
+#define  LPC_IOCONF_FUNC_USB_FTOGGLE   3
+
+/* PIO0_2 */
+#define  LPC_IOCONF_FUNC_PIO0_2                0
+#define  LPC_IOCONF_FUNC_SSEL0         1
+#define  LPC_IOCONF_FUNC_CT16B0_CAP0   2
+
+/* PIO0_3 */
+#define  LPC_IOCONF_FUNC_PIO0_3                0
+#define  LPC_IOCONF_FUNC_USB_VBUS      1
+
+/* PIO0_4
+#define  LPC_IOCONF_FUNC_PIO0_4                0
+#define  LPC_IOCONF_FUNC_I2C_SCL       1
+
+/* PIO0_5 */
+#define  LPC_IOCONF_FUNC_PIO0_5                0
+#define  LPC_IOCONF_FUNC_I2C_SDA       1
+
+/* PIO0_6 */
+#define  LPC_IOCONF_FUNC_PIO0_6                0
+#define  LPC_IOCONF_FUNC_USB_CONNECT   1
+#define  LPC_IOCONF_FUNC_PIO0_6_SCK0   2
+
+/* PIO0_7 */
+#define  LPC_IOCONF_FUNC_PIO0_7                0
+#define  LPC_IOCONF_FUNC_CTS           1
+
+/* PIO0_8 */
+#define  LPC_IOCONF_FUNC_PIO0_8                0
+#define  LPC_IOCONF_FUNC_MISO0         1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT0   2
+
+/* PIO0_9 */
+#define  LPC_IOCONF_FUNC_PIO0_9                0
+#define  LPC_IOCONF_FUNC_MOSI0         1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT1   2
+
+/* PIO0_10 */
+#define  LPC_IOCONF_FUNC_SWCLK         0
+#define  LPC_IOCONF_FUNC_PIO0_10       1
+#define  LPC_IOCONF_FUNC_PIO0_10_SCK0  2
+#define  LPC_IOCONF_FUNC_CT16B0_MAT2   3
+
+/* PIO0_11 */
+#define  LPC_IOCONF_FUNC_TDI           0
+#define  LPC_IOCONF_FUNC_PIO0_11       1
+#define  LPC_IOCONF_FUNC_AD0           2
+#define  LPC_IOCONF_FUNC_CT32B0_MAT3   3
+
+/* PIO0_12 */
+#define  LPC_IOCONF_FUNC_TMS           0
+#define  LPC_IOCONF_FUNC_PIO0_12       1
+#define  LPC_IOCONF_FUNC_AD1           2
+#define  LPC_IOCONF_FUNC_CT32B1_CAP0   3
+
+/* PIO0_13 */
+#define  LPC_IOCONF_FUNC_TD0           0
+#define  LPC_IOCONF_FUNC_PIO0_13       1
+#define  LPC_IOCONF_FUNC_AD2           2
+#define  LPC_IOCONF_FUNC_CT32B1_MAT0   3
+
+/* PIO0_14 */
+#define  LPC_IOCONF_FUNC_TRST          0
+#define  LPC_IOCONF_FUNC_PIO0_14       1
+#define  LPC_IOCONF_FUNC_AD3           2
+#define  LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1   3
+
+/* PIO0_15 */
+#define  LPC_IOCONF_FUNC_SWDIO         0
+#define  LPC_IOCONF_FUNC_PIO0_15       1
+#define  LPC_IOCONF_FUNC_AD4           2
+#define  LPC_IOCONF_FUNC_CT32B1_MAT2   3
+
+/* PIO0_16 */
+#define  LPC_IOCONF_FUNC_PIO0_16       0
+#define  LPC_IOCONF_FUNC_AD5           1
+#define  LPC_IOCONF_FUNC_CT32B1_MAT3   2
+
+/* PIO0_17 */
+#define  LPC_IOCONF_FUNC_PIO0_17       0
+#define  LPC_IOCONF_FUNC_RTS           1
+#define  LPC_IOCONF_FUNC_CT32B0_CAP0   2
+#define  LPC_IOCONF_FUNC_SCLK          3
+
+/* PIO0_18 */
+#define  LPC_IOCONF_FUNC_PIO0_18               0
+#define  LPC_IOCONF_FUNC_PIO0_18_RXD           1
+#define  LPC_IOCONF_FUNC_PIO0_18_CT32B0_MAT0   2
+
+/* PIO0_19 */
+#define  LPC_IOCONF_FUNC_PIO0_19               0
+#define  LPC_IOCONF_FUNC_PIO0_19_TXD           1
+#define  LPC_IOCONF_FUNC_PIO0_19_CT32B0_MAT1   2
+
+/* PIO0_20 */
+#define  LPC_IOCONF_FUNC_PIO0_20       0
+#define  LPC_IOCONF_FUNC_CT16B1_CAP0   1
+
+/* PIO0_21 */
+#define  LPC_IOCONF_FUNC_PIO0_21       0
+#define  LPC_IOCONF_FUNC_CT16B1_MAT0   1
+#define  LPC_IOCONF_FUNC_PIO0_21_MOSI1 2
+
+/* PIO0_22 */
+#define  LPC_IOCONF_FUNC_PIO0_22       0
+#define  LPC_IOCONF_FUNC_AD6           1
+#define  LPC_IOCONF_FUNC_CT16B1_MAT1   2
+#define  LPC_IOCONF_FUNC_PIO0_22_MISO1 3
+
+/* PIO0_23 */
+#define  LPC_IOCONF_FUNC_PIO0_23       0
+#define  LPC_IOCONF_FUNC_AD7           1
+
+/* PIO1_0 */
+#define  LPC_IOCONF_FUNC_PIO1_0                0
+#define  LPC_IOCONF_FUNC_CT32B1_MAT1   1
+
+/* PIO1_1 */
+#define  LPC_IOCONF_FUNC_PIO1_1                0
+#define  LPC_IOCONF_FUNC_CT32B1_MAT1   1
+
+/* PIO1_2 */
+#define  LPC_IOCONF_FUNC_PIO1_2                0
+#define  LPC_IOCONF_FUNC_PIO1_2_CT32B1_MAT2    1
+
+/* PIO1_3*/
+#define  LPC_IOCONF_FUNC_PIO1_3                0
+#define  LPC_IOCONF_FUNC_PIO1_3_CT32B1_MAT3    1
+
+/* PIO1_4 */
+#define  LPC_IOCONF_FUNC_PIO1_4                0
+#define  LPC_IOCONF_FUNC_PIO1_4_CT32B1_CAP0    1
+
+/* PIO1_5 */
+#define  LPC_IOCONF_FUNC_PIO1_5                0
+#define  LPC_IOCONF_FUNC_CT32B1_CAP1   1
+
+/* PIO1_6 */
+#define  LPC_IOCONF_FUNC_PIO1_6                0
+
+/* PIO1_7 */
+#define  LPC_IOCONF_FUNC_PIO1_7                0
+
+/* PIO1_8 */
+#define  LPC_IOCONF_FUNC_PIO1_8                0
+
+/* PIO1_9 */
+#define  LPC_IOCONF_FUNC_PIO1_9                0
+
+/* PIO1_10 */
+#define  LPC_IOCONF_FUNC_PIO1_10       0
+
+/* PIO1_11 */
+#define  LPC_IOCONF_FUNC_PIO1_11       0
+
+/* PIO1_12 */
+#define  LPC_IOCONF_FUNC_PIO1_12       0
+
+/* PIO1_13 */
+#define  LPC_IOCONF_FUNC_PIO1_13       0
+#define  LPC_IOCONF_FUNC_DTR           1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT0   2
+#define  LPC_IOCONF_FUNC_PIO1_13_TXD           3
+
+/* PIO1_14 */
+#define  LPC_IOCONF_FUNC_PIO1_14       0
+#define  LPC_IOCONF_FUNC_DSR           1
+#define  LPC_IOCONF_FUNC_CT16B0_MAT1   2
+#define  LPC_IOCONF_FUNC_PIO1_13_RXD           3
+
+/* PIO1_15 */
+#define  LPC_IOCONF_FUNC_PIO1_15       0
+#define  LPC_IOCONF_FUNC_DCD           1
+#define  LPC_IOCONF_FUNC_PIO1_15_CT16B0_MAT2   2
+#define  LPC_IOCONF_FUNC_PIO1_15_SCK1  3
+
+/* PIO1_16 */
+#define  LPC_IOCONF_FUNC_PIO1_16       0
+#define  LPC_IOCONF_FUNC_RI            1
+#define  LPC_IOCONF_FUNC_CT16B0_CAP0   2
+
+/* PIO1_17 */
+#define  LPC_IOCONF_FUNC_PIO1_17       0
+#define  LPC_IOCONF_FUNC_CT16B0_CAP1   1
+#define  LPC_IOCONF_FUNC_PIO1_17_RXD           2
+
+/* PIO1_18 */
+#define  LPC_IOCONF_FUNC_PIO1_18       0
+#define  LPC_IOCONF_FUNC_CT16B1_CAP1   1
+#define  LPC_IOCONF_FUNC_PIO1_18_TXD           2
+
+/* PIO1_19 */
+#define  LPC_IOCONF_FUNC_PIO1_19       0
+#define  LPC_IOCONF_FUNC_DTR           1
+#define  LPC_IOCONF_FUNC_SSEL1         2
+
+/* PIO1_20 */
+#define  LPC_IOCONF_FUNC_PIO1_20       0
+#define  LPC_IOCONF_FUNC_DSR           1
+#define  LPC_IOCONF_FUNC_PIO1_20_SCK1          2
+
+/* PIO1_21 */
+#define  LPC_IOCONF_FUNC_PIO1_21       0
+#define  LPC_IOCONF_FUNC_DCD           1
+#define  LPC_IOCONF_FUNC_PIO1_21_MISO1         2
+
+/* PIO1_22 */
+#define  LPC_IOCONF_FUNC_PIO1_22       0
+#define  LPC_IOCONF_FUNC_RI            1
+#define  LPC_IOCONF_FUNC_PIO1_22_MOSI1 2
+
+/* PIO1_23 */
+#define  LPC_IOCONF_FUNC_PIO1_23       0
+#define  LPC_IOCONF_FUNC_PIO1_23_CT16B1_MAT1   1
+#define  LPC_IOCONF_FUNC_SSEL1         2
+
+/* PIO1_24 */
+#define  LPC_IOCONF_FUNC_PIO1_24       0
+#define  LPC_IOCONF_FUNC_PIO1_24_CT32B0_MAT0   1
+
+/* PIO1_25 */
+#define  LPC_IOCONF_FUNC_PIO1_25       0
+#define  LPC_IOCONF_FUNC_PIO1_25_CT32B0_MAT1   1
+
+/* PIO1_26 */
+#define  LPC_IOCONF_FUNC_PIO1_26       0
+#define  LPC_IOCONF_FUNC_PIO1_26_CT32B0_MAT2   1
+#define  LPC_IOCONF_FUNC_PIO1_26_RXD           2
+
+/* PIO1_27 */
+#define  LPC_IOCONF_FUNC_PIO1_27       0
+#define  LPC_IOCONF_FUNC_PIO1_27_CT32B0_MAT3   1
+#define  LPC_IOCONF_FUNC_PIO1_27_TXD           2
+
+/* PIO1_28 */
+#define  LPC_IOCONF_FUNC_PIO1_28       0
+#define  LPC_IOCONF_FUNC_PIO1_28_CT32B0_CAP0   1
+#define  LPC_IOCONF_FUNC_PIO1_28_SCLK          2
+
+/* PIO1_29 */
+#define  LPC_IOCONF_FUNC_PIO1_29               0
+#define  LPC_IOCONF_FUNC_PIO1_29_SCK0          1
+#define  LPC_IOCONF_FUNC_PIO1_29_CT32B0_CAP1   2
+
+/* PIO1_31 */
+#define  LPC_IOCONF_FUNC_PIO1_31       0
+
+#define  LPC_IOCONF_FUNC_MASK          0x7
+
+#define ao_lpc_alternate(func) (((func) << LPC_IOCONF_FUNC) | \
+                               (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) | \
+                               (0 << LPC_IOCONF_HYS) |                 \
+                               (0 << LPC_IOCONF_INV) |                 \
+                               (0 << LPC_IOCONF_OD) |                  \
+                               0x80)
+
+#define LPC_IOCONF_MODE                        3
+#define  LPC_IOCONF_MODE_INACTIVE              0
+#define  LPC_IOCONF_MODE_PULL_DOWN             1
+#define  LPC_IOCONF_MODE_PULL_UP               2
+#define  LPC_IOCONF_MODE_REPEATER              3
+#define  LPC_IOCONF_MODE_MASK                  3
+
+#define LPC_IOCONF_HYS                 5
+
+#define LPC_IOCONF_INV                 6
+#define LPC_IOCONF_ADMODE              7
+#define LPC_IOCONF_FILTR               8
+#define LPC_IOCONF_OD                  10
+
+struct lpc_scb {
+       vuint32_t       sysmemremap;    /* 0x00 */
+       vuint32_t       presetctrl;
+       vuint32_t       syspllctrl;
+       vuint32_t       syspllstat;
+
+       vuint32_t       usbpllctrl;     /* 0x10 */
+       vuint32_t       usbpllstat;
+       uint32_t        r18;
+       uint32_t        r1c;
+
+       vuint32_t       sysoscctrl;     /* 0x20 */
+       vuint32_t       wdtoscctrl;
+       uint32_t        r28;
+       uint32_t        r2c;
+
+       vuint32_t       sysrststat;     /* 0x30 */
+       uint32_t        r34;
+       uint32_t        r38;
+       uint32_t        r3c;
+
+       vuint32_t       syspllclksel;   /* 0x40 */
+       vuint32_t       syspllclkuen;
+       vuint32_t       usbpllclksel;
+       vuint32_t       usbpllclkuen;
+
+       uint32_t        r50[8];
+
+       vuint32_t       mainclksel;     /* 0x70 */
+       vuint32_t       mainclkuen;
+       vuint32_t       sysahbclkdiv;
+       uint32_t        r7c;            
+
+       vuint32_t       sysahbclkctrl;  /* 0x80 */
+       uint32_t        r84[3];
+
+       uint32_t        r90;            /* 0x90 */
+       vuint32_t       ssp0clkdiv;
+       vuint32_t       uartclkdiv;
+       vuint32_t       ssp1clkdiv;
+
+       uint32_t        ra0[8];
+
+       vuint32_t       usbclksel;      /* 0xc0 */
+       vuint32_t       usbclkuen;
+       vuint32_t       usbclkdiv;
+       uint32_t        rcc;
+
+       uint32_t        rd0[4];
+       
+       vuint32_t       clkoutsel;      /* 0xe0 */
+       vuint32_t       clkoutuen;
+       vuint32_t       clkoutdiv;
+       uint32_t        rec;
+       
+       uint32_t        rf0[4];         /* 0xf0 */
+       
+       vuint32_t       pioporcap0;     /* 0x100 */
+       vuint32_t       pioporcap1;
+       uint32_t        r102[2];
+
+       uint32_t        r110[4];        /* 0x110 */
+       uint32_t        r120[4];        /* 0x120 */
+       uint32_t        r130[4];        /* 0x130 */
+       uint32_t        r140[4];        /* 0x140 */
+       
+       vuint32_t       bodctrl;        /* 0x150 */
+       vuint32_t       systckcal;
+       uint32_t        r158[2];
+
+       uint32_t        r160[4];        /* 0x160 */
+
+       vuint32_t       irqlatency;     /* 0x170 */
+       vuint32_t       nmisrc;
+       vuint32_t       pintsel[8];
+
+       vuint32_t       usbclkctrl;     /* 0x198 */
+       vuint32_t       usbclkst;
+
+       uint32_t        r1a0[6*4];      /* 0x1a0 */
+
+       uint32_t        r200;           /* 0x200 */
+       vuint32_t       starterp0;
+       uint32_t        r208[2];
+
+       uint32_t        r210;           /* 0x210 */
+       vuint32_t       starterp1;
+       uint32_t        r218[2];
+
+       uint32_t        r220[4];        /* 0x220 */
+
+       vuint32_t       pdsleepcfg;     /* 0x230 */
+       vuint32_t       pdawakecfg;
+       vuint32_t       pdruncfg;
+       uint32_t        r23c;
+
+       uint32_t        r240[12 * 4];   /* 0x240 */
+
+       uint32_t        r300[15 * 4];   /* 0x300 */
+                            
+       uint32_t        r3f0;           /* 0x3f0 */
+       vuint32_t       device_id;
+};
+
+extern struct lpc_scb lpc_scb;
+
+#define LPC_SCB_PRESETCTRL_SSP0_RST_N  0
+#define LPC_SCB_PRESETCTRL_I2C_RST_N   1
+#define LPC_SCB_PRESETCTRL_SSP1_RST_N  2
+
+#define LPC_SCB_SYSPLLCTRL_MSEL                0
+#define LPC_SCB_SYSPLLCTRL_PSEL                5
+#define  LPC_SCB_SYSPLLCTRL_PSEL_1             0
+#define  LPC_SCB_SYSPLLCTRL_PSEL_2             1
+#define  LPC_SCB_SYSPLLCTRL_PSEL_4             2
+#define  LPC_SCB_SYSPLLCTRL_PSEL_8             3
+#define  LPC_SCB_SYSPLLCTRL_PSEL_MASK          3
+
+#define LPC_SCB_SYSPLLSTAT_LOCK                0
+
+#define LPC_SCB_USBPLLCTRL_MSEL                0
+#define LPC_SCB_USBPLLCTRL_PSEL                5
+#define  LPC_SCB_USBPLLCTRL_PSEL_1             0
+#define  LPC_SCB_USBPLLCTRL_PSEL_2             1
+#define  LPC_SCB_USBPLLCTRL_PSEL_4             2
+#define  LPC_SCB_USBPLLCTRL_PSEL_8             3
+#define  LPC_SCB_USBPLLCTRL_PSEL_MASK          3
+
+#define LPC_SCB_USBPLLSTAT_LOCK                0
+
+#define LPC_SCB_SYSOSCCTRL_BYPASS      0
+#define LPC_SCB_SYSOSCCTRL_FREQRANGE   1
+#define  LPC_SCB_SYSOSCCTRL_FREQRANGE_1_20     0
+#define  LPC_SCB_SYSOSCCTRL_FREQRANGE_15_25    1
+
+#define LPC_SCB_WDTOSCCTRL_DIVSEL              0
+#define  LPC_SCB_WDTOSCCTRL_DIVSEL_MASK                        0x1f
+#define LPC_SCB_WDTOSCCTRL_FREQSEL             5
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_0_6                        1
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_05               2
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_4                        3
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_1_75               4
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_1                        5
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_4                        6
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_2_7                        7
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_0                        8
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_25               9
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_5                        0x0a
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_3_75               0x0b
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_0                        0x0c
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_2                        0x0d
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_4                        0x0e
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_4_6                        0x0f
+#define  LPC_SCB_WDTOSCCTRL_FREQSEL_MASK               0x0f
+
+#define LPC_SCB_SYSRSTSTAT_POR         0
+#define LPC_SCB_SYSRSTSTAT_EXTRST      1
+#define LPC_SCB_SYSRSTSTAT_WDT         2
+#define LPC_SCB_SYSRSTSTAT_BOD         3
+#define LPC_SCB_SYSRSTSTAT_SYSRST      4
+
+#define LPC_SCB_SYSPLLCLKSEL_SEL       0
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_IRC          0
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_SYSOSC       1
+#define  LPC_SCB_SYSPLLCLKSEL_SEL_MASK         3
+
+#define LPC_SCB_SYSPLLCLKUEN_ENA       0
+
+#define LPC_SCB_USBPLLCLKSEL_SEL       0
+#define  LPC_SCB_USBPLLCLKSEL_SEL_IRC          0
+#define  LPC_SCB_USBPLLCLKSEL_SEL_SYSOSC       1
+#define  LPC_SCB_USBPLLCLKSEL_SEL_MASK         3
+
+#define LPC_SCB_USBPLLCLKUEN_ENA       0
+
+#define LPC_SCB_MAINCLKSEL_SEL         0
+#define  LPC_SCB_MAINCLKSEL_SEL_IRC            0
+#define  LPC_SCB_MAINCLKSEL_SEL_PLL_INPUT      1
+#define  LPC_SCB_MAINCLKSEL_SEL_WATCHDOG       2
+#define  LPC_SCB_MAINCLKSEL_SEL_PLL_OUTPUT     3
+#define  LPC_SCB_MAINCLKSEL_SEL_MASK           3
+
+#define LPC_SCB_MAINCLKUEN_ENA         0
+
+#define LPC_SCB_SYSAHBCLKDIV_DIV       0
+
+#define LPC_SCB_SYSAHBCLKCTRL_SYS      0
+#define LPC_SCB_SYSAHBCLKCTRL_ROM      1
+#define LPC_SCB_SYSAHBCLKCTRL_RAM0     2
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHREG 3
+#define LPC_SCB_SYSAHBCLKCTRL_FLASHARRAY       4
+#define LPC_SCB_SYSAHBCLKCTRL_I2C      5
+#define LPC_SCB_SYSAHBCLKCTRL_GPIO     6
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B0   7
+#define LPC_SCB_SYSAHBCLKCTRL_CT16B1   8
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B0   9
+#define LPC_SCB_SYSAHBCLKCTRL_CT32B1   10
+#define LPC_SCB_SYSAHBCLKCTRL_SSP0     11
+#define LPC_SCB_SYSAHBCLKCTRL_USART    12
+#define LPC_SCB_SYSAHBCLKCTRL_ADC      13
+#define LPC_SCB_SYSAHBCLKCTRL_USB      14
+#define LPC_SCB_SYSAHBCLKCTRL_WWDT     15
+#define LPC_SCB_SYSAHBCLKCTRL_IOCON    16
+#define LPC_SCB_SYSAHBCLKCTRL_SSP1     18
+#define LPC_SCB_SYSAHBCLKCTRL_PINT     19
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP0INT        23
+#define LPC_SCB_SYSAHBCLKCTRL_GROUP1INT        24
+#define LPC_SCB_SYSAHBCLKCTRL_RAM1     26
+#define LPC_SCB_SYSAHBCLKCTRL_USBRAM   27
+
+#define LPC_SCB_SSP0CLKDIV_
+#define LPC_SCB_UARTCLKDIV_
+#define LPC_SCB_SSP1CLKDIV_
+
+#define LPC_SCB_USBCLKSEL_SEL          0
+#define LPC_SCB_USBCLKSEL_SEL_USB_PLL          0
+#define LPC_SCB_USBCLKSEL_SEL_MAIN_CLOCK       1
+
+#define LPC_SCB_USBCLKUEN_ENA          0
+#define LPC_SCB_USBCLKDIV_DIV          0
+
+#define LPC_SCB_CLKOUTSEL_SEL          0
+#define  LPC_SCB_CLKOUTSEL_SEL_IRC             0
+#define  LPC_SCB_CLKOUTSEL_SEL_SYSOSC          1
+#define  LPC_SCB_CLKOUTSEL_SEL_LF              2
+#define  LPC_SCB_CLKOUTSEL_SEL_MAIN_CLOCK      3
+
+#define LPC_SCB_CLKOUTUEN_ENA          0
+
+#define LPC_SCB_PDRUNCFG_IRCOUT_PD     0
+#define LPC_SCB_PDRUNCFG_IRC_PD                1
+#define LPC_SCB_PDRUNCFG_FLASH_PD      2
+#define LPC_SCB_PDRUNCFG_BOD_PD                3
+#define LPC_SCB_PDRUNCFG_ADC_PD                4
+#define LPC_SCB_PDRUNCFG_SYSOSC_PD     5
+#define LPC_SCB_PDRUNCFG_WDTOSC_PD     6
+#define LPC_SCB_PDRUNCFG_SYSPLL_PD     7
+#define LPC_SCB_PDRUNCFG_USBPLL_PD     8
+#define LPC_SCB_PDRUNCFG_USBPAD_PD     10
+
+struct lpc_flash {
+       uint32_t        r0[4];          /* 0x0 */
+
+       vuint32_t       flashcfg;       /* 0x10 */
+};
+
+extern struct lpc_flash lpc_flash;
+
+struct lpc_gpio_pin {
+       vuint32_t       isel;           /* 0x00 */
+       vuint32_t       ienr;
+       vuint32_t       sienr;
+       vuint32_t       cienr;
+
+       vuint32_t       ienf;           /* 0x10 */
+       vuint32_t       sienf;
+       vuint32_t       cienf;
+       vuint32_t       rise;
+
+       vuint32_t       fall;           /* 0x20 */
+       vuint32_t       ist;
+};
+
+extern struct lpc_gpio_pin lpc_gpio_pin;
+
+struct lpc_gpio_group0 {
+};
+
+extern struct lpc_gpio_group0 lpc_gpio_group0;
+
+struct lpc_gpio_group1 {
+};
+
+extern struct lpc_gpio_group1 lpc_gpio_group1;
+
+struct lpc_gpio {
+       vuint8_t        byte[0x40];     /* 0x0000 */
+
+       uint8_t         r0030[0x1000 - 0x40];
+
+       vuint32_t       word[0x40];     /* 0x1000 */
+
+       uint8_t         r1100[0x2000 - 0x1100];
+       
+       vuint32_t       dir[2];         /* 0x2000 */
+
+       uint8_t         r2008[0x2080 - 0x2008];
+
+       vuint32_t       mask[2];        /* 0x2080 */
+
+       uint8_t         r2088[0x2100 - 0x2088];
+
+       vuint32_t       pin[2];         /* 0x2100 */
+
+       uint8_t         r2108[0x2200 - 0x2108];
+
+       vuint32_t       set[2];         /* 0x2200 */
+
+       uint8_t         r2208[0x2280 - 0x2208];
+
+       vuint32_t       clr[2];         /* 0x2280 */
+
+       uint8_t         r2288[0x2300 - 0x2288];
+
+       vuint32_t       not[2];         /* 0x2300 */
+};
+
+extern struct lpc_gpio lpc_gpio;
+
+struct lpc_systick {
+       uint8_t         r0000[0x10];    /* 0x0000 */
+
+       vuint32_t       csr;            /* 0x0010 */
+       vuint32_t       rvr;
+       vuint32_t       cvr;
+       vuint32_t       calib;
+};
+
+extern struct lpc_systick lpc_systick;
+
+#define LPC_SYSTICK_CSR_ENABLE         0
+#define LPC_SYSTICK_CSR_TICKINT                1
+#define LPC_SYSTICK_CSR_CLKSOURCE      2
+#define  LPC_SYSTICK_CSR_CLKSOURCE_CPU_OVER_2          0
+#define  LPC_SYSTICK_CSR_CLKSOURCE_CPU                 1
+#define LPC_SYSTICK_CSR_COUNTFLAG      16
+
+struct lpc_usart {
+       vuint32_t       rbr_thr;        /* 0x0000 */
+       vuint32_t       ier;
+       vuint32_t       iir_fcr;
+       vuint32_t       lcr;
+
+       vuint32_t       mcr;            /* 0x0010 */
+       vuint32_t       lsr;
+       vuint32_t       msr;
+       vuint32_t       scr;
+
+       vuint32_t       acr;            /* 0x0020 */
+       vuint32_t       icr;
+       vuint32_t       fdr;
+       vuint32_t       osr;
+
+       vuint32_t       ter;            /* 0x0030 */
+       uint32_t        r34[3];
+
+       vuint32_t       hden;           /* 0x0040 */
+       uint32_t        r44;
+       vuint32_t       scictrl;
+       vuint32_t       rs485ctrl;
+
+       vuint32_t       rs485addrmatch; /* 0x0050 */
+       vuint32_t       rs485dly;
+       vuint32_t       syncctrl;
+};
+
+extern struct lpc_usart lpc_usart;
+
+#define LPC_USART_IER_RBRINTEN 0
+#define LPC_USART_IER_THREINTEN        1
+#define LPC_USART_IER_RSLINTEN 2
+#define LPC_USART_IER_MSINTEN  3
+#define LPC_USART_IER_ABEOINTEN        8
+#define LPC_USART_IER_ABTOINTEN        9
+
+#define LPC_USART_IIR_INTSTATUS                0
+#define LPC_USART_IIR_INTID            1
+#define LPC_USART_IIR_INTID_RLS                        3
+#define LPC_USART_IIR_INTID_RDA                        2
+#define LPC_USART_IIR_INTID_CTI                        6
+#define LPC_USART_IIR_INTID_THRE               1
+#define LPC_USART_IIR_INTID_MS                 0
+#define LPC_USART_IIR_INTID_MASK               7
+#define LPC_USART_IIR_FIFOEN           6
+#define LPC_USART_IIR_ABEOINT          8
+#define LPC_USART_IIR_ABTOINT          9
+
+#define LPC_USART_FCR_FIFOEN           0
+#define LPC_USART_FCR_RXFIFORES                1
+#define LPC_USART_FCR_TXFIFORES                2
+#define LPC_USART_FCR_RXTL             6
+#define LPC_USART_FCR_RXTL_1                   0
+#define LPC_USART_FCR_RXTL_4                   1
+#define LPC_USART_FCR_RXTL_8                   2
+#define LPC_USART_FCR_RXTL_14                  3
+
+#define LPC_USART_LCR_WLS      0
+#define LPC_USART_LCR_WLS_5            0
+#define LPC_USART_LCR_WLS_6            1
+#define LPC_USART_LCR_WLS_7            2
+#define LPC_USART_LCR_WLS_8            3
+#define LPC_USART_LCR_WLS_MASK         3
+#define LPC_USART_LCR_SBS      2
+#define LPC_USART_LCR_SBS_1            0
+#define LPC_USART_LCR_SBS_2            1
+#define LPC_USART_LCR_SBS_MASK         1
+#define LPC_USART_LCR_PE       3
+#define LPC_USART_LCR_PS       4
+#define LPC_USART_LCR_PS_ODD           0
+#define LPC_USART_LCR_PS_EVEN          1
+#define LPC_USART_LCR_PS_ONE           2
+#define LPC_USART_LCR_PS_ZERO          3
+#define LPC_USART_LCR_PS_MASK          3
+#define LPC_USART_LCR_BC       6
+#define LPC_USART_LCR_DLAB     7
+
+#define LPC_USART_MCR_DTRCTRL  0
+#define LPC_USART_MCR_RTSCTRL  1
+#define LPC_USART_MCR_LMS      4
+#define LPC_USART_MCR_RTSEN    6
+#define LPC_USART_MCR_CTSEN    7
+
+#define LPC_USART_LSR_RDR      0
+#define LPC_USART_LSR_OE       1
+#define LPC_USART_LSR_PE       2
+#define LPC_USART_LSR_FE       3
+#define LPC_USART_LSR_BI       4
+#define LPC_USART_LSR_THRE     5
+#define LPC_USART_LSR_TEMT     6
+#define LPC_USART_LSR_RXFE     7
+#define LPC_USART_LSR_TXERR    8
+
+#define LPC_USART_MSR_DCTS     0
+#define LPC_USART_MSR_DDSR     1
+#define LPC_USART_MSR_TERI     2
+#define LPC_USART_MSR_DDCD     3
+#define LPC_USART_MSR_CTS      4
+#define LPC_USART_MSR_DSR      5
+#define LPC_USART_MSR_RI       6
+#define LPC_USART_MSR_DCD      7
+
+#define LPC_USART_ACR_START    0
+#define LPC_USART_ACR_MODE     1
+#define LPC_USART_ACR_AUTORESTART      2
+#define LPC_USART_ACR_ABEOINTCLR       8
+#define LPC_USART_ACR_ABTOINTCLR       9
+
+#define LPC_USART_FDR_DIVADDVAL        0
+#define LPC_USART_FDR_MULVAL   4
+
+#define LPC_USART_OSR_OSFRAC   1
+#define LPC_USART_OSR_OSINT    4
+#define LPC_USART_OSR_FDINT    8
+
+#define LPC_USART_TER_TXEN     7
+
+#define LPC_USART_HDEN_HDEN    0
+
+struct lpc_usb {
+       vuint32_t       devcmdstat;
+       vuint32_t       info;
+       vuint32_t       epliststart;
+       vuint32_t       databufstart;
+       vuint32_t       lpm;
+       vuint32_t       epskip;
+       vuint32_t       epinuse;
+       vuint32_t       epbufcfg;
+       vuint32_t       intstat;
+       vuint32_t       inten;
+       vuint32_t       intsetstat;
+       vuint32_t       introuting;
+       uint32_t        r30;
+       vuint32_t       eptoggle;
+} lpc_usb;
+
+extern struct lpc_usb lpc_usb;
+
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR    0
+#define LPC_USB_DEVCMDSTAT_DEV_ADDR_MASK       0x7f
+#define LPC_USB_DEVCMDSTAT_DEV_EN      7
+#define LPC_USB_DEVCMDSTAT_SETUP       8
+#define LPC_USB_DEVCMDSTAT_PLL_ON      9
+#define LPC_USB_DEVCMDSTAT_LPM_SUP     11
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AO 12
+#define LPC_USB_DEVCMDSTAT_INTONNAK_AI 13
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CO 14
+#define LPC_USB_DEVCMDSTAT_INTONNAK_CI 15
+#define LPC_USB_DEVCMDSTAT_DCON                16
+#define LPC_USB_DEVCMDSTAT_DSUS                17
+#define LPC_USB_DEVCMDSTAT_LPM_SUS     19
+#define LPC_USB_DEVCMDSTAT_LPM_REWP    20
+#define LPC_USB_DEVCMDSTAT_DCON_C      24
+#define LPC_USB_DEVCMDSTAT_DSUS_C      25
+#define LPC_USB_DEVCMDSTAT_DRES_C      26
+#define LPC_USB_DEVCMDSTAT_VBUSDEBOUNCED       28
+
+#define LPC_USB_INFO_FRAME_NR          0
+#define LPC_USB_INFO_FRAME_NR_MASK     0x3ff
+#define LPC_USB_INFO_ERR_CODE          11
+#define LPC_USB_INFO_ERR_CODE_NO_ERROR                 0
+#define LPC_USB_INFO_ERR_CODE_PID_ENCODING_ERROR       1
+#define LPC_USB_INFO_ERR_CODE_PID_UNKNOWN              2
+#define LPC_USB_INFO_ERR_CODE_PACKET_UNEXPECTED                3
+#define LPC_USB_INFO_ERR_CODE_TOKEN_CRC_ERROR          4
+#define LPC_USB_INFO_ERR_CODE_DATA_CRC_ERROR           5
+#define LPC_USB_INFO_ERR_CODE_TIME_OUT                 6
+#define LPC_USB_INFO_ERR_CODE_BABBLE                   7
+#define LPC_USB_INFO_ERR_CODE_TRUNCATED_EOP            8
+#define LPC_USB_INFO_ERR_CODE_SENT_RECEIVED_NAK                9
+#define LPC_USB_INFO_ERR_CODE_SENT_STALL               0xa
+#define LPC_USB_INFO_ERR_CODE_OVERRUN                  0xb
+#define LPC_USB_INFO_ERR_CODE_SENT_EMPTY_PACKET                0xc
+#define LPC_USB_INFO_ERR_CODE_BITSTUFF_ERROR           0xd
+#define LPC_USB_INFO_ERR_CODE_SYNC_ERROR               0xe
+#define LPC_USB_INFO_ERR_CODE_WRONG_DATA_TOGGLE                0xf
+#define LPC_USB_INFO_ERR_CODE_MASK                     0xf
+
+#define LPC_USB_EPLISTSTART_EP_LIST                    0
+
+#define LPC_USB_DATABUFSTART_DA_BUF                    0
+
+#define LPC_USB_LPM_HIRD_HW            0
+#define LPC_USB_LPM_HIRD_HW_MASK               0xf
+#define LPC_USB_LPM_HIRD_SW            4
+#define LPC_USB_LPM_HIRD_SW_MASK               0xf
+#define LPC_USB_LPM_DATA_PENDING       8
+
+#define LPC_USB_EPSKIP_SKIP            0
+
+#define LPC_USB_EPINUSE_BUF(ep)                (ep)
+
+#define LPC_USB_EPBUFCFG_BUF_SB(ep)    (ep)
+
+#define LPC_USB_INT_EPOUT(ep)          ((ep) << 1)
+#define LPC_USB_INT_EPIN(ep)           (((ep) << 1) + 1)
+
+#define LPC_USB_INT_FRAME              30
+#define LPC_USB_INT_DEV                        31
+
+#define LPC_USB_INTIN_EP_INT_EN(ep)    (ep)
+#define LPC_USB_INTIN_FRAME_INT_EN     30
+#define LPC_USB_INTIN_DEV_INT_EN       31
+
+#define LPC_USB_INTSETSTAT_EP_SET_INT(ep)      (ep)
+#define LPC_USB_INTSETSTAT_FRAME_SET_INT       30
+#define LPC_USB_INTSETSTAT_DEV_SET_INT         31
+
+#define LPC_USB_INTROUTING_ROUTE_INT(ep)       (ep)
+#define LPC_USB_INTROUTING_INT30               30
+#define LPC_USB_INTROUTING_INT31               31
+
+#define LPC_USB_EPTOGGLE_TOGGLE(ep)            (ep)
+
+struct lpc_usb_epn {
+       vuint32_t               out[2];
+       vuint32_t               in[2];
+};
+
+struct lpc_usb_endpoint {
+       vuint32_t               ep0_out;
+       vuint32_t               setup;
+       vuint32_t               ep0_in;
+       vuint32_t               reserved_0c;
+       struct lpc_usb_epn      epn[4];
+};
+
+/* Assigned in registers.ld to point at the base
+ * of USB ram
+ */
+
+extern uint8_t lpc_usb_sram[];
+
+#define LPC_USB_EP_ACTIVE              31
+#define LPC_USB_EP_DISABLED            30
+#define LPC_USB_EP_STALL               29
+#define LPC_USB_EP_TOGGLE_RESET                28
+#define LPC_USB_EP_RATE_FEEDBACK       27
+#define LPC_USB_EP_ENDPOINT_ISO                26
+#define LPC_USB_EP_NBYTES              16
+#define  LPC_USB_EP_NBYTES_MASK                        0x3ff
+#define LPC_USB_EP_OFFSET              0
+
+#define LPC_ISR_PIN_INT0_POS   0
+#define LPC_ISR_PIN_INT1_POS   1
+#define LPC_ISR_PIN_INT2_POS   2
+#define LPC_ISR_PIN_INT3_POS   3
+#define LPC_ISR_PIN_INT4_POS   4
+#define LPC_ISR_PIN_INT5_POS   5
+#define LPC_ISR_PIN_INT6_POS   6
+#define LPC_ISR_PIN_INT7_POS   7
+#define LPC_ISR_GINT0_POS      8
+#define LPC_ISR_GINT1_POS      9
+#define LPC_ISR_SSP1_POS       14
+#define LPC_ISR_I2C_POS                15
+#define LPC_ISR_CT16B0_POS     16
+#define LPC_ISR_CT16B1_POS     17
+#define LPC_ISR_CT32B0_POS     18
+#define LPC_ISR_CT32B1_POS     19
+#define LPC_ISR_SSP0_POS       20
+#define LPC_ISR_USART_POS      21
+#define LPC_ISR_USB_IRQ_POS    22
+#define LPC_ISR_USB_FIQ_POS    23
+#define LPC_ISR_ADC_POS                24
+#define LPC_ISR_WWDT_POS       25
+#define LPC_ISR_BOD_POS                26
+#define LPC_ISR_FLASH_POS      27
+#define LPC_ISR_USB_WAKEUP_POS 30
+
+struct lpc_nvic {
+       vuint32_t       iser;           /* 0x000 0xe000e100 Set Enable Register */
+
+       uint8_t         _unused020[0x080 - 0x004];
+
+       vuint32_t       icer;           /* 0x080 0xe000e180 Clear Enable Register */
+
+       uint8_t         _unused0a0[0x100 - 0x084];
+
+       vuint32_t       ispr;           /* 0x100 0xe000e200 Set Pending Register */
+
+       uint8_t         _unused120[0x180 - 0x104];
+
+       vuint32_t       icpr;           /* 0x180 0xe000e280 Clear Pending Register */
+
+       uint8_t         _unused1a0[0x300 - 0x184];
+
+       vuint32_t       ipr[8];         /* 0x300 0xe000e400 Priority Register */
+};
+
+extern struct lpc_nvic lpc_nvic;
+
+static inline void
+lpc_nvic_set_enable(int irq) {
+       lpc_nvic.iser |= (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_enable(int irq) {
+       lpc_nvic.icer |= (1 << irq);
+}
+
+static inline int
+lpc_nvic_enabled(int irq) {
+       return (lpc_nvic.iser >> irq) & 1;
+}
+
+       
+static inline void
+lpc_nvic_set_pending(int irq) {
+       lpc_nvic.ispr = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_pending(int irq) {
+       lpc_nvic.icpr = (1 << irq);
+}
+
+static inline int
+lpc_nvic_pending(int irq) {
+       return (lpc_nvic.ispr >> irq) & 1;
+}
+
+#define IRQ_PRIO_REG(irq)      ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq)      (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq)     (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+lpc_nvic_set_priority(int irq, uint8_t prio) {
+       int             n = IRQ_PRIO_REG(irq);
+       uint32_t        v;
+
+       v = lpc_nvic.ipr[n];
+       v &= ~IRQ_PRIO_MASK(irq);
+       v |= (prio) << IRQ_PRIO_BIT(irq);
+       lpc_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+lpc_nvic_get_priority(int irq) {
+       return (lpc_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+struct arm_scb {
+       vuint32_t       cpuid;
+       vuint32_t       icsr;
+       uint32_t        reserved08;
+       vuint32_t       aircr;
+
+       vuint32_t       scr;
+       vuint32_t       ccr;
+       uint32_t        reserved18;
+       vuint32_t       shpr2;
+
+       vuint32_t       shpr3;
+};
+
+extern struct arm_scb arm_scb;
+
+struct lpc_ssp {
+       vuint32_t       cr0;    /* 0x00 */
+       vuint32_t       cr1;
+       vuint32_t       dr;
+       vuint32_t       sr;
+
+       vuint32_t       cpsr;   /* 0x10 */
+       vuint32_t       imsc;
+       vuint32_t       ris;
+       vuint32_t       mis;
+
+       vuint32_t       icr;    /* 0x20 */
+};
+
+extern struct lpc_ssp lpc_ssp0, lpc_ssp1;
+
+#define LPC_NUM_SPI            2
+
+#define LPC_SSP_FIFOSIZE       8
+
+#define LPC_SSP_CR0_DSS                0
+#define  LPC_SSP_CR0_DSS_4             0x3
+#define  LPC_SSP_CR0_DSS_5             0x4
+#define  LPC_SSP_CR0_DSS_6             0x5
+#define  LPC_SSP_CR0_DSS_7             0x6
+#define  LPC_SSP_CR0_DSS_8             0x7
+#define  LPC_SSP_CR0_DSS_9             0x8
+#define  LPC_SSP_CR0_DSS_10            0x9
+#define  LPC_SSP_CR0_DSS_11            0xa
+#define  LPC_SSP_CR0_DSS_12            0xb
+#define  LPC_SSP_CR0_DSS_13            0xc
+#define  LPC_SSP_CR0_DSS_14            0xd
+#define  LPC_SSP_CR0_DSS_15            0xe
+#define  LPC_SSP_CR0_DSS_16            0xf
+#define LPC_SSP_CR0_FRF                4
+#define  LPC_SSP_CR0_FRF_SPI           0
+#define  LPC_SSP_CR0_FRF_TI            1
+#define  LPC_SSP_CR0_FRF_MICROWIRE     2
+#define LPC_SSP_CR0_CPOL       6
+#define  LPC_SSP_CR0_CPOL_LOW          0
+#define  LPC_SSP_CR0_CPOL_HIGH         1
+#define LPC_SSP_CR0_CPHA       7
+#define  LPC_SSP_CR0_CPHA_FIRST                0
+#define  LPC_SSP_CR0_CPHA_SECOND       1
+#define LPC_SSP_CR0_SCR                8
+
+#define LPC_SSP_CR1_LBM                0
+#define LPC_SSP_CR1_SSE                1
+#define LPC_SSP_CR1_MS         2
+#define  LPC_SSP_CR1_MS_MASTER         0
+#define  LPC_SSP_CR1_MS_SLAVE          1
+#define LPC_SSP_CR1_SOD                3
+
+#define LPC_SSP_SR_TFE         0
+#define LPC_SSP_SR_TNF         1
+#define LPC_SSP_SR_RNE         2
+#define LPC_SSP_SR_RFF         3
+#define LPC_SSP_SR_BSY         4
+
+#define LPC_SSP_IMSC_RORIM     0
+#define LPC_SSP_IMSC_RTIM      1
+#define LPC_SSP_IMSC_RXIM      2
+#define LPC_SSP_IMSC_TXIM      3
+
+#define LPC_SSP_RIS_RORRIS     0
+#define LPC_SSP_RIS_RTRIS      1
+#define LPC_SSP_RIS_RXRIS      2
+#define LPC_SSP_RIS_TXRIS      3
+
+#define LPC_SSP_MIS_RORMIS     0
+#define LPC_SSP_MIS_RTMIS      1
+#define LPC_SSP_MIS_RXMIS      2
+#define LPC_SSP_MIS_TXMIS      3
+
+#define LPC_SSP_ICR_RORIC      0
+#define LPC_SSP_ICR_RTIC       1
+
+struct lpc_adc {
+       vuint32_t       cr;     /* 0x00 */
+       vuint32_t       gdr;
+       uint32_t        r08;
+       vuint32_t       inten;
+
+       vuint32_t       dr[8];  /* 0x10 */
+
+       vuint32_t       stat;   /* 0x30 */
+};
+
+extern struct lpc_adc lpc_adc;
+
+#define LPC_ADC_CR_SEL         0
+#define LPC_ADC_CR_CLKDIV      8
+#define LPC_ADC_CR_BURST       16
+#define LPC_ADC_CR_CLKS                17
+#define  LPC_ADC_CR_CLKS_11            0
+#define  LPC_ADC_CR_CLKS_10            1
+#define  LPC_ADC_CR_CLKS_9             2
+#define  LPC_ADC_CR_CLKS_8             3
+#define  LPC_ADC_CR_CLKS_7             4
+#define  LPC_ADC_CR_CLKS_6             5
+#define  LPC_ADC_CR_CLKS_5             6
+#define  LPC_ADC_CR_CLKS_4             7
+
+#define LPC_ADC_INTEN_ADINTEN  0
+#define LPC_ADC_INTEN_ADGINTEN 8
+
+#define LPC_ADC_STAT_DONE      0
+#define LPC_ADC_STAT_OVERRUN   8
+#define LPC_ADC_STAT_ADINT     16
+
+struct lpc_ct32b {
+       vuint32_t       ir;     /* 0x00 */
+       vuint32_t       tcr;
+       vuint32_t       tc;
+       vuint32_t       pr;
+       
+       vuint32_t       pc;     /* 0x10 */
+       vuint32_t       mcr;
+       vuint32_t       mr[4];  /* 0x18 */
+       vuint32_t       ccr;    /* 0x28 */
+       vuint32_t       cr0;
+       
+       vuint32_t       cr1_0;  /* 0x30 (only for ct32b0 */
+       vuint32_t       cr1_1;  /* 0x34 (only for ct32b1 */
+       uint32_t        r38;
+       vuint32_t       emr;
+
+       uint32_t        r40[12];
+
+       vuint32_t       ctcr;   /* 0x70 */
+       vuint32_t       pwmc;
+};
+
+extern struct lpc_ct32b lpc_ct32b0, lpc_ct32b1;
+
+#define LPC_CT32B_TCR_CEN      0
+#define LPC_CT32B_TCR_CRST     1
+
+#define LPC_CT32B_MCR_MR0R     1
+
+#define LPC_CT32B_PWMC_PWMEN0  0
+#define LPC_CT32B_PWMC_PWMEN1  1
+#define LPC_CT32B_PWMC_PWMEN2  2
+#define LPC_CT32B_PWMC_PWMEN3  3
+
+#define LPC_CT32B_EMR_EMC0     4
+#define LPC_CT32B_EMR_EMC1     6
+#define LPC_CT32B_EMR_EMC2     8
+#define LPC_CT32B_EMR_EMC3     10
+
+#define LPC_CT32B_EMR_EMC_NOTHING      0
+#define LPC_CT32B_EMR_EMC_CLEAR                1
+#define LPC_CT32B_EMR_EMC_SET          2
+#define LPC_CT32B_EMR_EMC_TOGGLE       3
+
+#endif /* _LPC_H_ */
diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld
new file mode 100644 (file)
index 0000000..a523c39
--- /dev/null
@@ -0,0 +1,19 @@
+lpc_usb_sram   = 0x20004000;
+lpc_usb_endpoint = 0x20004700;
+lpc_usart      = 0x40008000;
+lpc_ct32b0     = 0x40014000;
+lpc_ct32b1     = 0x40018000;
+lpc_adc                = 0x4001c000;
+lpc_flash      = 0x4003c000;
+lpc_ssp0       = 0x40040000;
+lpc_ioconf     = 0x40044000;
+lpc_scb                = 0x40048000;
+lpc_gpio_pin   = 0x4004c000;
+lpc_ssp1       = 0x40058000;
+lpc_gpio_group0 = 0x4005c000;
+lpc_gpio_group1 = 0x40060000;
+lpc_usb                = 0x40080000;
+lpc_gpio       = 0x50000000;
+lpc_systick    = 0xe000e000;
+lpc_nvic       = 0xe000e100;
+arm_scb                = 0xe000ed00;
diff --git a/src/lpcxpresso/Makefile b/src/lpcxpresso/Makefile
new file mode 100644 (file)
index 0000000..3745f28
--- /dev/null
@@ -0,0 +1,66 @@
+#
+# AltOS build
+#
+#
+
+include ../lpc/Makefile.defs
+
+INC = \
+       ao.h \
+       ao_arch.h \
+       ao_arch_funcs.h \
+       ao_pins.h \
+       ao_product.h \
+       lpc.h
+
+#
+# Common AltOS sources
+#
+ALTOS_SRC = \
+       ao_interrupt.c \
+       ao_romconfig.c \
+       ao_product.c \
+       ao_panic.c \
+       ao_led_lpc.c \
+       ao_task.c \
+       ao_cmd.c \
+       ao_timer_lpc.c \
+       ao_serial_lpc.c \
+       ao_usb_lpc.c \
+       ao_stdio.c
+
+PRODUCT=LpcDemo-v0.0
+PRODUCT_DEF=-DLPC_DEMO
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -g -Os
+
+PROG=lpc-demo.elf
+
+SRC=$(ALTOS_SRC) ao_demo.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG)
+
+LDFLAGS=-L../lpc -Wl,-Taltos.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)
+
+load: $(PROG)
+       lpc-load $(PROG)
+
+distclean:     clean
+
+clean:
+       rm -f *.o $(PROG)
+       rm -f ao_product.h
+
+install:
+
+uninstall:
diff --git a/src/lpcxpresso/ao_demo.c b/src/lpcxpresso/ao_demo.c
new file mode 100644 (file)
index 0000000..0c93161
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2011 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_usb.h>
+
+int
+main(void)
+{
+       int     i;
+       ao_led_init(LEDS_AVAILABLE);
+       ao_led_on(AO_LED_RED);
+       ao_clock_init();
+       ao_timer_init();
+       
+       ao_serial_init();
+       ao_usb_init();
+       ao_cmd_init();
+       ao_task_init();
+
+       ao_start_scheduler();
+
+       for (;;) {
+               ao_led_off(AO_LED_RED);
+               for (;;)
+                       if (ao_tick_count & 1)
+                               break;
+               ao_led_on(AO_LED_RED);
+               for (;;)
+                       if (!(ao_tick_count & 1))
+                               break;
+       }
+}
diff --git a/src/lpcxpresso/ao_pins.h b/src/lpcxpresso/ao_pins.h
new file mode 100644 (file)
index 0000000..c0074ce
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#define HAS_BEEP       0
+#define        HAS_LED         1
+
+/* Crystal on the board */
+#define AO_LPC_CLKIN   12000000
+
+/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */
+#define AO_LPC_CLKOUT  48000000
+
+/* System clock frequency */
+#define AO_LPC_SYSCLK  24000000
+
+#define LED_PORT       0
+#define LED_PIN_RED    7
+
+#define AO_LED_RED     (1 << LED_PIN_RED)
+
+#define LEDS_AVAILABLE AO_LED_RED
+
+#define HAS_USB                1
+
+#define HAS_USB_CONNECT        1
+#define HAS_USB_VBUS   1
+
+#define PACKET_HAS_SLAVE       0
+
+/* USART */
+
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     1
+#define SERIAL_0_18_19         1
+#define SERIAL_0_14_15         0
+#define SERIAL_0_17_18         0
+#define SERIAL_0_26_27         0
diff --git a/src/stm/ao_data.c b/src/stm/ao_data.c
deleted file mode 100644 (file)
index 38d2f7f..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * 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.
- */
-
-#include <ao.h>
-#include <ao_data.h>
-
-volatile __xdata struct ao_data        ao_data_ring[AO_DATA_RING];
-volatile __data uint8_t                ao_data_head;
-volatile __data uint8_t                ao_data_present;
-
-void
-ao_data_get(__xdata struct ao_data *packet)
-{
-#if HAS_FLIGHT
-       uint8_t i = ao_data_ring_prev(ao_sample_data);
-#else
-       uint8_t i = ao_data_ring_prev(ao_data_head);
-#endif
-       memcpy(packet, (void *) &ao_data_ring[i], sizeof (struct ao_data));
-}
index 35b56b571582fd392201bf0172767ff9f53119ad..ebea224d03d48934507e3673d5d049ba9bc2324e 100644 (file)
@@ -25,6 +25,7 @@
 #define AO_EXTI_PRIORITY_LOW   16
 #define AO_EXTI_PRIORITY_MED   0
 #define AO_EXTI_PRIORITY_HIGH  32
+#define AO_EXTI_PIN_NOCONFIGURE        64
 
 void
 ao_exti_setup(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)());
index 1361d0d4a8cb6caf0a41b3522c9ae49c53c71cf5..c1dcdf85303a84f0a7541023f7bca684fdaba037 100644 (file)
@@ -70,21 +70,23 @@ ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback
        /* configure gpio to interrupt routing */
        stm_exticr_set(gpio, pin);
 
-       /* configure pin as input, setting selected pull-up/down mode */
-       stm_moder_set(gpio, pin, STM_MODER_INPUT);
-       switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
-       case 0:
-       default:
-               pupdr  = STM_PUPDR_NONE;
-               break;
-       case AO_EXTI_MODE_PULL_UP:
-               pupdr = STM_PUPDR_PULL_UP;
-               break;
-       case AO_EXTI_MODE_PULL_DOWN:
-               pupdr = STM_PUPDR_PULL_DOWN;
-               break;
+       if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+               /* configure pin as input, setting selected pull-up/down mode */
+               stm_moder_set(gpio, pin, STM_MODER_INPUT);
+               switch (mode & (AO_EXTI_MODE_PULL_UP|AO_EXTI_MODE_PULL_DOWN)) {
+               case 0:
+               default:
+                       pupdr  = STM_PUPDR_NONE;
+                       break;
+               case AO_EXTI_MODE_PULL_UP:
+                       pupdr = STM_PUPDR_PULL_UP;
+                       break;
+               case AO_EXTI_MODE_PULL_DOWN:
+                       pupdr = STM_PUPDR_PULL_DOWN;
+                       break;
+               }
+               stm_pupdr_set(gpio, pin, pupdr);
        }
-       stm_pupdr_set(gpio, pin, pupdr);
 
        /* Set interrupt mask and rising/falling mode */
        stm_exti.imr &= ~mask;