src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx \
src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx \
src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx \
+ src/easymini-v2.0/easymini-v2.0-$(VERSION).ihx \
+ src/easymini-v3.0/easymini-v3.0-$(VERSION).ihx \
src/easymotor-v2/easymotor-v2-$(VERSION).ihx \
src/easytimer-v1/easytimer-v1-$(VERSION).ihx \
src/telebt-v3.0/telebt-v3.0-$(VERSION).ihx \
cp src/chaoskey-v1.0/{*.elf,*.ihx,*.bin,*.map} \
src/easymega-v[1-2].0/{*.elf,*.ihx,*.map} \
- src/easymini-v[1-2].0/{*.elf,*.ihx,*.map} \
+ src/easymini-v[1-3].0/{*.elf,*.ihx,*.map} \
src/easymotor-v2/{*.elf,*.ihx,*.map} \
src/easytimer-v1/{*.elf,*.ihx,*.map} \
src/telebt-v[3-4].0/{*.elf,*.ihx,*.map} \
return (voltage - base) / (max - base) * full_scale_pressure;
}
+ static double easy_motor_3_adc(double raw) {
+ return raw / 32767.0;
+ }
+
+ static double easy_motor_3_voltage(int sensor) {
+ double supply = 3.3;
+
+ return easy_motor_3_adc(sensor) * supply * 15.6 / 10.0;
+ }
+
static double easy_motor_2_motor_pressure(int sensor, double ground_sensor) {
double supply = 3.3;
double ground_voltage = easy_mini_2_adc(ground_sensor) * supply * 15.6 / 10.0;
return motor_pressure(voltage) - motor_pressure(ground_voltage);
}
+ static double easy_motor_3_motor_pressure(int sensor, double ground_sensor) {
+ double supply = 3.3;
+ double ground_voltage = easy_motor_3_adc(ground_sensor) * supply * 15.6 / 10.0;
+ double voltage = easy_motor_3_adc(sensor) * supply * 15.6 / 10.0;
+
+ return motor_pressure(voltage) - motor_pressure(ground_voltage);
+ }
+
public static double radio_to_frequency(int freq, int setting, int cal, int channel) {
double f;
case AltosLib.AO_LOG_SENSOR:
AltosConfigData config_data = eeprom.config_data();
- listener.set_battery_voltage(AltosConvert.easy_mini_2_voltage(v_batt()));
- double pa = AltosConvert.easy_motor_2_motor_pressure(motor_pres(), cal_data.ground_motor_pressure);
+ listener.set_battery_voltage(AltosConvert.easy_motor_3_voltage(v_batt()));
+ double pa = AltosConvert.easy_motor_3_motor_pressure(motor_pres(), cal_data.ground_motor_pressure);
listener.set_motor_pressure(pa);
int accel_along = accel_along();
FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
FIRMWARE_EMINI_2_0=$(top_srcdir)/src/easymini-v2.0/easymini-v2.0-$(VERSION).ihx
-FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0) $(FIRMWARE_EMINI_2_0)
+FIRMWARE_EMINI_3_0=$(top_srcdir)/src/easymini-v3.0/easymini-v3.0-$(VERSION).ihx
+FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0) $(FIRMWARE_EMINI_2_0) $(FIRMWARE_EMINI_3_0)
FIRMWARE_EMEGA_1_0=$(top_srcdir)/src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx
FIRMWARE_EMEGA_2_0=$(top_srcdir)/src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx
File "../src/telemega-v5.0/telemega-v5.0-${VERSION}.ihx"
File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
File "../src/easymini-v2.0/easymini-v2.0-${VERSION}.ihx"
+ File "../src/easymini-v3.0/easymini-v3.0-${VERSION}.ihx"
File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx"
File "../src/easymega-v2.0/easymega-v2.0-${VERSION}.ihx"
File "../src/easymotor-v2/easymotor-v2-${VERSION}.ihx"
echo 'E 1' > $dev
-./test-easymega
+./test-easymega-v1.0
exit $?
}
static void
-ao_pressure(int16_t value, int16_t max_adc, double ref, double r1, double r2)
+ao_pressure(int16_t value, int16_t max_adc, double ref, double r1, double r2, double sensor_range)
{
printf(" pressure %5d", value);
if (r1 && r2 && ref) {
if (volts < 0.5) volts = 0.5;
if (volts > 4.5) volts = 4.5;
- double psi = (volts - 0.5) / 4.0 * 2500.0;
+ double psi = (volts - 0.5) / 4.0 * sensor_range;
double pa = psi_to_pa(psi);
printf(" %9.3f kPa", pa / 1000.0);
}
double sense_r1 = 0.0, sense_r2 = 0.0;
double batt_r1 = 0.0, batt_r2 = 0.0;
double adc_ref = 0.0;
+ double pressure_sensor = 0.0;
int16_t max_adc = 0;
switch (eeprom->log_format) {
break;
case AO_LOG_FORMAT_TELEFIRETWO:
len = 32;
+ pressure_sensor = 2500.0;
max_adc = 4095;
adc_ref = 3.3;
sense_r1 = batt_r1 = 5600;
len = 16;
max_adc = 32767;
adc_ref = 3.3;
+ pressure_sensor = 1600.0;
batt_r1 = 5600;
batt_r2 = 10000;
sense_r1 = 5600;
log_mega = (struct ao_log_mega *) &eeprom->data[pos];
switch (log_mega->type) {
case AO_LOG_FLIGHT:
- printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u",
+ printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m",
eeprom->serial_number,
log_mega->u.flight.flight,
log_mega->u.flight.ground_accel,
- log_mega->u.flight.ground_pres);
+ log_mega->u.flight.ground_pres,
+ log_mega->u.flight.ground_pres / 1000.0,
+ ao_pressure_to_altitude(log_mega->u.flight.ground_pres));
+
printf(" along %6d aross %6d through %6d",
log_mega->u.flight.ground_accel_along,
log_mega->u.flight.ground_accel_across,
log_mini = (struct ao_log_mini *) &eeprom->data[pos];
switch (log_mini->type) {
case AO_LOG_FLIGHT:
- printf(" serial %5u flight %5u ground_pres %9u",
+ printf(" serial %5u flight %5u ground_pres %9u kPa %7.1f %7.1f m",
eeprom->serial_number,
log_mini->u.flight.flight,
- log_mini->u.flight.ground_pres);
+ log_mini->u.flight.ground_pres,
+ log_mini->u.flight.ground_pres / 1000.0,
+ ao_pressure_to_altitude(log_mini->u.flight.ground_pres));
break;
case AO_LOG_STATE:
ao_state(log_mini->u.state.state,
log_metrum = (struct ao_log_metrum *) &eeprom->data[pos];
switch (log_metrum->type) {
case AO_LOG_FLIGHT:
- printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u ground_temp %9u",
+ printf(" serial %5u flight %5u ground_accel %6d ground_pres %9u kPa %7.1f %7.1f m ground_temp %9u",
eeprom->serial_number,
log_metrum->u.flight.flight,
log_metrum->u.flight.ground_accel,
log_metrum->u.flight.ground_pres,
+ log_metrum->u.flight.ground_pres / 1000.0,
+ ao_pressure_to_altitude(log_metrum->u.flight.ground_pres),
log_metrum->u.flight.ground_temp);
break;
case AO_LOG_SENSOR:
case AO_LOG_SENSOR:
ao_pressure(log_firetwo->u.sensor.pressure,
max_adc, adc_ref,
- sense_r1, sense_r2);
+ sense_r1, sense_r2,
+ pressure_sensor);
ao_thrust(log_firetwo->u.sensor.thrust,
max_adc, adc_ref,
sense_r1, sense_r2);
break;
case AO_LOG_FORMAT_DETHERM:
break;
+ case AO_LOG_FORMAT_EASYMOTOR:
+ log_motor = (struct ao_log_motor *) &eeprom->data[pos];
+ switch (log_motor->type) {
+ case AO_LOG_FLIGHT:
+ printf(" serial %5u flight %5u",
+ eeprom->serial_number,
+ log_motor->u.flight.flight);
+ break;
+ case AO_LOG_STATE:
+ ao_state(log_motor->u.state.state,
+ log_motor->u.state.reason);
+ break;
+ case AO_LOG_SENSOR:
+ ao_pressure(log_motor->u.sensor.pressure,
+ max_adc, adc_ref,
+ sense_r1, sense_r2,
+ pressure_sensor);
+ ao_volts("v_batt",
+ log_motor->u.sensor.v_batt,
+ max_adc,
+ adc_ref,
+ batt_r1, batt_r2);
+ break;
+ }
+ break;
}
}
printf("\n");
.\"
.TH AO-LOAD 1 "ao-elftohex" ""
.SH NAME
-ao-elftohex \- convert a program to IHX format
+ao-elftohex \- convert programs to IHX format
.SH SYNOPSIS
.B "ao-elftohex"
[\--output-\fIoutput.ihx\fP]
[\--verbose]
-\fIinput.elf\fP
+\fIinput.elf ...\fP
.SH DESCRIPTION
.I ao-elftohex
-reads the specified .elf file and writes out a .ihx version.
+reads the specified .elf files and writes out a .ihx version.
.SH OPTIONS
.TP
\--output=\fIoutput.ihx\fP
.TP
\--verbose
Dumps some debug information.
+.TP
+\--nosym
+Excluded symbol table information from the resulting file. This
+information is a non-standard extension supported by the Altus Metrum
+tools.
.SH AUTHOR
Keith Packard
static const struct option options[] = {
{ .name = "verbose", .has_arg = 1, .val = 'v' },
{ .name = "output", .has_arg = 1, .val = 'o' },
+ { .name = "nosym", .has_arg = 0, .val = 'n' },
{ 0, 0, 0, 0},
};
{
char *input = NULL;
char *output = NULL;
- struct ao_hex_image *image;
- struct ao_sym *file_symbols;
+ struct ao_hex_image *full_image = NULL;
+ struct ao_sym *file_symbols = NULL;
int num_file_symbols;
FILE *file;
int c;
+ int i;
+ int nosym = 0;
- while ((c = getopt_long(argc, argv, "v:o:", options, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "nv:o:", options, NULL)) != -1) {
switch (c) {
case 'o':
output = optarg;
case 'v':
ao_verbose = (int) strtol(optarg, NULL, 0);
break;
+ case 'n':
+ nosym = 1;
+ break;
default:
usage(argv[0]);
break;
}
}
- input = argv[optind];
- if (input == NULL)
+ if (optind >= argc)
usage(argv[0]);
- if (ends_with (input, ".ihx"))
- image = ao_hex_load(input, &file_symbols, &num_file_symbols);
- else
- image = ao_load_elf(input, &file_symbols, &num_file_symbols);
+ for (i = optind; i < argc; i++) {
+ struct ao_hex_image *image;
- if (!image)
- usage(argv[0]);
+ input = argv[i];
+
+ free(file_symbols);
+ num_file_symbols = 0;
+ if (ends_with (input, ".ihx"))
+ image = ao_hex_load(input, &file_symbols, &num_file_symbols);
+ else
+ image = ao_load_elf(input, &file_symbols, &num_file_symbols);
+
+ if (!image) {
+ fprintf(stderr, "Failed to load %s\n", input);
+ usage(argv[0]);
+ }
+
+ if (nosym) {
+ free(file_symbols);
+ file_symbols = NULL;
+ num_file_symbols = 0;
+ }
+
+ if (full_image) {
+ full_image = ao_hex_image_cat(full_image, image);
+ if (!full_image) {
+ fprintf(stderr, "Can't merge image %s\n", input);
+ usage(argv[0]);
+ }
+ } else
+ full_image = image;
+ }
if (!output)
file = stdout;
}
}
- if (!ao_hex_save(file, image, file_symbols, num_file_symbols)) {
+ if (!ao_hex_save(file, full_image, file_symbols, num_file_symbols)) {
fprintf(stderr, "%s: failed to write hex file\n", output ? output : "<stdout>");
if (output)
unlink(output);
#define AO_LOG_FORMAT_TELESTATIC 17 /* 32 byte typed telestatic records */
#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */
#define AO_LOG_FORMAT_TELEMEGA_4 19 /* 32 byte typed telemega records with 32 bit gyro cal and Bmx160 */
-#define AO_LOG_FORMAT_EASYMOTOR 20 /* 16 byte typed easymotor records */
+#define AO_LOG_FORMAT_EASYMOTOR 20 /* 16 byte typed easymotor records with pressure sensor and adxl375 */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
enum ao_pyro_flag {
} u;
};
+struct ao_log_motor {
+ char type; /* 0 */
+ uint8_t csum; /* 1 */
+ uint16_t tick; /* 2 */
+ union { /* 4 */
+ /* AO_LOG_FLIGHT */
+ struct {
+ uint16_t flight; /* 4 */
+ int16_t ground_accel; /* 6 */
+ int16_t ground_accel_along; /* 8 */
+ int16_t ground_accel_across; /* 10 */
+ int16_t ground_accel_through; /* 12 */
+ int16_t ground_motor_pressure; /* 14 */
+ } flight; /* 16 */
+ /* AO_LOG_STATE */
+ struct {
+ uint16_t state; /* 4 */
+ uint16_t reason; /* 6 */
+ } state;
+ /* AO_LOG_SENSOR */
+ struct {
+ uint16_t pressure; /* 4 */
+ uint16_t v_batt; /* 6 */
+ int16_t accel; /* 8 */
+ int16_t accel_across; /* 10 */
+ int16_t accel_along; /* 12 */
+ int16_t accel_through; /* 14 */
+ } sensor; /* 16 */
+ } u;
+};
+
struct ao_eeprom {
struct ao_config config;
struct ao_ms5607_prom ms5607_prom;
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.9.10.4)
-ANDROID_VERSION=34
+AC_INIT([altos], 1.9.11)
+ANDROID_VERSION=35
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2022-02-21
+RELEASE_DATE=2022-05-29
AC_SUBST(RELEASE_DATE)
DOC_DATE=`LC_ALL=C date -d $RELEASE_DATE +'%d %b %Y'`
endif
RELNOTES_INC=\
+ release-notes-1.9.11.inc \
release-notes-1.9.10.inc \
release-notes-1.9.9.inc \
release-notes-1.9.8.inc \
config-ui.inc \
load-maps.inc \
aprs-operation.inc \
+ pyro-examples.inc \
handling.inc \
release-head.inc
* Make sure doc/altusmetrum-theme.yml has the right copyright year
+* Make sure header.inc has the right copyright year
+
* Add references to that as appropriate from each of the documents:
release-notes.inc
left:
content: '{page-number}'
right:
- content: '© 2021 Bdale Garbee and Keith Packard. Creative Commons ShareAlike 3.0 License'
+ content: '© 2022 Bdale Garbee and Keith Packard. Creative Commons ShareAlike 3.0 License'
verso:
left:
content: $footer_recto_right_content
:revdate: 1 Jan 1970
:icons:
:icontype: svg
-:copyright: Bdale Garbee and Keith Packard 2021
+:copyright: Bdale Garbee and Keith Packard 2022
:doctype: book
:numbered:
:stylesheet: am.css
include::system-operation.adoc[]
+ include::pyro-examples.adoc[]
+
include::handling.adoc[]
include::updating-firmware.adoc[]
flight. When disabled, the radio will not
transmit anything during flight at all.
+ ==== Limit transmit to 10mW
+
+ Reduces transmit power to no more than 10mW. This is
+ useful when operating under some UK radio regulations.
+
==== Telemetry baud rate
This sets the modulation bit rate for data
NAR #87103, TRA #12201
[verse]
- Keith Packard, KD7SQG
+ Keith Packard, K7WQ
NAR #88757, TRA #12200
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.11.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.10.adoc[]
:title-logo-image: image:../themes/background.png[]
:revnumber: v{version}
:revdate: 01 Jan 1970
-:copyright: Bdale Garbee and Keith Packard 2021
+:copyright: Bdale Garbee and Keith Packard 2022
:doctype: book
:numbered:
:toc:
[license]
== License
-Copyright © 2021 Bdale Garbee and Keith Packard
+Copyright © 2022 Bdale Garbee and Keith Packard
This document is released under the terms of the link:http://creativecommons.org/licenses/by-sa/3.0/[Creative Commons ShareAlike 3.0 License]
NAR #87103, TRA #12201
[verse]
- Keith Packard, KD7SQG
+ Keith Packard, K7WQ
NAR #88757, TRA #12200
== Using MicroPeak
--- /dev/null
+[appendix]
+== Example Pyro Channel Configurations
+
+ Programming configurable pyro channels on Altus Metrum products that
+ include them isn't difficult, but in an attempt to aid understanding
+ of the configuration interface and help "keep simple things simple",
+ we offer the following examples of the simplest configurations for
+ common situations, along with some hints on avoiding unexpected
+ results.
+
+ The rich set of conditions provided can be used to configure almost
+ any pyro event you can imagine, for a wide variety of objectives.
+ But don't be fooled! Typical events need only one or a few simple
+ conditions to be configured for success. A key thing to remember is
+ that *all* configured conditions must be true to allow a pyro channel
+ to fire. Trying to include too many conditions often results in
+ conflicting rules that never allow a channel to fire. The most
+ important advice we can offer is, therefore, to try and find the
+ simplest set of conditions that will do what you need for a given
+ project.
+
+ === Two-Stage Flights
+
+ Successful completion of a two-stage flight often involves
+ programming of two events. The first is firing a separation
+ charge, the second is igniting the sustainer's (primary)
+ motor.
+
+ Separation charges are best fired as soon as possible after
+ the previous stage has completed providing acceleration, to
+ minimize drag of the sustainer's coast phase before ignition.
+ Recovery, whether the remainder of the flight is nominal or
+ not, usually works best when the states are separated. So,
+ the "best" way to configure a pyro channel for a separation
+ charge is to just set "after motor number". For a 2-stage
+ project, set this to "1". This will cause the pyro channel
+ to fire as soon as the firmware's flight state machine
+ determines the first motor has burned out.
+
+ Safe ignition of a sustainer (primary) motor requires that
+ it happen after the previous stage burns out, while the
+ airframe remains mostly vertical, and typically after the
+ sustainer has coasted away from the booster a bit. A good
+ starting point is thus "after motor number" set the same as
+ the separation charge, which is "1" for a 2-stage rocket.
+ Then "angle from vertical less than" set to some
+ reasonably vertical amount, perhaps 20 degrees. Then "delay
+ after other conditions" set for the desired duration of coast.
+ Use simulations to figure out what a reasonable value here is,
+ but for typical high power rocketry sport flights that aren't
+ trying to set records, something like 2 seconds is usually a
+ good place to start.
+
+ === Triggered Clusters and Air Starts
+
+ When an airframe has a cluster of motors, one of which is
+ "primary" and centered, surrounding by a ring of "secondary"
+ motors, you may want to use the launch control system to fire the primary motor and use onboard electronics to light
+ the rest of the cluster as soon as launch is detected. This
+ is particularly true if the primary motor is significantly
+ different in geometry and may take longer to come up to
+ pressure than the secondary motors. In this case, a simple
+ configuration to light secondary motors is is "time since
+ boost greater than" enabled and set to "0". There's
+ really no point in setting an angle limit since no time has
+ transpired for the airframe to change orientation.
+
+ Air starts can use the same simple configuration, but with
+ the time set to a non-zero value. However, if air starts
+ are going to light after the airframe leaves the launch rail
+ or tower, add an "angle from vertical less than"
+ condition just you would for a 2-stage sustainer to stay safe.
+
+ === Redundant Apogee
+
+ When flying a board like TeleMega or EasyMega, it's easy to
+ configure a programmable channel to fire a redundant apogee
+ charge. This is of course not *fully* redundant, since it's
+ always possible that the board itself or its battery could
+ the the failure source, but far more often, pyro events fail
+ due to broken wires, bad connectors, or bad e-matches... so
+ firing two charges from one board can add useful redundancy.
+
+ The simplest configuration for redundant apogee is "flight
+ state after" set to "drogue", and then "delay after other
+ conditions" set to a second or two.
+
+ === Redundant Main
+
+ Similarly to apogee, configuring a redundant main charge can
+ provide useful redundancy. What we want is to configure an
+ altitude for deployment lower than the primary main deploy
+ altitude, and then ensure we only trigger on that condition
+ while descending.
+
+ The simplest configuration for redundant main is "flight
+ state after" set to "drogue", which will ensure we're in to
+ the descent phase, then "height less than" set to a number
+ lower than you've chosen for the primary main channel
+ deployment height.
+
+ === Apogee Above Baro Sensor Limit
+
+ A question we've seen increasingly often is "How does the
+ Telemega/Easymega detect apogee for flights above 100,000
+ feet?" Flights above that height are a bit outside
+ our original design envelope, but can be made to work...
+ This is *not* a simple flight, and the configuration for it
+ is also not simple, but we think including this information
+ is important for anyone contemplating such a project with our
+ electronics!
+
+ Our flight computers use a Kalman sensor-fusing filter to
+ estimate the flight state, which consists of three values:
+
+ 1. Height above ground
+ 2. Vertical speed
+ 3. Vertical acceleration
+
+ Apogee is assumed to be where vertical speed crosses zero.
+
+ Below 30km altitude (about 100k'), we use both the barometer
+ and the accelerometer to update the flight state, along with
+ a basic Newtonian model of motion. That works well, pegging
+ apogee within a few sensor samples essentially every time.
+
+ Above 30km, the barometric sensor doesn't provide useful data,
+ so we can't use it to update the flight state. Instead, the
+ Kalman filter falls back to a single sensor mode, using only
+ the accelerometer.
+
+ At all altitudes, we de-sense the barometric data when we
+ estimate the speed is near or above mach as the sensor is
+ often subjected to significant transients, which would
+ otherwise push the flight state estimates too fast and could
+ trigger a false apogee event.
+
+ That means the filter is no longer getting the benefit of two
+ sensors, and relies on just the accelerometer. The trouble
+ with accelerometers is they're measuring the derivative of
+ speed, so you have to integrate their values to compute speed.
+ Any offset error in acceleration measurement gets constantly
+ added to that speed.
+
+ In addition, we assume the axial acceleration is actually
+ vertical acceleration; our tilt measurements have enough
+ integration error during coast that we can't usefully use
+ that to get vertical acceleration. Because we don't live in
+ an inertial frame, that means we're mis-computing the total
+ acceleration acting on the airframe as we have to add gravity
+ into the mix, and simply adding that to the axial acceleration
+ value doesn't generate the right value.
+
+ The effect of this is to under-estimate apogee when you base
+ the computation purely on acceleration as the rocket flies a
+ parabolic path.
+
+ For flights *near* 100k', all of this works pretty well -
+ you've got the flight state estimates adjusted using the
+ barometric sensor up to 30km, then you're flying on inertial
+ data to apogee.
+
+ For flights well above 100k', it's not great; you're usually
+ going fast enough through 100k' that the baro sensor is still
+ de-sensed through the end of its useful range, so the flight
+ state estimates are not as close. After that, as you're flying
+ purely on accelerometer data, there's no way to re-correct the
+ state, so the apogee estimates can be off by quite a bit.
+
+ In the worst cases we have seen, the baro sensor data was
+ wildly incorrect above mach due to poor static port design,
+ leaving the state estimate of speed across the 30km boundary
+ way off and causing the apogee detection to happen far from
+ the correct time.
+
+ The good news is that correctly determining apogee is not
+ really all that important at high altitudes; there's so little
+ density that a drogue will have almost no drag anyways. Data
+ from customer flights shows a very parabolic path down to
+ about 50-60k feet, even with a recovery system deployed.
+
+ So, what we recommend is to set up two apogee plans:
+
+ 1. Use the built-in apogee detection, but add a
+ significant delay (as much as 30 seconds). This
+ will probably fire near enough to apogee to not
+ have a significant impact on the maximum height
+ achieved.
+
+ 2. Add a back-up apogee which fires after apogee
+ *when the height is below about 20-25km*. This
+ way, if the flight isn't nominal, and the sustainer
+ ends up reaching apogee in dense air, you aren't
+ hoping the chutes come out before it gets going
+ too fast. And, you get a second pyro channel firing
+ at that altitude even if it reached a higher
+ altitude before.
+
+ You can wire these two pyro channels to the same pyro device;
+ you just need to make sure they're wired + to + and - to -
+ (the manual shows which screw terminals are which).
+
+ The bottom line is that flights to altitudes modestly above
+ the range of the baro sensor with Altus Metrum products can
+ be accomplished safely, but flying "way high" (like 300k')
+ demands a deployment mechanism which doesn't solely rely on
+ altimeters (like ours) which are designed for modest altitude
+ rocketry. Flights to those altitudes also probably need
+ active stabilization to make sure they follow the prescribed
+ trajectory and stay inside their waiver.
--- /dev/null
+= Release Notes for Version 1.9.11
+include::release-head.adoc[]
+:doctype: article
+
+ Version 1.9.11
+
+ == AltOS
+
+ * Make Apogee Delay work again.
+
+ * Allow TX power to be limited to 10mW for compliance with
+ some uses under UK regulations.
+
+ * Fix numerous minor issues with 16- vs 32- bit time values.
+
+ == AltosUI
+
+ * Support M1-based Macs, follow AdoptOpenJDK to Adoptium
+
+ == AltosDroid
+
+ * Handle Bluetooth permissions reliably.
+
+ * Fix some screen rotation bugs.
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.11.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.10.adoc[]
NAR #87103, TRA #12201
[verse]
- Keith Packard, KD7SQG
+ Keith Packard, K7WQ
NAR #88757, TRA #12200
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.11.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.10.adoc[]
:title-logo-image: image:../themes/background.png[]
:revnumber: v{version}
:revdate: 01 Jan 1970
-:copyright: Bdale Garbee and Keith Packard 2021
+:copyright: Bdale Garbee and Keith Packard 2022
:stylesheet: am.css
:linkcss:
:toc:
NAR #87103, TRA #12201
[verse]
- Keith Packard, KD7SQG
+ Keith Packard, K7WQ
NAR #88757, TRA #12200
chaoskey-v1.0 chaoskey-v1.0/flash-loader \
telemini-v3.0 telemini-v3.0/flash-loader \
easymini-v2.0 easymini-v2.0/flash-loader \
+ easymini-v3.0 easymini-v3.0/flash-loader \
micropeak-v2.0
AVRDIRS=\
static word32 key[16/4];
static roundkey rkk;
-static word32 iv[16/4];
+static word32 iv[32/4];
void
ao_aes_set_mode(enum ao_aes_mode mode)
PROGNAME=easymini-v1.0
PROG=$(PROGNAME)-$(VERSION).elf
HEX=$(PROGNAME)-$(VERSION).ihx
+FLASH_PROG=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
+BOTH_HEX=$(PROGNAME)-combined-$(VERSION).ihx
SRC=$(ALTOS_SRC) ao_easymini.c
OBJ=$(SRC:.c=.o)
-all: $(PROG) $(HEX)
+all: $(PROG) $(HEX) $(BOTH_HEX)
$(PROG): Makefile $(OBJ) altos.ld
$(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+$(BOTH_HEX): $(PROG) $(FLASH_PROG)
+ ../../ao-tools/ao-elftohex/ao-elftohex -n --output=$@ $(FLASH_PROG) $(PROG)
+
+$(FLASH_PROG): FRC
+ +cd flash-loader && make
+
+FRC:
+
$(OBJ): $(INC)
load: $(PROG)
--- /dev/null
+ao_product.h
+*.elf
--- /dev/null
+#
+# 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_boot_chain.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_convert_volt.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_usb_lpc.c \
+ ao_spi_lpc.c \
+ ao_adc_lpc.c \
+ ao_beep_lpc.c \
+ ao_m25.c \
+ ao_ms5607.c
+
+PRODUCT=EasyMini-v3.0
+PRODUCT_DEF=-DEASYMINI_V_3_0
+IDPRODUCT=0x0026
+
+CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS)
+
+PROGNAME=easymini-v3.0
+PROG=$(PROGNAME)-$(VERSION).elf
+HEX=$(PROGNAME)-$(VERSION).ihx
+FLASH_PROG=flash-loader/$(PROGNAME)-altos-flash-$(VERSION).elf
+BOTH_HEX=$(PROGNAME)-combined-$(VERSION).ihx
+
+SRC=$(ALTOS_SRC) ao_easymini.c
+OBJ=$(SRC:.c=.o)
+
+all: $(PROG) $(HEX) $(BOTH_HEX)
+
+$(PROG): Makefile $(OBJ) altos.ld
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(BOTH_HEX): $(PROG) $(FLASH_PROG)
+ ../../ao-tools/ao-elftohex/ao-elftohex -n --output=$@ $(FLASH_PROG) $(PROG)
+
+$(FLASH_PROG): FRC
+ +cd flash-loader && make
+
+$(OBJ): $(INC)
+
+load: $(PROG)
+ lpc-load $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx $(PROGNAME)-*.map
+ rm -f ao_product.h
+
+install:
+
+uninstall:
+
+FRC:
--- /dev/null
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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>
+
+int
+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();
+}
--- /dev/null
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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_BATTERY_REPORT 1
+
+#define AO_STACK_SIZE 352
+#define SLEEP_HASH_SIZE 3
+#define AO_NUM_TASKS 6
+
+#define IS_FLASH_LOADER 0
+
+/* 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 HAS_USB 1
+
+#define HAS_USB_CONNECT 0
+#define HAS_USB_VBUS 0
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 1
+#define AO_USB_PULLUP_PIN 23
+
+#define PACKET_HAS_SLAVE 0
+
+#define AO_LOG_FORMAT AO_LOG_FORMAT_EASYMINI1
+
+/* Beeper */
+#define AO_LPC_BEEP_TIMER 0
+#define AO_LPC_BEEP_CHANNEL 3
+#define AO_LPC_BEEP_PORT 1
+#define AO_LPC_BEEP_PIN 27
+
+/* USART */
+
+#define HAS_SERIAL 0
+#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_20 1
+#define SPI_MISO1_P0_22 1
+#define SPI_MOSI1_P1_22 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 1
+#define AO_MS5607_CS_PIN 5
+#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 SLEEP_HASH_SIZE 3
+
+#define AO_DATA_RING 16
+
+/*
+ * ADC
+ */
+
+#define HAS_ADC 1
+
+#define AO_NUM_ADC 3
+
+#define AO_ADC_0 1
+#define AO_ADC_2 1
+#define AO_ADC_5 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 1
+#define AO_IGNITER_DROGUE_PIN 25
+
+#define AO_IGNITER_MAIN_PORT 0
+#define AO_IGNITER_MAIN_PIN 2
+
+#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: %5lu apogee: %5d main: %5d batt: %5d\n", \
+ (p)->tick, (p)->adc.sense_a, (p)->adc.sense_m, (p)->adc.v_batt)
+
+/*
+ * Voltage divider on ADC battery sampler
+ */
+#define AO_BATTERY_DIV_PLUS 100 /* 100k */
+#define AO_BATTERY_DIV_MINUS 27 /* 27k */
+
+/*
+ * Voltage divider on ADC igniter samplers
+ */
+#define AO_IGNITE_DIV_PLUS 100 /* 100k */
+#define AO_IGNITE_DIV_MINUS 27 /* 27k */
+
+/*
+ * ADC reference in decivolts
+ */
+#define AO_ADC_REFERENCE_DV 33
--- /dev/null
+#
+# AltOS flash loader build
+#
+#
+
+TOPDIR=../..
+HARDWARE=easymini-v3.0
+include $(TOPDIR)/lpc/Makefile-flash.defs
--- /dev/null
+/*
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef _AO_PINS_H_
+#define _AO_PINS_H_
+
+#include <ao_flash_lpc_pins.h>
+
+#define AO_BOOT_PIN 1
+#define AO_BOOT_APPLICATION_GPIO 1
+#define AO_BOOT_APPLICATION_PIN 13
+#define AO_BOOT_APPLICATION_VALUE 1
+#define AO_BOOT_APPLICATION_MODE AO_EXTI_MODE_PULL_UP
+
+#define HAS_USB_PULLUP 1
+#define AO_USB_PULLUP_PORT 1
+#define AO_USB_PULLUP_PIN 23
+
+#endif /* _AO_PINS_H_ */
#define AO_LOG_FORMAT_TELESTATIC 17 /* 32 byte typed telestatic records */
#define AO_LOG_FORMAT_MICROPEAK2 18 /* 2-byte baro values with header */
#define AO_LOG_FORMAT_TELEMEGA_4 19 /* 32 byte typed telemega records with 32 bit gyro cal and Bmx160 */
-#define AO_LOG_FORMAT_EASYMOTOR 20 /* ? byte typed easymotor records with pressure sensor and adxl375 */
+#define AO_LOG_FORMAT_EASYMOTOR 20 /* 16 byte typed easymotor records with pressure sensor and adxl375 */
#define AO_LOG_FORMAT_TELEMEGA_5 21 /* 32 byte typed telemega records with 32 bit gyro cal, mpu6000 and mmc5983 */
#define AO_LOG_FORMAT_NONE 127 /* No log at all */
interval = min_interval[ao_config.radio_rate];
#endif
ao_telemetry_interval = interval;
+ if (interval) {
#if AO_SEND_MEGA
- if (interval > 1)
- ao_telemetry_mega_data_max = 1;
- else
- ao_telemetry_mega_data_max = 2;
- if (ao_telemetry_mega_data_max > cur)
- cur++;
- ao_telemetry_mega_data_cur = cur;
+ if (interval > 1)
+ ao_telemetry_mega_data_max = 1;
+ else
+ ao_telemetry_mega_data_max = 2;
+ if (ao_telemetry_mega_data_max > cur)
+ cur++;
+ ao_telemetry_mega_data_cur = cur;
#endif
#if AO_SEND_METRUM
- ao_telemetry_metrum_data_max = (int16_t) (AO_SEC_TO_TICKS(1) / interval);
- if (ao_telemetry_metrum_data_max > cur)
- cur++;
- ao_telemetry_metrum_data_cur = cur;
+ ao_telemetry_metrum_data_max = (int16_t) (AO_SEC_TO_TICKS(1) / interval);
+ if (ao_telemetry_metrum_data_max > cur)
+ cur++;
+ ao_telemetry_metrum_data_cur = cur;
#endif
#if HAS_COMPANION
- if (!ao_companion_setup.update_period)
- ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
- ao_telemetry_companion_max = (int16_t) (ao_companion_setup.update_period / interval);
- if (ao_telemetry_companion_max > cur)
- cur++;
- ao_telemetry_companion_cur = cur;
+ if (!ao_companion_setup.update_period)
+ ao_companion_setup.update_period = AO_SEC_TO_TICKS(1);
+ ao_telemetry_companion_max = (int16_t) (ao_companion_setup.update_period / interval);
+ if (ao_telemetry_companion_max > cur)
+ cur++;
+ ao_telemetry_companion_cur = cur;
#endif
#if HAS_GPS
- ao_telemetry_gps_max = (int16_t) (AO_SEC_TO_TICKS(1) / interval);
- if (ao_telemetry_gps_max > cur)
- cur++;
- ao_telemetry_loc_cur = cur;
- if (ao_telemetry_gps_max > cur)
- cur++;
- ao_telemetry_sat_cur = cur;
-#endif
-
- ao_telemetry_config_max = (int16_t) (AO_SEC_TO_TICKS(5) / interval);
- if (ao_telemetry_config_max > cur)
- cur++;
- ao_telemetry_config_cur = cur;
+ ao_telemetry_gps_max = (int16_t) (AO_SEC_TO_TICKS(1) / interval);
+ if (ao_telemetry_gps_max > cur)
+ cur++;
+ ao_telemetry_loc_cur = cur;
+ if (ao_telemetry_gps_max > cur)
+ cur++;
+ ao_telemetry_sat_cur = cur;
+#endif
+
+ ao_telemetry_config_max = (int16_t) (AO_SEC_TO_TICKS(5) / interval);
+ if (ao_telemetry_config_max > cur)
+ cur++;
+ ao_telemetry_config_cur = cur;
+ }
#ifndef SIMPLIFY
ao_telemetry_time =
1 << 4,
#endif
#if AO_ADC_5
- 1 << 6,
+ 1 << 5,
#endif
#if AO_ADC_6
1 << 6,
#include "ao.h"
-#define _cat(a,b) a##b
-#define cat(a,b) _cat(a,b)
+#define _cat2(a,b) a##b
+#define cat2(a,b) _cat2(a,b)
#define _cat4(a,b,c,d) a##b##c##d
#define cat4(a,b,c,d) _cat4(a,b,c,d)
#define _cat8(a,b,c,d,e,f,g,h) a##b##c##d##e##f##g##h
#define cat8(a,b,c,d,e,f,g,h) _cat8(a,b,c,d,e,f,g,h)
-#define AO_TIMER_CLKCTRL cat(LPC_SCB_SYSAHBCLKCTRL_CT32B, BEEPER_TIMER)
-#define AO_TIMER cat(lpc_ct32b, BEEPER_TIMER)
-#define AO_TIMER_EMC cat(LPC_CT32B_EMR_EMC, BEEPER_OUTPUT)
-#define AO_TIMER_PIO cat4(pio, BEEPER_PORT, _, BEEPER_PIN)
-/* LPC_IOCONF_FUNC_PIO0_14_CT32B1_MAT1 */
-#define AO_TIMER_FUNC cat8(LPC_IOCONF_FUNC_PIO, BEEPER_PORT, _, BEEPER_PIN, _CT32B, BEEPER_TIMER, _MAT, BEEPER_OUTPUT)
-#define AO_TIMER_PWM cat(LPC_CT32B_PWMC_PWMEN, BEEPER_OUTPUT)
+#ifndef AO_LPC_BEEP_TIMER
+#define AO_LPC_BEEP_TIMER 1
+#define AO_LPC_BEEP_CHANNEL 1
+#define AO_LPC_BEEP_PORT 0
+#define AO_LPC_BEEP_PIN 14
+#endif
+
+#define AO_LPC_CT_BEEP cat2(lpc_ct32b, AO_LPC_BEEP_TIMER)
+#define AO_LPC_CT_BEEP_CLKCTRL cat2(LPC_SCB_SYSAHBCLKCTRL_CT32B, AO_LPC_BEEP_TIMER)
+#define AO_LPC_CT_BEEP_EMR cat2(LPC_CT32B_EMR_EMC, AO_LPC_BEEP_CHANNEL)
+#define AO_LPC_CT_BEEP_MR AO_LPC_BEEP_CHANNEL
+#define AO_LPC_CT_BEEP_PWMC cat2(LPC_CT32B_PWMC_PWMEN, AO_LPC_BEEP_CHANNEL)
+#define AO_LPC_CT_BEEP_IOCONF cat4(pio,AO_LPC_BEEP_PORT,_,AO_LPC_BEEP_PIN)
+#define AO_LPC_CT_BEEP_FUNC cat8(LPC_IOCONF_FUNC_PIO,AO_LPC_BEEP_PORT,_,AO_LPC_BEEP_PIN,_CT32B,AO_LPC_BEEP_TIMER,_MAT,AO_LPC_BEEP_CHANNEL)
void
ao_beep(uint8_t beep)
{
if (beep == 0) {
- AO_TIMER.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+ AO_LPC_CT_BEEP.tcr = ((0 << LPC_CT32B_TCR_CEN) |
(1 << LPC_CT32B_TCR_CRST));
- lpc_scb.sysahbclkctrl &= ~(1UL << AO_TIMER_CLKCTRL);
+ lpc_scb.sysahbclkctrl &= ~(1UL << AO_LPC_CT_BEEP_CLKCTRL);
} else {
- lpc_scb.sysahbclkctrl |= (1 << AO_TIMER_CLKCTRL);
+ lpc_scb.sysahbclkctrl |= (1UL << AO_LPC_CT_BEEP_CLKCTRL);
/* Set prescaler to match cc1111 clocks
*/
- AO_TIMER.pr = AO_LPC_SYSCLK / 750000 - 1;
+ AO_LPC_CT_BEEP.pr = AO_LPC_SYSCLK / 750000 - 1;
/* Write the desired data in the match registers */
/* Reset after two time units */
- AO_TIMER.mr[0] = beep << 1;
+ AO_LPC_CT_BEEP.mr[0] = beep << 1;
/* PWM width is half of that */
- AO_TIMER.mr[BEEPER_OUTPUT] = beep;
+ AO_LPC_CT_BEEP.mr[AO_LPC_CT_BEEP_MR] = beep;
/* Flip output on PWM match */
- AO_TIMER.emr = (LPC_CT32B_EMR_EMC_TOGGLE << AO_TIMER_EMC);
+ AO_LPC_CT_BEEP.emr = (LPC_CT32B_EMR_EMC_TOGGLE << AO_LPC_CT_BEEP_EMR);
/* Reset on match 0 */
- AO_TIMER.mcr = (1 << LPC_CT32B_MCR_MR0R);
+ AO_LPC_CT_BEEP.mcr = (1 << LPC_CT32B_MCR_MR0R);
/* PWM on match */
- AO_TIMER.pwmc = (1 << AO_TIMER_PWM);
+ AO_LPC_CT_BEEP.pwmc = (1 << AO_LPC_CT_BEEP_PWMC);
/* timer mode */
- AO_TIMER.ctcr = 0;
+ AO_LPC_CT_BEEP.ctcr = 0;
/* And turn the timer on */
- AO_TIMER.tcr = ((1 << LPC_CT32B_TCR_CEN) |
+ AO_LPC_CT_BEEP.tcr = ((1 << LPC_CT32B_TCR_CEN) |
(0 << LPC_CT32B_TCR_CRST));
}
}
void
ao_beep_init(void)
{
- lpc_ioconf.AO_TIMER_PIO = ((AO_TIMER_FUNC << LPC_IOCONF_FUNC) |
+ /* Our beeper is on c32b1_mat1
+ * which is on pin pio0_14
+ */
+
+ lpc_ioconf.AO_LPC_CT_BEEP_IOCONF = ((AO_LPC_CT_BEEP_FUNC << 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 << AO_LPC_CT_BEEP_CLKCTRL);
+
+ /* Disable the counter and reset the value */
+ AO_LPC_CT_BEEP.tcr = ((0 << LPC_CT32B_TCR_CEN) |
+ (1 << LPC_CT32B_TCR_CRST));
}