reset();
link.printf("c s\nf\nv\n");
read_link(link, "software-version");
+ System.out.printf("Log format %d\n", log_format);
switch (log_format) {
- case AltosLib.AO_LOG_FORMAT_TELEMETRY:
- case AltosLib.AO_LOG_FORMAT_TELESCIENCE:
- break;
- default:
+ case AltosLib.AO_LOG_FORMAT_FULL:
+ case AltosLib.AO_LOG_FORMAT_TINY:
+ case AltosLib.AO_LOG_FORMAT_MEGAMETRUM:
link.printf("l\n");
read_link(link, "done");
+ default:
+ break;
}
}
frequency = in_frequency;
config_data();
set_radio_frequency(frequency,
- config_data.radio_frequency != 0,
- config_data.radio_setting != 0,
+ config_data.radio_frequency > 0,
+ config_data.radio_setting > 0,
config_data.radio_calibration);
}
public String name;
public void start_remote() throws TimeoutException, InterruptedException {
- if (debug)
- System.out.printf("start remote %7.3f\n", frequency);
if (frequency == 0.0)
frequency = AltosPreferences.frequency(serial);
+ if (debug)
+ System.out.printf("start remote %7.3f\n", frequency);
set_radio_frequency(frequency);
set_callsign(AltosPreferences.callsign());
printf("p\nE 0\n");
public void init (AltosRecord cur, AltosState prev_state) {
data = cur;
+ /* Discard previous state if it was for a different board */
+ if (prev_state != null && prev_state.data.serial != data.serial)
+ prev_state = null;
ground_altitude = data.ground_altitude();
altitude = data.altitude();
apogee and main ejection charges. All Altus Metrum products are
designed for use with single-cell batteries with 3.7 volts nominal.
</para>
+ <para>
+ The battery connectors are a standard 2-pin JST connector and
+ match batteries sold by Spark Fun. These batteries are
+ single-cell Lithium Polymer batteries that nominally provide 3.7
+ volts. Other vendors sell similar batteries for RC aircraft
+ using mating connectors, however the polarity for those is
+ generally reversed from the batteries used by Altus Metrum
+ products. In particular, the Tenergy batteries supplied for use
+ in Featherweight flight computers are not compatible with Altus
+ Metrum flight computers or battery chargers. <emphasis>Check
+ polarity and voltage before connecting any battery not purchased
+ from Altus Metrum or Spark Fun.</emphasis>
+ </para>
<para>
By default, we use the unregulated output of the Li-Po battery directly
to fire ejection charges. This works marvelously with standard
<para>
You can monitor the operation of the radio link by watching the
lights on the devices. The red LED will flash each time a packet
- is tramsitted, while the green LED will light up on TeleDongle when
+ is transmitted, while the green LED will light up on TeleDongle when
it is waiting to receive a packet from the altimeter.
</para>
</section>
</listitem>
<listitem>
<para>
- RF interface for battery charging, configuration, and data recovery.
+ RF interface for configuration, and data recovery.
</para>
</listitem>
<listitem>
Updates for version 1.0 release.
</revremark>
</revision>
+ <revision>
+ <revnumber>1.1</revnumber>
+ <date>12 December 2012</date>
+ <revremark>
+ Add comments about EEPROM storage format and programming jig.
+ </revremark>
+ </revision>
</revhistory>
</bookinfo>
<acknowledgements>
with the negative battery terminal.
</para>
<para>
- Shipping restrictions prevent us from including a CR1025
- battery with MicroPeak. Many stores carry CR1025 batteries as
- they are commonly used in small electronic devices such as
- flash lights.
+ Shipping restrictions may prevent us from including a CR1025
+ battery with MicroPeak. If so, many stores carry CR1025
+ batteries as they are commonly used in small electronic
+ devices such as flash lights.
</para>
</section>
<section>
serve to further protect the switch from launch forces.
</para>
</section>
+ <section>
+ <title>On-board data storage</title>
+ <para>
+ The ATtiny85 has 512 bytes of non-volatile storage, separate
+ from the code storage memory. The MicroPeak firmware uses this
+ to store information about the last completed
+ flight. Barometric measurements from the ground before launch
+ and at apogee are stored, and used at power-on to compute the
+ height of the last flight.
+ </para>
+ <para>
+ In addition to the data used to present the height of the last
+ flight, MicroPeak also stores barometric information sampled
+ at regular intervals during the flight. This information can
+ be extracted from MicroPeak through any AVR programming
+ tool.
+ </para>
+ <table frame='all'>
+ <title>MicroPeak EEPROM Data Storage</title>
+ <tgroup cols='3' align='center' colsep='1' rowsep='1'>
+ <colspec align='center' colwidth='2*' colname='Address'/>
+ <colspec align='center' colwidth='*' colname='Size (bytes)'/>
+ <colspec align='left' colwidth='7*' colname='Description'/>
+ <thead>
+ <row>
+ <entry align='center'>Address</entry>
+ <entry align='center'>Size (bytes)</entry>
+ <entry align='center'>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>0x000</entry>
+ <entry>4</entry>
+ <entry>Average ground pressure (Pa)</entry>
+ </row>
+ <row>
+ <entry>0x004</entry>
+ <entry>4</entry>
+ <entry>Minimum flight pressure (Pa)</entry>
+ </row>
+ <row>
+ <entry>0x008</entry>
+ <entry>2</entry>
+ <entry>Number of in-flight samples</entry>
+ </row>
+ <row>
+ <entry>0x00a … 0x1fe</entry>
+ <entry>2</entry>
+ <entry>Instantaneous flight pressure (Pa) low 16 bits</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>
+ All EEPROM data are stored least-significant byte first. The
+ instantaneous flight pressure data are stored without the
+ upper 16 bits of data. The upper bits can be reconstructed
+ from the previous sample, assuming that pressure doesn't
+ change by more more than 32kPa in a single sample
+ interval. Note that this pressure data is <emphasis>not</emphasis>
+ filtered in any way, while both the recorded ground and apogee
+ pressure values are, so you shouldn't expect the minimum
+ instantaneous pressure value to match the recorded minimum
+ pressure value exactly.
+ </para>
+ <para>
+ MicroPeak samples pressure every 96ms, but stores only every
+ other sample in the EEPROM. This provides for 251 pressure
+ samples at 192ms intervals, or 48.192s of storage. The clock
+ used for these samples is a factory calibrated RC circuit
+ built into the ATtiny85 and is accurate only to within ±10% at
+ 25°C. So, you can count on the pressure data being accurate,
+ but speed or acceleration data computed from this will be
+ limited by the accuracy of this clock.
+ </para>
+ </section>
+ <section>
+ <title>MicroPeak Programming Interface</title>
+ <para>
+ MicroPeak exposes a standard 6-pin AVR programming interface,
+ but not using the usual 2x3 array of pins on 0.1"
+ centers. Instead, there is a single row of tiny 0.60mm ×
+ 0.85mm pads on 1.20mm centers exposed near the edge of the
+ circuit board. We couldn't find any connector that was
+ small enough to include on the circuit board.
+ </para>
+ <para>
+ In lieu of an actual connector, the easiest way to connect to
+ the bare pads is through a set of Pogo pins. These
+ spring-loaded contacts are designed to connect in precisely
+ this way. We've designed a programming jig, the MicroPeak
+ Pogo Pin board which provides a standard AVR interface on one
+ end and a recessed slot for MicroPeak to align the board with
+ the Pogo Pins.
+ </para>
+ <para>
+ The MicroPeak Pogo Pin board is not a complete AVR programmer,
+ it is an interface board that provides a 3.3V regulated power
+ supply to run the MicroPeak via USB and a standard 6-pin AVR
+ programming interface with the usual 2x3 grid of pins on 0.1"
+ centers. This can be connected to any AVR programming
+ dongle.
+ </para>
+ <para>
+ The AVR programming interface cannot run faster than ¼ of the
+ AVR CPU clock frequency. Because MicroPeak runs at 250kHz to
+ save power, you must configure your AVR programming system to
+ clock the AVR programming interface at no faster than
+ 62.5kHz, or a clock period of 32µS.
+ </para>
+ </section>
</chapter>
</book>
<!-- LocalWords: Altusmetrum MicroPeak
if (pa < 0)
pa = 0;
- if (pa > 120000)
- pa = 120000;
+ if (pa > 120000L)
+ pa = 120000L;
o = pa >> ALT_SHIFT;
part = pa & ALT_MASK;
- low = (alt_t) FETCH_ALT(o) * (ALT_SCALE - part);
- high = (alt_t) FETCH_ALT(o+1) * part + (ALT_SCALE >> 1);
+ low = (int32_t) FETCH_ALT(o) * (ALT_SCALE - part);
+ high = (int32_t) FETCH_ALT(o+1) * part + (ALT_SCALE >> 1);
return (low + high) >> ALT_SHIFT;
}
#PROGRAMMER=stk500v2 -P usb
PROGRAMMER=usbtiny
LOADCMD=avrdude
+LOADSLOW=-i 32 -B 32
LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w:
CC=avr-gcc
OBJCOPY=avr-objcopy
load: $(PROG).hex
$(LOADCMD) $(LOADARG)$(PROG).hex
+load-slow: $(PROG).hex
+ $(LOADCMD) $(LOADSLOW) $(LOADARG)$(PROG).hex
+
ao_product.h: ao-make-product.5c ../Version
$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
}
#if !HAS_EEPROM
+
+#define PA_GROUND_OFFSET 0
+#define PA_MIN_OFFSET 4
+#define N_SAMPLES_OFFSET 8
+#define STARTING_LOG_OFFSET 10
+#define MAX_LOG_OFFSET 512
+
+static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
+
void
ao_save_flight(void)
{
- ao_eeprom_write(0, &pa_ground, sizeof (pa_ground));
- ao_eeprom_write(sizeof (pa_ground), &pa_min, sizeof (pa_min));
+ uint16_t n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
+ ao_eeprom_write(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_write(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+ ao_eeprom_write(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
}
void
ao_restore_flight(void)
{
- ao_eeprom_read(0, &pa_ground, sizeof (pa_ground));
- ao_eeprom_read(sizeof (pa_ground), &pa_min, sizeof (pa_min));
+ ao_eeprom_read(PA_GROUND_OFFSET, &pa_ground, sizeof (pa_ground));
+ ao_eeprom_read(PA_MIN_OFFSET, &pa_min, sizeof (pa_min));
+}
+
+void
+ao_log_micro(void)
+{
+ uint16_t low_bits = pa;
+
+ if (ao_log_offset < MAX_LOG_OFFSET) {
+ ao_eeprom_write(ao_log_offset, &low_bits, sizeof (low_bits));
+ ao_log_offset += sizeof (low_bits);
+ }
}
#endif
#endif
ao_restore_flight();
ao_compute_height();
+ /* Give the person a second to get their finger out of the way */
+ ao_delay(AO_MS_TO_TICKS(1000));
ao_report_altitude();
ao_spi_init();
ao_led_off(AO_LED_REPORT);
#if HAS_EEPROM
ao_log_micro_data(AO_LOG_MICRO_DATA | pa);
+#else
+ if (sample_count & 1)
+ ao_log_micro();
#endif
pa_avg = pa_avg - (pa_avg >> FILTER_SHIFT) + pa;
if (pa_avg < pa_min)
#define I2C_PIN_SDA PINB0
#define AO_CONST_ATTRIB PROGMEM
+typedef int32_t alt_t;
#define FETCH_ALT(o) ((alt_t) pgm_read_dword(&altitude_table[o]))
-#define AO_ALT_VALUE(x) ((x) * 10)
+#define AO_ALT_VALUE(x) ((x) * (alt_t) 10)
#endif /* _AO_PINS_H_ */
ao_report_digit(uint8_t digit) __reentrant
{
if (!digit) {
- mid(AO_MS_TO_TICKS(600));
+ mid(AO_MS_TO_TICKS(1000));
pause(AO_MS_TO_TICKS(300));
} else {
while (digit--) {
pause(AO_MS_TO_TICKS(300));
}
}
- pause(AO_MS_TO_TICKS(600));
+ pause(AO_MS_TO_TICKS(1000));
}
void
ao_report_altitude(void)
{
- __pdata int16_t agl = ao_max_height;
- __xdata uint8_t digits[10];
+ __pdata alt_t agl = ao_max_height;
+ static __xdata uint8_t digits[11];
__pdata uint8_t ndigits, i;
if (agl < 0)