- store a stable copy of ARM binaries for production use
- cp src/chaoskey-v1.0/{*.elf,*.ihx,*.bin} \
- src/easymega-v1.0/{*.elf,*.ihx} \
- src/easymega-v2.0/{*.elf,*.ihx} \
- src/easymini-v1.0/{*.elf,*.ihx} \
- src/easymini-v2.0/{*.elf,*.ihx} \
- src/easytimer-v1/{*.elf,*.ihx} \
- src/telebt-v3.0/{*.elf,*.ihx} \
- src/telebt-v4.0/{*.elf,*.ihx} \
- src/teledongle-v3.0/{*.elf,*.ihx} \
- src/telegps-v1.0/{*.elf,*.ihx} \
- src/telegps-v2.0/{*.elf,*.ihx} \
- src/telemega-v[1-4].0/{*.elf,*.ihx} \
- src/telemetrum-v2.0/{*.elf,*.ihx} \
- src/telemetrum-v3.0/{*.elf,*.ihx} \
- src/telemini-v3.0/{*.elf,*.ihx} \
- src/telelco-v2.0/{*.elf,*.ihx} \
- src/telefireeight-v1.0/{*.elf,*.ihx} \
- src/telefireeight-v2.0/{*.elf,*.ihx} \
+ cp src/chaoskey-v1.0/{*.elf,*.ihx,*.bin,*.map} \
+ src/easymega-v1.0/{*.elf,*.ihx,*.map} \
+ src/easymega-v2.0/{*.elf,*.ihx,*.map} \
+ src/easymini-v1.0/{*.elf,*.ihx,*.map} \
+ src/easymini-v2.0/{*.elf,*.ihx,*.map} \
+ src/easytimer-v1/{*.elf,*.ihx,*.map} \
+ src/telebt-v3.0/{*.elf,*.ihx,*.map} \
+ src/telebt-v4.0/{*.elf,*.ihx,*.map} \
+ src/teledongle-v3.0/{*.elf,*.ihx,*.map} \
+ src/telegps-v1.0/{*.elf,*.ihx,*.map} \
+ src/telegps-v2.0/{*.elf,*.ihx,*.map} \
+ src/telemega-v[1-4].0/{*.elf,*.ihx,*.map} \
+ src/telemetrum-v2.0/{*.elf,*.ihx,*.map} \
+ src/telemetrum-v3.0/{*.elf,*.ihx,*.map} \
+ src/telemini-v3.0/{*.elf,*.ihx,*.map} \
+ src/telelco-v2.0/{*.elf,*.ihx,*.map} \
+ src/telefireeight-v1.0/{*.elf,*.ihx,*.map} \
+ src/telefireeight-v2.0/{*.elf,*.ihx,*.map} \
~/altusmetrumllc/Binaries/
- cp src/chaoskey-v1.0/flash-loader/{*.elf,*.bin} \
+ cp src/chaoskey-v1.0/flash-loader/{*.elf,*.bin,*.map} \
src/easymega-v1.0/flash-loader/*.elf \
src/easymega-v2.0/flash-loader/*.elf \
src/easymini-v1.0/flash-loader/*.elf \
- src/easymini-v2.0/flash-loader/{*.elf,*.bin} \
- src/easytimer-v1/flash-loader/{*.elf,*.bin} \
+ src/easymini-v2.0/flash-loader/{*.elf,*.bin,*.map} \
+ src/easytimer-v1/flash-loader/{*.elf,*.bin,*.map} \
src/telebt-v3.0/flash-loader/*.elf \
- src/telebt-v4.0/flash-loader/{*.elf,*.bin} \
+ src/telebt-v4.0/flash-loader/{*.elf,*.bin,*.map} \
src/teledongle-v3.0/flash-loader/*.elf \
src/telegps-v1.0/flash-loader/*.elf \
- src/telegps-v2.0/flash-loader/{*.elf,*.bin} \
+ src/telegps-v2.0/flash-loader/{*.elf,*.bin,*.map} \
src/telemega-v[1-4].0/flash-loader/*.elf \
src/telemetrum-v2.0/flash-loader/*.elf \
src/telemetrum-v3.0/flash-loader/*.elf \
- src/telemini-v3.0/flash-loader/{*.elf,*.bin} \
+ src/telemini-v3.0/flash-loader/{*.elf,*.bin,*.map} \
src/telelco-v2.0/flash-loader/*.elf \
src/telefireeight-v1.0/flash-loader/*.elf \
src/telefireeight-v2.0/flash-loader/*.elf \
if ANDROID
all_target=$(DBG_APK)
+all_target += bin/AltosDroid-debug.apk
if ANDROID_RELEASE
all_target+=$(REL_APK)
+all_target += bin/AltosDroid-release.apk
endif
else
all_target=
all: $(all_target)
+bin/AltosDroid-debug.apk: $(DBG_APK)
+ mkdir -p bin
+ cp $^ $@
+
+bin/AltosDroid-release.apk: $(REL_APK)
+ mkdir -p bin
+ cp $^ $@
+
.NOTPARALLEL:
$(ALTOSLIB): $(ALTOSLIB_SRCDIR)/$(ALTOSLIB_JAR)
has_setting,
radio_calibration);
/* When remote, reset the dongle frequency at the same time */
- if (remote) {
- link.flush_output();
+ if (remote && frequency != link.frequency) {
link.stop_remote();
link.set_radio_frequency(frequency);
- link.flush_output();
link.start_remote();
}
}
if (telemetry_rate != AltosLib.MISSING) {
link.printf("c T %d\n", telemetry_rate);
- if (remote) {
- link.flush_output();
+ if (remote && telemetry_rate != link.telemetry_rate) {
link.stop_remote();
link.set_telemetry_rate(telemetry_rate);
- link.flush_output();
link.start_remote();
}
}
if (callsign != null) {
link.printf("c c %s\n", callsign);
- if (remote) {
- link.flush_output();
+ if (remote && !callsign.equals(link.callsign)) {
+ System.out.printf("changing link callsign from %s to %s\n", link.callsign, callsign);
link.stop_remote();
link.set_callsign(callsign);
- link.flush_output();
link.start_remote();
}
}
/* UI doesn't support accel cal */
link.printf("c w\n");
- link.flush_output();
+ read_link(link, "Saved");
}
public AltosConfigData(AltosLink link) throws InterruptedException, TimeoutException {
return null;
}
+ private static final int look_around[] = { 0, -2, 2, -4, 4 };
+
private long find_usb_descriptors() {
AltosHexsym usb_descriptors = lookup_symbol("ao_usb_descriptors");
long a;
if (usb_descriptors == null)
return -1;
- try {
- /* The address of this has moved depending on
- * padding in the linker script. Look forward
- * and backwards two bytes to see if we can find it
- */
- a = usb_descriptors.address;
-
- if (get_u8(a) == 0x12 && get_u8(a+1) == AO_USB_DESC_DEVICE)
- return a;
- else if (get_u8(a+1) == 0x12 && get_u8(a+3) == AO_USB_DESC_DEVICE)
- return a + 2;
- else if (get_u8(a-2) == 0x12 && get_u8(a-1) == AO_USB_DESC_DEVICE)
- return a - 2;
+ /* The address of this has moved depending on padding
+ * in the linker script and romconfig symbols. Look
+ * forward and backwards two and four bytes to see if
+ * we can find it
+ */
+ a = usb_descriptors.address;
- return -1;
- } catch (ArrayIndexOutOfBoundsException ae) {
- return -1;
+ for (int look : look_around) {
+ try {
+ if (get_u8(a + look) == 0x12 && get_u8(a + look + 1) == AO_USB_DESC_DEVICE)
+ return a;
+ } catch (ArrayIndexOutOfBoundsException ae) {
+ continue;
+ }
}
+ return -1;
}
public AltosUsbId find_usb_id() {
try {
boolean matched = false;
/* Fetch config data from remote */
- AltosConfigData config_data = new AltosConfigData(link);
+ AltosConfigData config_data = link.config_data();
listener.set_state(AltosLib.ao_flight_stateless);
for (AltosIdler idler : idlers) {
if (idler.matches(config_data)) {
if (debug)
System.out.printf("stop remote\n");
try {
+ flush_output();
flush_input();
} finally {
printf ("~\n");
/* Launcher channel preference name */
public final static String launcherChannelPreference = "LAUNCHER-CHANNEL";
- /* Default logdir is ~/TeleMetrum */
- public final static String logdirName = "TeleMetrum";
+ /* Default logdir is ~/AltusMetrum */
+ public final static String logdirName = "AltusMetrum";
/* Log directory */
public static File logdir;
public int check;
public int serial_number;
public int radio_calibration;
+ public int address_offset;
public AltosUsbId usb_id;
public String usb_product;
return (int) (find_address(hexfile, name, len) - hexfile.address);
}
- static int get_int(AltosHexfile hexfile, String name, int len) throws AltosNoSymbol {
+ static private int get_int(AltosHexfile hexfile, String name, int len, int adjust) throws AltosNoSymbol {
byte[] bytes = hexfile.data;
- int start = (int) find_offset(hexfile, name, len);
+ int start = (int) find_offset(hexfile, name, len) + adjust;
int v = 0;
int o = 0;
}
}
+ static final int adjust_rom[] = { 0, -4, 4 };
+
public AltosRomconfig(AltosHexfile hexfile) {
try {
- version = get_int(hexfile, ao_romconfig_version, 2);
- check = get_int(hexfile, ao_romconfig_check, 2);
- if (check == (~version & 0xffff)) {
- switch (version) {
- case 2:
- case 1:
- serial_number = get_int(hexfile, ao_serial_number, 2);
- try {
- radio_calibration = get_int(hexfile, ao_radio_cal, 4);
- } catch (AltosNoSymbol missing) {
- radio_calibration = 0;
- }
-
- valid = true;
-
- /* XXX TeleBT v4.0 units originally shipped without RF calibration programmed. Go fetch
- * the correct value from the web site
- */
- if (serial_number == 2584 ||
- (3686 <= serial_number && serial_number <= 3938 && radio_calibration == 5695485))
- {
- fetch_radio_cal();
+ for (int adjust : adjust_rom) {
+ try {
+ version = get_int(hexfile, ao_romconfig_version, 2, adjust);
+ check = get_int(hexfile, ao_romconfig_check, 2, adjust);
+ if (check == (~version & 0xffff)) {
+ System.out.printf("adjust %d version %x check %x success\n", adjust, version, check);
+ switch (version) {
+ case 2:
+ case 1:
+ serial_number = get_int(hexfile, ao_serial_number, 2, adjust);
+ try {
+ radio_calibration = get_int(hexfile, ao_radio_cal, 4, adjust);
+ } catch (AltosNoSymbol missing) {
+ radio_calibration = 0;
+ }
+
+ valid = true;
+
+ /* XXX TeleBT v4.0 units originally shipped without RF calibration programmed. Go fetch
+ * the correct value from the web site
+ */
+ if (serial_number == 2584 ||
+ (3686 <= serial_number && serial_number <= 3938 && radio_calibration == 5695485))
+ {
+ fetch_radio_cal();
+ }
+
+ break;
+ }
+ break;
+ } else {
+ System.out.printf("adjust %d version %x check %x fail\n", adjust, version, check);
}
-
- break;
+ } catch (ArrayIndexOutOfBoundsException aie) {
+ System.out.printf("adjust %d out of bounds\n", adjust);
+ continue;
}
}
usb_id = hexfile.find_usb_id();
ActionListener listener;
+ static final String title = "Configure Flight Computer";
+
static String[] main_deploy_values_m = {
"100", "150", "200", "250", "300", "350",
"400", "450", "500"
"Dual Deploy",
"Redundant Apogee",
"Redundant Main",
+ "Separation & Apogee",
};
static String[] aprs_interval_values = {
}
}
+ void set_pad_orientation_values() {
+ String [] new_values;
+ if (has_radio())
+ new_values = pad_orientation_values_radio;
+ else
+ new_values = pad_orientation_values_no_radio;
+ if (new_values != pad_orientation_values) {
+ int id = pad_orientation_value.getSelectedIndex();
+ pad_orientation_value.removeAllItems();
+ pad_orientation_values = new_values;
+ for (int i = 0; i < new_values.length; i++)
+ pad_orientation_value.addItem(pad_orientation_values[i]);
+ pad_orientation_value.setSelectedIndex(id);
+ }
+ }
+
void set_accel_tool_tips() {
if (accel_plus_value.isVisible()) {
accel_plus_value.setToolTipText("Pad acceleration value in flight orientation");
/* Build the UI using a grid bag */
public AltosConfigFCUI(JFrame in_owner, boolean remote) {
- super (in_owner, "Configure Flight Computer", false);
+ super (in_owner, title, false);
owner = in_owner;
GridBagConstraints c;
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
+
pane.setLayout(new GridBagLayout());
/* Product */
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
c.ipady = 5;
- if (has_radio())
- pad_orientation_values = pad_orientation_values_radio;
- else
- pad_orientation_values = pad_orientation_values_no_radio;
+ pad_orientation_values = pad_orientation_values_no_radio;
pad_orientation_value = new JComboBox<String>(pad_orientation_values);
pad_orientation_value.setEditable(false);
public void set_dirty() {
dirty = true;
+ setTitle(title + " (modified)");
save.setEnabled(true);
}
public void set_clean() {
dirty = false;
+ setTitle(title);
save.setEnabled(false);
}
if (cmd.equals("Close") || cmd.equals("Reboot"))
if (!check_dirty(cmd))
return;
+ if (cmd.equals("Save"))
+ save.setEnabled(false);
listener.actionPerformed(e);
if (cmd.equals("Close") || cmd.equals("Reboot")) {
setVisible(false);
dispose();
}
- if (cmd.equals("Save") || cmd.equals("Reset"))
- set_clean();
}
/* ItemListener interface method */
set_pad_orientation_tool_tip();
set_accel_tool_tips();
set_flight_log_max_tool_tip();
+ set_pad_orientation_values();
}
public void set_version(String version) {
GridBagConstraints c;
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
int nrow = 0;
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
/* Product */
voice = in_voice;
reader = in_reader;
- bag = getContentPane();
+ bag = getScrollablePane();
bag.setLayout(new GridBagLayout());
setTitle(String.format("AltOS %s", reader.name));
/* We let the user set the freq/callsign, so don't bother with the cancel dialog */
link.set_cancel_enable(false);
- bag = getContentPane();
+ bag = getScrollablePane();
bag.setLayout(new GridBagLayout());
setTitle(String.format("AltOS %s", device.toShortString()));
}
Igniter(AltosIgniteUI ui, String label, String name, int y) {
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
private void make_ui() {
group = new ButtonGroup();
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
if (!open())
return;
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
setVisible(true);
}
-}
\ No newline at end of file
+}
#!/bin/bash
+#
+# Fix fonts. I don't know why the getting the
+# basename of the app set to . matters, but it does
+#
+case "$0" in
+ /*)
+ cd `dirname "$0"`
+ ./`basename "$0"` "$@"
+ exit $?
+ ;;
+esac
+export FREETYPE_PROPERTIES=truetype:interpreter-version=35
##################################################################################
# #
# universalJavaApplicationStub #
var skip
Function GetJRE
- ${OpenURL} "java.com"
+ ${OpenURL} "adoptopenjdk.net"
MessageBox MB_OK "Click OK to continue after completing the Java Install."
FunctionEnd
LINUX_EXTRA=altosui-fat
MACOSX_INFO_PLIST=Info.plist
-MACOSX_INSTALL=install-macosx
+MACOSX_INSTALL=install-macosx ask-pass
MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf $(MACOSX_ICONS) $(MACOSX_INSTALL)
MACOSX_EXTRA=$(FIRMWARE)
SetOutPath $INSTDIR
File "../src/telemetrum-v2.0/telemetrum-v2.0-${VERSION}.ihx"
-; File "../src/telemetrum-v3.0/telemetrum-v3.0-${VERSION}.ihx"
+ File "../src/telemetrum-v3.0/telemetrum-v3.0-${VERSION}.ihx"
File "../src/telemini-v3.0/telemini-v3.0-${VERSION}.ihx"
File "../src/telegps-v1.0/telegps-v1.0-${VERSION}.ihx"
File "../src/telegps-v2.0/telegps-v2.0-${VERSION}.ihx"
--- /dev/null
+#!/bin/bash
+osascript -e 'display dialog "Password:" with hidden answer default answer "" with title "Password for '$USER'"' -e 'text returned of result'
-#!/bin/sh
+#!/bin/bash
+
+JVM=/Library/Java/JavaVirtualMachines
dir=`dirname "$0"`
+
+case `id -u` in
+ 0)
+ ;;
+ *)
+ SUDO_ASKPASS="${dir}/ask-pass" sudo -A "$0" "$@"
+ exit 0
+ ;;
+esac
+
+# Check for java
+if ls "$JVM" | grep -q adopt; then
+ echo "Adopt OpenJDK already present"
+else
+ open https://adoptopenjdk.net/
+ osascript -e 'display dialog "Install Java from https://adoptopenjdk.net then click Continue" buttons {"Continue"} default button 1 with title "Install Java"' >/dev/null
+fi
+
cd "$dir"
-mkdir -p ~/Applications/AltOS
-find ~/Applications/AltOS -type d -print0 | xargs -0 chmod +w
-cp -f -a * ~/Applications/AltOS
-cd ~/Applications/AltOS
-chmod +w *
-xattr -c *
+LIBRARY=/Library/AltusMetrum
+APPLICATIONS=/Applications
+INSTALLED=
+for file in *; do
+ echo 'Installing' "$file"
+ case "$file" in
+ *.app)
+ mkdir -p "${APPLICATIONS}"
+ if [ -d "${APPLICATIONS}/${file}" ]; then
+ rm -rf "${APPLICATIONS}/${file}"
+ fi
+ cp -a "$file" "${APPLICATIONS}/${file}"
+ chmod -R +w "${APPLICATIONS}/${file}"
+ xattr -rc "${APPLICATIONS}/${file}"
+ APP=`basename "$file" .app`
+ INSTALLED="${INSTALLED} ${APP}"
+ ;;
+ *)
+ mkdir -p "${LIBRARY}"
+ cp -a "$file" "${LIBRARY}"
+ ;;
+ esac
+done
+osascript -e 'display dialog "Installation of'"${INSTALLED}"' complete" with title "Installation Complete" buttons {"OK"} default button 1' >/dev/null
found_devices = new LinkedBlockingQueue<AltosBTDevice>();
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
got_ok = false;
frame = in_frame;
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
frequencies = new FrequencyList(in_frequencies);
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
c = new GridBagConstraints();
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
c = new GridBagConstraints();
public AltosHexfileFilter(String usb_product) {
int l;
+ int dash;
/* Trim off any trailing variants (1.0a vs 1.0) */
- for (l = usb_product.length(); l > 0; l--) {
+ for (dash = usb_product.length(); dash > 0; dash--) {
+ char c = usb_product.charAt(dash-1);
+ if (c == '-')
+ break;
+ }
+ if (dash == 0)
+ dash = usb_product.length();
+
+ for (l = usb_product.length(); l > dash; l--) {
char c = usb_product.charAt(l-1);
if (c < 'a' || 'z' < c)
break;
super(in_owner, "Open Flash Target Device", true);
owner = in_owner;
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
int y = 0;
c.weightx = 1;
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
- product_value = new JLabel(config.usb_product);
+ String product = "unknown";
+ if (config != null)
+ product = config.usb_product;
+ product_value = new JLabel(product);
pane.add(product_value, c);
y++;
if (!open())
return;
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
this.link = link;
this.config_values = config_values;
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
super(in_owner, name, false);
owner = in_owner;
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
row = 0;
public class AltosUIDialog extends JDialog implements AltosUIListener {
+ private Container scrollPane;
+
+ public Container getScrollablePane() {
+ if (scrollPane == null) {
+ Container content = super.getContentPane();
+ /* Create a container to hold the dialog contents */
+ scrollPane = new Container();
+
+ /* Make an opaque box to use the right color */
+ Box box = new Box(BoxLayout.X_AXIS);
+ box.add(scrollPane);
+ box.setOpaque(true);
+
+ /* Create a scrollpane to hold the box */
+ JScrollPane scroll = new JScrollPane();
+ JViewport view = scroll.getViewport();
+ view.add(box);
+
+ /* Add the scroll pane to the top level */
+ content.add(scroll);
+ }
+ return (Container) scrollPane;
+ }
+
public void ui_changed(String look_and_feel) {
SwingUtilities.updateComponentTreeUI(this);
this.pack();
this.pack();
}
+ private Container scrollPane;
+
+ public Container getScrollablePane() {
+ if (scrollPane == null) {
+ Container content = super.getContentPane();
+ /* Create a container to hold the dialog contents */
+ scrollPane = new Container();
+
+ /* Make an opaque box to use the right color */
+ Box box = new Box(BoxLayout.X_AXIS);
+ box.add(scrollPane);
+ box.setOpaque(true);
+
+ /* Create a scrollpane to hold the box */
+ JScrollPane scroll = new JScrollPane();
+ JViewport view = scroll.getViewport();
+ view.add(box);
+
+ /* Add the scroll pane to the top level */
+ content.add(scroll);
+ }
+ return (Container) scrollPane;
+ }
+
static String[] altos_icon_names = {
"/altusmetrum-altosui-16.png",
"/altusmetrum-altosui-32.png",
public AltosUIMapPreload(AltosUIFrame in_owner) {
owner = in_owner;
- Container pane = getContentPane();
+ Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
backend.putInt(fontSizePreference, font_size);
flush_preferences();
AltosUILib.set_fonts(font_size);
- for (AltosFontListener l : font_listeners)
+ for (AltosFontListener l : font_listeners) {
+ System.out.printf("notifying %s of font size change\n", l);
l.font_size_changed(font_size);
+ }
+ System.out.printf("all fonts changed\n");
}
}
public static void register_font_listener(AltosFontListener l) {
+ System.out.printf("register font listener\n");
synchronized (backend) {
font_listeners.add(l);
}
}
public static void unregister_font_listener(AltosFontListener l) {
+ System.out.printf("unregister font listener\n");
synchronized (backend) {
font_listeners.remove(l);
}
public String toString() {
String name = getName();
- if (name == null)
+ if (name == null || "".equals(name))
name = "Altus Metrum";
return String.format("%-20.20s %4d %s",
name, getSerial(), getPath());
public String toShortString() {
String name = getName();
- if (name == null)
+ if (name == null || "".equals(name))
name = "Altus Metrum";
return String.format("%s %d %s",
name, getSerial(), getPath());
CALFILE=cal-$SERIAL.txt
-echo 'E 0' > $dev
-
../ao-tools/ao-cal-freq/ao-cal-freq --nosave --output=$CALFILE --tty=$dev
-# echo 'E 1' > $dev
-
CAL_VALUE=`cat $CALFILE`
echo $SERIAL","$CAL_VALUE >> cal_values
echo "Reflashing with calibration: $CAL_VALUE"
echo 'E 1' > $dev
-./test-telemega
+./test-telemega-v1.0
exit $?
echo 'E 1' > $dev
-./test-telemega
+./test-telemega-v3.0
exit $?
break;
case AO_LOG_FORMAT_TELEGPS:
log_gps = (struct ao_log_gps *) &eeprom->data[pos];
- (void) log_gps;
+ switch (log_gps->type) {
+ case AO_LOG_GPS_TIME:
+ printf(" lat %10.7f ° lon %10.7f ° alt %8d m",
+ log_gps->u.gps.latitude / 10000000.0,
+ log_gps->u.gps.longitude/ 10000000.0,
+ (int32_t) (log_gps->u.gps.altitude_low |
+ (log_gps->u.gps.altitude_high << 16)));
+ printf(" time %02d:%02d:%02d %04d-%02d-%02d flags %02x",
+ log_gps->u.gps.hour,
+ log_gps->u.gps.minute,
+ log_gps->u.gps.second,
+ log_gps->u.gps.year + 2000,
+ log_gps->u.gps.month,
+ log_gps->u.gps.day,
+ log_gps->u.gps.flags);
+ printf(" course %3d ground_speed %5u climb_rate %6d pdop %3d hdop %3d vdop %3d mode %3d",
+ log_gps->u.gps.course,
+ log_gps->u.gps.ground_speed,
+ log_gps->u.gps.climb_rate,
+ log_gps->u.gps.pdop,
+ log_gps->u.gps.hdop,
+ log_gps->u.gps.vdop,
+ log_gps->u.gps.mode);
+ break;
+ case AO_LOG_GPS_SAT:
+ printf(" channels %2d",
+ log_gps->u.gps_sat.channels);
+ for (i = 0; i < 12; i++) {
+ printf(" svid %3d c_n %2d",
+ log_gps->u.gps_sat.sats[i].svid,
+ log_gps->u.gps_sat.sats[i].c_n);
+ }
+ break;
+ default:
+ printf (" unknown");
+ break;
+ }
break;
case AO_LOG_FORMAT_DETHERM:
break;
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.9.4)
+AC_INIT([altos], 1.9.5)
ANDROID_VERSION=27
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
-RELEASE_DATE=2020-07-02
+RELEASE_DATE=2020-09-29
AC_SUBST(RELEASE_DATE)
DOC_DATE=`LC_ALL=C date -d $RELEASE_DATE +'%d %b %Y'`
endif
RELNOTES_INC=\
+ release-notes-1.9.5.inc \
release-notes-1.9.4.inc \
release-notes-1.9.3.inc \
release-notes-1.9.2.inc \
Creating documentation for a new release of AltOS
-* Write release notes in release-notes-${version}.inc. Add to Makefile
+* Write release notes in release-notes-${version}.inc.
* Make sure that doc/altusmetrum.txt has the right copyright year
is fired first, followed after a two second
delay by the 'main' channel.
+ Separation & Apogee::
+ This fires the 'main' channel when the first motor
+ burns out and fires the 'apogee' charge at apogee.
+
ifdef::telemetrum,telemega,easymega,easytimer[]
==== Pad Orientation
:notitle:
:doctype: article
-== EasyMini Outline and Hole Pattern
+== EasyMini/EasyMotor/EasyTimer Outline and Hole Pattern
This image, when printed, provides a precise template for the
- mounting holes in EasyMini. EasyMini has overall dimensions
- of 0.800 x 1.500 inches, and the mounting holes are sized for
- use with 4-40 or M3 screws.
+ mounting holes in EasyMini, EasyMotor, and EasyTimer. Each of
+ these products has overall dimensions of 0.800 x 1.500 inches,
+ and the mounting holes are sized for use with 4-40 or M3 screws.
image::easymini.svg[align="center"]
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.5.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.4.adoc[]
--- /dev/null
+= Release Notes for Version 1.9.5
+include::release-head.adoc[]
+:doctype: article
+
+ Version 1.9.5
+
+ == AltOS
+
+ * Add Booster mode for all dual-deploy altimeters. Select
+ "Separation & Apogee" mode in AltosUI to fire the 'main'
+ channel at first motor burnout and the 'apogee' channel at
+ apogee.
+
+ * Improve reliability of stm32l firmware under heavy
+ load. This was found using Monitor Idle on TeleMega with all
+ flash slots full of data which would occasionally lock up.
+
+ * Fix orientation label in AltosUI for devices with
+ radios. This makes the orientation say 'Antenna up' and
+ 'Antenna Down' for TeleMetrum and TeleMega again.
+
+ * Fix log data for pyro channels which were inhibited (often
+ because of a tilt limit). They used to report 'fired' as
+ soon as they were inhibited, which was misleading. Now they
+ never report as having been fired.
+
+ * Allow Igniter Test to fire each igniter more than once.
+
+ == AltosUI
+
+ * Improve performance of Monitor Idle mode by sending less data for each
+ update.
+
+ * Improve Mac OS X install scripts so that they work on
+ Catalina. This involves sending the user to get Java from
+ the AdoptOpenJDK project which provides a version that works
+ with Java applications.
+
+ * Make larger dialogs scrollable for use on smaller screens.
+
+ * Fix troubles re-flashing EasyMega boards running older
+ firmware.
+
+ * Add TeleMetrum v3.0 firmware to the Windows
+ AltosUI packages.
[appendix]
== Release Notes
+ :leveloffset: 2
+ include::release-notes-1.9.5.adoc[]
+
+ <<<<
:leveloffset: 2
include::release-notes-1.9.4.adoc[]
[appendix]
== Release Notes
:leveloffset: 2
- include::release-notes-1.9.4.adoc[]
+ include::release-notes-1.9.5.adoc[]
<<<<
+ :leveloffset: 2
+ include::release-notes-1.9.4.adoc[]
+ <<<<
:leveloffset: 2
include::release-notes-1.9.3.adoc[]
<<<<
-
:leveloffset: 2
include::release-notes-1.9.1.adoc[]
memory. For example, the default 435.750 MHz would be
configured using
- c f 435750 +
+ c F 435750
c w
+ Note that the 'f' parameter is a frequency calibration value
+ that you really, really, really don't want to change. So,
+ please be careful to make sure you use capital 'F', not lower
+ case 'f' when changing the operating frequency!
=== Callsign
Connect pin 6 and pin 1 of the companion
connector. Pin 1 can be identified by the square pad
- around it, and then the pins could sequentially across
+ around it, and then the pins count sequentially across
the board. Be very careful to *not* short pin 8 to
anything as that is connected directly to the
battery. Pin 7 carries 3.3V and the board will crash
Connect pin 6 and pin 1 of the companion
connector. Pin 1 can be identified by the square pad
- around it, and then the pins could sequentially across
+ around it, and then the pins count sequentially across
the board. Be very careful to *not* short pin 8 to
anything as that is connected directly to the
battery. Pin 7 carries 3.3V and the board will crash
Connect pin 5 and pin 1 of the debug connector, which
is the six holes next to the beeper. Pin 1 can be
identified by the square pad around it, and then the
- pins could sequentially across the board, making Pin 5
+ pins count sequentially across the board, making Pin 5
the one on the other end of the row.
endif::easytimer[]
Connect pin 6 and pin 1 of the companion
connector. Pin 1 can be identified by the square pad
- around it, and then the pins could sequentially across
+ around it, and then the pins count sequentially across
the board. Be very careful to *not* short pin 8 to
anything as that is connected directly to the
battery. Pin 7 carries 3.3V and the board will crash
Connect pin 6 and pin 1 of the debug connector, which
is the six holes next to the beeper. Pin 1 can be
identified by the square pad around it, and then the
- pins could sequentially across the board, making Pin 6
+ pins count sequentially across the board, making Pin 6
the one on the other end of the row.
endif::easymini[]
# -iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \
# -iwithsysroot /System/Library/Frameworks/CoreFoundation.framework/Headers
-XCODE=/Applications/Xcode-beta.app
-SDK=$(XCODE)/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk
+XCODE=/Applications/Xcode.app
+SDK=$(XCODE)/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
MINVERSION=10.5
OS_LIB_CFLAGS=\
- -DDARWIN -DPOSIX_TTY -arch i386 -arch x86_64 -isysroot $(SDK) \
+ -DDARWIN -DPOSIX_TTY -arch x86_64 -isysroot $(SDK) \
-mmacosx-version-min=10.5 \
-iwithsysroot /System/Library/Frameworks/JavaVM.framework/Headers \
-iwithsysroot /System/Library/Frameworks/IOKit.framework/Headers \
if (get_number (usb_device, CFSTR(kUSBVendorID), &device->vendor) &&
get_number (usb_device, CFSTR(kUSBProductID), &device->product) &&
get_string (object, CFSTR(kIOCalloutDeviceKey), device->path, sizeof (device->path)) &&
- get_string (usb_device, CFSTR(kUSBProductString), device->name, sizeof (device->name)) &&
+ (get_string (usb_device, CFSTR("kUSBProductString"), device->name, sizeof (device->name)) ||
+ get_string (usb_device, CFSTR(kUSBProductString), device->name, sizeof (device->name))) &&
get_string (usb_device, CFSTR(kUSBSerialNumberString), serial_string, sizeof (serial_string))) {
device->serial = atoi(serial_string);
IOObjectRelease(object);
return list;
}
+static struct {
+ char *windows;
+ char *real;
+} name_map[] = {
+ { .windows = "AltusMetrum28", .real = "EasyMega" },
+ { .windows = "AltusMetrum2c", .real = "EasyMotor" },
+ { 0, 0 },
+};
+
PUBLIC int
altos_list_next(struct altos_list *list, struct altos_device *device)
{
DWORD friendlyname_len;
char instanceid[1024];
DWORD instanceid_len;
+ int i;
dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
altos_set_last_windows_error();
continue;
}
+ for (i = 0; name_map[i].windows; i++)
+ if (!strcmp(name_map[i].windows, friendlyname)) {
+ strcpy(friendlyname, name_map[i].real);
+ break;
+ }
+
+ char *space = strchr(friendlyname, ' ');
+ if (space)
+ *space = '\0';
+
device->vendor = vid;
device->product = pid;
device->serial = serial;
MACOSX_INFO_PLIST=Info.plist
MACOSX_README=ReadMe-Mac.rtf
-MACOSX_INSTALL=../altosui/install-macosx
+MACOSX_INSTALL=../altosui/install-macosx ../altosui/ask-pass
MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_DRIVERS) $(MACOSX_README) $(DOC) $(MACOSX_ICONS) $(MACOSX_INSTALL)
$(MACOSX_DRIVER_0):
private double time_step;
private ArrayList<Integer> bytes;
+ public int nsamples;
public int log_id;
String name;
+ String unique_id;
public static final int LOG_ID_MICROPEAK = 0;
public static final int LOG_ID_MICROKITE = 1;
return v;
}
+ private String get_line(InputStream f) throws IOException, FileEndedException, NonHexcharException {
+ int c;
+ StringBuffer line = new StringBuffer();
+
+ do {
+ c = f.read();
+ } while (Character.isWhitespace(c));
+
+ do {
+ line.append((char) c);
+ c = f.read();
+ } while (!Character.isWhitespace(c));
+ return new String(line);
+ }
+
private int swap16(int i) {
return ((i << 8) & 0xff00) | ((i >> 8) & 0xff);
}
file_crc = 0xffff;
ground_pressure = get_32(f);
min_pressure = get_32(f);
- int nsamples = get_16(f);
+ nsamples = get_16(f);
log_id = nsamples >> 12;
nsamples &= 0xfff;
+ if (log_id == LOG_ID_MICROPEAK2) {
+ int nsamples_high = get_16(f);
+ nsamples |= (nsamples_high << 12);
+ }
cal_data.set_ground_pressure(ground_pressure);
flight_series.set_pressure(cur);
}
+ int current_crc = swap16(~file_crc & 0xffff);
+ int crc = get_16(f);
+
+ crc_valid = crc == current_crc;
+
+ if (log_id == LOG_ID_MICROPEAK2) {
+ unique_id = get_line(f);
+ }
+
flight_series.finish();
/* Build states */
flight_series.set_time(0);
flight_series.set_state(AltosLib.ao_flight_boost);
- flight_series.set_time(flight_series.speed_series.max().time);
- flight_series.set_state(AltosLib.ao_flight_coast);
+ if (flight_series.speed_series != null && flight_series.speed_series.max() != null) {
+ flight_series.set_time(flight_series.speed_series.max().time);
+ flight_series.set_state(AltosLib.ao_flight_coast);
+ }
flight_series.set_time(flight_series.height_series.max().time);
flight_series.set_state(AltosLib.ao_flight_drogue);
flight_stats = new AltosFlightStats(flight_series);
- int current_crc = swap16(~file_crc & 0xffff);
- int crc = get_16(f);
-
- crc_valid = crc == current_crc;
} catch (FileEndedException fe) {
throw new IOException("File Ended Unexpectedly");
}
private void done_internal() {
- setVisible(false);
- dispose();
-
if (data != null && data.crc_valid) {
- status_value.setText("Received MicroPeak Data");
- owner = owner.SetData(data);
- MicroSave save = new MicroSave(owner, data);
- if (save.runDialog())
- owner.SetName(data.name);
+ if (data.nsamples == 0) {
+ JOptionPane.showMessageDialog(owner,
+ "No Flight Data Present",
+ "Empty Log",
+ JOptionPane.WARNING_MESSAGE);
+ } else {
+ status_value.setText("Received MicroPeak Data");
+ owner = owner.SetData(data);
+ MicroSave save = new MicroSave(owner, data);
+ if (save.runDialog())
+ owner.SetName(data.name);
+ }
} else {
JOptionPane.showMessageDialog(owner,
"Download Failed",
"Flight data corrupted",
JOptionPane.ERROR_MESSAGE);
}
+ setVisible(false);
+ dispose();
}
public void drain_queue() {
} catch (MicroData.NonHexcharException nhe) {
}
}
+ write_thread.join();
} catch (FileNotFoundException fe) {
} catch (IOException ioe) {
} catch (InterruptedException ie) {
}
Thread serial_thread;
+ Thread write_thread;
+
+ public class SerialWriter implements Runnable {
+ MicroSerial serial;
+
+ public void run () {
+ try {
+ Thread.sleep(100);
+ serial.write('l');
+ serial.write('\n');
+ serial.flush();
+ } catch (InterruptedException ie) {
+ }
+ }
+
+ public SerialWriter(MicroSerial serial) {
+ this.serial = serial;
+ }
+ }
public void start() {
try {
}
serial_thread = new Thread(this);
serial_thread.start();
+
+ SerialWriter writer = new SerialWriter(serial);
+ write_thread = new Thread(writer);
+ write_thread.start();
}
public void actionPerformed(ActionEvent ae) {
this.owner = owner;
this.device = device;
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
c = new GridBagConstraints();
public class MicroFile {
- public static File make(File directory, int year, int month, int day) {
+ public static File make(MicroData data, File directory, int year, int month, int day) {
+ String unique = "";
+ if (data != null && data.unique_id != null)
+ unique = String.format("-%s", data.unique_id);
for (int sequence = 1;; sequence++) {
- String s = String.format("%04d-%02d-%02d-flight-%03d.mpd",
- year, month, day, sequence);
+ String s = String.format("%04d-%02d-%02d%s-flight-%03d.mpd",
+ year, month, day, unique, sequence);
File file = new File(directory, s);
if (!file.exists())
return file;
}
}
- public static File make(File directory) {
+ public static File make(MicroData data, File directory) {
Calendar cal = Calendar.getInstance();
- return make(directory, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
+ return make(data, directory, cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH));
+ }
+
+ public static File make(MicroData data) {
+ return make(data, AltosUIPreferences.logdir());
}
public static File make() {
- return make(AltosUIPreferences.logdir());
+ return make(null);
}
-}
\ No newline at end of file
+}
#!/bin/bash
+#
+# Fix fonts. I don't know why the getting the
+# basename of the app set to . matters, but it does
+#
+case "$0" in
+ /*)
+ cd `dirname "$0"`
+ ./`basename "$0"` "$@"
+ exit $?
+ ;;
+esac
+export FREETYPE_PROPERTIES=truetype:interpreter-version=35
##################################################################################
# #
# universalJavaApplicationStub #
MicroData data;
Container container;
JTabbedPane pane;
+ JMenuBar menu_bar;
static int number_of_windows;
+ /* File menu */
+ final static String open_command = "open";
+ final static String save_command = "save";
+ final static String export_command = "export";
+ final static String preferences_command = "preferences";
+ final static String close_command = "close";
+ final static String exit_command = "exit";
+
+ static final String[][] file_menu_entries = new String[][] {
+ { "Open", open_command },
+ { "Save a Copy", save_command },
+ { "Export Data", export_command },
+ { "Preferences", preferences_command },
+ { "Close", close_command },
+ { "Exit", exit_command },
+ };
+
+ /* Download menu */
+ final static String download_command = "download";
+ final static String download_label = "Download";
+
MicroPeak SetData(MicroData data) {
MicroPeak mp = this;
if (this.data != null) {
}
public void actionPerformed(ActionEvent ev) {
- if ("Exit".equals(ev.getActionCommand()))
- System.exit(0);
- else if ("Close".equals(ev.getActionCommand()))
- Close();
- else if ("Open".equals(ev.getActionCommand()))
+ if (open_command.equals(ev.getActionCommand()))
SelectFile();
- else if ("Download".equals(ev.getActionCommand()))
- DownloadData();
- else if ("Export".equals(ev.getActionCommand()))
+ else if (save_command.equals(ev.getActionCommand()))
+ Save();
+ else if (export_command.equals(ev.getActionCommand()))
Export();
- else if ("Preferences".equals(ev.getActionCommand()))
+ else if (preferences_command.equals(ev.getActionCommand()))
Preferences();
- else if ("Save a Copy".equals(ev.getActionCommand()))
- Save();
+ else if (close_command.equals(ev.getActionCommand()))
+ Close();
+ else if (exit_command.equals(ev.getActionCommand()))
+ System.exit(0);
+ else if (download_command.equals(ev.getActionCommand()))
+ DownloadData();
}
public void itemStateChanged(ItemEvent e) {
return 1.0;
}
+ private void add_menu(JMenu menu, String label, String action) {
+ JMenuItem item = new JMenuItem(label);
+ menu.add(item);
+ item.addActionListener(this);
+ item.setActionCommand(action);
+ }
+
+
+ private JMenu make_menu(String label, String[][] items) {
+ JMenu menu = new JMenu(label);
+ for (int i = 0; i < items.length; i++) {
+ if (MAC_OS_X) {
+ if (items[i][1].equals("exit"))
+ continue;
+ if (items[i][1].equals("preferences"))
+ continue;
+ }
+ add_menu(menu, items[i][0], items[i][1]);
+ }
+ menu_bar.add(menu);
+ return menu;
+ }
+
public MicroPeak() {
++number_of_windows;
setTitle("MicroPeak");
- JMenuBar menuBar = new JMenuBar();
- setJMenuBar(menuBar);
-
- JMenu fileMenu = new JMenu("File");
- menuBar.add(fileMenu);
-
- JMenuItem openAction = new JMenuItem("Open");
- fileMenu.add(openAction);
- openAction.addActionListener(this);
-
- JMenuItem downloadAction = new JMenuItem("Download");
- fileMenu.add(downloadAction);
- downloadAction.addActionListener(this);
-
- JMenuItem saveAction = new JMenuItem("Save a Copy");
- fileMenu.add(saveAction);
- saveAction.addActionListener(this);
-
- JMenuItem exportAction = new JMenuItem("Export");
- fileMenu.add(exportAction);
- exportAction.addActionListener(this);
-
- JMenuItem preferencesAction = new JMenuItem("Preferences");
- fileMenu.add(preferencesAction);
- preferencesAction.addActionListener(this);
-
- JMenuItem closeAction = new JMenuItem("Close");
- fileMenu.add(closeAction);
- closeAction.addActionListener(this);
+ menu_bar = new JMenuBar();
+ setJMenuBar(menu_bar);
- JMenuItem exitAction = new JMenuItem("Exit");
- fileMenu.add(exitAction);
- exitAction.addActionListener(this);
+ JMenu file_menu = make_menu("File", file_menu_entries);
- JButton downloadButton = new JButton ("Download");
- downloadButton.addActionListener(this);
- menuBar.add(downloadButton);
+ JButton download_button = new JButton (download_label);
+ download_button.setActionCommand(download_command);
+ download_button.addActionListener(this);
+ menu_bar.add(download_button);
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
container.validate();
doLayout();
validate();
- Insets i = getInsets();
- Dimension ps = pane.getPreferredSize();
- ps.width += i.left + i.right;
- ps.height += i.top + i.bottom;
-// setPreferredSize(ps);
- setSize(ps);
+ pack();
setVisible(true);
}
JOptionPane.YES_NO_OPTION);
if (r != JOptionPane.YES_OPTION)
continue;
-
+
if (!file.canWrite()) {
JOptionPane.showMessageDialog(frame,
String.format("\"%s\" is not writable",
setFileFilter(new FileNameExtensionFilter("MicroPeak data file",
"mpd"));
setCurrentDirectory(AltosUIPreferences.last_logdir());
- setSelectedFile(MicroFile.make());
+ setSelectedFile(MicroFile.make(data));
}
}
private MicroSerialLog log;
public int read() {
+ if (file == null)
+ return -1;
int c = libaltos.altos_getchar(file, 0);
if (Thread.interrupted())
return -1;
return c;
}
+ public void write(char c) {
+ libaltos.altos_putchar(file, c);
+ }
+
+ public void flush() {
+ libaltos.altos_flush(file);
+ }
+
public void close() {
if (file != null) {
libaltos.altos_close(file);
chaoskey-v1.0 chaoskey-v1.0/flash-loader \
telemini-v3.0 telemini-v3.0/flash-loader \
easymini-v2.0 easymini-v2.0/flash-loader \
- micropeak-v2.0 micropeak-v2.0/flash-loader
+ micropeak-v2.0
AVRDIRS=\
micropeak microkite microsplash
#define ao_arch_block_interrupts() cli()
#define ao_arch_release_interrupts() sei()
-#define ao_mutex_get(m)
-#define ao_mutex_put(m)
-
void
-ao_delay_until(uint16_t target);
+ao_delay_until(AO_TICK_TYPE target);
/* We can't hit 100 Hz, but we can hit 125 */
#define AO_HERTZ 125
void ao_delay_us(uint16_t us);
+void
+ao_led_toggle(uint8_t colors);
AO_TICK_TYPE
ao_time(void)
{
- uint16_t r;
+ AO_TICK_TYPE r;
cli();
r = ao_tick_count;
}
void
-ao_delay_until(uint16_t target)
+ao_delay_until(AO_TICK_TYPE target)
{
cli();
ao_wakeup_count = target;
}
void
-ao_delay(uint16_t ticks)
+ao_delay(AO_TICK_TYPE ticks)
{
ao_delay_until(ao_time() + ticks);
}
#define ao_arch_task_globals uint8_t ao_cpu_sleep_disable;
-#define ao_arch_init_stack(task, start) \
+#define ao_arch_init_stack(task, sp, start) \
do { \
- uint8_t *sp = task->stack8 + AO_STACK_SIZE - 1; \
uint16_t a = (uint16_t) start; \
int i; \
\
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define PRINTD(l,...)
#endif
+#define AO_ADXL375_SPI_SPEED ao_spi_speed(5000000)
+
struct ao_adxl375_sample ao_adxl375_current;
static void
static struct ao_bmm150_trim ao_bmm150_trim;
-#define ao_bmx160_spi_get() ao_spi_get(AO_BMX160_SPI_BUS, AO_SPI_SPEED_8MHz)
+#define AO_BMX160_SPI_SPEED ao_spi_speed(10000000)
+
+#define ao_bmx160_spi_get() ao_spi_get(AO_BMX160_SPI_BUS, AO_BMX160_SPI_SPEED)
#define ao_bmx160_spi_put() ao_spi_put(AO_BMX160_SPI_BUS)
#define ao_bmx160_spi_start() ao_spi_set_cs(AO_BMX160_SPI_CS_PORT, \
#define FOSC 32000000
-#define ao_radio_try_select(task_id) ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz, task_id)
-#define ao_radio_select() ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_SPI_SPEED_4MHz)
+#define AO_CC1120_SPI_SPEED ao_spi_speed(6100000) /* 6.1MHz max with 32MHz osc */
+
+#define ao_radio_try_select(task_id) ao_spi_try_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_CC1120_SPI_SPEED, task_id)
+#define ao_radio_select() ao_spi_get_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS,AO_CC1120_SPI_SPEED)
#define ao_radio_deselect() ao_spi_put_mask(AO_CC1120_SPI_CS_PORT,(1 << AO_CC1120_SPI_CS_PIN),AO_CC1120_SPI_BUS)
#define ao_radio_spi_start_bytes() ao_spi_start_bytes(AO_CC1120_SPI_BUS)
#define ao_radio_spi_stop_bytes() ao_spi_stop_bytes(AO_CC1120_SPI_BUS)
#define FOSC 26000000
+#define AO_CC115L_SPI_SPEED ao_spi_speed(6500000) /* for back-to-back access */
+
#define ao_radio_select() ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_CC115L_SPI_SPEED)
#define ao_radio_deselect() ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)
#define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC115L_SPI_BUS)
#define FOSC 40000000
#endif
-#ifndef AO_CC1200_SPI_SPEED
-#error AO_CC1200_SPI_SPEED undefined
-#endif
+#define AO_CC1200_SPI_SPEED ao_spi_speed(7700000) /* 7.7MHz max for extended memory reads */
#define ao_radio_select() ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_CC1200_SPI_SPEED)
#define ao_radio_deselect() ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS)
#error HAS_COMPANION not set in ao_companion.c
#endif
+#define AO_COMPANION_SPI_SPEED ao_spi_speed(200000)
+
#define COMPANION_SELECT() do { \
ao_spi_get_bit(AO_COMPANION_CS_PORT, \
AO_COMPANION_CS_PIN, \
AO_COMPANION_SPI_BUS, \
- AO_SPI_SPEED_200kHz); \
+ AO_COMPANION_SPI_SPEED); \
} while (0)
#define COMPANION_DESELECT() do { \
ao_gpio_set(ao_leds[i].port, ao_leds[i].pin, (colors >> i) & 1);
}
-void
-ao_led_toggle(AO_LED_TYPE colors)
-{
- AO_LED_TYPE i;
- for (i = 0; i < N_LED; i++)
- if (colors & (1 << i))
- ao_gpio_set(ao_leds[i].port, ao_leds[i].pin, ~ao_gpio_get(ao_leds[i].port, ao_leds[i].pin));
-}
-
void
ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks)
{
*/
#if M25_MAX_CHIPS > 1
-static uint8_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in each chip */
+static uint32_t ao_m25_size[M25_MAX_CHIPS]; /* number of sectors in 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 */
+static uint32_t ao_m25_total; /* total sectors available */
static ao_port_t ao_m25_wip; /* write in progress */
static uint8_t ao_m25_mutex;
static uint8_t ao_m25_instruction[4];
-#define M25_SELECT(cs) ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS, AO_SPI_SPEED_FAST)
+#define AO_M25_SPI_SPEED ao_spi_speed(10000000) /* this seems like a reasonable minimum speed to require */
+
+#define M25_SELECT(cs) ao_spi_get_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS,AO_M25_SPI_SPEED)
#define M25_DESELECT(cs) ao_spi_put_mask(AO_M25_SPI_CS_PORT,cs,AO_M25_SPI_BUS)
#define M25_BLOCK_SHIFT 16
#define M25_BLOCK 65536L
-#define M25_POS_TO_SECTOR(pos) ((uint8_t) ((pos) >> M25_BLOCK_SHIFT))
+#define M25_POS_TO_SECTOR(pos) ((uint32_t) ((pos) >> M25_BLOCK_SHIFT))
#define M25_SECTOR_TO_POS(sector) (((uint32_t) (sector)) << M25_BLOCK_SHIFT)
/*
/*
* Returns the number of 64kB sectors
*/
-static uint8_t
+static uint32_t
ao_m25_read_capacity(ao_port_t cs)
{
uint8_t capacity;
{
ao_port_t mask;
#if M25_MAX_CHIPS > 1
- uint8_t size;
+ uint32_t size;
uint8_t chip;
for (chip = 0; chip < ao_m25_numchips; chip++) {
ao_m25_scan(void)
{
#if M25_MAX_CHIPS > 1
- uint8_t pin, size;
+ uint8_t pin;
+ uint32_t size;
#endif
if (ao_m25_total)
ao_mutex_put(&ao_m25_mutex);
#if M25_MAX_CHIPS > 1
- printf ("Detected chips %d size %d\n", ao_m25_numchips, ao_m25_total);
+ printf ("Detected chips %d size %ld\n", ao_m25_numchips, ao_m25_total);
for (chip = 0; chip < ao_m25_numchips; chip++)
printf ("Flash chip %d select %02x size %d\n",
chip, ao_m25_pin[chip], ao_m25_size[chip]);
#else
- printf ("Detected chips 1 size %d\n", ao_m25_total);
+ printf ("Detected chips 1 size %ld\n", ao_m25_total);
#endif
#if M25_DEBUG
#define PRINTD(l,...)
#endif
+#define AO_MMA655X_SPI_SPEED ao_spi_speed(8333333) /* 120ns clock period */
+
static void
ao_mma655x_start(void) {
ao_spi_get_bit(AO_MMA655X_CS_PORT,
AO_MMA655X_CS_PIN,
AO_MMA655X_SPI_INDEX,
- AO_SPI_SPEED_FAST);
+ AO_MMA655X_SPI_SPEED);
}
static void
#if AO_MPU6000_SPI
-#define ao_mpu6000_spi_get() ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz)
+#define AO_MPU6000_SPI_SPEED ao_spi_speed(1000000) /* 1Mhz for all register access */
+
+#define ao_mpu6000_spi_get() ao_spi_get(AO_MPU6000_SPI_BUS, AO_MPU6000_SPI_SPEED)
#define ao_mpu6000_spi_put() ao_spi_put(AO_MPU6000_SPI_BUS)
#define ao_mpu6000_spi_start() ao_spi_set_cs(AO_MPU6000_SPI_CS_PORT, \
*/
ao_cur_task = &ao_mpu6000_task;
- ao_spi_get(AO_MPU6000_SPI_BUS, AO_SPI_SPEED_1MHz);
+ ao_mpu6000_spi_get();
ao_cur_task = NULL;
#endif
#if AO_MPU9250_SPI
#ifndef AO_MPU9250_SPI_SPEED
-#define AO_MPU9250_SPI_SPEED AO_SPI_SPEED_1MHz
+#define AO_MPU9250_SPI_SPEED ao_spi_speed(1000000) /* 1MHz max SCLK */
#endif
#define ao_mpu9250_spi_get() ao_spi_get(AO_MPU9250_SPI_BUS, AO_MPU9250_SPI_SPEED)
struct ao_ms5607_prom ao_ms5607_prom;
static uint8_t ms5607_configured;
-#ifndef AO_MS5607_SPI_SPEED
-#define AO_MS5607_SPI_SPEED AO_SPI_SPEED_FAST
-#endif
+#define AO_MS5607_SPI_SPEED ao_spi_speed(20000000)
static void
ao_ms5607_start(void) {
{
int i;
for (;;) {
- for (i = 0; i < 50; i++) {
- ao_led_toggle(AO_BT_LED);
+ for (i = 0; i < 25; i++) {
+ ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(10));
ao_delay(AO_MS_TO_TICKS(10));
}
- ao_led_off(AO_BT_LED);
ao_delay(AO_MS_TO_TICKS(500));
for (i = 0; i < where; i++) {
ao_led_for(AO_BT_LED, AO_MS_TO_TICKS(200));
v = 1-v;
ao_delay(AO_MS_TO_TICKS(50));
ao_gpio_set(AO_RN_P3_1_PORT, AO_RN_P3_1_PIN, v);
- ao_led_toggle(AO_BT_LED);
+ if (v)
+ ao_led_on(AO_BT_LED);
+ else
+ ao_led_off(AO_BT_LED);
}
/* And let P3_1 float again */
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 16MHz High speed external crystal */
#define AO_HSE 16000000
#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
#define AO_ADXL375_CS_PORT (&stm_gpioc)
#define AO_ADXL375_CS_PIN 12
-#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
#define AO_ADXL375_INT1_PORT (&stm_gpiob)
#define AO_ADXL375_INT1_PIN 8
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 16MHz High speed external crystal */
#define AO_HSE 16000000
#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
#define AO_ADXL375_CS_PORT (&stm_gpioc)
#define AO_ADXL375_CS_PIN 12
-#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
#define AO_ADXL375_INT1_PORT (&stm_gpiob)
#define AO_ADXL375_INT1_PIN 8
#define HAS_BEEP 1
#define HAS_BATTERY_REPORT 1
-#define AO_STACK_SIZE 376
+#define AO_STACK_SIZE 360
+#define SLEEP_HASH_SIZE 3
+#define AO_NUM_TASKS 6
#define IS_FLASH_LOADER 0
#define USE_INTERNAL_FLASH 0
#define HAS_IGNITE 1
#define HAS_IGNITE_REPORT 1
+#define SLEEP_HASH_SIZE 3
#define AO_DATA_RING 16
#define AO_MS5607_MISO_PIN 6
#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN)
#define AO_MS5607_SPI_INDEX AO_SPI_1_PA5_PA6_PA7
-#define AO_MS5607_SPI_SPEED AO_SPI_SPEED_12MHz
#define AO_DATA_RING 64
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 16MHz High speed external crystal */
#define AO_HSE 16000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
typedef AO_PORT_TYPE ao_port_t;
+#ifndef AO_TICK_TYPE
+#define AO_TICK_TYPE uint32_t
+#define AO_TICK_SIGNED int32_t
+#endif
+
#if HAS_TASK
#include <ao_task.h>
#else
/* Stop the operating system, beeping and blinking the reason */
void
-ao_panic(uint8_t reason);
+ao_panic(uint8_t reason) __attribute__((noreturn));
/*
* ao_romconfig.c
* ao_timer.c
*/
-#ifndef AO_TICK_TYPE
-#define AO_TICK_TYPE uint32_t
-#define AO_TICK_SIGNED int32_t
-#endif
-
extern volatile AO_TICK_TYPE ao_tick_count;
/* Our timer runs at 100Hz */
/* Suspend the current task until ticks time has passed */
void
-ao_delay(uint16_t ticks);
+ao_delay(AO_TICK_TYPE ticks);
/* Set the ADC interval */
void
ao_igniter_main = 1
};
-void
-ao_ignite(enum ao_igniter igniter);
-
enum ao_igniter_status {
ao_igniter_unknown, /* unknown status (ambiguous voltage) */
ao_igniter_ready, /* continuity detected */
/* Turn on the beeper for the specified time */
void
-ao_beep_for(uint8_t beep, uint16_t ticks);
+ao_beep_for(uint8_t beep, AO_TICK_TYPE ticks);
/* Initialize the beeper */
void
ao_config_log_set, ao_config_log_show },
#endif
#if HAS_IGNITE
- { "i <0 dual, 1 apogee, 2 main>\0Igniter mode",
+ { "i <0 dual, 1 apogee, 2 main, 3 booster>\0Igniter mode",
ao_config_ignite_mode_set, ao_config_ignite_mode_show },
#endif
#if HAS_AES
#define AO_IGNITE_MODE_DUAL 0
#define AO_IGNITE_MODE_APOGEE 1
#define AO_IGNITE_MODE_MAIN 2
+#define AO_IGNITE_MODE_BOOSTER 3
#define AO_RADIO_ENABLE_CORE 1
#define AO_RADIO_DISABLE_TELEMETRY 2
)
{
ao_flight_state = ao_flight_boost;
+ ao_wakeup(&ao_flight_state);
+
ao_launch_tick = ao_boost_tick = ao_sample_tick;
/* start logging data */
ao_gps_new = AO_GPS_NEW_DATA | AO_GPS_NEW_TRACKING;
ao_wakeup(&ao_gps_new);
#endif
-
- ao_wakeup(&ao_flight_state);
}
break;
case ao_flight_boost:
#else
ao_flight_state = ao_flight_coast;
#endif
- ++ao_motor_number;
ao_wakeup(&ao_flight_state);
+ ++ao_motor_number;
}
break;
#if HAS_ACCEL && HAS_BARO
#endif
)
{
-#if HAS_IGNITE
- /* ignite the drogue charge */
- ao_ignite(ao_igniter_drogue);
-#endif
-
+ /* enter drogue state */
+ ao_flight_state = ao_flight_drogue;
+ ao_wakeup(&ao_flight_state);
#if HAS_TELEMETRY
/* slow down the telemetry system */
ao_telemetry_set_interval(AO_TELEMETRY_INTERVAL_RECOVER);
/* Turn the RDF beacon back on */
ao_rdf_set(1);
#endif
-
- /* and enter drogue state */
- ao_flight_state = ao_flight_drogue;
- ao_wakeup(&ao_flight_state);
}
else
#else /* not HAS_BARO */
ao_interval_max_accel_through - ao_interval_min_accel_through <= ao_data_accel_to_sample(MAX_QUIET_ACCEL))
{
ao_flight_state = ao_flight_landed;
+ ao_wakeup(&ao_flight_state);
#if HAS_ADC
/* turn off the ADC capture */
ao_timer_set_adc_interval(0);
#endif
-
- ao_wakeup(&ao_flight_state);
}
/* Reset interval values */
*/
if (ao_height <= ao_config.main_deploy)
{
-#if HAS_IGNITE
- ao_ignite(ao_igniter_main);
-#endif
+ ao_flight_state = ao_flight_main;
+ ao_wakeup(&ao_flight_state);
/*
* Start recording min/max height
ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
ao_interval_min_height = ao_interval_max_height = ao_avg_height;
-
- ao_flight_state = ao_flight_main;
- ao_wakeup(&ao_flight_state);
}
break;
if (ao_interval_max_height - ao_interval_min_height <= AO_M_TO_HEIGHT(4))
{
ao_flight_state = ao_flight_landed;
-
+ ao_wakeup(&ao_flight_state);
#if HAS_ADC
/* turn off the ADC capture */
ao_timer_set_adc_interval(0);
#endif
-
- ao_wakeup(&ao_flight_state);
}
ao_interval_min_height = ao_interval_max_height = ao_avg_height;
ao_interval_end = ao_sample_tick + AO_INTERVAL_TICKS;
#if HAS_IGNITE
struct ao_ignition ao_ignition[2];
-void
-ao_ignite(enum ao_igniter igniter)
-{
- ao_arch_block_interrupts();
- ao_ignition[igniter].request = 1;
- ao_wakeup(&ao_ignition);
- ao_arch_release_interrupts();
-}
-
#ifndef AO_SENSE_DROGUE
#define AO_SENSE_DROGUE(p) ((p)->adc.sense_d)
#define AO_SENSE_MAIN(p) ((p)->adc.sense_m)
static void
ao_igniter_fire(enum ao_igniter igniter)
{
- ao_ignition[igniter].firing = 1;
- switch(ao_config.ignite_mode) {
- case AO_IGNITE_MODE_DUAL:
+ if (!ao_ignition[igniter].fired) {
+ ao_ignition[igniter].firing = 1;
+ ao_ignition[igniter].fired = 1;
switch (igniter) {
case ao_igniter_drogue:
AO_IGNITER_SET_DROGUE(1);
AO_IGNITER_SET_MAIN(0);
break;
}
- break;
- case AO_IGNITE_MODE_APOGEE:
- switch (igniter) {
- case ao_igniter_drogue:
- AO_IGNITER_SET_DROGUE(1);
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_SET_DROGUE(0);
- ao_delay(AO_IGNITER_CHARGE_TIME);
- AO_IGNITER_SET_MAIN(1);
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_SET_MAIN(0);
- break;
- default:
- break;
- }
- break;
- case AO_IGNITE_MODE_MAIN:
- switch (igniter) {
- case ao_igniter_main:
- AO_IGNITER_SET_DROGUE(1);
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_SET_DROGUE(0);
- ao_delay(AO_IGNITER_CHARGE_TIME);
- AO_IGNITER_SET_MAIN(1);
- ao_delay(AO_IGNITER_FIRE_TIME);
- AO_IGNITER_SET_MAIN(0);
- break;
- default:
- break;
- }
- break;
+ ao_ignition[igniter].firing = 0;
+ ao_delay(AO_IGNITER_CHARGE_TIME);
}
- ao_ignition[igniter].firing = 0;
}
static void
ao_igniter(void)
{
- enum ao_igniter igniter;
-
ao_config_get();
for (;;) {
- ao_sleep(&ao_ignition);
- for (igniter = ao_igniter_drogue; igniter <= ao_igniter_main; igniter++) {
- if (ao_ignition[igniter].request && !ao_ignition[igniter].fired) {
- if (igniter == ao_igniter_drogue && ao_config.apogee_delay)
- ao_delay(AO_SEC_TO_TICKS(ao_config.apogee_delay));
-
- ao_igniter_fire(igniter);
- ao_delay(AO_IGNITER_CHARGE_TIME);
- ao_ignition[igniter].fired = 1;
+ /* Wait for flight state change */
+ ao_sleep(&ao_flight_state);
+
+ /* Fire any igniters that are supposed to be triggered
+ * in this new state
+ */
+ switch(ao_config.ignite_mode) {
+ case AO_IGNITE_MODE_DUAL:
+ if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed)
+ ao_igniter_fire(ao_igniter_drogue);
+ if (ao_flight_main <= ao_flight_state && ao_flight_state < ao_flight_landed)
+ ao_igniter_fire(ao_igniter_main);
+ break;
+ case AO_IGNITE_MODE_APOGEE:
+ if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed) {
+ ao_igniter_fire(ao_igniter_drogue);
+ ao_igniter_fire(ao_igniter_main);
}
+ break;
+ case AO_IGNITE_MODE_MAIN:
+ if (ao_flight_main <= ao_flight_state && ao_flight_state < ao_flight_landed) {
+ ao_igniter_fire(ao_igniter_drogue);
+ ao_igniter_fire(ao_igniter_main);
+ }
+ break;
+ case AO_IGNITE_MODE_BOOSTER:
+ if (ao_flight_fast <= ao_flight_state && ao_flight_state < ao_flight_landed)
+ ao_igniter_fire(ao_igniter_main);
+ if (ao_flight_drogue <= ao_flight_state && ao_flight_state < ao_flight_landed)
+ ao_igniter_fire(ao_igniter_drogue);
+ break;
}
}
}
ao_cmd_white();
#if HAS_IGNITE
if (ao_cmd_lex_c == 'm' && ao_match_word("main")) {
+ ao_ignition[ao_igniter_main].fired = 0;
ao_igniter_fire(ao_igniter_main);
return;
}
if (ao_cmd_lex_c == 'd' && ao_match_word("drogue")) {
+ ao_ignition[ao_igniter_drogue].fired = 0;
ao_igniter_fire(ao_igniter_drogue);
return;
}
void
ao_led_set_mask(AO_LED_TYPE colors, AO_LED_TYPE mask);
-/* Toggle the specified LEDs */
-void
-ao_led_toggle(AO_LED_TYPE colors);
-
/* Turn on the specified LEDs for the indicated interval */
void
ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks);
#include <ao.h>
#include <ao_micropeak.h>
#include <ao_log_micro.h>
-#ifndef ao_async_byte
+#ifndef LOG_MICRO_ASYNC
+#define LOG_MICRO_ASYNC 1
+#endif
+#if LOG_MICRO_ASYNC
#include <ao_async.h>
#else
#include <ao_serial.h>
#endif
#include <ao_storage.h>
-static uint16_t ao_log_offset = STARTING_LOG_OFFSET;
+static N_SAMPLES_TYPE ao_log_offset = STARTING_LOG_OFFSET;
-#define AO_LOG_ID_SHIFT 12
-#define AO_LOG_ID_MASK ((1 << AO_LOG_ID_SHIFT) - 1)
void
ao_log_micro_save(void)
{
- uint16_t n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
+ N_SAMPLES_TYPE n_samples = (ao_log_offset - STARTING_LOG_OFFSET) / sizeof (uint16_t);
-#if AO_LOG_ID
- n_samples |= AO_LOG_ID << AO_LOG_ID_SHIFT;
-#endif
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));
ao_async_byte('a' - 10 + b);
}
-static void
+void
ao_log_hex(uint8_t b)
{
ao_log_hex_nibble(b>>4);
ao_log_hex_nibble(b&0xf);
}
-static void
+void
ao_log_newline(void)
{
ao_async_byte('\r');
ao_async_byte('\n');
}
+#define MAX_N_SAMPLES ((MAX_LOG_OFFSET - STARTING_LOG_OFFSET) / 2)
+
void
ao_log_micro_dump(void)
{
- uint16_t n_samples;
+ N_SAMPLES_TYPE n_samples;
uint16_t nbytes;
uint8_t byte;
uint16_t b;
ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
- if (n_samples == 0xffff)
+ if (n_samples == (N_SAMPLES_TYPE) (~0))
n_samples = 0;
+ nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
+
+ /*
+ * Rewrite n_samples so that it includes the log ID value with
+ * 32-bit n_samples split into two chunks
+ */
+ if (sizeof (n_samples) > 2) {
+ N_SAMPLES_TYPE n_samples_low;
+ N_SAMPLES_TYPE n_samples_high;
+ n_samples_low = n_samples & ((1 << AO_LOG_ID_SHIFT) - 1);
+ n_samples_high = (n_samples - n_samples_low) << AO_LOG_ID_WIDTH;
+ n_samples = n_samples_low | n_samples_high;
+ }
#if AO_LOG_ID
- n_samples &= AO_LOG_ID_MASK;
+ n_samples |= AO_LOG_ID << AO_LOG_ID_SHIFT;
#endif
- nbytes = STARTING_LOG_OFFSET + sizeof (uint16_t) * n_samples;
ao_async_start();
ao_async_byte('M');
ao_async_byte('P');
if ((b & 0xf) == 0)
ao_log_newline();
ao_eeprom_read(b, &byte, 1);
+#if AO_LOG_ID
+ if (N_SAMPLES_OFFSET <= b && b < (N_SAMPLES_OFFSET + sizeof(n_samples))) {
+ byte = n_samples >> ((b - N_SAMPLES_OFFSET) << 3);
+ }
+#endif
ao_log_hex(byte);
crc = ao_log_micro_crc(crc, byte);
}
#ifndef _AO_LOG_MICRO_H_
#define _AO_LOG_MICRO_H_
+#ifndef N_SAMPLES_TYPE
+#define N_SAMPLES_TYPE uint16_t
+#endif
+
#define PA_GROUND_OFFSET 0
#define PA_MIN_OFFSET 4
#define N_SAMPLES_OFFSET 8
-#define STARTING_LOG_OFFSET 10
+#define STARTING_LOG_OFFSET (N_SAMPLES_OFFSET + sizeof (N_SAMPLES_TYPE))
#ifndef MAX_LOG_OFFSET
#define MAX_LOG_OFFSET 512
#endif
+#define AO_LOG_ID_SHIFT 12
+#define AO_LOG_ID_WIDTH 4
+#define AO_LOG_ID_MASK (((1 << AO_LOG_ID_WIDTH) - 1) << AO_LOG_ID_SHIFT);
+
+void
+ao_log_hex(uint8_t b);
+
+void
+ao_log_newline(void);
+
void
ao_log_micro_save(void);
#if HAS_AO_DELAY
void
-ao_delay(uint16_t ticks)
+ao_delay_until(AO_TICK_TYPE target)
{
- AO_TICK_TYPE target;
-
- if (!ticks)
- ticks = 1;
- target = ao_tick_count + ticks;
- do {
- ao_sleep(&ao_time);
- } while ((int16_t) (target - ao_tick_count) > 0);
+ ao_arch_block_interrupts();
+ while ((int16_t) (target - ao_tick_count) > 0)
+ ao_sleep((void *) &ao_tick_count);
+ ao_arch_release_interrupts();
}
+
+void
+ao_delay(AO_TICK_TYPE ticks)
+{
+ ao_delay_until(ao_time() + ticks);
+}
+
#endif
void
#ifndef _AO_NOTASK_H_
#define _AO_NOTASK_H_
+void
+ao_delay_until(AO_TICK_TYPE target);
+
uint8_t
ao_sleep(void *wchan);
void
ao_wakeup(void *wchan);
+static inline void ao_mutex_get(uint8_t *m) {(void) m;}
+static inline void ao_mutex_put(uint8_t *m) {(void) m;}
+
#endif /* _AO_NOTASK_H_ */
#endif
uint16_t ao_pyro_fired;
+uint16_t ao_pyro_inhibited;
#ifndef PYRO_DBG
#define PYRO_DBG 0
for (p = 0; p < AO_PYRO_NUM; p++) {
pyro = &ao_config.pyro[p];
- /* Ignore igniters which have already fired
+ /* Ignore igniters which have already fired or inhibited
*/
- if (ao_pyro_fired & (1 << p))
+ if ((ao_pyro_fired|ao_pyro_inhibited) & (1 << p))
continue;
/* Ignore disabled igniters
/* Check to make sure the required conditions
* remain valid. If not, inhibit the channel
- * by setting the fired bit
+ * by setting the inhibited bit
*/
if (!ao_pyro_ready(pyro)) {
- ao_pyro_fired |= (1 << p);
+ ao_pyro_inhibited |= (1 << p);
continue;
}
#define AO_STORAGE_DATA_SIZE 128
static uint8_t storage_data[AO_STORAGE_DATA_SIZE];
+static uint8_t storage_mutex;
uint8_t
ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len)
return 1;
}
+#ifndef AO_STORAGE_ERASED_BYTE
+#define AO_STORAGE_ERASED_BYTE 0xff
+#endif
+
uint8_t
ao_storage_is_erased(uint32_t pos)
{
uint32_t read_pos;
uint32_t read_len;
uint32_t i;
+ uint8_t ret = 1;
+ ao_storage_setup();
+ ao_mutex_get(&storage_mutex);
read_pos = pos;
read_len = ao_storage_block;
while (read_len) {
uint32_t this_time = AO_STORAGE_DATA_SIZE;
if (this_time > read_len)
this_time = read_len;
- if (!ao_storage_read(read_pos, storage_data, this_time))
- return 0;
+ if (!ao_storage_read(read_pos, storage_data, this_time)) {
+ ret = 0;
+ goto done;
+ }
for (i = 0; i < this_time; i++)
- if (storage_data[i] != 0xff)
- return 0;
+ if (storage_data[i] != AO_STORAGE_ERASED_BYTE) {
+ ret = 0;
+ goto done;
+ }
read_pos += this_time;
read_len -= this_time;
}
- return 1;
+done:
+ ao_mutex_put(&storage_mutex);
+ return ret;
}
uint8_t
ao_storage_dump(void)
{
uint32_t block;
- uint8_t i, j;
+ uint8_t i, j, k;
block = ao_cmd_hex();
if (ao_cmd_status != ao_cmd_success)
return;
- for (i = 0; ; i += 8) {
+ ao_mutex_get(&storage_mutex);
+ for (i = 0; ; i += AO_STORAGE_DATA_SIZE) {
if (ao_storage_read((block << 8) + i,
storage_data,
- 8)) {
- ao_cmd_put16((uint16_t) i);
- for (j = 0; j < 8; j++) {
- putchar(' ');
- ao_cmd_put8(storage_data[j]);
+ AO_STORAGE_DATA_SIZE)) {
+ for (k = 0; k < AO_STORAGE_DATA_SIZE; k += 8) {
+ ao_cmd_put16((uint16_t) i + k);
+ for (j = 0; j < 8; j++) {
+ putchar(' ');
+ ao_cmd_put8(storage_data[k + j]);
+ }
+ putchar ('\n');
}
- putchar ('\n');
}
- if (i == 248)
+ if (i == 256 - AO_STORAGE_DATA_SIZE)
break;
}
+ ao_mutex_put(&storage_mutex);
}
#if HAS_STORAGE_DEBUG
typedef ao_storage_pos_t ao_pos_t;
/* Total bytes of available storage */
+#ifndef ao_storage_total
extern ao_pos_t ao_storage_total;
+#endif
/* Block size - device is erased in these units. At least 256 bytes */
+#ifndef ao_storage_block
extern ao_pos_t ao_storage_block;
+#endif
#ifndef USE_STORAGE_CONFIG
#define USE_STORAGE_CONFIG 1
#endif
/* Storage unit size - device reads and writes must be within blocks of this size. Usually 256 bytes. */
+#ifndef ao_storage_unit
extern uint16_t ao_storage_unit;
+#endif
/* Initialize above values. Can only be called once the OS is running */
void
#if HAS_STACK_GUARD
#include <ao_mpu.h>
#endif
+#include <picotls.h>
#define DEBUG 0
-#define AO_NO_TASK_INDEX 0xff
-
struct ao_task * ao_tasks[AO_NUM_TASKS];
uint8_t ao_num_tasks;
struct ao_task *ao_cur_task;
-#if !HAS_TASK_QUEUE
-static uint8_t ao_cur_task_index;
-#endif
-
#ifdef ao_arch_task_globals
ao_arch_task_globals
#endif
#define ao_task_irq_check()
#endif
-#if HAS_TASK_QUEUE
-
+#ifndef SLEEP_HASH_SIZE
#define SLEEP_HASH_SIZE 17
+#endif
static struct ao_list run_queue;
static struct ao_list alarm_queue;
static struct ao_list ao_sleep_queue[SLEEP_HASH_SIZE];
static void
-ao_task_to_run_queue(struct ao_task *task)
+_ao_task_to_run_queue(struct ao_task *task)
{
ao_task_irq_check();
ao_list_del(&task->queue);
}
static void
-ao_task_to_sleep_queue(struct ao_task *task, void *wchan)
+_ao_task_to_sleep_queue(struct ao_task *task, void *wchan)
{
ao_task_irq_check();
ao_list_del(&task->queue);
#define ao_task_validate_alarm_queue()
#endif
-uint16_t ao_task_alarm_tick;
+AO_TICK_TYPE ao_task_alarm_tick;
static void
-ao_task_to_alarm_queue(struct ao_task *task)
+_ao_task_to_alarm_queue(struct ao_task *task)
{
struct ao_task *alarm;
ao_task_irq_check();
}
static void
-ao_task_from_alarm_queue(struct ao_task *task)
+_ao_task_from_alarm_queue(struct ao_task *task)
{
ao_task_irq_check();
ao_list_del(&task->alarm_queue);
}
void
-ao_task_check_alarm(uint16_t tick)
+ao_task_alarm(AO_TICK_TYPE tick)
{
struct ao_task *alarm, *next;
ao_arch_critical(
ao_list_for_each_entry_safe(alarm, next, &alarm_queue, struct ao_task, alarm_queue) {
- if ((int16_t) (tick - alarm->alarm) < 0)
+ if ((AO_TICK_SIGNED) (tick - alarm->alarm) < 0)
break;
alarm->alarm = 0;
- ao_task_from_alarm_queue(alarm);
- ao_task_to_run_queue(alarm);
+ _ao_task_from_alarm_queue(alarm);
+ _ao_task_to_run_queue(alarm);
});
}
}
#endif /* DEBUG */
-#endif /* HAS_TASK_QUEUE */
+static inline void *
+ao_stack_top(struct ao_task *task)
+{
+ uint8_t *top = &task->stack8[AO_STACK_SIZE];
+
+ /* Subtract off the TLS space, but keep the resulting
+ * stack 8-byte aligned
+ */
+#if USE_TLS
+ return top - ((_tls_size() + 7) & ~3);
+#else
+ return top;
+#endif
+}
void
ao_add_task(struct ao_task * task, void (*task_func)(void), const char *name)
* Construct a stack frame so that it will 'return'
* to the start of the task
*/
- ao_arch_init_stack(task, task_func);
- ao_arch_critical(
-#if HAS_TASK_QUEUE
- ao_task_init_queue(task);
- ao_task_to_run_queue(task);
+ uint32_t *sp = ao_stack_top(task);
+#if USE_TLS
+ _init_tls(sp);
#endif
+ ao_arch_init_stack(task, sp, task_func);
+ ao_task_init_queue(task);
+ ao_arch_critical(
+ _ao_task_to_run_queue(task);
ao_tasks[ao_num_tasks] = task;
ao_num_tasks++;
);
uint8_t ao_task_minimize_latency;
-/* Task switching function. This must not use any stack variables */
+/* Task switching function. */
void
-ao_yield(void) ao_arch_naked_define
+ao_yield(void)
{
- ao_arch_save_regs();
-
-#if HAS_TASK_QUEUE
- if (ao_cur_task == NULL)
- ao_cur_task = ao_tasks[ao_num_tasks-1];
-#else
- if (ao_cur_task_index == AO_NO_TASK_INDEX)
- ao_cur_task_index = ao_num_tasks-1;
-#endif
- else
+ if (ao_cur_task)
{
#if HAS_SAMPLE_PROFILE
- uint16_t tick = ao_sample_profile_timer_value();
- uint16_t run = tick - ao_cur_task->start;
+ AO_TICK_TYPE tick = ao_sample_profile_timer_value();
+ AO_TICK_TYPE run = tick - ao_cur_task->start;
if (run > ao_cur_task->max_run)
ao_cur_task->max_run = run;
++ao_cur_task->yields;
#endif
+ ao_arch_save_regs();
ao_arch_save_stack();
}
ao_arch_isr_stack();
-#if !HAS_TASK_QUEUE
- if (ao_task_minimize_latency)
- ao_arch_release_interrupts();
- else
-#endif
- ao_arch_block_interrupts();
+ ao_arch_block_interrupts();
#if AO_CHECK_STACK
in_yield = 1;
/* Find a task to run. If there isn't any runnable task,
* this loop will run forever, which is just fine
*/
-#if HAS_TASK_QUEUE
/* If the current task is running, move it to the
* end of the queue to allow other tasks a chance
*/
- if (ao_cur_task->wchan == NULL)
- ao_task_to_run_queue(ao_cur_task);
+ if (ao_cur_task && ao_cur_task->wchan == NULL)
+ _ao_task_to_run_queue(ao_cur_task);
for (;;) {
ao_arch_memory_barrier();
if (!ao_list_is_empty(&run_queue))
ao_arch_wait_interrupt();
}
ao_cur_task = ao_list_first_entry(&run_queue, struct ao_task, queue);
-#else
- {
- uint8_t ao_last_task_index = ao_cur_task_index;
- for (;;) {
- ++ao_cur_task_index;
- if (ao_cur_task_index == ao_num_tasks)
- ao_cur_task_index = 0;
-
- ao_cur_task = ao_tasks[ao_cur_task_index];
-
- /* Check for ready task */
- if (ao_cur_task->wchan == NULL)
- break;
-
- /* Check if the alarm is set for a time which has passed */
- if (ao_cur_task->alarm &&
- (int16_t) (ao_time() - ao_cur_task->alarm) >= 0)
- break;
-
- /* Wait for interrupts when there's nothing ready */
- if (ao_cur_task_index == ao_last_task_index && !ao_task_minimize_latency)
- ao_arch_wait_interrupt();
- }
- }
-#endif
#if HAS_SAMPLE_PROFILE
ao_cur_task->start = ao_sample_profile_timer_value();
#endif
#endif
#if AO_CHECK_STACK
in_yield = 0;
+#endif
+#if USE_TLS
+ _set_tls(ao_stack_top(ao_cur_task));
#endif
ao_arch_restore_stack();
}
uint8_t
ao_sleep(void *wchan)
{
-#if HAS_TASK_QUEUE
- uint32_t flags;
- flags = ao_arch_irqsave();
-#endif
- ao_cur_task->wchan = wchan;
-#if HAS_TASK_QUEUE
- ao_task_to_sleep_queue(ao_cur_task, wchan);
- ao_arch_irqrestore(flags);
-#endif
+ ao_arch_critical(
+ ao_cur_task->wchan = wchan;
+ _ao_task_to_sleep_queue(ao_cur_task, wchan);
+ );
ao_yield();
if (ao_cur_task->wchan) {
ao_cur_task->wchan = NULL;
ao_wakeup(void *wchan)
{
ao_validate_cur_stack();
-#if HAS_TASK_QUEUE
struct ao_task *sleep, *next;
struct ao_list *sleep_queue;
uint32_t flags;
ao_list_for_each_entry_safe(sleep, next, sleep_queue, struct ao_task, queue) {
if (sleep->wchan == wchan) {
sleep->wchan = NULL;
- ao_task_to_run_queue(sleep);
+ _ao_task_to_run_queue(sleep);
}
}
ao_arch_irqrestore(flags);
-#else
- {
- uint8_t i;
- for (i = 0; i < ao_num_tasks; i++)
- if (ao_tasks[i]->wchan == wchan)
- ao_tasks[i]->wchan = NULL;
- }
-#endif
ao_check_stack();
}
uint8_t
-ao_sleep_for(void *wchan, uint16_t timeout)
+ao_sleep_for(void *wchan, AO_TICK_TYPE timeout)
{
uint8_t ret;
if (timeout) {
-#if HAS_TASK_QUEUE
- uint32_t flags;
- flags = ao_arch_irqsave();
-#endif
- /* Make sure we sleep *at least* delay ticks, which means adding
- * one to account for the fact that we may be close to the next tick
- */
- if (!(ao_cur_task->alarm = ao_time() + timeout + 1))
- ao_cur_task->alarm = 1;
-#if HAS_TASK_QUEUE
- ao_task_to_alarm_queue(ao_cur_task);
- ao_arch_irqrestore(flags);
-#endif
+ ao_arch_critical(
+ /* Make sure we sleep *at least* delay ticks, which means adding
+ * one to account for the fact that we may be close to the next tick
+ */
+ if (!(ao_cur_task->alarm = ao_time() + timeout + 1))
+ ao_cur_task->alarm = 1;
+ _ao_task_to_alarm_queue(ao_cur_task);
+ );
}
ret = ao_sleep(wchan);
if (timeout) {
-#if HAS_TASK_QUEUE
- uint32_t flags;
-
- flags = ao_arch_irqsave();
-#endif
- ao_cur_task->alarm = 0;
-#if HAS_TASK_QUEUE
- ao_task_from_alarm_queue(ao_cur_task);
- ao_arch_irqrestore(flags);
-#endif
+ ao_arch_critical(
+ ao_cur_task->alarm = 0;
+ _ao_task_from_alarm_queue(ao_cur_task);
+ );
}
return ret;
}
static uint8_t ao_forever;
void
-ao_delay(uint16_t ticks)
+ao_delay(AO_TICK_TYPE ticks)
{
if (!ticks)
ticks = 1;
{
uint8_t i;
ao_arch_block_interrupts();
- ao_num_tasks--;
-#if HAS_TASK_QUEUE
for (i = 0; i < ao_num_tasks; i++)
if (ao_tasks[i] == ao_cur_task)
break;
ao_task_exit_queue(ao_cur_task);
-#else
- i = ao_cur_task_index;
- ao_cur_task_index = AO_NO_TASK_INDEX;
-#endif
+ /* Remove task from list */
+ ao_num_tasks--;
for (; i < ao_num_tasks; i++)
ao_tasks[i] = ao_tasks[i+1];
ao_cur_task = NULL;
ao_yield();
- /* we'll never get back here */
+ __builtin_unreachable();
}
#if HAS_TASK_INFO
{
uint8_t i;
struct ao_task *task;
- uint16_t now = ao_time();
+ AO_TICK_TYPE now = ao_time();
for (i = 0; i < ao_num_tasks; i++) {
task = ao_tasks[i];
task->alarm ? (int16_t) (task->alarm - now) : 9999,
task->name);
}
-#if HAS_TASK_QUEUE && DEBUG
+#if DEBUG
ao_task_validate();
#endif
}
void
ao_start_scheduler(void)
{
-#if !HAS_TASK_QUEUE
- ao_cur_task_index = AO_NO_TASK_INDEX;
-#endif
ao_cur_task = NULL;
#if HAS_ARCH_START_SCHEDULER
ao_arch_start_scheduler();
#ifndef _AO_TASK_H_
#define _AO_TASK_H_
-#if HAS_TASK_QUEUE
+
#include <ao_list.h>
-#endif
#ifndef HAS_TASK_INFO
#define HAS_TASK_INFO 1
/* An AltOS task */
struct ao_task {
void *wchan; /* current wait channel (NULL if running) */
- uint16_t alarm; /* abort ao_sleep time */
+ AO_TICK_TYPE alarm; /* abort ao_sleep time */
uint16_t task_id; /* unique id */
/* Saved stack pointer */
union {
uint8_t *sp8;
};
const char *name; /* task name */
-#if HAS_TASK_QUEUE
struct ao_list queue;
struct ao_list alarm_queue;
-#endif
/* Provide both 32-bit and 8-bit stacks */
union {
uint32_t stack32[AO_STACK_SIZE>>2];
#define AO_NUM_TASKS 16 /* maximum number of tasks */
#endif
-#define AO_NO_TASK 0 /* no task id */
-
extern struct ao_task * ao_tasks[AO_NUM_TASKS];
extern uint8_t ao_num_tasks;
extern struct ao_task *ao_cur_task;
* 1 on alarm
*/
uint8_t
-ao_sleep_for(void *wchan, uint16_t timeout);
+ao_sleep_for(void *wchan, AO_TICK_TYPE timeout);
/* Wake all tasks sleeping on wchan */
void
#if 0
/* set an alarm to go off in 'delay' ticks */
void
-ao_alarm(uint16_t delay);
+ao_alarm(AO_TICK_TYPE delay);
/* Clear any pending alarm */
void
void
ao_add_task(struct ao_task * task, void (*start)(void), const char *name);
-#if HAS_TASK_QUEUE
/* Called on timer interrupt to check alarms */
-extern uint16_t ao_task_alarm_tick;
+extern AO_TICK_TYPE ao_task_alarm_tick;
+extern volatile AO_TICK_TYPE ao_tick_count;
+
void
-ao_task_check_alarm(uint16_t tick);
+ao_task_alarm(AO_TICK_TYPE tick);
+
+static inline void
+ao_task_check_alarm(void) {
+#if HAS_TASK
+ if ((AO_TICK_SIGNED) (ao_tick_count - ao_task_alarm_tick) >= 0)
+ ao_task_alarm(ao_tick_count);
#endif
+}
/* Terminate the current task */
void
-ao_exit(void);
+ao_exit(void) __attribute__ ((noreturn));
/* Dump task info to console */
void
void
ao_start_scheduler(void) __attribute__((noreturn));
-#if HAS_TASK_QUEUE
void
ao_task_init(void);
-#else
-#define ao_task_init()
-#endif
#endif
/* SPI definitions */
-#define AO_SPI_SPEED_12MHz 4
-#define AO_SPI_SPEED_8MHz 6
-#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_125kHz 384
-#define AO_SPI_SPEED_62500Hz 768
-
-#define AO_SPI_SPEED_FAST AO_SPI_SPEED_12MHz
+#define _AO_SPI_SPEED_12MHz 4
+#define _AO_SPI_SPEED_8MHz 6
+#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_125kHz 384
+#define _AO_SPI_SPEED_62500Hz 768
+
+static inline uint32_t
+ao_spi_speed(uint32_t hz)
+{
+ if (hz >= 4000000) return _AO_SPI_SPEED_4MHz;
+ if (hz >= 2000000) return _AO_SPI_SPEED_2MHz;
+ if (hz >= 1000000) return _AO_SPI_SPEED_1MHz;
+ if (hz >= 500000) return _AO_SPI_SPEED_500kHz;
+ if (hz >= 250000) return _AO_SPI_SPEED_250kHz;
+ if (hz >= 125000) return _AO_SPI_SPEED_125kHz;
+ return _AO_SPI_SPEED_62500Hz;
+}
#define AO_BOOT_APPLICATION_BASE ((uint32_t *) 0x00001000)
#define AO_BOOT_APPLICATION_BOUND ((uint32_t *) (0x00000000 + 32 * 1024))
#if HAS_TASK
static inline void
-ao_arch_init_stack(struct ao_task *task, void *start)
+ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
{
- uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
uint32_t a = (uint32_t) start;
int i;
}
void
-ao_beep_for(uint8_t beep, uint16_t ticks)
+ao_beep_for(uint8_t beep, AO_TICK_TYPE ticks)
{
ao_beep(beep);
ao_delay(ticks);
ao_led_on(on);
}
-void
-ao_led_toggle(AO_PORT_TYPE colors)
-{
- lpc_gpio.pin[LED_PORT] ^= colors;
-}
-
void
ao_led_for(AO_PORT_TYPE colors, AO_TICK_TYPE ticks)
{
*/
#include <ao.h>
+#include <ao_task.h>
#define AO_SYSTICK (AO_LPC_SYSCLK / 2)
{
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
+ ao_task_check_alarm();
#if AO_DATA_ALL
if (++ao_data_count == ao_data_interval) {
ao_data_count = 0;
#
#
-include ../stmf0/Makefile.defs
+include ../stm32l0/Makefile.defs
PUBLISH_DIR=$(HOME)/altusmetrumllc/Binaries
PUBLISH_HEX=$(PUBLISH_DIR)/$(HEX)
ao_microflight.c \
ao_microkalman.c
-ALTOS_SRC = \
- ao_micropeak.c \
- ao_spi_stm.c \
- ao_dma_stm.c \
- ao_led_stmf0.c \
- ao_timer.c \
- ao_ms5607.c \
- ao_exti_stm.c \
- ao_convert_pa.c \
- ao_romconfig.c \
- ao_product.c \
- ao_panic.c \
- ao_stdio.c \
- ao_serial_stm.c \
- ao_usb_stm.c \
- ao_mutex.c \
- ao_interrupt.c \
- ao_cmd.c \
- ao_config.c \
- ao_task.c \
- ao_data.c \
- ao_boot_chain.c \
- ao_microflight.c \
- ao_report_micro.c \
- ao_storage_stm.c \
- ao_storage.c \
- ao_log_micro.c \
- ao_microkalman.c
-
INC=\
ao.h \
ao_pins.h \
ao_ms5607.h \
ao_log_micro.h \
ao_micropeak.h \
+ ao_lpuart.h \
altitude-pa.h \
ao_product.h \
- stm32f0.h
+ stm32l0.h
+
+ALTOS_SRC = \
+ ao_interrupt.c \
+ ao_panic.c \
+ ao_micro.c \
+ ao_report_micro.c \
+ ao_stdio.c \
+ ao_notask.c \
+ ao_serial_stm.c \
+ ao_lpuart_stm.c \
+ ao_timer.c \
+ ao_spi_stm32l0.c \
+ ao_adc_stm32l0.c \
+ ao_ms5607.c \
+ ao_exti_stm.c \
+ ao_convert_pa.c \
+ ao_led.c \
+ ao_cmd.c \
+ ao_product.c \
+ ao_romconfig.c \
+ ao_flash_stm32l0.c \
+ ao_microflight.c \
+ ao_log_micro.c \
+ ao_microkalman.c
IDPRODUCT=0x14
PRODUCT=MicroPeak-v2.0
PRODUCT_DEF=-DMICROPEAK
-CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS)
+CFLAGS = $(PRODUCT_DEF) $(STML0_CFLAGS) -Wl,--gc-sections -ffunction-sections -fdata-sections
PROGNAME=micropeak-v2.0
PROG=$(PROGNAME)-$(VERSION).elf
all: $(PROG) $(HEX)
-LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stmf0 -Tmicropeak.ld -n
+LDFLAGS=-nostartfiles $(CFLAGS) -L$(TOPDIR)/stm32l0 -Taltos.ld -n
$(PROG): Makefile $(OBJ) micropeak.ld
$(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS) -Wl,-Map=$(PROGNAME)-$(VERSION).map
--- /dev/null
+/*
+ * Copyright © 2020 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>
+#include <ao_micropeak.h>
+#include <ao_adc_stm32l0.h>
+#include <ao_report_micro.h>
+#include <ao_log_micro.h>
+
+uint32_t pa;
+alt_t ground_alt, max_alt;
+alt_t ao_max_height;
+
+static void
+ao_msi_init(void)
+{
+ uint32_t icscr = stm_rcc.icscr;
+
+ /* Set MSI clock to desired range */
+ icscr &= ~(STM_RCC_ICSCR_MSIRANGE_MASK << STM_RCC_ICSCR_MSIRANGE);
+ icscr |= (AO_MSI_RANGE << STM_RCC_ICSCR_MSIRANGE);
+ stm_rcc.icscr = icscr;
+
+ /* Set vcore to 1.2V */
+ uint32_t cr = stm_pwr.cr;
+ cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
+ cr |= (STM_PWR_CR_VOS_1_2 << STM_PWR_CR_VOS);
+ stm_pwr.cr = cr;
+}
+
+void
+ao_pa_get(void)
+{
+ static struct ao_ms5607_value value;
+
+ ao_ms5607_sample(&ao_ms5607_current);
+ ao_ms5607_convert(&ao_ms5607_current, &value);
+ pa = value.pres;
+}
+
+static void
+ao_compute_height(void)
+{
+ ground_alt = ao_pa_to_altitude(pa_ground);
+ max_alt = ao_pa_to_altitude(pa_min);
+ ao_max_height = max_alt - ground_alt;
+}
+
+static void
+ao_pips(void)
+{
+ uint8_t i;
+ for (i = 0; i < 5; i++) {
+ ao_led_on(AO_LED_REPORT);
+ ao_delay(AO_MS_TO_TICKS(80));
+ ao_led_off(AO_LED_REPORT);
+ ao_delay(AO_MS_TO_TICKS(80));
+ }
+ ao_delay(AO_MS_TO_TICKS(200));
+}
+
+static void
+power_down(void)
+{
+ ao_timer_stop();
+ for(;;) {
+ /*
+ * Table 40, entering standby mode
+ *
+ * SLEEPDEEP = 1 in M0 SCR
+ * PDDS = 1
+ * WUF = 0
+ */
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGEN);
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
+ stm_scb.scr |= ((1 << STM_SCB_SCR_SLEEPDEEP) |
+ (1 << STM_SCB_SCR_SLEEPONEXIT));
+ stm_pwr.cr |= (1 << STM_PWR_CR_PDDS);
+ stm_pwr.csr &= ~(1 << STM_PWR_CSR_WUF);
+ ao_arch_wait_interrupt();
+ }
+}
+
+static bool log_stdout;
+
+static void
+log_micro_dump(void)
+{
+ int i;
+ if (!log_stdout) {
+ ao_led_off(AO_LED_REPORT);
+ ao_lpuart1_enable();
+ }
+ ao_log_micro_dump();
+ for (i = 0; i < 4; i++)
+ ao_async_byte(stm_device_id.lot_num_0_3[i]);
+ for (i = 0; i < 3; i++)
+ ao_async_byte(stm_device_id.lot_num_4_6[i]);
+ ao_async_byte('-');
+ ao_log_hex(stm_device_id.waf_num);
+ ao_async_byte('-');
+ for (i = 0; i < 4; i++)
+ ao_log_hex(stm_device_id.unique_id[i]);
+ ao_log_newline();
+ if (!log_stdout)
+ ao_lpuart1_disable();
+}
+
+static void
+log_erase(void)
+{
+ uint32_t pos;
+
+ for (pos = 0; pos < ao_storage_total; pos += STM_FLASH_PAGE_SIZE)
+ {
+ if (!ao_storage_device_is_erased(pos))
+ ao_storage_device_erase(pos);
+ }
+}
+
+static void
+flight_mode(void)
+{
+ /* Give the person a second to get their finger out of the way */
+ ao_delay(AO_MS_TO_TICKS(1000));
+
+ ao_log_micro_restore();
+ ao_compute_height();
+ ao_report_altitude();
+ ao_pips();
+ log_micro_dump();
+#if BOOST_DELAY
+ ao_delay(BOOST_DELAY);
+#endif
+ log_erase();
+ ao_microflight();
+ ao_log_micro_save();
+ ao_compute_height();
+ ao_report_altitude();
+ power_down();
+}
+
+void ao_async_byte(char c)
+{
+ if (log_stdout)
+ putchar(c);
+ else
+ ao_lpuart1_putchar(c);
+}
+
+static void
+log_micro_dump_uart(void)
+{
+ log_stdout = true;
+ log_micro_dump();
+ log_stdout = false;
+}
+
+static void
+log_erase_cmd(void)
+{
+ ao_cmd_white();
+ if (!ao_match_word("DoIt"))
+ return;
+ log_erase();
+}
+
+const struct ao_cmds ao_micro_cmds[] = {
+ { log_micro_dump_uart, "l\0Dump log" },
+ { flight_mode, "F\0Flight mode" },
+ { power_down, "S\0Standby" },
+ { log_erase_cmd, "z <key>\0Erase. <key> is doit with D&I" },
+ {}
+};
+
+static void
+cmd_mode(void)
+{
+ ao_serial_init();
+ ao_cmd_init();
+ ao_cmd_register(ao_micro_cmds);
+ ao_cmd();
+}
+
+int
+main(void)
+{
+ ao_msi_init();
+ ao_led_init();
+ ao_timer_init();
+ ao_spi_init();
+ ao_ms5607_init();
+ ao_ms5607_setup();
+
+ /* Check the power supply voltage; it'll be 3.3V if
+ * the I/O board is connected
+ */
+ uint16_t vref = ao_adc_read_vref();
+
+ uint32_t vdda = 3 * stm_vrefint_cal.vrefint_cal * 1000 / vref;
+
+ /* Power supply > 3.25V means we're on USB power */
+ if (vdda > 3250) {
+ cmd_mode();
+ } else {
+ flight_mode();
+ }
+}
}
void
-ao_delay_until(uint16_t target) {
+ao_delay_until(AO_TICK_TYPE target) {
int16_t delay = target - ao_time();
if (delay > 0) {
ao_sleep_for(ao_delay_until, delay);
stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_ADCEN);
}
-static uint16_t
+static AO_TICK_TYPE
ao_battery_voltage(void)
{
- uint16_t vrefint;
+ AO_TICK_TYPE vrefint;
ao_battery_init();
uint8_t
ao_log_present(void)
{
- uint16_t n_samples;
+ AO_TICK_TYPE n_samples;
ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
extern uint8_t ao_on_battery;
-#define AO_SYSCLK (ao_on_battery ? STM_HSI_FREQ : 48000000)
+#define HAS_TASK 0
-#define LED_PORT_ENABLE STM_RCC_AHBENR_IOPAEN
-#define LED_PORT (&stm_gpioa)
-#define LED_PIN_ORANGE 2
-#define AO_LED_ORANGE (1 << LED_PIN_ORANGE)
+#define AO_SYSCLK STM_MSI_FREQ_524288
+#define AO_MSI_RANGE STM_RCC_ICSCR_MSIRANGE_524288
+
+#define LED_0_PORT (&stm_gpioa)
+#define LED_0_PIN 1
+#define AO_LED_ORANGE (1 << 0)
#define AO_LED_REPORT AO_LED_ORANGE
#define AO_LED_PANIC AO_LED_ORANGE
#define AO_POWER_MANAGEMENT 0
-/* 48MHz clock based on USB */
-#define AO_HSI48 1
-/* Need HSI running to flash */
-#define AO_NEED_HSI 1
-
-/* HCLK = 12MHz usb / 2MHz battery */
-#define AO_AHB_PRESCALER (ao_on_battery ? 16 : 1)
-#define AO_RCC_CFGR_HPRE_DIV (ao_on_battery ? STM_RCC_CFGR_HPRE_DIV_16 : STM_RCC_CFGR_HPRE_DIV_1)
+/* HCLK = MSI (2.097MHz) */
+#define AO_AHB_PRESCALER (1)
+#define AO_RCC_CFGR_HPRE_DIV (STM_RCC_CFGR_HPRE_DIV_1)
-/* APB = 12MHz usb / 2MHz battery */
-#define AO_APB_PRESCALER (ao_on_battery ? 2 : 1)
-#define AO_RCC_CFGR_PPRE_DIV (ao_on_battery ? STM_RCC_CFGR_PPRE_DIV_2 : STM_RCC_CFGR_PPRE_DIV_1)
-
-#define HAS_USB 1
-#define AO_PA11_PA12_RMP 1
+/* APB = MSI */
+#define AO_APB1_PRESCALER (1)
+#define AO_APB2_PRESCALER (1)
+#define AO_RCC_CFGR_PPRE_DIV (STM_RCC_CFGR_PPRE_DIV_1)
#define PACKET_HAS_SLAVE 0
#define HAS_SERIAL_1 0
#define HAS_SERIAL_2 1
-#define USE_SERIAL_2_STDIN 0
+#define USE_SERIAL_2_STDIN 1
#define USE_SERIAL_2_FLOW 0
#define USE_SERIAL_2_SW_FLOW 0
-#define SERIAL_2_PA2_PA3 1
-#define SERIAL_2_PA14_PA15 0
-#define USE_SERIAL2_FLOW 0
-#define USE_SERIAL2_SW_FLOW 0
+#define SERIAL_2_PA9_PA10 1
+
+#define HAS_LPUART_1 1
+#define LPUART_1_PA0_PA1 1
+#define USE_LPUART_1_STDIN 0
+#define USE_LPUART_1_FLOW 0
+#define USE_LPUART_1_SW_FLOW 0
#define IS_FLASH_LOADER 0
#define AO_ALT_VALUE(x) ((x) * (alt_t) 10)
-#define AO_DATA_RING 32
-
#define HAS_ADC 0
+#define HAS_AO_DELAY 1
static inline void
ao_power_off(void) __attribute((noreturn));
extern alt_t ao_max_height;
-void ao_delay_until(uint16_t target);
-
-#define ao_async_stop() do { \
- ao_serial2_drain(); \
- stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT); \
- ao_serial_shutdown(); \
- } while (0)
+#define ao_async_stop()
+#define ao_async_start()
-#define ao_async_start() do { \
- ao_serial_init(); \
- stm_moder_set(&stm_gpioa, 2, STM_MODER_ALTERNATE); \
- ao_delay(AO_MS_TO_TICKS(100)); \
- } while (0)
+#define LOG_MICRO_ASYNC 0
-#define ao_async_byte(b) ao_serial2_putchar((char) (b))
+void ao_async_byte(char c);
-#define ao_eeprom_read(pos, ptr, size) ao_storage_read(pos, ptr, size)
-#define ao_eeprom_write(pos, ptr, size) ao_storage_write(pos, ptr, size)
+#define ao_eeprom_read(pos, ptr, size) ao_storage_device_read(pos, ptr, size)
+#define ao_eeprom_write(pos, ptr, size) ao_storage_device_write(pos, ptr, size)
+#define N_SAMPLES_TYPE uint32_t
#define MAX_LOG_OFFSET ao_storage_total
#define ao_storage_log_max ao_storage_total
#define AO_BOOT_APPLICATION_BOUND ((uint32_t *) __flash__)
#define USE_STORAGE_CONFIG 0
+#define HAS_STORAGE_DEBUG 1
+
#endif /* _AO_PINS_H_ */
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
-__flash = 0x08001000;
-__flash_size = 22K;
+__flash = 0x08000000;
+__flash_size = 10K;
__flash__ = __flash + __flash_size;
__flash_end__ = __flash__ + 6K;
__ram = 0x20000000;
-__ram_size = 6K;
+__ram_size = 2K;
__stack_size = 512;
-INCLUDE registers.ld
INCLUDE picolibc.ld
all: $(PROG) $(HEX)
-$(PROG): Makefile $(OBJ) altos.ld
- $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
-
-ao_product.h: ao-make-product.5c ../Version
- $(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@
+$(PROG): Makefile $(OBJ)
+ $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
$(OBJ): $(INC)
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
#define IS_FLASH_LOADER 0
/* Common definitions for the USB flash loader */
-#define HAS_TASK_QUEUE 0
-
#define HAS_USB 1
#define USE_USB_STDIO 0
#define HAS_USB_DISABLE 0
ao_panic(uint8_t reason)
{
(void) reason;
+ for (;;);
}
void
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 0
/* Bridge SB17 on the board and use the MCO from the other chip */
#define AO_HSE 8000000
#define HAS_USB 1
#define HAS_BEEP 0
#define PACKET_HAS_SLAVE 0
-#define HAS_TASK_QUEUE 1
#define CONSOLE_STDIN 1
/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */
-#define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2
-#define AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
-#define AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
-#define AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
-#define AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
-#define AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
-#define AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
-#define AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
+//#define AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2 /* too fast to use safely */
+#define _AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
+#define _AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
+#define _AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
+#define _AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
+#define _AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
+#define _AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
+#define _AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
-#define AO_SPI_SPEED_FAST AO_SPI_SPEED_8MHz
-
-/* Companion bus wants something no faster than 200kHz */
-
-#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_125kHz
+static inline uint32_t
+ao_spi_speed(uint32_t hz)
+{
+ if (hz >= 4000000) return _AO_SPI_SPEED_4MHz;
+ if (hz >= 2000000) return _AO_SPI_SPEED_2MHz;
+ if (hz >= 1000000) return _AO_SPI_SPEED_1MHz;
+ if (hz >= 500000) return _AO_SPI_SPEED_500kHz;
+ if (hz >= 250000) return _AO_SPI_SPEED_250kHz;
+ if (hz >= 125000) return _AO_SPI_SPEED_125kHz;
+ return _AO_SPI_SPEED_62500Hz;
+}
#define AO_SPI_CPOL_BIT 4
#define AO_SPI_CPHA_BIT 5
void
ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index);
-extern uint16_t ao_spi_speed[STM_NUM_SPI];
-
void
ao_spi_init(void);
#if HAS_TASK
static inline void
-ao_arch_init_stack(struct ao_task *task, void *start)
+ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
{
- uint32_t *sp = &task->stack32[AO_STACK_SIZE>>2];
uint32_t a = (uint32_t) start;
int i;
asm("mrs %0,psp" : "=&r" (psp));
if (ao_cur_task &&
- psp <= ao_cur_task->stack &&
- psp >= ao_cur_task->stack - 256)
+ (psp <= ao_cur_task->stack8 ||
+ psp >= ao_cur_task->stack8 + AO_STACK_SIZE))
ao_panic(AO_PANIC_STACK);
}
#endif
}
void
-ao_beep_for(uint8_t beep, uint16_t ticks)
+ao_beep_for(uint8_t beep, AO_TICK_TYPE ticks)
{
ao_beep(beep);
ao_delay(ticks);
ao_led_on(on);
}
-void
-ao_led_toggle(AO_LED_TYPE colors)
-{
-#ifdef LED_PORT
- LED_PORT->odr ^= (colors & LEDS_AVAILABLE);
-#else
-#ifdef LED_PORT_0
- LED_PORT_0->odr ^= ((colors & LEDS_AVAILABLE) & LED_PORT_0_MASK) << LED_PORT_0_SHIFT;
-#endif
-#ifdef LED_PORT_1
- LED_PORT_1->odr ^= ((colors & LEDS_AVAILABLE) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT;
-#endif
-#ifdef LED_PORT_2
- LED_PORT_2->odr ^= ((colors & LEDS_AVAILABLE) & LED_PORT_2_MASK) << LED_PORT_2_SHIFT;
-#endif
-#endif
-}
-
void
ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks)
{
data,
len,
(0 << STM_DMA_CCR_MEM2MEM) |
- (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_PL_VERY_HIGH << STM_DMA_CCR_PL) |
(STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
(STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
(minc << STM_DMA_CCR_MINC) |
#if HAS_TICK
++ao_tick_count;
#endif
-#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
+ ao_task_check_alarm();
#if AO_DATA_ALL
if (++ao_data_count == ao_data_interval) {
ao_data_count = 0;
#define AO_STACK_SIZE 2048
#endif
-#ifndef HAS_TASK_QUEUE
-#define HAS_TASK_QUEUE 1
-#endif
-
#define AO_STACK_ALIGNMENT __attribute__ ((aligned(8)))
#define AO_PORT_TYPE uint16_t
#if HAS_TASK
static inline void
-ao_arch_init_stack(struct ao_task *task, void *start)
+ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
{
- uint32_t *sp = &task->stack32[AO_STACK_SIZE>>2];
uint32_t a = (uint32_t) start;
int i;
#ifdef AO_BOOT_CHAIN
if (ao_boot_check_chain()) {
#ifdef AO_BOOT_PIN
- ao_boot_check_pin();
+ if (ao_boot_check_pin())
#endif
+ {
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+ }
}
#endif
/* Enable FPU */
#if HAS_TICK
++ao_tick_count;
#endif
-#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
+ ao_task_check_alarm();
#if AO_DATA_ALL
if (++ao_data_count == ao_data_interval) {
ao_data_count = 0;
--- /dev/null
+include $(TOPDIR)/stm/Makefile-stm.defs
+
+INC = \
+ ao.h \
+ ao_arch.h \
+ ao_arch_funcs.h \
+ ao_flash_pins.h \
+ ao_flash_stm_pins.h \
+ ao_flash_task.h \
+ ao_pins.h \
+ ao_product.h \
+ Makefile
+
+#
+# Common AltOS sources
+#
+SRC = \
+ ao_interrupt.c \
+ ao_romconfig.c \
+ ao_boot_chain.c \
+ ao_boot_pin.c \
+ ao_product.c \
+ ao_notask.c \
+ ao_timer.c \
+ ao_usb_stm.c \
+ ao_flash_stm.c \
+ ao_flash_task.c \
+ ao_flash_loader_stm.c
+
+OBJ=$(SRC:.c=.o)
+
+PRODUCT=AltosFlash
+PRODUCT_DEF=-DALTOS_FLASH
+IDPRODUCT=0x000a
+
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS)
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm -Wl,-Taltos-loader.ld -n
+
+PROGNAME=altos-flash
+PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf
+
+$(PROG): Makefile $(OBJ) altos-loader.ld
+ $(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS)
+
+$(OBJ): $(INC)
+
+all: $(PROG)
+
+distclean: clean
+
+clean:
+ rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf
+ rm -f ao_product.h
+
+install:
+
+uninstall:
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+# Disable floating-point support in printf to save space
+
+PICOLIBC_PRINTF_CFLAGS = -DPICOLIBC_INTEGER_PRINTF_SCANF
+
+include $(TOPDIR)/Makefile.defs
+
+vpath % $(TOPDIR)/stm32l0:$(AO_VPATH)
+
+CC=$(ARM_CC)
+
+STML0_CFLAGS=-mlittle-endian -mcpu=cortex-m0 -mthumb \
+ -I$(TOPDIR)/stm32l0 $(AO_CFLAGS) $(PICOLIBC_CFLAGS)
--- /dev/null
+ifndef TOPDIR
+TOPDIR=..
+endif
+
+include $(TOPDIR)/stm32l0/Makefile-stm32l0.defs
+
+LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stm32l0 -Taltos.ld
--- /dev/null
+/*
+ * 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; 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.
+ */
+
+__flash = 0x08000000;
+__flash_size = 12k;
+__storage = __flash + __flash_size;
+__storage_size = 16k - __flash_size;
+__ram = 0x20000000;
+__ram_size = 2k;
+__stack_size = 512;
+
+PROVIDE(__storage = __storage);
+PROVIDE(__storage_size = __storage_size);
+
+INCLUDE picolibc.ld
+INCLUDE stm32l0.ld
--- /dev/null
+/*
+ * Copyright © 2020 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_adc_stm32l0.h>
+
+void
+ao_adc_init(void)
+{
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN);
+
+ /* Configure */
+ stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */
+ (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */
+ (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */
+ (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */
+ (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */
+ (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */
+ (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */
+ (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */
+ (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */
+ (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */
+ (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */
+ (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */
+ (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */
+ (0 << STM_ADC_CFGR1_DMAEN)); /* disable DMA */
+
+ /* Set the clock */
+ stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE;
+
+ /* Shortest sample time */
+ stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP;
+
+#define AO_ADC_LFMEN (AO_SYSCLK < 3500000)
+
+ stm_adc.ccr = ((AO_ADC_LFMEN << STM_ADC_CCR_LFMEN) |
+ (0 << STM_ADC_CCR_VLCDEN) |
+ (0 << STM_ADC_CCR_TSEN) |
+ (0 << STM_ADC_CCR_VREFEN));
+
+ /* Calibrate. This also enables the ADC vreg */
+ stm_adc.cr |= (1 << STM_ADC_CR_ADCAL);
+ while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0)
+ ;
+
+ /* Enable */
+ stm_adc.isr = (1 << STM_ADC_ISR_ADRDY); /* Clear ADRDY bit */
+ stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
+ while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0)
+ ;
+}
+
+static void
+ao_adc_shutdown(void)
+{
+ /* Disable ADC */
+ stm_adc.cr |= (1 << STM_ADC_CR_ADDIS);
+ while ((stm_adc.cr & (1 << STM_ADC_CR_ADEN)) != 0)
+ ;
+
+ /* Clear ADRDY bit */
+ stm_adc.isr = (1 << STM_ADC_ISR_ADRDY);
+
+ /* Disable ADC vreg */
+ stm_adc.cr &= ~(1 << STM_ADC_CR_ADVREGEN);
+
+ /* Disable ADC clocks */
+ stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_ADCEN);
+}
+
+uint16_t
+ao_adc_read_vref(void)
+{
+ uint16_t value;
+
+ ao_adc_init();
+
+ /* Turn on voltage reference */
+ stm_adc.ccr |= (1 << STM_ADC_CCR_VREFEN);
+
+ /* Select VREF */
+ stm_adc.chselr = (1 << STM_ADC_CHSEL_VREF);
+
+ /* Start conversion */
+ stm_adc.cr |= (1 << STM_ADC_CR_ADSTART);
+
+ /* Wait for conversion complete */
+ while ((stm_adc.isr & (1 << STM_ADC_ISR_EOC)) == 0)
+ ;
+
+ /* Fetch result */
+ value = stm_adc.dr;
+
+ ao_adc_shutdown();
+ return value;
+}
--- /dev/null
+/*
+ * Copyright © 2020 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.
+ */
+
+#pragma once
+
+uint16_t
+ao_adc_read_vref(void);
--- /dev/null
+/*
+ * 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; 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_ARCH_H_
+#define _AO_ARCH_H_
+
+#include <stdio.h>
+#include <stm32l0.h>
+
+/*
+ * STM32L0 definitions and code fragments for AltOS
+ */
+
+#ifndef AO_STACK_SIZE
+#define AO_STACK_SIZE 256
+#endif
+
+#define HAS_USB 0
+
+#define AO_PORT_TYPE uint16_t
+
+/* Various definitions to make GCC look more like SDCC */
+
+#define ao_arch_naked_declare __attribute__((naked))
+#define ao_arch_naked_define
+#define __interrupt(n)
+#define __at(n)
+
+#define ao_arch_reboot() \
+ (stm_scb.aircr = ((STM_SCB_AIRCR_VECTKEY_KEY << STM_SCB_AIRCR_VECTKEY) | \
+ (1 << STM_SCB_AIRCR_SYSRESETREQ)))
+
+#define ao_arch_nop() asm("nop")
+
+#define ao_arch_interrupt(n) /* nothing */
+
+/*
+ * ao_romconfig.c
+ */
+
+#define AO_ROMCONFIG_SYMBOL __attribute__((section(".romconfig"))) const
+
+#ifndef AO_SYSCLK
+#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)
+#endif
+
+#define AO_HCLK (AO_SYSCLK / AO_AHB_PRESCALER)
+#define AO_FCLK AO_HCLK
+#define AO_PCLK1 (AO_HCLK / AO_APB1_PRESCALER)
+#define AO_PCLK2 (AO_HCLK / AO_APB2_PRESCALER)
+#define AO_SYSTICK (AO_HCLK / 8)
+
+#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
+
+/* The stm32l implements only 4 bits of the priority fields */
+
+#if AO_NONMASK_INTERRUPT
+#define AO_STM_NVIC_NONMASK_PRIORITY 0x00
+
+/* Set the basepri register to this value to mask all
+ * non-maskable priorities
+ */
+#define AO_STM_NVIC_BASEPRI_MASK 0x10
+#endif
+
+#define AO_STM_NVIC_HIGH_PRIORITY 0x40
+#define AO_STM_NVIC_MED_PRIORITY 0x80
+#define AO_STM_NVIC_LOW_PRIORITY 0xC0
+#define AO_STM_NVIC_CLOCK_PRIORITY 0xf0
+
+void ao_lcd_stm_init(void);
+
+void ao_lcd_font_init(void);
+
+void ao_lcd_font_string(char *s);
+
+extern const uint32_t ao_radio_cal;
+
+void
+ao_adc_init(void);
+
+/* ADC maximum reported value */
+#define AO_ADC_MAX 4095
+
+#define HAS_BOOT_LOADER 0
+
+#ifndef AO_LED_TYPE
+#define AO_LED_TYPE uint16_t
+#endif
+
+void
+ao_timer_stop(void);
+
+#endif /* _AO_ARCH_H_ */
+
+
--- /dev/null
+/*
+ * 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; 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_ARCH_FUNCS_H_
+#define _AO_ARCH_FUNCS_H_
+
+/* ao_spi_stm.c
+ */
+
+/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */
+
+#define _AO_SPI_SPEED_8MHz STM_SPI_CR1_BR_PCLK_2
+#define _AO_SPI_SPEED_4MHz STM_SPI_CR1_BR_PCLK_4
+#define _AO_SPI_SPEED_2MHz STM_SPI_CR1_BR_PCLK_8
+#define _AO_SPI_SPEED_1MHz STM_SPI_CR1_BR_PCLK_16
+#define _AO_SPI_SPEED_500kHz STM_SPI_CR1_BR_PCLK_32
+#define _AO_SPI_SPEED_250kHz STM_SPI_CR1_BR_PCLK_64
+#define _AO_SPI_SPEED_125kHz STM_SPI_CR1_BR_PCLK_128
+#define _AO_SPI_SPEED_62500Hz STM_SPI_CR1_BR_PCLK_256
+
+/* Companion bus wants something no faster than 200kHz */
+
+static inline uint32_t
+ao_spi_speed(uint32_t hz)
+{
+ if (hz >= 4000000) return _AO_SPI_SPEED_4MHz;
+ if (hz >= 2000000) return _AO_SPI_SPEED_2MHz;
+ if (hz >= 1000000) return _AO_SPI_SPEED_1MHz;
+ if (hz >= 500000) return _AO_SPI_SPEED_500kHz;
+ if (hz >= 250000) return _AO_SPI_SPEED_250kHz;
+ if (hz >= 125000) return _AO_SPI_SPEED_125kHz;
+ return _AO_SPI_SPEED_62500Hz;
+}
+
+#define AO_SPI_CPOL_BIT 4
+#define AO_SPI_CPHA_BIT 5
+
+#define AO_SPI_CONFIG_1 0x00
+#define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1
+
+#define AO_SPI_CONFIG_2 0x04
+#define AO_SPI_1_CONFIG_PA12_PA13_PA14 AO_SPI_CONFIG_2
+#define AO_SPI_2_CONFIG_PD1_PD3_PD4 AO_SPI_CONFIG_2
+
+#define AO_SPI_CONFIG_3 0x08
+#define AO_SPI_1_CONFIG_PB3_PB4_PB5 AO_SPI_CONFIG_3
+
+#define AO_SPI_CONFIG_NONE 0x0c
+
+#define AO_SPI_INDEX_MASK 0x01
+#define AO_SPI_CONFIG_MASK 0x0c
+
+#define AO_SPI_1_PA5_PA6_PA7 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PA5_PA6_PA7)
+#define AO_SPI_1_PA12_PA13_PA14 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PA12_PA13_PA14)
+#define AO_SPI_1_PB3_PB4_PB5 (STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PB3_PB4_PB5)
+
+#define AO_SPI_2_PB13_PB14_PB15 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PB13_PB14_PB15)
+#define AO_SPI_2_PD1_PD3_PD4 (STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PD1_PD3_PD4)
+
+#define AO_SPI_INDEX(id) ((id) & AO_SPI_INDEX_MASK)
+#define AO_SPI_CONFIG(id) ((id) & AO_SPI_CONFIG_MASK)
+#define AO_SPI_PIN_CONFIG(id) ((id) & (AO_SPI_INDEX_MASK | AO_SPI_CONFIG_MASK))
+#define AO_SPI_CPOL(id) ((uint32_t) (((id) >> AO_SPI_CPOL_BIT) & 1))
+#define AO_SPI_CPHA(id) ((uint32_t) (((id) >> AO_SPI_CPHA_BIT) & 1))
+
+#define AO_SPI_MAKE_MODE(pol,pha) (((pol) << AO_SPI_CPOL_BIT) | ((pha) << AO_SPI_CPHA_BIT))
+#define AO_SPI_MODE_0 AO_SPI_MAKE_MODE(0,0)
+#define AO_SPI_MODE_1 AO_SPI_MAKE_MODE(0,1)
+#define AO_SPI_MODE_2 AO_SPI_MAKE_MODE(1,0)
+#define AO_SPI_MODE_3 AO_SPI_MAKE_MODE(1,1)
+
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id);
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_send(const 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_send_sync(const void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_start_bytes(uint8_t spi_index);
+
+void
+ao_spi_stop_bytes(uint8_t spi_index);
+
+static inline void
+ao_spi_send_byte(uint8_t byte, uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = &stm_spi1;
+ (void) spi_index;
+
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)))
+ ;
+ stm_spi->dr = byte;
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)))
+ ;
+ (void) stm_spi->dr;
+}
+
+static inline uint8_t
+ao_spi_recv_byte(uint8_t spi_index)
+{
+ struct stm_spi *stm_spi = &stm_spi1;
+ (void) spi_index;
+
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)))
+ ;
+ stm_spi->dr = 0xff;
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)))
+ ;
+ return stm_spi->dr;
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_init(void);
+
+#define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16)
+#define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask))
+
+#define ao_spi_get_mask(reg,mask,bus, speed) do { \
+ ao_spi_get(bus, speed); \
+ ao_spi_set_cs(reg,mask); \
+ } while (0)
+
+static inline uint8_t
+ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t speed, uint8_t task_id)
+{
+ if (!ao_spi_try_get(bus, speed, task_id))
+ return 0;
+ ao_spi_set_cs(reg, mask);
+ return 1;
+}
+
+#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,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed)
+#define ao_spi_put_bit(reg,bit,bus) ao_spi_put_mask(reg,(1<<bit),bus)
+
+#define ao_enable_port(port) do { \
+ if ((port) == &stm_gpioa) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPAEN); \
+ else if ((port) == &stm_gpiob) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPBEN); \
+ else if ((port) == &stm_gpioc) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPCEN); \
+ else if ((port) == &stm_gpiod) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPDEN); \
+ else if ((port) == &stm_gpioe) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPEEN); \
+ else if ((port) == &stm_gpioh) \
+ stm_rcc.iopenr |= (1 << STM_RCC_IOPENR_IOPHEN); \
+ } while (0)
+
+#define ao_disable_port(port) do { \
+ if ((port) == &stm_gpioa) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPAEN); \
+ else if ((port) == &stm_gpiob) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPBEN); \
+ else if ((port) == &stm_gpioc) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPCEN); \
+ else if ((port) == &stm_gpiod) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPDEN); \
+ else if ((port) == &stm_gpioe) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPEEN); \
+ else if ((port) == &stm_gpioh) \
+ stm_rcc.iopenr &= ~(1 << STM_RCC_IOPENR_IOPHEN); \
+ } while (0)
+
+
+#define ao_gpio_set(port, bit, v) stm_gpio_set(port, bit, v)
+
+#define ao_gpio_get(port, bit) stm_gpio_get(port, bit)
+
+#define ao_gpio_set_bits(port, bits) stm_gpio_set_bits(port, bits)
+
+#define ao_gpio_set_mask(port, bits, mask) stm_gpio_set_mask(port, bits, mask)
+
+#define ao_gpio_clr_bits(port, bits) stm_gpio_clr_bits(port, bits);
+
+#define ao_gpio_get_all(port) stm_gpio_get_all(port)
+
+#define ao_enable_output(port,bit,v) do { \
+ ao_enable_port(port); \
+ ao_gpio_set(port, bit, v); \
+ stm_moder_set(port, bit, STM_MODER_OUTPUT);\
+ } while (0)
+
+#define ao_enable_output_mask(port,bits,mask) do { \
+ ao_enable_port(port); \
+ ao_gpio_set_mask(port, bits, mask); \
+ ao_set_output_mask(port, mask); \
+ } while (0)
+
+#define AO_OUTPUT_PUSH_PULL STM_OTYPER_PUSH_PULL
+#define AO_OUTPUT_OPEN_DRAIN STM_OTYPER_OPEN_DRAIN
+
+#define ao_gpio_set_output_mode(port,bit,mode) \
+ stm_otyper_set(port, pin, mode)
+
+#define ao_gpio_set_mode(port,bit,mode) do { \
+ if (mode == AO_EXTI_MODE_PULL_UP) \
+ stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP); \
+ else if (mode == AO_EXTI_MODE_PULL_DOWN) \
+ stm_pupdr_set(port, bit, STM_PUPDR_PULL_DOWN); \
+ else \
+ stm_pupdr_set(port, bit, STM_PUPDR_NONE); \
+ } while (0)
+
+#define ao_gpio_set_mode_mask(port,mask,mode) do { \
+ if (mode == AO_EXTI_MODE_PULL_UP) \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_UP); \
+ else if (mode == AO_EXTI_MODE_PULL_DOWN) \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_PULL_DOWN); \
+ else \
+ stm_pupdr_set_mask(port, mask, STM_PUPDR_NONE); \
+ } while (0)
+
+#define ao_set_input(port, bit) do { \
+ stm_moder_set(port, bit, STM_MODER_INPUT); \
+ } while (0)
+
+#define ao_set_output(port, bit, v) do { \
+ ao_gpio_set(port, bit, v); \
+ stm_moder_set(port, bit, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_set_output_mask(port, mask) do { \
+ stm_moder_set_mask(port, mask, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_set_input_mask(port, mask) do { \
+ stm_moder_set_mask(port, mask, STM_MODER_INPUT); \
+ } while (0)
+
+#define ao_enable_input(port,bit,mode) do { \
+ ao_enable_port(port); \
+ ao_set_input(port, bit); \
+ ao_gpio_set_mode(port, bit, mode); \
+ } while (0)
+
+#define ao_enable_input_mask(port,mask,mode) do { \
+ ao_enable_port(port); \
+ ao_gpio_set_mode_mask(port, mask, mode); \
+ ao_set_input_mask(port, mask); \
+ } while (0)
+
+#define _ao_enable_cs(port, bit) do { \
+ stm_gpio_set((port), bit, 1); \
+ stm_moder_set((port), bit, STM_MODER_OUTPUT); \
+ } while (0)
+
+#define ao_enable_cs(port,bit) do { \
+ ao_enable_port(port); \
+ _ao_enable_cs(port, bit); \
+ } while (0)
+
+#define ao_spi_init_cs(port, mask) do { \
+ ao_enable_port(port); \
+ if ((mask) & 0x0001) _ao_enable_cs(port, 0); \
+ if ((mask) & 0x0002) _ao_enable_cs(port, 1); \
+ if ((mask) & 0x0004) _ao_enable_cs(port, 2); \
+ if ((mask) & 0x0008) _ao_enable_cs(port, 3); \
+ if ((mask) & 0x0010) _ao_enable_cs(port, 4); \
+ if ((mask) & 0x0020) _ao_enable_cs(port, 5); \
+ if ((mask) & 0x0040) _ao_enable_cs(port, 6); \
+ if ((mask) & 0x0080) _ao_enable_cs(port, 7); \
+ if ((mask) & 0x0100) _ao_enable_cs(port, 8); \
+ if ((mask) & 0x0200) _ao_enable_cs(port, 9); \
+ if ((mask) & 0x0400) _ao_enable_cs(port, 10);\
+ if ((mask) & 0x0800) _ao_enable_cs(port, 11);\
+ if ((mask) & 0x1000) _ao_enable_cs(port, 12);\
+ if ((mask) & 0x2000) _ao_enable_cs(port, 13);\
+ if ((mask) & 0x4000) _ao_enable_cs(port, 14);\
+ if ((mask) & 0x8000) _ao_enable_cs(port, 15);\
+ } while (0)
+
+/* ao_dma_stm.c
+ */
+
+extern uint8_t ao_dma_done[STM_NUM_DMA];
+
+void
+ao_dma_set_transfer(uint8_t index,
+ volatile void *peripheral,
+ void *memory,
+ uint16_t count,
+ uint32_t ccr);
+
+void
+ao_dma_set_isr(uint8_t index, void (*isr)(int index));
+
+void
+ao_dma_start(uint8_t index);
+
+void
+ao_dma_done_transfer(uint8_t index);
+
+void
+ao_dma_alloc(uint8_t index, uint8_t cselr);
+
+void
+ao_dma_init(void);
+
+/* ao_i2c_stm.c */
+
+void
+ao_i2c_get(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_start(uint8_t i2c_index, uint16_t address);
+
+void
+ao_i2c_put(uint8_t i2c_index);
+
+uint8_t
+ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
+
+uint8_t
+ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
+
+void
+ao_i2c_init(void);
+
+#if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW
+#define HAS_SERIAL_SW_FLOW 1
+#else
+#define HAS_SERIAL_SW_FLOW 0
+#endif
+
+#if USE_SERIAL_1_FLOW && !USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_FLOW && !USE_SERIAL_3_SW_FLOW
+#define HAS_SERIAL_HW_FLOW 1
+#else
+#define HAS_SERIAL_HW_FLOW 0
+#endif
+
+/* ao_serial_stm.c */
+struct ao_stm_usart {
+ struct ao_fifo rx_fifo;
+ struct ao_fifo tx_fifo;
+ struct stm_usart *reg;
+ uint8_t tx_running;
+ uint8_t draining;
+#if HAS_SERIAL_SW_FLOW
+ /* RTS - 0 if we have FIFO space, 1 if not
+ * CTS - 0 if we can send, 0 if not
+ */
+ struct stm_gpio *gpio_rts;
+ struct stm_gpio *gpio_cts;
+ uint8_t pin_rts;
+ uint8_t pin_cts;
+ uint8_t rts;
+#endif
+};
+
+#include <ao_lpuart.h>
+
+void
+ao_debug_out(char c);
+
+#if HAS_SERIAL_1
+extern struct ao_stm_usart ao_stm_usart1;
+#endif
+
+#if HAS_SERIAL_2
+extern struct ao_stm_usart ao_stm_usart2;
+#endif
+
+#if HAS_SERIAL_3
+extern struct ao_stm_usart ao_stm_usart3;
+#endif
+
+#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
+
+typedef uint32_t ao_arch_irq_t;
+
+static inline void
+ao_arch_block_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+ asm("cpsid i");
+#endif
+}
+
+static inline void
+ao_arch_release_interrupts(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (0x0));
+#else
+ asm("cpsie i");
+#endif
+}
+
+static inline uint32_t
+ao_arch_irqsave(void) {
+ uint32_t val;
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("mrs %0,basepri" : "=r" (val));
+#else
+ asm("mrs %0,primask" : "=r" (val));
+#endif
+ ao_arch_block_interrupts();
+ return val;
+}
+
+static inline void
+ao_arch_irqrestore(uint32_t basepri) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm("msr basepri,%0" : : "r" (basepri));
+#else
+ asm("msr primask,%0" : : "r" (basepri));
+#endif
+}
+
+static inline void
+ao_arch_memory_barrier(void) {
+ asm volatile("" ::: "memory");
+}
+
+static inline void
+ao_arch_irq_check(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ uint32_t basepri;
+ asm("mrs %0,basepri" : "=r" (basepri));
+ if (basepri == 0)
+ ao_panic(AO_PANIC_IRQ);
+#else
+ uint32_t primask;
+ asm("mrs %0,primask" : "=r" (primask));
+ if ((primask & 1) == 0)
+ ao_panic(AO_PANIC_IRQ);
+#endif
+}
+
+#if HAS_TASK
+static inline void
+ao_arch_init_stack(struct ao_task *task, void *start)
+{
+ uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
+ 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->sp32 = 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->sp32 = (sp);
+}
+
+static inline void ao_arch_restore_stack(void) {
+ /* Switch stacks */
+ asm("mov sp, %0" : : "r" (ao_cur_task->sp32) );
+
+ /* Restore PRIMASK */
+ asm("pop {r0}");
+ asm("msr primask,r0");
+
+ /* Restore APSR */
+ asm("pop {r0}");
+ asm("msr apsr_nczvq,r0");
+
+ /* Restore general registers */
+ asm("pop {r0-r7,pc}\n");
+}
+
+#ifndef HAS_SAMPLE_PROFILE
+#define HAS_SAMPLE_PROFILE 0
+#endif
+
+#if DEBUG
+#define HAS_ARCH_VALIDATE_CUR_STACK 1
+
+static inline void
+ao_validate_cur_stack(void)
+{
+ uint8_t *psp;
+
+ asm("mrs %0,psp" : "=&r" (psp));
+ if (ao_cur_task &&
+ psp <= ao_cur_task->stack &&
+ psp >= ao_cur_task->stack - 256)
+ ao_panic(AO_PANIC_STACK);
+}
+#endif
+
+#if !HAS_SAMPLE_PROFILE
+#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));
+ asm("isb");
+}
+#endif
+
+#define ao_arch_isr_stack()
+
+#endif
+
+static inline void
+ao_arch_wait_interrupt(void) {
+#ifdef AO_NONMASK_INTERRUPTS
+ asm(
+ "dsb\n" /* Serialize data */
+ "isb\n" /* Serialize instructions */
+ "cpsid i\n" /* Block all interrupts */
+ "msr basepri,%0\n" /* Allow all interrupts through basepri */
+ "wfi\n" /* Wait for an interrupt */
+ "cpsie i\n" /* Allow all interrupts */
+ "msr basepri,%1\n" /* Block interrupts through basepri */
+ : : "r" (0), "r" (AO_STM_NVIC_BASEPRI_MASK));
+#else
+ asm("\twfi\n");
+ ao_arch_release_interrupts();
+ ao_arch_block_interrupts();
+#endif
+}
+
+#define ao_arch_critical(b) do { \
+ uint32_t __mask = ao_arch_irqsave(); \
+ do { b } while (0); \
+ ao_arch_irqrestore(__mask); \
+ } while (0)
+
+void start(void);
+
+bool
+ao_storage_device_is_erased(uint32_t pos);
+
+#endif /* _AO_ARCH_FUNCS_H_ */
--- /dev/null
+/*
+ * 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; 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"
+
+#define NUM_DMA 7
+
+struct ao_dma_config {
+ void (*isr)(int index);
+};
+
+uint8_t ao_dma_done[NUM_DMA];
+
+static struct ao_dma_config ao_dma_config[NUM_DMA];
+static uint8_t ao_dma_allocated[NUM_DMA];
+static uint8_t ao_dma_mutex[NUM_DMA];
+static uint8_t ao_dma_active;
+
+#ifndef LEAVE_DMA_ON
+static uint8_t ao_dma_active;
+#endif
+
+#define ch_mask(id) (STM_DMA_ISR_MASK << STM_DMA_ISR(id))
+
+static void
+ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
+ /* Get channel interrupt bits */
+ uint32_t isr = stm_dma1.isr & mask;
+ uint8_t index;
+
+ /* Ack them */
+ stm_dma1.ifcr = isr;
+ for (index = low_index; index <= high_index; index++) {
+ if (isr & ch_mask(index)) {
+ if (ao_dma_config[index].isr)
+ (*ao_dma_config[index].isr)(index);
+ else {
+ ao_dma_done[index] = 1;
+ ao_wakeup(&ao_dma_done[index]);
+ }
+ }
+ }
+}
+
+void stm_dma1_channel1_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(1),
+ STM_DMA_INDEX(1),
+ ch_mask(STM_DMA_INDEX(1)));
+}
+
+void stm_dma1_channel3_2_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(2),
+ STM_DMA_INDEX(3),
+ ch_mask(STM_DMA_INDEX(2)) |
+ ch_mask(STM_DMA_INDEX(3)));
+}
+
+void stm_dma1_channel7_4_isr(void) {
+ ao_dma_isr(STM_DMA_INDEX(4), STM_DMA_INDEX(7),
+ ch_mask(STM_DMA_INDEX(4)) |
+ ch_mask(STM_DMA_INDEX(5)) |
+ ch_mask(STM_DMA_INDEX(6)) |
+ ch_mask(STM_DMA_INDEX(7)));
+}
+
+void
+ao_dma_set_transfer(uint8_t index,
+ volatile void *peripheral,
+ void *memory,
+ uint16_t count,
+ uint32_t ccr)
+{
+ if (ao_dma_allocated[index]) {
+ if (ao_dma_mutex[index])
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_mutex[index] = 0xff;
+ } else
+ ao_mutex_get(&ao_dma_mutex[index]);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (ao_dma_active++ == 0)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ stm_dma1.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
+ stm_dma1.channel[index].cndtr = count;
+ stm_dma1.channel[index].cpar = peripheral;
+ stm_dma1.channel[index].cmar = memory;
+ ao_dma_config[index].isr = NULL;
+}
+
+void
+ao_dma_set_isr(uint8_t index, void (*isr)(int))
+{
+ ao_dma_config[index].isr = isr;
+}
+
+void
+ao_dma_start(uint8_t index)
+{
+ ao_dma_done[index] = 0;
+ stm_dma1.channel[index].ccr |= (1 << STM_DMA_CCR_EN);
+}
+
+void
+ao_dma_done_transfer(uint8_t index)
+{
+ stm_dma1.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (--ao_dma_active == 0)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ if (ao_dma_allocated[index])
+ ao_dma_mutex[index] = 0;
+ else
+ ao_mutex_put(&ao_dma_mutex[index]);
+}
+
+void
+ao_dma_alloc(uint8_t index, uint8_t cselr)
+{
+ if (ao_dma_allocated[index])
+ ao_panic(AO_PANIC_DMA);
+ ao_dma_allocated[index] = 1;
+
+ int shift = (index << 2);
+ uint32_t mask = ~(0xf << shift);
+ stm_dma1.cselr = (stm_dma1.cselr & mask) | (cselr << shift);
+}
+
+#if DEBUG
+void
+ao_dma_dump_cmd(void)
+{
+ int i;
+
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (ao_dma_active++ == 0)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+ printf ("isr %08x ifcr%08x\n", stm_dma1.isr, stm_dma1.ifcr);
+ for (i = 0; i < NUM_DMA; i++)
+ printf("%d: done %d allocated %d mutex %2d ccr %04x cndtr %04x cpar %08x cmar %08x isr %08x\n",
+ i,
+ ao_dma_done[i],
+ ao_dma_allocated[i],
+ ao_dma_mutex[i],
+ stm_dma1.channel[i].ccr,
+ stm_dma1.channel[i].cndtr,
+ stm_dma1.channel[i].cpar,
+ stm_dma1.channel[i].cmar,
+ ao_dma_config[i].isr);
+#ifndef LEAVE_DMA_ON
+ ao_arch_critical(
+ if (--ao_dma_active == 0)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
+ );
+#endif
+}
+
+static const struct ao_cmds ao_dma_cmds[] = {
+ { ao_dma_dump_cmd, "D\0Dump DMA status" },
+ { 0, NULL }
+};
+#endif
+
+void
+ao_dma_init(void)
+{
+ int index;
+
+#ifdef LEAVE_DMA_ON
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+#endif
+ for (index = 0; index < STM_NUM_DMA; index++) {
+ stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index);
+ stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index,
+ AO_STM_NVIC_MED_PRIORITY);
+ ao_dma_allocated[index] = 0;
+ ao_dma_mutex[index] = 0;
+ }
+#if DEBUG
+ ao_cmd_register(&ao_dma_cmds[0]);
+#endif
+}
--- /dev/null
+/*
+ * 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; 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_EXTI_H_
+#define _AO_EXTI_H_
+
+#define AO_EXTI_MODE_RISING 1
+#define AO_EXTI_MODE_FALLING 2
+#define AO_EXTI_MODE_PULL_NONE 0
+#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(struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void));
+
+void
+ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode);
+
+void
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void));
+
+void
+ao_exti_enable(struct stm_gpio *gpio, uint8_t pin);
+
+void
+ao_exti_disable(struct stm_gpio *gpio, uint8_t pin);
+
+void
+ao_exti_init(void);
+
+#endif /* _AO_EXTI_H_ */
--- /dev/null
+/*
+ * 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; 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>
+
+static void (*ao_exti_callback[16])(void);
+
+uint32_t ao_last_exti;
+
+static void ao_exti_range_isr(uint8_t first, uint8_t last, uint16_t mask) {
+ uint16_t pending = (ao_last_exti = stm_exti.pr) & mask;
+ uint8_t pin;
+ static uint16_t last_mask;
+ static uint8_t last_pin;
+
+ if (pending == last_mask) {
+ stm_exti.pr = last_mask;
+ (*ao_exti_callback[last_pin])();
+ return;
+ }
+ stm_exti.pr = pending;
+ for (pin = first; pin <= last; pin++)
+ if ((pending & ((uint32_t) 1 << pin)) && ao_exti_callback[pin]) {
+ last_mask = (1 << pin);
+ last_pin = pin;
+ (*ao_exti_callback[pin])();
+ }
+}
+
+void stm_exti1_0_isr(void) { ao_exti_range_isr(0, 1, 0x3); }
+void stm_exti3_2_isr(void) { ao_exti_range_isr(2, 3, 0xc); }
+void stm_exti15_4_isr(void) { ao_exti_range_isr(4, 15, 0xfff0); }
+
+void
+ao_exti_setup (struct stm_gpio *gpio, uint8_t pin, uint8_t mode, void (*callback)(void)) {
+ uint32_t mask = 1 << pin;
+ uint8_t irq;
+ uint8_t prio;
+
+ ao_exti_callback[pin] = callback;
+
+ /* configure gpio to interrupt routing */
+ stm_exticr_set(gpio, pin);
+
+#if 0
+ if (!(mode & AO_EXTI_PIN_NOCONFIGURE)) {
+ uint32_t pupdr;
+ /* 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);
+ }
+#endif
+
+ /* Set interrupt mask and rising/falling mode */
+ stm_exti.imr &= ~mask;
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+
+ if (pin <= 1)
+ irq = STM_ISR_EXTI1_0_POS;
+ else if (2 <= pin && pin <= 3)
+ irq = STM_ISR_EXTI3_2_POS;
+ else
+ irq = STM_ISR_EXTI15_4_POS;
+
+ /* Set priority */
+ prio = AO_STM_NVIC_MED_PRIORITY;
+ if (mode & AO_EXTI_PRIORITY_LOW)
+ prio = AO_STM_NVIC_LOW_PRIORITY;
+ else if (mode & AO_EXTI_PRIORITY_HIGH)
+ prio = AO_STM_NVIC_HIGH_PRIORITY;
+
+ stm_nvic_set_priority(irq, prio);
+ stm_nvic_set_enable(irq);
+}
+
+void
+ao_exti_set_mode(struct stm_gpio *gpio, uint8_t pin, uint8_t mode) {
+ (void) gpio;
+
+ uint32_t mask = 1 << pin;
+
+ if (mode & AO_EXTI_MODE_RISING)
+ stm_exti.rtsr |= mask;
+ else
+ stm_exti.rtsr &= ~mask;
+ if (mode & AO_EXTI_MODE_FALLING)
+ stm_exti.ftsr |= mask;
+ else
+ stm_exti.ftsr &= ~mask;
+}
+
+void
+ao_exti_set_callback(struct stm_gpio *gpio, uint8_t pin, void (*callback)(void)) {
+ (void) gpio;
+ ao_exti_callback[pin] = callback;
+}
+
+void
+ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.pr = mask;
+ stm_exti.imr |= mask;
+}
+
+void
+ao_exti_disable(struct stm_gpio *gpio, uint8_t pin) {
+ uint32_t mask = (1 << pin);
+ (void) gpio;
+ stm_exti.imr &= ~mask;
+ stm_exti.pr = mask;
+}
+
+void
+ao_exti_init(void)
+{
+}
--- /dev/null
+/*
+ * Copyright © 2020 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_FLASH_H_
+#define _AO_FLASH_H_
+
+void
+ao_flash_erase_page(uint32_t *page);
+
+void
+ao_flash_page(uint32_t *page, uint32_t *src);
+
+#endif /* _AO_FLASH_H_ */
--- /dev/null
+/*
+ * Copyright © 2020 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_flash.h>
+
+static uint8_t
+ao_flash_pecr_is_locked(void)
+{
+ return (stm_flash.pecr & (1 << STM_FLASH_PECR_PE_LOCK)) != 0;
+}
+
+static uint8_t
+ao_flash_pgr_is_locked(void)
+{
+ return (stm_flash.pecr & (1 << STM_FLASH_PECR_PRG_LOCK)) != 0;
+}
+
+static void
+ao_flash_pecr_unlock(void)
+{
+ if (!ao_flash_pecr_is_locked())
+ return;
+
+ /* Unlock Data EEPROM and FLASH_PECR register */
+ stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY1;
+ stm_flash.pekeyr = STM_FLASH_PEKEYR_PEKEY2;
+ if (ao_flash_pecr_is_locked())
+ ao_panic(AO_PANIC_FLASH);
+}
+
+static void
+ao_flash_pgr_unlock(void)
+{
+ if (!ao_flash_pgr_is_locked())
+ return;
+
+ /* Unlock program memory */
+ stm_flash.prgkeyr = STM_FLASH_PRGKEYR_PRGKEY1;
+ stm_flash.prgkeyr = STM_FLASH_PRGKEYR_PRGKEY2;
+ if (ao_flash_pgr_is_locked())
+ ao_panic(AO_PANIC_FLASH);
+}
+
+static void
+ao_flash_lock(void)
+{
+ stm_flash.pecr |= (1 << STM_FLASH_PECR_OPT_LOCK) | (1 << STM_FLASH_PECR_PRG_LOCK) | (1 << STM_FLASH_PECR_PE_LOCK);
+}
+
+static void
+ao_flash_wait_bsy(void)
+{
+ while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
+ ;
+}
+
+static void __attribute__ ((section(".sdata2.flash"), noinline))
+_ao_flash_erase_page(uint32_t *page)
+{
+ stm_flash.pecr |= (1 << STM_FLASH_PECR_ERASE) | (1 << STM_FLASH_PECR_PROG);
+
+ *page = 0x00000000;
+
+ ao_flash_wait_bsy();
+}
+
+void
+ao_flash_erase_page(uint32_t *page)
+{
+ ao_arch_block_interrupts();
+ ao_flash_pecr_unlock();
+ ao_flash_pgr_unlock();
+
+ _ao_flash_erase_page(page);
+
+ ao_flash_lock();
+ ao_arch_release_interrupts();
+}
+
+#if 0
+static void __attribute__ ((section(".sdata2.flash"), noinline))
+_ao_flash_half_page(uint32_t *dst, uint32_t *src)
+{
+ uint8_t i;
+
+ stm_flash.pecr |= (1 << STM_FLASH_PECR_FPRG);
+ stm_flash.pecr |= (1 << STM_FLASH_PECR_PROG);
+
+ ao_flash_wait_bsy();
+
+ for (i = 0; i < 32; i++) {
+ *dst++ = *src++;
+ }
+
+ while (stm_flash.sr & (1 << STM_FLASH_SR_BSY))
+ ;
+}
+
+void
+ao_flash_page(uint32_t *page, uint32_t *src)
+{
+ uint8_t h;
+
+ ao_flash_erase_page(page);
+
+ ao_arch_block_interrupts();
+ ao_flash_pecr_unlock();
+ ao_flash_pgr_unlock();
+ for (h = 0; h < 2; h++) {
+ _ao_flash_half_page(page, src);
+ page += 32;
+ src += 32;
+ }
+ ao_flash_lock();
+ ao_arch_release_interrupts();
+}
+#endif
+
+static ao_pos_t write_pos;
+static uint8_t write_pending;
+static union {
+ uint32_t u32;
+ uint8_t u8[4];
+} write_buf;
+
+void
+ao_storage_flush(void)
+{
+ if (write_pending) {
+ ao_flash_pecr_unlock();
+ ao_flash_pgr_unlock();
+ __storage[write_pos] = write_buf.u32;
+ ao_flash_lock();
+ write_pending = 0;
+ }
+}
+
+/* Read data within a storage unit */
+uint8_t
+ao_storage_device_read(ao_pos_t pos, void *buf, uint16_t len)
+{
+ memcpy(buf, ((uint8_t *) __storage) + pos, len);
+ return 1;
+}
+
+static void
+flash_write_select(ao_pos_t pos)
+{
+ /* Flush any pending writes to another word */
+ if (write_pending) {
+ if (pos == write_pos)
+ return;
+ __storage[write_pos] = write_buf.u32;
+ write_pending = 0;
+ }
+ write_pos = pos;
+}
+
+/* Write data within a storage unit */
+uint8_t
+ao_storage_device_write(ao_pos_t pos, void *buf, uint16_t len)
+{
+ uint8_t *b8 = buf;
+
+ ao_flash_pecr_unlock();
+ ao_flash_pgr_unlock();
+ while (len) {
+ ao_pos_t this_pos = pos >> 2;
+
+ flash_write_select(this_pos);
+
+ /* Update write buffer with new contents */
+ int this_word = 4 - (pos & 3);
+ if (this_word > len)
+ this_word = len;
+ memcpy(&write_buf.u8[pos & 3], b8, this_word);
+ pos += this_word;
+ len -= this_word;
+ b8 += this_word;
+
+ /* If we filled the buffer, flush it out */
+ if ((pos & 3) == 0) {
+ __storage[write_pos] = write_buf.u32;
+ } else {
+ write_pending = 1;
+ }
+ }
+ ao_flash_lock();
+ return 1;
+}
+
+bool
+ao_storage_device_is_erased(uint32_t pos)
+{
+ uint8_t *m = ((uint8_t *) __storage) + pos;
+ uint32_t i;
+
+ for (i = 0; i < STM_FLASH_PAGE_SIZE; i++)
+ if (*m++ != AO_STORAGE_ERASED_BYTE)
+ return false;
+ return true;
+}
+
+/* Erase device from pos through pos + ao_storage_block */
+uint8_t
+ao_storage_device_erase(uint32_t pos)
+{
+ ao_flash_erase_page(__storage + (pos >> 2));
+ return 1;
+}
--- /dev/null
+/*
+ * 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; 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 <string.h>
+#include <ao_boot.h>
+
+/* Interrupt functions */
+
+void stm_halt_isr(void)
+{
+ ao_panic(AO_PANIC_CRASH);
+}
+
+void stm_ignore_isr(void)
+{
+}
+
+void _start(void);
+
+#define STRINGIFY(x) #x
+
+#define isr(name) \
+ void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr))
+
+#define isr_halt(name) \
+ void __attribute__ ((weak)) stm_ ## name ## _isr(void); \
+ _Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_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(wwdg)
+isr(pvd)
+isr(rtc)
+isr(flash)
+isr(rcc_crs)
+isr(exti1_0)
+isr(exti3_2)
+isr(exti15_4)
+isr(dma1_channel1)
+isr(dma1_channel3_2)
+isr(dma1_channel7_4)
+isr(adc_comp)
+isr(lptim1)
+isr(usart4_usart5)
+isr(tim2)
+isr(tim3)
+isr(tim4)
+isr(tim6)
+isr(tim7)
+isr(tim21)
+isr(i2c3)
+isr(tim22)
+isr(i2c1)
+isr(i2c2)
+isr(spi1)
+isr(spi2)
+isr(usart1)
+isr(usart2)
+isr(usart3)
+isr(lpuart1_aes)
+
+#define i(addr,name) [(addr)/4] = stm_ ## name ## _isr
+
+extern char __stack[];
+void _start(void) __attribute__((__noreturn__));
+void main(void) __attribute__((__noreturn__));
+
+__attribute__ ((section(".init")))
+const void *const __interrupt_vector[] = {
+ [0] = &__stack,
+ [1] = _start,
+ i(0x08, nmi),
+ i(0x0c, hardfault),
+ i(0x2c, svc),
+ i(0x38, pendsv),
+ i(0x3c, systick),
+ i(0x40, wwdg),
+ i(0x44, pvd),
+ i(0x48, rtc),
+ i(0x4c, flash),
+ i(0x50, rcc_crs),
+ i(0x54, exti1_0),
+ i(0x58, exti3_2),
+ i(0x5c, exti15_4),
+ i(0x64, dma1_channel1),
+ i(0x68, dma1_channel3_2),
+ i(0x6c, dma1_channel7_4),
+ i(0x70, adc_comp),
+ i(0x74, lptim1),
+ i(0x78, usart4_usart5),
+ i(0x7c, tim2),
+ i(0x80, tim3),
+ i(0x84, tim6),
+ i(0x88, tim7),
+ i(0x90, tim21),
+ i(0x94, i2c3),
+ i(0x98, tim22),
+ i(0x9c, i2c1),
+ i(0xa0, i2c2),
+ i(0xa4, spi1),
+ i(0xa8, spi2),
+ i(0xac, usart1),
+ i(0xb0, usart2),
+ i(0xb4, lpuart1_aes),
+};
+
+extern char __data_source[];
+extern char __data_start[];
+extern char __data_size[];
+extern char __bss_start[];
+extern char __bss_size[];
+
+void _start(void)
+{
+#ifdef AO_BOOT_CHAIN
+ if (ao_boot_check_chain()) {
+#ifdef AO_BOOT_PIN
+ if (ao_boot_check_pin())
+#endif
+ {
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+ }
+ }
+#endif
+ memcpy(__data_start, __data_source, (uintptr_t) __data_size);
+ memset(__bss_start, '\0', (uintptr_t) __bss_size);
+
+ main();
+}
--- /dev/null
+/*
+ * Copyright © 2020 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.
+ */
+
+char
+ao_lpuart1_getchar(void);
+
+void
+ao_lpuart1_putchar(char c);
+
+int
+_ao_lpuart1_pollchar(void);
+
+void
+ao_lpuart1_drain(void);
+
+void
+ao_lpuart1_set_speed(uint8_t speed);
+
+void
+ao_lpuart1_enable(void);
+
+void
+ao_lpuart1_disable(void);
--- /dev/null
+/*
+ * Copyright © 2020 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.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+#include <ao_lpuart.h>
+
+struct ao_stm_lpuart {
+ struct ao_fifo rx_fifo;
+ struct ao_fifo tx_fifo;
+ struct stm_lpuart *reg;
+ uint8_t tx_running;
+ uint8_t draining;
+#if HAS_SERIAL_SW_FLOW
+ /* RTS - 0 if we have FIFO space, 1 if not
+ * CTS - 0 if we can send, 0 if not
+ */
+ struct stm_gpio *gpio_rts;
+ struct stm_gpio *gpio_cts;
+ uint8_t pin_rts;
+ uint8_t pin_cts;
+ uint8_t rts;
+#endif
+};
+
+static int
+_ao_lpuart_tx_start(struct ao_stm_lpuart *lpuart)
+{
+ if (!ao_fifo_empty(lpuart->tx_fifo)) {
+#if HAS_LPUART_SW_FLOW
+ if (lpuart->gpio_cts && ao_gpio_get(lpuart->gpio_cts, lpuart->pin_cts) == 1) {
+ ao_exti_enable(lpuart->gpio_cts, lpuart->pin_cts);
+ return 0;
+ }
+#endif
+ if (lpuart->reg->isr & (1 << STM_LPUART_ISR_TXE))
+ {
+ lpuart->tx_running = 1;
+ lpuart->reg->cr1 |= (1 << STM_LPUART_CR1_TXEIE) | (1 << STM_LPUART_CR1_TCIE);
+ ao_fifo_remove(lpuart->tx_fifo, lpuart->reg->tdr);
+ ao_wakeup(&lpuart->tx_fifo);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#if HAS_LPUART_SW_FLOW
+static void
+_ao_lpuart_cts(struct ao_stm_lpuart *lpuart)
+{
+ if (_ao_lpuart_tx_start(lpuart))
+ ao_exti_disable(lpuart->gpio_cts, lpuart->pin_cts);
+}
+#endif
+
+static void
+_ao_lpuart_rx(struct ao_stm_lpuart *lpuart, int is_stdin)
+{
+ if (lpuart->reg->isr & (1 << STM_LPUART_ISR_RXNE)) {
+ lpuart->reg->icr = (1 << STM_LPUART_ICR_ORECF);
+ if (!ao_fifo_full(lpuart->rx_fifo)) {
+ ao_fifo_insert(lpuart->rx_fifo, lpuart->reg->rdr);
+ ao_wakeup(&lpuart->rx_fifo);
+ if (is_stdin)
+ ao_wakeup(&ao_stdin_ready);
+#if HAS_LPUART_SW_FLOW
+ /* If the fifo is nearly full, turn off RTS and wait
+ * for it to drain a bunch
+ */
+ if (lpuart->gpio_rts && ao_fifo_mostly(lpuart->rx_fifo)) {
+ ao_gpio_set(lpuart->gpio_rts, lpuart->pin_rts, 1);
+ lpuart->rts = 0;
+ }
+#endif
+ } else {
+ lpuart->reg->cr1 &= ~(1 << STM_LPUART_CR1_RXNEIE);
+ }
+ }
+}
+
+static void
+ao_lpuart_isr(struct ao_stm_lpuart *lpuart, int is_stdin)
+{
+ _ao_lpuart_rx(lpuart, is_stdin);
+
+ if (!_ao_lpuart_tx_start(lpuart))
+ lpuart->reg->cr1 &= ~(1<< STM_LPUART_CR1_TXEIE);
+
+ if (lpuart->reg->isr & (1 << STM_LPUART_ISR_TC)) {
+ lpuart->tx_running = 0;
+ lpuart->reg->cr1 &= ~(1 << STM_LPUART_CR1_TCIE);
+ if (lpuart->draining) {
+ lpuart->draining = 0;
+ ao_wakeup(&lpuart->tx_fifo);
+ }
+ }
+}
+
+static int
+_ao_lpuart_pollchar(struct ao_stm_lpuart *lpuart)
+{
+ int c;
+
+ if (ao_fifo_empty(lpuart->rx_fifo))
+ c = AO_READ_AGAIN;
+ else {
+ uint8_t u;
+ ao_fifo_remove(lpuart->rx_fifo,u);
+ if ((lpuart->reg->cr1 & (1 << STM_LPUART_CR1_RXNEIE)) == 0) {
+ if (ao_fifo_barely(lpuart->rx_fifo))
+ lpuart->reg->cr1 |= (1 << STM_LPUART_CR1_RXNEIE);
+ }
+#if HAS_LPUART_SW_FLOW
+ /* If we've cleared RTS, check if there's space now and turn it back on */
+ if (lpuart->gpio_rts && lpuart->rts == 0 && ao_fifo_barely(lpuart->rx_fifo)) {
+ ao_gpio_set(lpuart->gpio_rts, lpuart->pin_rts, 0);
+ lpuart->rts = 1;
+ }
+#endif
+ c = u;
+ }
+ return c;
+}
+
+static char
+ao_lpuart_getchar(struct ao_stm_lpuart *lpuart)
+{
+ int c;
+ ao_arch_block_interrupts();
+ while ((c = _ao_lpuart_pollchar(lpuart)) == AO_READ_AGAIN)
+ ao_sleep(&lpuart->rx_fifo);
+ ao_arch_release_interrupts();
+ return (char) c;
+}
+
+#if 0
+static inline uint8_t
+_ao_lpuart_sleep_for(struct ao_stm_lpuart *lpuart, uint16_t timeout)
+{
+ return ao_sleep_for(&lpuart->rx_fifo, timeout);
+}
+#endif
+
+static void
+ao_lpuart_putchar(struct ao_stm_lpuart *lpuart, char c)
+{
+ ao_arch_block_interrupts();
+ while (ao_fifo_full(lpuart->tx_fifo))
+ ao_sleep(&lpuart->tx_fifo);
+ ao_fifo_insert(lpuart->tx_fifo, c);
+ _ao_lpuart_tx_start(lpuart);
+ ao_arch_release_interrupts();
+}
+
+static void
+ao_lpuart_drain(struct ao_stm_lpuart *lpuart)
+{
+ ao_arch_block_interrupts();
+ while (!ao_fifo_empty(lpuart->tx_fifo) || lpuart->tx_running) {
+ lpuart->draining = 1;
+ ao_sleep(&lpuart->tx_fifo);
+ }
+ ao_arch_release_interrupts();
+}
+
+extern const uint32_t ao_usart_speeds[];
+
+static void
+ao_lpuart_set_speed(struct ao_stm_lpuart *lpuart, uint8_t speed)
+{
+ if (speed > AO_SERIAL_SPEED_115200)
+ return;
+ lpuart->reg->brr = 256 * AO_PCLK1 / ao_usart_speeds[speed];
+}
+
+static void
+ao_lpuart_enable(struct ao_stm_lpuart *lpuart, int hw_flow)
+{
+ lpuart->reg->cr1 = ((0 << STM_LPUART_CR1_M1) |
+ (0 << STM_LPUART_CR1_DEAT) |
+ (0 << STM_LPUART_CR1_DEDT) |
+ (0 << STM_LPUART_CR1_CMIE) |
+ (0 << STM_LPUART_CR1_MME) |
+ (0 << STM_LPUART_CR1_M0) |
+ (0 << STM_LPUART_CR1_WAKE) |
+ (0 << STM_LPUART_CR1_PCE) |
+ (0 << STM_LPUART_CR1_PS) |
+ (0 << STM_LPUART_CR1_PEIE) |
+ (0 << STM_LPUART_CR1_TXEIE) |
+ (0 << STM_LPUART_CR1_TCIE) |
+ (1 << STM_LPUART_CR1_RXNEIE) |
+ (0 << STM_LPUART_CR1_IDLEIE) |
+ (1 << STM_LPUART_CR1_TE) |
+ (1 << STM_LPUART_CR1_RE) |
+ (0 << STM_LPUART_CR1_UESM) |
+ (0 << STM_LPUART_CR1_UE));
+
+ lpuart->reg->cr2 = ((0 << STM_LPUART_CR2_ADD) |
+ (0 << STM_LPUART_CR2_MSBFIRST) |
+ (0 << STM_LPUART_CR2_DATAINV) |
+ (0 << STM_LPUART_CR2_TXINV) |
+ (0 << STM_LPUART_CR2_RXINV) |
+ (0 << STM_LPUART_CR2_SWAP) |
+ (0 << STM_LPUART_CR2_STOP) |
+ (0 << STM_LPUART_CR2_ADDM7));
+
+ uint32_t cr3 = ((0 << STM_LPUART_CR3_UCESM) |
+ (0 << STM_LPUART_CR3_WUFIE) |
+ (0 << STM_LPUART_CR3_WUS) |
+ (0 << STM_LPUART_CR3_DEP) |
+ (0 << STM_LPUART_CR3_DEM) |
+ (0 << STM_LPUART_CR3_DDRE) |
+ (0 << STM_LPUART_CR3_OVRDIS) |
+ (0 << STM_LPUART_CR3_CTSIE) |
+ (0 << STM_LPUART_CR3_CTSE) |
+ (0 << STM_LPUART_CR3_RTSE) |
+ (0 << STM_LPUART_CR3_DMAT) |
+ (0 << STM_LPUART_CR3_DMAR) |
+ (0 << STM_LPUART_CR3_HDSEL) |
+ (0 << STM_LPUART_CR3_EIE));
+
+ if (hw_flow)
+ cr3 |= ((1 << STM_LPUART_CR3_CTSE) |
+ (1 << STM_LPUART_CR3_RTSE));
+
+ lpuart->reg->cr3 = cr3;
+
+ /* Pick a 9600 baud rate */
+ ao_lpuart_set_speed(lpuart, AO_SERIAL_SPEED_9600);
+
+ /* Enable the lpuart */
+ lpuart->reg->cr1 |= (1 << STM_LPUART_CR1_UE);
+}
+
+static void
+ao_lpuart_disable(struct ao_stm_lpuart *lpuart)
+{
+ ao_lpuart_drain(lpuart);
+ lpuart->reg->cr1 = 0;
+}
+
+#if HAS_LPUART_1
+
+struct ao_stm_lpuart ao_stm_lpuart1;
+
+void stm_lpuart1_aes_isr(void) {
+ ao_lpuart_isr(&ao_stm_lpuart1, USE_LPUART_1_STDIN);
+}
+
+char
+ao_lpuart1_getchar(void)
+{
+ return ao_lpuart_getchar(&ao_stm_lpuart1);
+}
+
+void
+ao_lpuart1_putchar(char c)
+{
+ ao_lpuart_putchar(&ao_stm_lpuart1, c);
+}
+
+int
+_ao_lpuart1_pollchar(void)
+{
+ return _ao_lpuart_pollchar(&ao_stm_lpuart1);
+}
+
+void
+ao_lpuart1_drain(void)
+{
+ ao_lpuart_drain(&ao_stm_lpuart1);
+}
+
+void
+ao_lpuart1_set_speed(uint8_t speed)
+{
+ ao_lpuart_drain(&ao_stm_lpuart1);
+ ao_lpuart_set_speed(&ao_stm_lpuart1, speed);
+}
+
+#endif /* HAS_LPUART_1 */
+
+#if HAS_LPUART_SW_FLOW
+static void
+ao_lpuart_set_sw_rts_cts(struct ao_stm_lpuart *lpuart,
+ void (*isr)(void),
+ struct stm_gpio *port_rts,
+ int pin_rts,
+ struct stm_gpio *port_cts,
+ int pin_cts)
+{
+ /* Pull RTS low to note that there's space in the FIFO
+ */
+ ao_enable_output(port_rts, pin_rts, 0);
+ lpuart->gpio_rts = port_rts;
+ lpuart->pin_rts = pin_rts;
+ lpuart->rts = 1;
+
+ ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
+ lpuart->gpio_cts = port_cts;
+ lpuart->pin_cts = pin_cts;
+}
+#endif
+
+void
+ao_lpuart1_enable(void)
+{
+ /*
+ * TX RX
+ * PA1 PA0
+ * PA2 PA3
+ * PA4 PA3
+ * PA14 PA13
+ * PB6 PB7
+ */
+
+#ifdef HAS_LPUART_1
+ /* Clock source defaults to PCLK1, so just leave it */
+
+# if LPUART_1_PA0_PA1
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 0, STM_AFR_AF6);
+ stm_afr_set(&stm_gpioa, 1, STM_AFR_AF6);
+# else
+# error "No LPUART_1 port configuration specified"
+# endif
+ /* Enable LPUART */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_LPUART1EN);
+
+ ao_stm_lpuart1.reg = &stm_lpuart1;
+ ao_lpuart_enable(&ao_stm_lpuart1, USE_LPUART_1_FLOW && !USE_LPUART_1_SW_FLOW);
+
+ stm_nvic_set_enable(STM_ISR_LPUART1_AES_POS);
+ stm_nvic_set_priority(STM_ISR_LPUART1_AES_POS, 4);
+# if USE_LPUART_1_STDIN && !DELAY_LPUART_1_STDIN
+ ao_add_stdio(_ao_lpuart1_pollchar,
+ ao_lpuart1_putchar,
+ NULL);
+# endif
+#endif
+}
+
+void
+ao_lpuart1_disable(void)
+{
+ /* Stop LPUART */
+ ao_lpuart_disable(&ao_stm_lpuart1);
+
+ /* Disable interrupts */
+ stm_nvic_clear_enable(STM_ISR_LPUART1_AES_POS);
+
+ /* Remap pins to GPIO use */
+# if LPUART_1_PA0_PA1
+ stm_moder_set(&stm_gpioa, 0, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 1, STM_MODER_OUTPUT);
+# else
+# error "No LPUART_1 port configuration specified"
+# endif
+
+ /* Disable LPUART */
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_LPUART1EN);
+}
+
--- /dev/null
+/*
+ * Copyright © 2015 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_pwm.h"
+
+static uint8_t pwm_running;
+
+static uint16_t pwm_value[NUM_PWM];
+
+static void
+ao_pwm_up(void)
+{
+ if (pwm_running++ == 0) {
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ tim->ccr1 = 0;
+ tim->ccr2 = 0;
+ tim->ccr3 = 0;
+ tim->ccr4 = 0;
+ tim->arr = PWM_MAX - 1; /* turn on the timer */
+ tim->cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+ (0 << STM_TIM234_CR1_ARPE) |
+ (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+ (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+ (0 << STM_TIM234_CR1_OPM) |
+ (0 << STM_TIM234_CR1_URS) |
+ (0 << STM_TIM234_CR1_UDIS) |
+ (1 << STM_TIM234_CR1_CEN));
+
+ /* Set the timer running */
+ tim->egr = (1 << STM_TIM234_EGR_UG);
+ }
+}
+
+static void
+ao_pwm_down(void)
+{
+ if (--pwm_running == 0) {
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ tim->arr = 0;
+ tim->cr1 = ((STM_TIM234_CR1_CKD_1 << STM_TIM234_CR1_CKD) |
+ (0 << STM_TIM234_CR1_ARPE) |
+ (STM_TIM234_CR1_CMS_EDGE << STM_TIM234_CR1_CMS) |
+ (STM_TIM234_CR1_DIR_UP << STM_TIM234_CR1_DIR) |
+ (0 << STM_TIM234_CR1_OPM) |
+ (0 << STM_TIM234_CR1_URS) |
+ (0 << STM_TIM234_CR1_UDIS) |
+ (0 << STM_TIM234_CR1_CEN));
+
+ /* Stop the timer */
+ tim->egr = (1 << STM_TIM234_EGR_UG);
+ }
+}
+
+void
+ao_pwm_set(uint8_t pwm, uint16_t value)
+{
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ if (value > PWM_MAX)
+ value = PWM_MAX;
+ if (value != 0) {
+ if (pwm_value[pwm] == 0)
+ ao_pwm_up();
+ }
+ switch (pwm) {
+ case 0:
+ tim->ccr1 = value;
+ break;
+ case 1:
+ tim->ccr2 = value;
+ break;
+ case 2:
+ tim->ccr3 = value;
+ break;
+ case 3:
+ tim->ccr4 = value;
+ break;
+ }
+ if (value == 0) {
+ if (pwm_value[pwm] != 0)
+ ao_pwm_down();
+ }
+ pwm_value[pwm] = value;
+}
+
+static void
+ao_pwm_cmd(void)
+{
+ uint8_t ch;
+ uint16_t val;
+
+ ch = ao_cmd_decimal();
+ val = ao_cmd_decimal();
+ if (ao_cmd_status != ao_cmd_success)
+ return;
+
+ printf("Set channel %d to %d\n", ch, val);
+ ao_pwm_set(ch, val);
+}
+
+static const struct ao_cmds ao_pwm_cmds[] = {
+ { ao_pwm_cmd, "P <ch> <val>\0Set PWM ch to val" },
+ { 0, NULL },
+};
+
+void
+ao_pwm_init(void)
+{
+ struct stm_tim234 *tim = &AO_PWM_TIMER;
+
+ stm_rcc.apb1enr |= (1 << AO_PWM_TIMER_ENABLE);
+
+ tim->cr1 = 0;
+ tim->psc = AO_PWM_TIMER_SCALE - 1;
+ tim->cnt = 0;
+ tim->ccer = ((1 << STM_TIM234_CCER_CC1E) |
+ (0 << STM_TIM234_CCER_CC1P) |
+ (1 << STM_TIM234_CCER_CC2E) |
+ (0 << STM_TIM234_CCER_CC2P) |
+ (1 << STM_TIM234_CCER_CC3E) |
+ (0 << STM_TIM234_CCER_CC3P) |
+ (1 << STM_TIM234_CCER_CC4E) |
+ (0 << STM_TIM234_CCER_CC4P));
+
+ tim->ccmr1 = ((0 << STM_TIM234_CCMR1_OC2CE) |
+ (STM_TIM234_CCMR1_OC2M_PWM_MODE_1 << STM_TIM234_CCMR1_OC2M) |
+ (0 << STM_TIM234_CCMR1_OC2PE) |
+ (0 << STM_TIM234_CCMR1_OC2FE) |
+ (STM_TIM234_CCMR1_CC2S_OUTPUT << STM_TIM234_CCMR1_CC2S) |
+
+ (0 << STM_TIM234_CCMR1_OC1CE) |
+ (STM_TIM234_CCMR1_OC1M_PWM_MODE_1 << STM_TIM234_CCMR1_OC1M) |
+ (0 << STM_TIM234_CCMR1_OC1PE) |
+ (0 << STM_TIM234_CCMR1_OC1FE) |
+ (STM_TIM234_CCMR1_CC1S_OUTPUT << STM_TIM234_CCMR1_CC1S));
+
+
+ tim->ccmr2 = ((0 << STM_TIM234_CCMR2_OC4CE) |
+ (STM_TIM234_CCMR2_OC4M_PWM_MODE_1 << STM_TIM234_CCMR2_OC4M) |
+ (0 << STM_TIM234_CCMR2_OC4PE) |
+ (0 << STM_TIM234_CCMR2_OC4FE) |
+ (STM_TIM234_CCMR2_CC4S_OUTPUT << STM_TIM234_CCMR2_CC4S) |
+
+ (0 << STM_TIM234_CCMR2_OC3CE) |
+ (STM_TIM234_CCMR2_OC3M_PWM_MODE_1 << STM_TIM234_CCMR2_OC3M) |
+ (0 << STM_TIM234_CCMR2_OC3PE) |
+ (0 << STM_TIM234_CCMR2_OC3FE) |
+ (STM_TIM234_CCMR2_CC3S_OUTPUT << STM_TIM234_CCMR2_CC3S));
+ tim->egr = 0;
+
+ tim->sr = 0;
+ tim->dier = 0;
+ tim->smcr = 0;
+ tim->cr2 = ((0 << STM_TIM234_CR2_TI1S) |
+ (STM_TIM234_CR2_MMS_RESET<< STM_TIM234_CR2_MMS) |
+ (0 << STM_TIM234_CR2_CCDS));
+
+ stm_afr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_0_GPIO, AO_PWM_0_PIN, STM_OSPEEDR_40MHz);
+#if NUM_PWM > 1
+ stm_afr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_1_GPIO, AO_PWM_1_PIN, STM_OSPEEDR_40MHz);
+#endif
+#if NUM_PWM > 2
+ stm_afr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_2_GPIO, AO_PWM_2_PIN, STM_OSPEEDR_40MHz);
+#endif
+#if NUM_PWM > 3
+ stm_afr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_AFR_AF2);
+ stm_ospeedr_set(AO_PWM_3_GPIO, AO_PWM_3_PIN, STM_OSPEEDR_40MHz);
+#endif
+ ao_cmd_register(&ao_pwm_cmds[0]);
+}
--- /dev/null
+/*
+ * Copyright © 2020 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.
+ */
+
+#include <ao.h>
+#include <ao_exti.h>
+
+static int
+_ao_usart_tx_start(struct ao_stm_usart *usart)
+{
+ if (!ao_fifo_empty(usart->tx_fifo)) {
+#if HAS_SERIAL_SW_FLOW
+ if (usart->gpio_cts && ao_gpio_get(usart->gpio_cts, usart->pin_cts) == 1) {
+ ao_exti_enable(usart->gpio_cts, usart->pin_cts);
+ return 0;
+ }
+#endif
+ if (usart->reg->isr & (1 << STM_USART_ISR_TXE))
+ {
+ usart->tx_running = 1;
+ usart->reg->cr1 |= (1 << STM_USART_CR1_TXEIE) | (1 << STM_USART_CR1_TCIE);
+ ao_fifo_remove(usart->tx_fifo, usart->reg->tdr);
+ ao_wakeup(&usart->tx_fifo);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#if HAS_SERIAL_SW_FLOW
+static void
+_ao_usart_cts(struct ao_stm_usart *usart)
+{
+ if (_ao_usart_tx_start(usart))
+ ao_exti_disable(usart->gpio_cts, usart->pin_cts);
+}
+#endif
+
+static void
+_ao_usart_rx(struct ao_stm_usart *usart, int is_stdin)
+{
+ if (usart->reg->isr & (1 << STM_USART_ISR_RXNE)) {
+ usart->reg->icr = (1 << STM_USART_ICR_ORECF);
+ if (!ao_fifo_full(usart->rx_fifo)) {
+ ao_fifo_insert(usart->rx_fifo, usart->reg->rdr);
+ ao_wakeup(&usart->rx_fifo);
+ if (is_stdin)
+ ao_wakeup(&ao_stdin_ready);
+#if HAS_SERIAL_SW_FLOW
+ /* If the fifo is nearly full, turn off RTS and wait
+ * for it to drain a bunch
+ */
+ if (usart->gpio_rts && ao_fifo_mostly(usart->rx_fifo)) {
+ ao_gpio_set(usart->gpio_rts, usart->pin_rts, 1);
+ usart->rts = 0;
+ }
+#endif
+ } else {
+ usart->reg->cr1 &= ~(1 << STM_USART_CR1_RXNEIE);
+ }
+ }
+}
+
+static void
+ao_usart_isr(struct ao_stm_usart *usart, int is_stdin)
+{
+ _ao_usart_rx(usart, is_stdin);
+
+ if (!_ao_usart_tx_start(usart))
+ usart->reg->cr1 &= ~(1<< STM_USART_CR1_TXEIE);
+
+ if (usart->reg->isr & (1 << STM_USART_ISR_TC)) {
+ usart->tx_running = 0;
+ usart->reg->cr1 &= ~(1 << STM_USART_CR1_TCIE);
+ if (usart->draining) {
+ usart->draining = 0;
+ ao_wakeup(&usart->tx_fifo);
+ }
+ }
+}
+
+static int
+_ao_usart_pollchar(struct ao_stm_usart *usart)
+{
+ int c;
+
+ if (ao_fifo_empty(usart->rx_fifo))
+ c = AO_READ_AGAIN;
+ else {
+ uint8_t u;
+ ao_fifo_remove(usart->rx_fifo,u);
+ if ((usart->reg->cr1 & (1 << STM_USART_CR1_RXNEIE)) == 0) {
+ if (ao_fifo_barely(usart->rx_fifo))
+ usart->reg->cr1 |= (1 << STM_USART_CR1_RXNEIE);
+ }
+#if HAS_SERIAL_SW_FLOW
+ /* If we've cleared RTS, check if there's space now and turn it back on */
+ if (usart->gpio_rts && usart->rts == 0 && ao_fifo_barely(usart->rx_fifo)) {
+ ao_gpio_set(usart->gpio_rts, usart->pin_rts, 0);
+ usart->rts = 1;
+ }
+#endif
+ c = u;
+ }
+ return c;
+}
+
+static char
+ao_usart_getchar(struct ao_stm_usart *usart)
+{
+ int c;
+ ao_arch_block_interrupts();
+ while ((c = _ao_usart_pollchar(usart)) == AO_READ_AGAIN)
+ ao_sleep(&usart->rx_fifo);
+ ao_arch_release_interrupts();
+ return (char) c;
+}
+
+#if 0
+static inline uint8_t
+_ao_usart_sleep_for(struct ao_stm_usart *usart, uint16_t timeout)
+{
+ return ao_sleep_for(&usart->rx_fifo, timeout);
+}
+#endif
+
+static void
+ao_usart_putchar(struct ao_stm_usart *usart, char c)
+{
+ ao_arch_block_interrupts();
+ while (ao_fifo_full(usart->tx_fifo))
+ ao_sleep(&usart->tx_fifo);
+ ao_fifo_insert(usart->tx_fifo, c);
+ _ao_usart_tx_start(usart);
+ ao_arch_release_interrupts();
+}
+
+#if 0
+static void
+ao_usart_drain(struct ao_stm_usart *usart)
+{
+ ao_arch_block_interrupts();
+ while (!ao_fifo_empty(usart->tx_fifo) || usart->tx_running) {
+ usart->draining = 1;
+ ao_sleep(&usart->tx_fifo);
+ }
+ ao_arch_release_interrupts();
+}
+#endif
+
+const uint32_t ao_usart_speeds[] = {
+ [AO_SERIAL_SPEED_4800] = 4800,
+ [AO_SERIAL_SPEED_9600] = 9600,
+ [AO_SERIAL_SPEED_19200] = 19200,
+ [AO_SERIAL_SPEED_57600] = 57600,
+ [AO_SERIAL_SPEED_115200] = 115200,
+};
+
+static void
+ao_usart_set_speed(struct ao_stm_usart *usart, uint8_t speed)
+{
+ if (speed > AO_SERIAL_SPEED_115200)
+ return;
+ usart->reg->brr = AO_PCLK2 / ao_usart_speeds[speed];
+}
+
+static void
+ao_usart_init(struct ao_stm_usart *usart, int hw_flow)
+{
+ usart->reg->cr1 = ((0 << STM_USART_CR1_M1) |
+ (0 << STM_USART_CR1_EOBIE) |
+ (0 << STM_USART_CR1_RTOIE) |
+ (0 << STM_USART_CR1_DEAT) |
+ (0 << STM_USART_CR1_DEDT) |
+ (0 << STM_USART_CR1_OVER8) |
+ (0 << STM_USART_CR1_CMIE) |
+ (0 << STM_USART_CR1_MME) |
+ (0 << STM_USART_CR1_M0) |
+ (0 << STM_USART_CR1_WAKE) |
+ (0 << STM_USART_CR1_PCE) |
+ (0 << STM_USART_CR1_PS) |
+ (0 << STM_USART_CR1_PEIE) |
+ (0 << STM_USART_CR1_TXEIE) |
+ (0 << STM_USART_CR1_TCIE) |
+ (1 << STM_USART_CR1_RXNEIE) |
+ (0 << STM_USART_CR1_IDLEIE) |
+ (1 << STM_USART_CR1_TE) |
+ (1 << STM_USART_CR1_RE) |
+ (0 << STM_USART_CR1_UESM) |
+ (0 << STM_USART_CR1_UE));
+
+ usart->reg->cr2 = ((0 << STM_USART_CR2_ADD) |
+ (0 << STM_USART_CR2_RTOEN) |
+ (0 << STM_USART_CR2_ABRMOD) |
+ (0 << STM_USART_CR2_ABREN) |
+ (0 << STM_USART_CR2_MSBFIRST) |
+ (0 << STM_USART_CR2_DATAINV) |
+ (0 << STM_USART_CR2_TXINV) |
+ (0 << STM_USART_CR2_RXINV) |
+ (0 << STM_USART_CR2_SWAP) |
+ (0 << STM_USART_CR2_LINEN) |
+ (0 << STM_USART_CR2_STOP) |
+ (0 << STM_USART_CR2_CLKEN) |
+ (0 << STM_USART_CR2_CPOL) |
+ (0 << STM_USART_CR2_CHPA) |
+ (0 << STM_USART_CR2_LBCL) |
+ (0 << STM_USART_CR2_LBDIE) |
+ (0 << STM_USART_CR2_LBDL) |
+ (0 << STM_USART_CR2_ADDM7));
+
+ uint32_t cr3 = ((0 << STM_USART_CR3_WUFIE) |
+ (0 << STM_USART_CR3_WUS) |
+ (0 << STM_USART_CR3_SCARCNT) |
+ (0 << STM_USART_CR3_DEP) |
+ (0 << STM_USART_CR3_DEM) |
+ (0 << STM_USART_CR3_DDRE) |
+ (0 << STM_USART_CR3_OVRDIS) |
+ (0 << STM_USART_CR3_ONEBIT) |
+ (0 << STM_USART_CR3_CTIIE) |
+ (0 << STM_USART_CR3_CTSE) |
+ (0 << STM_USART_CR3_RTSE) |
+ (0 << STM_USART_CR3_DMAT) |
+ (0 << STM_USART_CR3_DMAR) |
+ (0 << STM_USART_CR3_SCEN) |
+ (0 << STM_USART_CR3_NACK) |
+ (0 << STM_USART_CR3_HDSEL) |
+ (0 << STM_USART_CR3_IRLP) |
+ (0 << STM_USART_CR3_IREN) |
+ (0 << STM_USART_CR3_EIE));
+
+ if (hw_flow)
+ cr3 |= ((1 << STM_USART_CR3_CTSE) |
+ (1 << STM_USART_CR3_RTSE));
+
+ usart->reg->cr3 = cr3;
+
+ /* Pick a 9600 baud rate */
+ ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);
+
+ /* Enable the usart */
+ usart->reg->cr1 |= (1 << STM_USART_CR1_UE);
+}
+
+#if HAS_SERIAL_1
+
+struct ao_stm_usart ao_stm_usart1;
+
+void stm_usart1_isr(void) { ao_usart_isr(&ao_stm_usart1, USE_SERIAL_1_STDIN); }
+
+char
+ao_serial1_getchar(void)
+{
+ return ao_usart_getchar(&ao_stm_usart1);
+}
+
+void
+ao_serial1_putchar(char c)
+{
+ ao_usart_putchar(&ao_stm_usart1, c);
+}
+
+int
+_ao_serial1_pollchar(void)
+{
+ return _ao_usart_pollchar(&ao_stm_usart1);
+}
+
+#if 0
+uint8_t
+_ao_serial1_sleep_for(uint16_t timeout)
+{
+ return _ao_usart_sleep_for(&ao_stm_usart1, timeout);
+}
+#endif
+
+#if 0
+void
+ao_serial1_drain(void)
+{
+ ao_usart_drain(&ao_stm_usart1);
+}
+
+void
+ao_serial1_set_speed(uint8_t speed)
+{
+ ao_usart_drain(&ao_stm_usart1);
+ ao_usart_set_speed(&ao_stm_usart1, speed);
+}
+#endif
+#endif /* HAS_SERIAL_1 */
+
+#if HAS_SERIAL_2
+
+struct ao_stm_usart ao_stm_usart2;
+
+void stm_usart2_isr(void) { ao_usart_isr(&ao_stm_usart2, USE_SERIAL_2_STDIN); }
+
+char
+ao_serial2_getchar(void)
+{
+ return ao_usart_getchar(&ao_stm_usart2);
+}
+
+void
+ao_serial2_putchar(char c)
+{
+ ao_usart_putchar(&ao_stm_usart2, c);
+}
+
+int
+_ao_serial2_pollchar(void)
+{
+ return _ao_usart_pollchar(&ao_stm_usart2);
+}
+
+#if 0
+uint8_t
+_ao_serial2_sleep_for(uint16_t timeout)
+{
+ return _ao_usart_sleep_for(&ao_stm_usart2, timeout);
+}
+
+void
+ao_serial2_drain(void)
+{
+ ao_usart_drain(&ao_stm_usart2);
+}
+
+void
+ao_serial2_set_speed(uint8_t speed)
+{
+ ao_usart_drain(&ao_stm_usart2);
+ ao_usart_set_speed(&ao_stm_usart2, speed);
+}
+#endif
+
+#if USE_SERIAL_2_FLOW && USE_SERIAL_2_SW_FLOW
+void
+ao_serial2_cts(void)
+{
+ _ao_usart_cts(&ao_stm_usart2);
+}
+#endif
+
+#endif /* HAS_SERIAL_2 */
+
+#if HAS_SERIAL_SW_FLOW
+static void
+ao_serial_set_sw_rts_cts(struct ao_stm_usart *usart,
+ void (*isr)(void),
+ struct stm_gpio *port_rts,
+ int pin_rts,
+ struct stm_gpio *port_cts,
+ int pin_cts)
+{
+ /* Pull RTS low to note that there's space in the FIFO
+ */
+ ao_enable_output(port_rts, pin_rts, 0);
+ usart->gpio_rts = port_rts;
+ usart->pin_rts = pin_rts;
+ usart->rts = 1;
+
+ ao_exti_setup(port_cts, pin_cts, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_MED, isr);
+ usart->gpio_cts = port_cts;
+ usart->pin_cts = pin_cts;
+}
+#endif
+
+#if 0
+void
+ao_serial_shutdown(void)
+{
+# if SERIAL_2_PA2_PA3
+ stm_moder_set(&stm_gpioa, 2, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 3, STM_MODER_INPUT);
+# elif SERIAL_2_PA9_PA10
+ stm_moder_set(&stm_gpioa, 9, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 10, STM_MODER_INPUT);
+# elif SERIAL_2_PA14_PA15
+ stm_moder_set(&stm_gpioa, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 15, STM_MODER_INPUT);
+# elif SERIAL_2_PB6_PB7
+ stm_moder_set(&stm_gpiob, 6, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 7, STM_MODER_INPUT);
+#endif
+#if HAS_SERIAL_1
+ stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_USART1EN);
+#endif
+#if HAS_SERIAL_2
+ stm_nvic_set_disable(STM_ISR_USART2_POS);
+ stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USART2EN);
+#endif
+}
+#endif
+
+void
+ao_serial_init(void)
+{
+#if HAS_SERIAL_1
+#endif
+
+#if HAS_SERIAL_2
+ /*
+ * TX RX
+ * PA2 PA3
+ * PA9 PA10
+ * PA14 PA15
+ * PB6 PB7
+ */
+
+# if SERIAL_2_PA2_PA3
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 2, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 3, STM_AFR_AF4);
+# elif SERIAL_2_PA9_PA10
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 9, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 10, STM_AFR_AF4);
+# elif SERIAL_2_PA14_PA15
+ ao_enable_port(&stm_gpioa);
+ stm_afr_set(&stm_gpioa, 14, STM_AFR_AF4);
+ stm_afr_set(&stm_gpioa, 15, STM_AFR_AF4);
+# elif SERIAL_2_PB6_PB7
+ ao_enable_port(&stm_gpiob);
+ stm_afr_set(&stm_gpiob, 6, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 7, STM_AFR_AF0);
+# else
+# error "No SERIAL_2 port configuration specified"
+# endif
+ /* Enable USART */
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);
+
+ ao_stm_usart2.reg = &stm_usart2;
+ ao_usart_init(&ao_stm_usart2, USE_SERIAL_2_FLOW && !USE_SERIAL_2_SW_FLOW);
+
+ stm_nvic_set_enable(STM_ISR_USART2_POS);
+ stm_nvic_set_priority(STM_ISR_USART2_POS, 4);
+# if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN
+ ao_add_stdio(_ao_serial2_pollchar,
+ ao_serial2_putchar,
+ NULL);
+# endif
+#endif
+}
--- /dev/null
+/*
+ * Copyright © 2020 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>
+
+static uint8_t ao_spi_mutex;
+static uint8_t ao_spi_pin_config;
+
+#define AO_DMA_SPI1_RX_INDEX STM_DMA_INDEX(2)
+#define AO_DMA_SPI1_RX_CSELR STM_DMA_CSELR_C2S_SPI1_RX
+#define AO_DMA_SPI1_TX_INDEX STM_DMA_INDEX(3)
+#define AO_DMA_SPI1_TX_CSELR STM_DMA_CSELR_C3S_SPI1_TX
+
+#if 0
+static uint8_t spi_dev_null;
+
+static void
+ao_spi_set_dma_mosi(uint8_t id, const void *data, uint16_t len, uint32_t minc)
+{
+ (void) id;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ ao_dma_set_transfer(AO_DMA_SPI1_TX_INDEX,
+ &stm_spi->dr,
+ (void *) data,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (minc << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+}
+
+static void
+ao_spi_set_dma_miso(uint8_t id, void *data, uint16_t len, uint32_t minc)
+{
+ (void) id;
+ uint8_t miso_dma_index = STM_DMA_INDEX(2);
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ ao_dma_set_transfer(miso_dma_index,
+ &stm_spi->dr,
+ data,
+ len,
+ (0 << STM_DMA_CCR_MEM2MEM) |
+ (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) |
+ (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+ (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+ (minc << STM_DMA_CCR_MINC) |
+ (0 << STM_DMA_CCR_PINC) |
+ (0 << STM_DMA_CCR_CIRC) |
+ (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+}
+
+static void
+ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
+{
+ (void) id;
+ uint8_t mosi_dma_index = STM_DMA_INDEX(3);
+ uint8_t miso_dma_index = STM_DMA_INDEX(2);
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (1 << STM_SPI_CR2_TXDMAEN) |
+ (1 << STM_SPI_CR2_RXDMAEN));
+
+ ao_dma_start(miso_dma_index);
+ ao_dma_start(mosi_dma_index);
+
+ ao_arch_critical(
+ while (!ao_dma_done[miso_dma_index])
+ ao_sleep(&ao_dma_done[miso_dma_index]);
+ );
+
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
+
+ stm_spi->cr2 = 0;
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+#endif
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+{
+ (void) spi_index;
+#if 0
+ /* Set up the transmit DMA to deliver data */
+ ao_spi_set_dma_mosi(id, block, len, 1);
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+ ao_spi_run(id, 1, len);
+#else
+ const uint8_t *bytes = block;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ while (len--) {
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+ stm_spi->dr = *bytes++;
+ while ((stm_spi->sr & (1 << STM_SPI_SR_RXNE)) == 0);
+ (void) stm_spi->dr;
+ }
+#endif
+}
+
+#if 0
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ /* Set up the transmit DMA to deliver data */
+ ao_spi_set_dma_mosi(id, &value, len, 0);
+
+ /* Set up the receive DMA -- when this is done, we know the SPI unit
+ * is idle. Without this, we'd have to poll waiting for the BSY bit to
+ * be cleared
+ */
+ ao_spi_set_dma_miso(id, &spi_dev_null, len, 0);
+
+ ao_spi_run(id, 3, len);
+}
+
+void
+ao_spi_start_bytes(uint8_t spi_index)
+{
+ (void) spi_index;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+}
+
+void
+ao_spi_stop_bytes(uint8_t spi_index)
+{
+ (void) spi_index;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ;
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+ ;
+ /* Clear the OVR flag */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+ stm_spi->cr2 = 0;
+}
+
+void
+ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
+{
+ (void) spi_index;
+ const uint8_t *b = block;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+ while (len--) {
+ while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
+ stm_spi->dr = *b++;
+ }
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ;
+ while (stm_spi->sr & (1 << STM_SPI_SR_BSY))
+ ;
+ /* Clear the OVR flag */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+}
+#endif
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+ (void) spi_index;
+#if 0
+
+ spi_dev_null = 0xff;
+
+ /* Set up transmit DMA to make the SPI hardware actually run */
+ ao_spi_set_dma_mosi(id, &spi_dev_null, len, 0);
+
+ /* Set up the receive DMA to capture data */
+ ao_spi_set_dma_miso(id, block, len, 1);
+
+ ao_spi_run(id, 9, len);
+#else
+ uint8_t *bytes = block;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ while (len--) {
+ while ((stm_spi->sr & (1 << STM_SPI_SR_TXE)) == 0);
+ stm_spi->dr = 0xff;
+ while ((stm_spi->sr & (1 << STM_SPI_SR_RXNE)) == 0);
+ *bytes++ = stm_spi->dr;
+ }
+#endif
+}
+
+#if 0
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ /* Set up transmit DMA to send data */
+ ao_spi_set_dma_mosi(id, out, len, 1);
+
+ /* Set up the receive DMA to capture data */
+ ao_spi_set_dma_miso(id, in, len, 1);
+
+ ao_spi_run(id, 11, len);
+}
+#endif
+
+static void
+ao_spi_disable_pin_config(uint8_t spi_pin_config)
+{
+ /* Disable current config
+ */
+ switch (spi_pin_config) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_gpio_set(&stm_gpioa, 5, 1);
+ stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_1_PA12_PA13_PA14:
+ stm_gpio_set(&stm_gpioa, 13, 1);
+ stm_moder_set(&stm_gpioa, 13, STM_MODER_OUTPUT); /* clk */
+ stm_moder_set(&stm_gpioa, 12, STM_MODER_OUTPUT); /* mosi */
+ stm_moder_set(&stm_gpioa, 14, STM_MODER_INPUT); /* miso */
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_gpio_set(&stm_gpiob, 3, 1);
+ stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+ break;
+ }
+}
+
+static void
+ao_spi_enable_pin_config(uint8_t spi_pin_config)
+{
+ /* Enable new config
+ */
+ switch (spi_pin_config) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
+ stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
+ stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
+ break;
+ case AO_SPI_1_PA12_PA13_PA14:
+ stm_afr_set(&stm_gpioe, 12, STM_AFR_AF0); /* yes, AF0 */
+ stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+ break;
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
+ stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
+ break;
+ }
+}
+
+static void
+ao_spi_config(uint8_t spi_index, uint32_t speed)
+{
+ uint8_t spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ if (spi_pin_config != ao_spi_pin_config) {
+
+ /* Disable old config
+ */
+ ao_spi_disable_pin_config(ao_spi_pin_config);
+
+ /* Enable new config
+ */
+ ao_spi_enable_pin_config(spi_pin_config);
+
+ /* Remember current config
+ */
+ ao_spi_pin_config = spi_pin_config;
+ }
+
+ /* Turn the SPI transceiver on and set the mode */
+ stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) | /* Three wire mode */
+ (0 << STM_SPI_CR1_BIDIOE) |
+ (0 << STM_SPI_CR1_CRCEN) | /* CRC disabled */
+ (0 << STM_SPI_CR1_CRCNEXT) |
+ (0 << STM_SPI_CR1_DFF) |
+ (0 << STM_SPI_CR1_RXONLY) |
+ (1 << STM_SPI_CR1_SSM) | /* Software SS handling */
+ (1 << STM_SPI_CR1_SSI) | /* ... */
+ (0 << STM_SPI_CR1_LSBFIRST) | /* Big endian */
+ (1 << STM_SPI_CR1_SPE) | /* Enable SPI unit */
+ (speed << STM_SPI_CR1_BR) | /* baud rate to pclk/4 */
+ (1 << STM_SPI_CR1_MSTR) |
+ (AO_SPI_CPOL(spi_index) << STM_SPI_CR1_CPOL) | /* Format */
+ (AO_SPI_CPHA(spi_index) << STM_SPI_CR1_CPHA));
+}
+
+#if HAS_TASK
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+
+ if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
+ return 0;
+ ao_spi_config(spi_index, speed);
+ return 1;
+}
+#endif
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed)
+{
+ (void) spi_index;
+
+ ao_mutex_get(&ao_spi_mutex);
+ ao_spi_config(spi_index, speed);
+}
+
+void
+ao_spi_put(uint8_t spi_index)
+{
+ (void) spi_index;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ stm_spi->cr1 = 0;
+ ao_mutex_put(&ao_spi_mutex);
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+ (void) spi_index;
+ struct stm_spi *stm_spi = &stm_spi1;
+
+ ao_spi_disable_pin_config(AO_SPI_PIN_CONFIG(spi_index));
+
+ stm_spi->cr1 = 0;
+ stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+ (0 << STM_SPI_CR2_RXNEIE) |
+ (0 << STM_SPI_CR2_ERRIE) |
+ (0 << STM_SPI_CR2_SSOE) |
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+
+ /* Clear any pending data and error flags */
+ (void) stm_spi->dr;
+ (void) stm_spi->sr;
+}
+
+#if DEBUG
+void
+ao_spi_dump_cmd(void)
+{
+ int s;
+
+ for (s = 0; s < 64; s++) {
+ int i = (spi_task_index + s) & 63;
+ if (spi_tasks[i].which) {
+ int t;
+ const char *name = "(none)";
+ for (t = 0; t < ao_num_tasks; t++)
+ if (ao_tasks[t]->task_id == spi_tasks[i].task) {
+ name = ao_tasks[t]->name;
+ break;
+ }
+ printf("%2d: %5d task %2d which %2d len %5d %s\n",
+ s,
+ spi_tasks[i].tick,
+ spi_tasks[i].task,
+ spi_tasks[i].which,
+ spi_tasks[i].len,
+ name);
+ }
+ }
+ for (s = 0; s < STM_NUM_SPI; s++) {
+ struct stm_spi *spi = ao_spi_stm_info[s].stm_spi;
+
+ printf("%1d: mutex %2d index %3d miso dma %3d mosi dma %3d",
+ s, ao_spi_mutex[s], ao_spi_index[s],
+ ao_spi_stm_info[s].miso_dma_index,
+ ao_spi_stm_info[s].mosi_dma_index);
+ printf(" cr1 %04x cr2 %02x sr %03x\n",
+ spi->cr1, spi->cr2, spi->sr);
+ }
+
+}
+
+static const struct ao_cmds ao_spi_cmds[] = {
+ { ao_spi_dump_cmd, "S\0Dump SPI status" },
+ { 0, NULL }
+};
+#endif
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_1
+# if SPI_1_PA5_PA6_PA7
+ ao_enable_port(&stm_gpioa);
+ stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PB3_PB4_PB5
+ ao_enable_port(&stm_gpiob);
+ stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PE13_PE14_PE15
+ ao_enable_port(&stm_gpioe);
+ stm_ospeedr_set(&stm_gpioe, 13, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioe, 14, SPI_1_OSPEEDR);
+ stm_ospeedr_set(&stm_gpioe, 15, SPI_1_OSPEEDR);
+# endif
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+ ao_spi_pin_config = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(0);
+#if 0
+ ao_dma_alloc(AO_DMA_SPI1_RX_INDEX, AO_DMA_SPI1_RX_CSELR);
+ ao_dma_alloc(AO_DMA_SPI1_TX_INDEX, AO_DMA_SPI1_TX_CSELR);
+#endif
+#endif
+
+#if HAS_SPI_2
+# if SPI_2_PB13_PB14_PB15
+ ao_enable_port(&stm_gpiob);
+ stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
+# define HAS_SPI_2_CONFIG 1
+# endif
+# if SPI_2_PD1_PD3_PD4
+ ao_enable_port(&stm_gpiod);
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
+ stm_ospeedr_set(&stm_gpiod, 1, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiod, 3, SPI_2_OSPEEDR);
+ stm_ospeedr_set(&stm_gpiod, 4, SPI_2_OSPEEDR);
+# define HAS_SPI_2_CONFIG 1
+# endif
+# ifndef HAS_SPI_2_CONFIG 1
+ #error "no config for SPI2"
+# endif
+ stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+ ao_spi_pin_config[1] = AO_SPI_CONFIG_NONE;
+ ao_spi_channel_init(1);
+ ao_dma_alloc(AO_DMA_SPI2_RX_INDEX, AO_DMA_SPI2_RX_CSELR);
+ ao_dma_alloc(AO_DMA_SPI2_TX_INDEX, AO_DMA_SPI2_TX_CSELR);
+#endif
+#if DEBUG
+ ao_cmd_register(&ao_spi_cmds[0]);
+#endif
+}
--- /dev/null
+/*
+ * Copyright © 2020 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_task.h>
+#if HAS_FAKE_FLIGHT
+#include <ao_fake_flight.h>
+#endif
+
+#ifndef HAS_TICK
+#define HAS_TICK 1
+#endif
+
+#if HAS_TICK
+volatile AO_TICK_TYPE ao_tick_count;
+
+AO_TICK_TYPE
+ao_time(void)
+{
+ return ao_tick_count;
+}
+
+#if 0
+uint64_t
+ao_time_ns(void)
+{
+ AO_TICK_TYPE before, after;
+ uint32_t cvr;
+
+ do {
+ before = ao_tick_count;
+ cvr = stm_systick.cvr;
+ after = ao_tick_count;
+ } while (before != after);
+
+ return (uint64_t) after * (1000000000ULL / AO_HERTZ) +
+ (uint64_t) cvr * (1000000000ULL / AO_SYSTICK);
+}
+#endif
+
+#if AO_DATA_ALL
+volatile uint8_t ao_data_interval = 1;
+volatile uint8_t ao_data_count;
+#endif
+
+void stm_systick_isr(void)
+{
+ if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) {
+ ++ao_tick_count;
+ ao_task_check_alarm();
+#if AO_DATA_ALL
+ if (++ao_data_count == ao_data_interval) {
+ ao_data_count = 0;
+#if HAS_ADC
+#if HAS_FAKE_FLIGHT
+ if (ao_fake_flight_active)
+ ao_fake_flight_poll();
+ else
+#endif
+ ao_adc_poll();
+#endif
+#if (AO_DATA_ALL & ~(AO_DATA_ADC))
+ ao_wakeup((void *) &ao_data_count);
+#endif
+ }
+#endif
+#ifdef AO_TIMER_HOOK
+ AO_TIMER_HOOK;
+#endif
+ }
+}
+
+#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1)
+
+void
+ao_timer_init(void)
+{
+ stm_systick.csr = 0;
+ stm_systick.rvr = SYSTICK_RELOAD;
+ stm_systick.cvr = 0;
+ stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) |
+ (1 << STM_SYSTICK_CSR_TICKINT) |
+ (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE));
+}
+
+void
+ao_timer_stop(void)
+{
+ stm_systick.csr = 0;
+}
+
+#endif
--- /dev/null
+/*
+ * 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; 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 _STM32L0_H_
+#define _STM32L0_H_
+
+#include <stdint.h>
+
+typedef volatile uint32_t vuint32_t;
+typedef volatile uint16_t vuint16_t;
+typedef volatile void * vvoid_t;
+
+struct stm_gpio {
+ vuint32_t moder;
+ vuint32_t otyper;
+ vuint32_t ospeedr;
+ vuint32_t pupdr;
+
+ vuint32_t idr;
+ vuint32_t odr;
+ vuint32_t bsrr;
+ vuint32_t lckr;
+
+ vuint32_t afrl;
+ vuint32_t afrh;
+ vuint32_t brr;
+};
+
+#define STM_MODER_SHIFT(pin) ((pin) << 1)
+#define STM_MODER_MASK 3
+#define STM_MODER_INPUT 0
+#define STM_MODER_OUTPUT 1
+#define STM_MODER_ALTERNATE 2
+#define STM_MODER_ANALOG 3
+
+static inline void
+stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->moder = ((gpio->moder &
+ ~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) |
+ value << STM_MODER_SHIFT(pin));
+}
+
+static inline uint32_t
+stm_spread_mask(uint16_t mask) {
+ uint32_t m = mask;
+
+ /* 0000000000000000mmmmmmmmmmmmmmmm */
+ m = (m & 0xff) | ((m & 0xff00) << 8);
+ /* 00000000mmmmmmmm00000000mmmmmmmm */
+ m = (m & 0x000f000f) | ((m & 0x00f000f0) << 4);
+ /* 0000mmmm0000mmmm0000mmmm0000mmmm */
+ m = (m & 0x03030303) | ((m & 0x0c0c0c0c) << 2);
+ /* 00mm00mm00mm00mm00mm00mm00mm00mm */
+ m = (m & 0x11111111) | ((m & 0x22222222) << 2);
+ /* 0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m0m */
+ return m;
+}
+
+static inline void
+stm_moder_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->moder = ((gpio->moder & ~mask32) | value32);
+}
+
+static inline uint32_t
+stm_moder_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK;
+}
+
+#define STM_OTYPER_SHIFT(pin) (pin)
+#define STM_OTYPER_MASK 1
+#define STM_OTYPER_PUSH_PULL 0
+#define STM_OTYPER_OPEN_DRAIN 1
+
+static inline void
+stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) {
+ gpio->otyper = ((gpio->otyper &
+ ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) |
+ value << STM_OTYPER_SHIFT(pin));
+}
+
+static inline uint32_t
+stm_otyper_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK;
+}
+
+#define STM_OSPEEDR_SHIFT(pin) ((pin) << 1)
+#define STM_OSPEEDR_MASK 3
+#define STM_OSPEEDR_LOW 0
+#define STM_OSPEEDR_MEDIUM 1
+#define STM_OSPEEDR_HIGH 2
+#define STM_OSPEEDR_VERY_HIGH 3
+
+static inline void
+stm_ospeedr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ gpio->ospeedr = ((gpio->ospeedr &
+ ~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) |
+ value << STM_OSPEEDR_SHIFT(pin));
+}
+
+static inline void
+stm_ospeedr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->ospeedr = ((gpio->ospeedr & ~mask32) | value32);
+}
+
+static inline uint32_t
+stm_ospeedr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK;
+}
+
+#define STM_PUPDR_SHIFT(pin) ((pin) << 1)
+#define STM_PUPDR_MASK 3
+#define STM_PUPDR_NONE 0
+#define STM_PUPDR_PULL_UP 1
+#define STM_PUPDR_PULL_DOWN 2
+#define STM_PUPDR_RESERVED 3
+
+static inline void
+stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ gpio->pupdr = ((gpio->pupdr &
+ ~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) |
+ value << STM_PUPDR_SHIFT(pin));
+}
+
+static inline void
+stm_pupdr_set_mask(struct stm_gpio *gpio, uint16_t mask, uint32_t value) {
+ uint32_t bits32 = stm_spread_mask(mask);
+ uint32_t mask32 = 3 * bits32;
+ uint32_t value32 = (value & 3) * bits32;
+
+ gpio->pupdr = (gpio->pupdr & ~mask32) | value32;
+}
+
+static inline uint32_t
+stm_pupdr_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK;
+}
+
+#define STM_AFR_SHIFT(pin) ((pin) << 2)
+#define STM_AFR_MASK 0xf
+#define STM_AFR_AF0 0x0
+#define STM_AFR_AF1 0x1
+#define STM_AFR_AF2 0x2
+#define STM_AFR_AF3 0x3
+#define STM_AFR_AF4 0x4
+#define STM_AFR_AF5 0x5
+#define STM_AFR_AF6 0x6
+#define STM_AFR_AF7 0x7
+#define STM_AFR_AF8 0x8
+#define STM_AFR_AF9 0x9
+#define STM_AFR_AF10 0xa
+#define STM_AFR_AF11 0xb
+#define STM_AFR_AF12 0xc
+#define STM_AFR_AF13 0xd
+#define STM_AFR_AF14 0xe
+#define STM_AFR_AF15 0xf
+
+static inline void
+stm_afr_set(struct stm_gpio *gpio, int pin, uint32_t value) {
+ /*
+ * Set alternate pin mode too
+ */
+ stm_moder_set(gpio, pin, STM_MODER_ALTERNATE);
+ if (pin < 8)
+ gpio->afrl = ((gpio->afrl &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ else {
+ pin -= 8;
+ gpio->afrh = ((gpio->afrh &
+ ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) |
+ value << STM_AFR_SHIFT(pin));
+ }
+}
+
+static inline uint32_t
+stm_afr_get(struct stm_gpio *gpio, int pin) {
+ if (pin < 8)
+ return (gpio->afrl >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ else {
+ pin -= 8;
+ return (gpio->afrh >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK;
+ }
+}
+
+static inline void
+stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) {
+ /* Use the bit set/reset register to do this atomically */
+ gpio->bsrr = value ? (1 << pin) : (1 << (pin + 16));
+}
+
+static inline void
+stm_gpio_set_mask(struct stm_gpio *gpio, uint16_t bits, uint16_t mask) {
+ /* Use the bit set/reset register to do this atomically */
+ gpio->bsrr = ((uint32_t) (~bits & mask) << 16) | ((uint32_t) (bits & mask));
+}
+
+static inline void
+stm_gpio_set_bits(struct stm_gpio *gpio, uint16_t bits) {
+ gpio->bsrr = bits;
+}
+
+static inline void
+stm_gpio_clr_bits(struct stm_gpio *gpio, uint16_t bits) {
+ gpio->bsrr = ((uint32_t) bits) << 16;
+}
+
+static inline uint8_t
+stm_gpio_get(struct stm_gpio *gpio, int pin) {
+ return (gpio->idr >> pin) & 1;
+}
+
+static inline uint16_t
+stm_gpio_get_all(struct stm_gpio *gpio) {
+ return gpio->idr;
+}
+
+/*
+ * We can't define these in registers.ld or our fancy
+ * ao_enable_gpio macro will expand into a huge pile of code
+ * as the compiler won't do correct constant folding and
+ * dead-code elimination
+ */
+
+extern struct stm_gpio stm_gpioa;
+extern struct stm_gpio stm_gpiob;
+extern struct stm_gpio stm_gpioc;
+extern struct stm_gpio stm_gpiod;
+extern struct stm_gpio stm_gpioe;
+extern struct stm_gpio stm_gpioh;
+
+#define stm_gpiob (*((struct stm_gpio *) 0x50000400))
+#define stm_gpioa (*((struct stm_gpio *) 0x50000000))
+
+struct stm_usart {
+ vuint32_t cr1; /* control register 1 */
+ vuint32_t cr2; /* control register 2 */
+ vuint32_t cr3; /* control register 3 */
+ vuint32_t brr; /* baud rate register */
+
+ vuint32_t gtpr; /* guard time and prescaler */
+ vuint32_t rtor; /* receiver timeout register */
+ vuint32_t rqr; /* request register */
+ vuint32_t isr; /* interrupt and status register */
+
+ vuint32_t icr; /* interrupt flag clear register */
+ vuint32_t rdr; /* receive data register */
+ vuint32_t tdr; /* transmit data register */
+};
+
+#define STM_USART_CR1_M1 28
+#define STM_USART_CR1_EOBIE 27
+#define STM_USART_CR1_RTOIE 26
+#define STM_USART_CR1_DEAT 21
+#define STM_USART_CR1_DEDT 16
+#define STM_USART_CR1_OVER8 15
+#define STM_USART_CR1_CMIE 14
+#define STM_USART_CR1_MME 13
+#define STM_USART_CR1_M0 12
+#define STM_USART_CR1_WAKE 11
+#define STM_USART_CR1_PCE 10
+#define STM_USART_CR1_PS 9
+#define STM_USART_CR1_PEIE 8
+#define STM_USART_CR1_TXEIE 7
+#define STM_USART_CR1_TCIE 6
+#define STM_USART_CR1_RXNEIE 5
+#define STM_USART_CR1_IDLEIE 4
+#define STM_USART_CR1_TE 3
+#define STM_USART_CR1_RE 2
+#define STM_USART_CR1_UESM 1
+#define STM_USART_CR1_UE 0
+
+#define STM_USART_CR2_ADD 24
+#define STM_USART_CR2_RTOEN 23
+#define STM_USART_CR2_ABRMOD 21
+#define STM_USART_CR2_ABREN 20
+#define STM_USART_CR2_MSBFIRST 19
+#define STM_USART_CR2_DATAINV 18
+#define STM_USART_CR2_TXINV 17
+#define STM_USART_CR2_RXINV 16
+#define STM_USART_CR2_SWAP 15
+#define STM_USART_CR2_LINEN 14
+#define STM_USART_CR2_STOP 12
+#define STM_USART_CR2_CLKEN 11
+#define STM_USART_CR2_CPOL 10
+#define STM_USART_CR2_CHPA 9
+#define STM_USART_CR2_LBCL 8
+#define STM_USART_CR2_LBDIE 6
+#define STM_USART_CR2_LBDL 5
+#define STM_USART_CR2_ADDM7 4
+
+#define STM_USART_CR3_WUFIE 22
+#define STM_USART_CR3_WUS 20
+#define STM_USART_CR3_SCARCNT 17
+#define STM_USART_CR3_DEP 15
+#define STM_USART_CR3_DEM 14
+#define STM_USART_CR3_DDRE 13
+#define STM_USART_CR3_OVRDIS 12
+#define STM_USART_CR3_ONEBIT 11
+#define STM_USART_CR3_CTIIE 10
+#define STM_USART_CR3_CTSE 9
+#define STM_USART_CR3_RTSE 8
+#define STM_USART_CR3_DMAT 7
+#define STM_USART_CR3_DMAR 6
+#define STM_USART_CR3_SCEN 5
+#define STM_USART_CR3_NACK 4
+#define STM_USART_CR3_HDSEL 3
+#define STM_USART_CR3_IRLP 2
+#define STM_USART_CR3_IREN 1
+#define STM_USART_CR3_EIE 0
+
+#define STM_USART_GTPR_GT 8
+#define STM_USART_GTPR_PSC 0
+
+#define STM_USART_RQR_TXFRQ 4
+#define STM_USART_RQR_RXFRQ 3
+#define STM_USART_RQR_MMRQ 2
+#define STM_USART_RQR_SBKRQ 1
+#define STM_USART_RQR_ABRRQ 0
+
+#define STM_USART_ISR_REACK 22
+#define STM_USART_ISR_TEACK 21
+#define STM_USART_ISR_WUF 20
+#define STM_USART_ISR_RWU 19
+#define STM_USART_ISR_SBKF 18
+#define STM_USART_ISR_CMF 17
+#define STM_USART_ISR_BUSY 16
+#define STM_USART_ISR_ABRF 15
+#define STM_USART_ISR_ABRE 14
+#define STM_USART_ISR_EOBF 12
+#define STM_USART_ISR_RTOF 11
+#define STM_USART_ISR_CTS 10
+#define STM_USART_ISR_CTSIF 9
+#define STM_USART_ISR_LBDF 8
+#define STM_USART_ISR_TXE 7
+#define STM_USART_ISR_TC 6
+#define STM_USART_ISR_RXNE 5
+#define STM_USART_ISR_IDLE 4
+#define STM_USART_ISR_ORE 3
+#define STM_USART_ISR_NF 2
+#define STM_USART_ISR_FE 1
+#define STM_USART_ISR_PE 0
+
+#define STM_USART_ICR_WUCF 20
+#define STM_USART_ICR_CMCF 17
+#define STM_USART_ICR_EOBCF 12
+#define STM_USART_ICR_RTOCF 11
+#define STM_USART_ICR_CTSCF 9
+#define STM_USART_ICR_LBDCF 8
+#define STM_USART_ICR_TCCF 6
+#define STM_USART_ICR_IDLECF 4
+#define STM_USART_ICR_ORECF 3
+#define STM_USART_ICR_NCF 2
+#define STM_USART_ICR_FECF 1
+#define STM_USART_ICR_PECF 0
+
+extern struct stm_usart stm_usart1;
+extern struct stm_usart stm_usart2;
+#define stm_usart1 (*((struct stm_usart *) 0x40013800))
+#define stm_usart2 (*((struct stm_usart *) 0x40004400))
+
+struct stm_lpuart {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t cr3;
+ vuint32_t brr;
+
+ uint32_t unused_10;
+ uint32_t unused_14;
+ vuint32_t rqr;
+ vuint32_t isr;
+
+ vuint32_t icr;
+ vuint32_t rdr;
+ vuint32_t tdr;
+};
+extern struct stm_lpuart stm_lpuart1;
+
+#define stm_lpuart1 (*((struct stm_lpuart *) 0x40004800))
+
+#define STM_LPUART_CR1_M1 28
+#define STM_LPUART_CR1_DEAT 21
+#define STM_LPUART_CR1_DEDT 16
+#define STM_LPUART_CR1_CMIE 14
+#define STM_LPUART_CR1_MME 13
+#define STM_LPUART_CR1_M0 12
+#define STM_LPUART_CR1_WAKE 11
+#define STM_LPUART_CR1_PCE 10
+#define STM_LPUART_CR1_PS 9
+#define STM_LPUART_CR1_PEIE 8
+#define STM_LPUART_CR1_TXEIE 7
+#define STM_LPUART_CR1_TCIE 6
+#define STM_LPUART_CR1_RXNEIE 5
+#define STM_LPUART_CR1_IDLEIE 4
+#define STM_LPUART_CR1_TE 3
+#define STM_LPUART_CR1_RE 2
+#define STM_LPUART_CR1_UESM 1
+#define STM_LPUART_CR1_UE 0
+
+#define STM_LPUART_CR2_ADD 24
+#define STM_LPUART_CR2_MSBFIRST 19
+#define STM_LPUART_CR2_DATAINV 18
+#define STM_LPUART_CR2_TXINV 17
+#define STM_LPUART_CR2_RXINV 16
+#define STM_LPUART_CR2_SWAP 15
+#define STM_LPUART_CR2_STOP 12
+#define STM_LPUART_CR2_ADDM7 4
+
+#define STM_LPUART_CR3_UCESM 23
+#define STM_LPUART_CR3_WUFIE 22
+#define STM_LPUART_CR3_WUS 20
+#define STM_LPUART_CR3_DEP 15
+#define STM_LPUART_CR3_DEM 14
+#define STM_LPUART_CR3_DDRE 13
+#define STM_LPUART_CR3_OVRDIS 12
+#define STM_LPUART_CR3_CTSIE 10
+#define STM_LPUART_CR3_CTSE 9
+#define STM_LPUART_CR3_RTSE 8
+#define STM_LPUART_CR3_DMAT 7
+#define STM_LPUART_CR3_DMAR 6
+#define STM_LPUART_CR3_HDSEL 3
+#define STM_LPUART_CR3_EIE 0
+
+#define STM_LPUART_RQR_RXFRQ 3
+#define STM_LPUART_RQR_MMRQ 2
+#define STM_LPUART_RQR_SBKRQ 1
+
+#define STM_LPUART_ISR_REACK 22
+#define STM_LPUART_ISR_TEACK 21
+#define STM_LPUART_ISR_WUF 20
+#define STM_LPUART_ISR_RWU 19
+#define STM_LPUART_ISR_SBKF 18
+#define STM_LPUART_ISR_CMF 17
+#define STM_LPUART_ISR_BUSY 16
+#define STM_LPUART_ISR_CTS 10
+#define STM_LPUART_ISR_CTSIF 9
+#define STM_LPUART_ISR_TXE 7
+#define STM_LPUART_ISR_TC 6
+#define STM_LPUART_ISR_RXNE 5
+#define STM_LPUART_ISR_IDLE 4
+#define STM_LPUART_ISR_ORE 3
+#define STM_LPUART_ISR_NF 2
+#define STM_LPUART_ISR_FE 1
+#define STM_LPUART_ISR_PE 1
+
+#define STM_LPUART_ICR_WUCF 20
+#define STM_LPUART_ICR_CMCF 17
+#define STM_LPUART_ICR_CTSCF 9
+#define STM_LPUART_ICR_TCCF 6
+#define STM_LPUART_ICR_IDLECF 4
+#define STM_LPUART_ICR_ORECF 3
+#define STM_LPUART_ICR_NCF 2
+#define STM_LPUART_ICR_FECF 1
+#define STM_LPUART_ICR_PECF 0
+
+struct stm_tim {
+};
+
+extern struct stm_tim stm_tim9;
+
+struct stm_tim1011 {
+ vuint32_t cr1;
+ uint32_t unused_4;
+ vuint32_t smcr;
+ vuint32_t dier;
+ vuint32_t sr;
+ vuint32_t egr;
+ vuint32_t ccmr1;
+ uint32_t unused_1c;
+ vuint32_t ccer;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+ uint32_t unused_30;
+ vuint32_t ccr1;
+ uint32_t unused_38;
+ uint32_t unused_3c;
+ uint32_t unused_40;
+ uint32_t unused_44;
+ uint32_t unused_48;
+ uint32_t unused_4c;
+ vuint32_t or;
+};
+
+extern struct stm_tim1011 stm_tim10;
+extern struct stm_tim1011 stm_tim11;
+
+#define STM_TIM1011_CR1_CKD 8
+#define STM_TIM1011_CR1_CKD_1 0
+#define STM_TIM1011_CR1_CKD_2 1
+#define STM_TIM1011_CR1_CKD_4 2
+#define STM_TIM1011_CR1_CKD_MASK 3
+#define STM_TIM1011_CR1_ARPE 7
+#define STM_TIM1011_CR1_URS 2
+#define STM_TIM1011_CR1_UDIS 1
+#define STM_TIM1011_CR1_CEN 0
+
+#define STM_TIM1011_SMCR_ETP 15
+#define STM_TIM1011_SMCR_ECE 14
+#define STM_TIM1011_SMCR_ETPS 12
+#define STM_TIM1011_SMCR_ETPS_OFF 0
+#define STM_TIM1011_SMCR_ETPS_2 1
+#define STM_TIM1011_SMCR_ETPS_4 2
+#define STM_TIM1011_SMCR_ETPS_8 3
+#define STM_TIM1011_SMCR_ETPS_MASK 3
+#define STM_TIM1011_SMCR_ETF 8
+#define STM_TIM1011_SMCR_ETF_NONE 0
+#define STM_TIM1011_SMCR_ETF_CK_INT_2 1
+#define STM_TIM1011_SMCR_ETF_CK_INT_4 2
+#define STM_TIM1011_SMCR_ETF_CK_INT_8 3
+#define STM_TIM1011_SMCR_ETF_DTS_2_6 4
+#define STM_TIM1011_SMCR_ETF_DTS_2_8 5
+#define STM_TIM1011_SMCR_ETF_DTS_4_6 6
+#define STM_TIM1011_SMCR_ETF_DTS_4_8 7
+#define STM_TIM1011_SMCR_ETF_DTS_8_6 8
+#define STM_TIM1011_SMCR_ETF_DTS_8_8 9
+#define STM_TIM1011_SMCR_ETF_DTS_16_5 10
+#define STM_TIM1011_SMCR_ETF_DTS_16_6 11
+#define STM_TIM1011_SMCR_ETF_DTS_16_8 12
+#define STM_TIM1011_SMCR_ETF_DTS_32_5 13
+#define STM_TIM1011_SMCR_ETF_DTS_32_6 14
+#define STM_TIM1011_SMCR_ETF_DTS_32_8 15
+#define STM_TIM1011_SMCR_ETF_MASK 15
+
+#define STM_TIM1011_DIER_CC1E 1
+#define STM_TIM1011_DIER_UIE 0
+
+#define STM_TIM1011_SR_CC1OF 9
+#define STM_TIM1011_SR_CC1IF 1
+#define STM_TIM1011_SR_UIF 0
+
+#define STM_TIM1011_EGR_CC1G 1
+#define STM_TIM1011_EGR_UG 0
+
+#define STM_TIM1011_CCMR1_OC1CE 7
+#define STM_TIM1011_CCMR1_OC1M 4
+#define STM_TIM1011_CCMR1_OC1M_FROZEN 0
+#define STM_TIM1011_CCMR1_OC1M_SET_1_ACTIVE_ON_MATCH 1
+#define STM_TIM1011_CCMR1_OC1M_SET_1_INACTIVE_ON_MATCH 2
+#define STM_TIM1011_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM1011_CCMR1_OC1M_FORCE_INACTIVE 4
+#define STM_TIM1011_CCMR1_OC1M_FORCE_ACTIVE 5
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM1011_CCMR1_OC1M_MASK 7
+#define STM_TIM1011_CCMR1_OC1PE 3
+#define STM_TIM1011_CCMR1_OC1FE 2
+#define STM_TIM1011_CCMR1_CC1S 0
+#define STM_TIM1011_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM1011_CCMR1_CC1S_MASK 3
+
+#define STM_TIM1011_CCMR1_IC1F_NONE 0
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_2 1
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_4 2
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_8 3
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_6 4
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_8 5
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_6 6
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_8 7
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_6 8
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_8 9
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_5 10
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_6 11
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_8 12
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_5 13
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_6 14
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_8 15
+#define STM_TIM1011_CCMR1_IC1F_MASK 15
+#define STM_TIM1011_CCMR1_IC1PSC 2
+#define STM_TIM1011_CCMR1_IC1PSC_1 0
+#define STM_TIM1011_CCMR1_IC1PSC_2 1
+#define STM_TIM1011_CCMR1_IC1PSC_4 2
+#define STM_TIM1011_CCMR1_IC1PSC_8 3
+#define STM_TIM1011_CCMR1_IC1PSC_MASK 3
+#define STM_TIM1011_CCMR1_CC1S 0
+
+#define STM_TIM1011_CCER_CC1NP 3
+#define STM_TIM1011_CCER_CC1P 1
+#define STM_TIM1011_CCER_CC1E 0
+
+#define STM_TIM1011_OR_TI1_RMP_RI 3
+#define STM_TIM1011_ETR_RMP 2
+#define STM_TIM1011_TI1_RMP 0
+#define STM_TIM1011_TI1_RMP_GPIO 0
+#define STM_TIM1011_TI1_RMP_LSI 1
+#define STM_TIM1011_TI1_RMP_LSE 2
+#define STM_TIM1011_TI1_RMP_RTC 3
+#define STM_TIM1011_TI1_RMP_MASK 3
+
+struct stm_rcc {
+ vuint32_t cr;
+ vuint32_t icscr;
+ uint32_t unused08;
+ vuint32_t cfgr;
+
+ vuint32_t cier;
+ vuint32_t cifr;
+ vuint32_t cicr;
+ vuint32_t iopstr;
+
+ vuint32_t ahbrstr;
+ vuint32_t apb2rstr;
+ vuint32_t apb1rstr;
+ vuint32_t iopenr;
+
+ vuint32_t ahbenr;
+ vuint32_t apb2enr;
+ vuint32_t apb1enr;
+ vuint32_t iopsmen;
+
+ vuint32_t ahbsmenr;
+ vuint32_t apb2smenr;
+ vuint32_t apb1smenr;
+ vuint32_t ccipr;
+
+ vuint32_t csr;
+};
+
+extern struct stm_rcc stm_rcc;
+
+/* Nominal high speed internal oscillator frequency is 16MHz */
+#define STM_HSI_FREQ 16000000
+#define STM_MSI_FREQ_65536 65536
+#define STM_MSI_FREQ_131072 131072
+#define STM_MSI_FREQ_262144 262144
+#define STM_MSI_FREQ_524288 524288
+#define STM_MSI_FREQ_1048576 1048576
+#define STM_MSI_FREQ_2097152 2097152
+#define STM_MSI_FREQ_4194304 4194304
+
+#define STM_RCC_CR_RTCPRE (29)
+#define STM_RCC_CR_RTCPRE_HSE_DIV_2 0
+#define STM_RCC_CR_RTCPRE_HSE_DIV_4 1
+#define STM_RCC_CR_RTCPRE_HSE_DIV_8 2
+#define STM_RCC_CR_RTCPRE_HSE_DIV_16 3
+#define STM_RCC_CR_RTCPRE_HSE_MASK 3
+
+#define STM_RCC_CR_CSSON (28)
+#define STM_RCC_CR_PLLRDY (25)
+#define STM_RCC_CR_PLLON (24)
+#define STM_RCC_CR_HSEBYP (18)
+#define STM_RCC_CR_HSERDY (17)
+#define STM_RCC_CR_HSEON (16)
+#define STM_RCC_CR_MSIRDY (9)
+#define STM_RCC_CR_MSION (8)
+#define STM_RCC_CR_HSIRDY (1)
+#define STM_RCC_CR_HSION (0)
+
+#define STM_RCC_ICSCR_HSI16CAL 0
+#define STM_RCC_ICSCR_HSI16TRIM 8
+#define STM_RCC_ICSCR_MSIRANGE 13
+#define STM_RCC_ICSCR_MSIRANGE_65536 0
+#define STM_RCC_ICSCR_MSIRANGE_131072
+#define STM_RCC_ICSCR_MSIRANGE_262144 2
+#define STM_RCC_ICSCR_MSIRANGE_524288 3
+#define STM_RCC_ICSCR_MSIRANGE_1048576 4
+#define STM_RCC_ICSCR_MSIRANGE_2097152 5
+#define STM_RCC_ICSCR_MSIRANGE_4194304 6
+#define STM_RCC_ICSCR_MSIRANGE_MASK 0x7
+#define STM_RCC_ICSCR_MSICAL 16
+#define STM_RCC_ICSCR_MSITRIM 24
+
+#define STM_RCC_CFGR_MCOPRE (28)
+#define STM_RCC_CFGR_MCOPRE_DIV_1 0
+#define STM_RCC_CFGR_MCOPRE_DIV_2 1
+#define STM_RCC_CFGR_MCOPRE_DIV_4 2
+#define STM_RCC_CFGR_MCOPRE_DIV_8 3
+#define STM_RCC_CFGR_MCOPRE_DIV_16 4
+#define STM_RCC_CFGR_MCOPRE_MASK 7
+
+#define STM_RCC_CFGR_MCOSEL (24)
+#define STM_RCC_CFGR_MCOSEL_DISABLE 0
+#define STM_RCC_CFGR_MCOSEL_SYSCLK 1
+#define STM_RCC_CFGR_MCOSEL_HSI 2
+#define STM_RCC_CFGR_MCOSEL_MSI 3
+#define STM_RCC_CFGR_MCOSEL_HSE 4
+#define STM_RCC_CFGR_MCOSEL_PLL 5
+#define STM_RCC_CFGR_MCOSEL_LSI 6
+#define STM_RCC_CFGR_MCOSEL_LSE 7
+#define STM_RCC_CFGR_MCOSEL_MASK 7
+
+#define STM_RCC_CFGR_PLLDIV (22)
+#define STM_RCC_CFGR_PLLDIV_2 1
+#define STM_RCC_CFGR_PLLDIV_3 2
+#define STM_RCC_CFGR_PLLDIV_4 3
+#define STM_RCC_CFGR_PLLDIV_MASK 3
+
+#define STM_RCC_CFGR_PLLMUL (18)
+#define STM_RCC_CFGR_PLLMUL_3 0
+#define STM_RCC_CFGR_PLLMUL_4 1
+#define STM_RCC_CFGR_PLLMUL_6 2
+#define STM_RCC_CFGR_PLLMUL_8 3
+#define STM_RCC_CFGR_PLLMUL_12 4
+#define STM_RCC_CFGR_PLLMUL_16 5
+#define STM_RCC_CFGR_PLLMUL_24 6
+#define STM_RCC_CFGR_PLLMUL_32 7
+#define STM_RCC_CFGR_PLLMUL_48 8
+#define STM_RCC_CFGR_PLLMUL_MASK 0xf
+
+#define STM_RCC_CFGR_PLLSRC (16)
+
+#define STM_RCC_CFGR_PPRE2 (11)
+#define STM_RCC_CFGR_PPRE2_DIV_1 0
+#define STM_RCC_CFGR_PPRE2_DIV_2 4
+#define STM_RCC_CFGR_PPRE2_DIV_4 5
+#define STM_RCC_CFGR_PPRE2_DIV_8 6
+#define STM_RCC_CFGR_PPRE2_DIV_16 7
+#define STM_RCC_CFGR_PPRE2_MASK 7
+
+#define STM_RCC_CFGR_PPRE1 (8)
+#define STM_RCC_CFGR_PPRE1_DIV_1 0
+#define STM_RCC_CFGR_PPRE1_DIV_2 4
+#define STM_RCC_CFGR_PPRE1_DIV_4 5
+#define STM_RCC_CFGR_PPRE1_DIV_8 6
+#define STM_RCC_CFGR_PPRE1_DIV_16 7
+#define STM_RCC_CFGR_PPRE1_MASK 7
+
+#define STM_RCC_CFGR_HPRE (4)
+#define STM_RCC_CFGR_HPRE_DIV_1 0
+#define STM_RCC_CFGR_HPRE_DIV_2 8
+#define STM_RCC_CFGR_HPRE_DIV_4 9
+#define STM_RCC_CFGR_HPRE_DIV_8 0xa
+#define STM_RCC_CFGR_HPRE_DIV_16 0xb
+#define STM_RCC_CFGR_HPRE_DIV_64 0xc
+#define STM_RCC_CFGR_HPRE_DIV_128 0xd
+#define STM_RCC_CFGR_HPRE_DIV_256 0xe
+#define STM_RCC_CFGR_HPRE_DIV_512 0xf
+#define STM_RCC_CFGR_HPRE_MASK 0xf
+
+#define STM_RCC_CFGR_SWS (2)
+#define STM_RCC_CFGR_SWS_MSI 0
+#define STM_RCC_CFGR_SWS_HSI 1
+#define STM_RCC_CFGR_SWS_HSE 2
+#define STM_RCC_CFGR_SWS_PLL 3
+#define STM_RCC_CFGR_SWS_MASK 3
+
+#define STM_RCC_CFGR_SW (0)
+#define STM_RCC_CFGR_SW_MSI 0
+#define STM_RCC_CFGR_SW_HSI 1
+#define STM_RCC_CFGR_SW_HSE 2
+#define STM_RCC_CFGR_SW_PLL 3
+#define STM_RCC_CFGR_SW_MASK 3
+
+#define STM_RCC_IOPENR_IOPAEN 0
+#define STM_RCC_IOPENR_IOPBEN 1
+#define STM_RCC_IOPENR_IOPCEN 2
+#define STM_RCC_IOPENR_IOPDEN 3
+#define STM_RCC_IOPENR_IOPEEN 4
+#define STM_RCC_IOPENR_IOPHEN 7
+
+#define STM_RCC_AHBENR_DMA1EN 0
+#define STM_RCC_AHBENR_MIFEN 8
+#define STM_RCC_AHBENR_CRCEN 12
+#define STM_RCC_AHBENR_CRYPEN 24
+
+#define STM_RCC_APB2ENR_DBGEN (22)
+#define STM_RCC_APB2ENR_USART1EN (14)
+#define STM_RCC_APB2ENR_SPI1EN (12)
+#define STM_RCC_APB2ENR_ADCEN (9)
+#define STM_RCC_APB2ENR_FWEN (7)
+#define STM_RCC_APB2ENR_TIM22EN (5)
+#define STM_RCC_APB2ENR_TIM21EN (2)
+#define STM_RCC_APB2ENR_SYSCFGEN (0)
+
+#define STM_RCC_APB1ENR_LPTIM1EN 31
+#define STM_RCC_APB1ENR_I2C3EN 30
+#define STM_RCC_APB1ENR_PWREN 28
+#define STM_RCC_APB1ENR_I2C2EN 22
+#define STM_RCC_APB1ENR_I2C1EN 21
+#define STM_RCC_APB1ENR_USART5EN 20
+#define STM_RCC_APB1ENR_USART4EN 19
+#define STM_RCC_APB1ENR_LPUART1EN 18
+#define STM_RCC_APB1ENR_USART2EN 17
+#define STM_RCC_APB1ENR_SPI2EN 14
+#define STM_RCC_APB1ENR_WWDGEN 11
+#define STM_RCC_APB1ENR_TIM7EN 5
+#define STM_RCC_APB1ENR_TIM6EN 4
+#define STM_RCC_APB1ENR_TIM3EN 1
+#define STM_RCC_APB1ENR_TIM2EN 0
+
+#define STM_RCC_CCIPR_LPTIM1SEL 18
+#define STM_RCC_CCIPR_I2C3SEL 16
+#define STM_RCC_CCIPR_I2C1SEL 12
+#define STM_RCC_CCIPR_LPUART1SEL 10
+#define STM_RCC_CCIPR_LPUART1SEL_APB 0
+#define STM_RCC_CCIPR_LPUART1SEL_SYSTEM 1
+#define STM_RCC_CCIPR_LPUART1SEL_HSI16 2
+#define STM_RCC_CCIPR_LPUART1SEL_LSE 3
+#define STM_RCC_CCIPR_USART2SEL 2
+#define STM_RCC_CCIPR_USART1SEL 0
+
+#define STM_RCC_CSR_LPWRRSTF (31)
+#define STM_RCC_CSR_WWDGRSTF (30)
+#define STM_RCC_CSR_IWDGRSTF (29)
+#define STM_RCC_CSR_SFTRSTF (28)
+#define STM_RCC_CSR_PORRSTF (27)
+#define STM_RCC_CSR_PINRSTF (26)
+#define STM_RCC_CSR_OBLRSTF (25)
+#define STM_RCC_CSR_RMVF (24)
+#define STM_RCC_CSR_RTFRST (23)
+#define STM_RCC_CSR_RTCEN (22)
+#define STM_RCC_CSR_RTCSEL (16)
+
+#define STM_RCC_CSR_RTCSEL_NONE 0
+#define STM_RCC_CSR_RTCSEL_LSE 1
+#define STM_RCC_CSR_RTCSEL_LSI 2
+#define STM_RCC_CSR_RTCSEL_HSE 3
+#define STM_RCC_CSR_RTCSEL_MASK 3
+
+#define STM_RCC_CSR_LSEBYP (10)
+#define STM_RCC_CSR_LSERDY (9)
+#define STM_RCC_CSR_LSEON (8)
+#define STM_RCC_CSR_LSIRDY (1)
+#define STM_RCC_CSR_LSION (0)
+
+struct stm_pwr {
+ vuint32_t cr;
+ vuint32_t csr;
+};
+
+extern struct stm_pwr stm_pwr;
+
+
+#define STM_PWR_CR_LPDS 16
+#define STM_PWR_CR_LPRUN 14
+#define STM_PWR_CR_DS_EE_KOFF 13
+#define STM_PWR_CR_VOS 11
+#define STM_PWR_CR_VOS_1_8 1
+#define STM_PWR_CR_VOS_1_5 2
+#define STM_PWR_CR_VOS_1_2 3
+#define STM_PWR_CR_VOS_MASK 3
+#define STM_PWR_CR_FWU 10
+#define STM_PWR_CR_ULP 9
+#define STM_PWR_CR_DBP 8
+#define STM_PWR_CR_PLS 5
+#define STM_PWR_CR_PLS_1_9 0
+#define STM_PWR_CR_PLS_2_1 1
+#define STM_PWR_CR_PLS_2_3 2
+#define STM_PWR_CR_PLS_2_5 3
+#define STM_PWR_CR_PLS_2_7 4
+#define STM_PWR_CR_PLS_2_9 5
+#define STM_PWR_CR_PLS_3_1 6
+#define STM_PWR_CR_PLS_EXT 7
+#define STM_PWR_CR_PLS_MASK 7
+#define STM_PWR_CR_PVDE 4
+#define STM_PWR_CR_CSBF 3
+#define STM_PWR_CR_CWUF 2
+#define STM_PWR_CR_PDDS 1
+#define STM_PWR_CR_LPSDSR 0
+
+#define STM_PWR_CSR_EWUP3 (10)
+#define STM_PWR_CSR_EWUP2 (9)
+#define STM_PWR_CSR_EWUP1 (8)
+#define STM_PWR_CSR_REGLPF (5)
+#define STM_PWR_CSR_VOSF (4)
+#define STM_PWR_CSR_VREFINTRDYF (3)
+#define STM_PWR_CSR_PVDO (2)
+#define STM_PWR_CSR_SBF (1)
+#define STM_PWR_CSR_WUF (0)
+
+struct stm_tim67 {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ uint32_t _unused_08;
+ vuint32_t dier;
+
+ vuint32_t sr;
+ vuint32_t egr;
+ uint32_t _unused_18;
+ uint32_t _unused_1c;
+
+ uint32_t _unused_20;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+};
+
+extern struct stm_tim67 stm_tim6;
+
+#define STM_TIM67_CR1_ARPE (7)
+#define STM_TIM67_CR1_OPM (3)
+#define STM_TIM67_CR1_URS (2)
+#define STM_TIM67_CR1_UDIS (1)
+#define STM_TIM67_CR1_CEN (0)
+
+#define STM_TIM67_CR2_MMS (4)
+#define STM_TIM67_CR2_MMS_RESET 0
+#define STM_TIM67_CR2_MMS_ENABLE 1
+#define STM_TIM67_CR2_MMS_UPDATE 2
+#define STM_TIM67_CR2_MMS_MASK 7
+
+#define STM_TIM67_DIER_UDE (8)
+#define STM_TIM67_DIER_UIE (0)
+
+#define STM_TIM67_SR_UIF (0)
+
+#define STM_TIM67_EGR_UG (0)
+
+struct stm_lcd {
+ vuint32_t cr;
+ vuint32_t fcr;
+ vuint32_t sr;
+ vuint32_t clr;
+ uint32_t unused_0x10;
+ vuint32_t ram[8*2];
+};
+
+extern struct stm_lcd stm_lcd;
+
+#define STM_LCD_CR_MUX_SEG (7)
+
+#define STM_LCD_CR_BIAS (5)
+#define STM_LCD_CR_BIAS_1_4 0
+#define STM_LCD_CR_BIAS_1_2 1
+#define STM_LCD_CR_BIAS_1_3 2
+#define STM_LCD_CR_BIAS_MASK 3
+
+#define STM_LCD_CR_DUTY (2)
+#define STM_LCD_CR_DUTY_STATIC 0
+#define STM_LCD_CR_DUTY_1_2 1
+#define STM_LCD_CR_DUTY_1_3 2
+#define STM_LCD_CR_DUTY_1_4 3
+#define STM_LCD_CR_DUTY_1_8 4
+#define STM_LCD_CR_DUTY_MASK 7
+
+#define STM_LCD_CR_VSEL (1)
+#define STM_LCD_CR_LCDEN (0)
+
+#define STM_LCD_FCR_PS (22)
+#define STM_LCD_FCR_PS_1 0x0
+#define STM_LCD_FCR_PS_2 0x1
+#define STM_LCD_FCR_PS_4 0x2
+#define STM_LCD_FCR_PS_8 0x3
+#define STM_LCD_FCR_PS_16 0x4
+#define STM_LCD_FCR_PS_32 0x5
+#define STM_LCD_FCR_PS_64 0x6
+#define STM_LCD_FCR_PS_128 0x7
+#define STM_LCD_FCR_PS_256 0x8
+#define STM_LCD_FCR_PS_512 0x9
+#define STM_LCD_FCR_PS_1024 0xa
+#define STM_LCD_FCR_PS_2048 0xb
+#define STM_LCD_FCR_PS_4096 0xc
+#define STM_LCD_FCR_PS_8192 0xd
+#define STM_LCD_FCR_PS_16384 0xe
+#define STM_LCD_FCR_PS_32768 0xf
+#define STM_LCD_FCR_PS_MASK 0xf
+
+#define STM_LCD_FCR_DIV (18)
+#define STM_LCD_FCR_DIV_16 0x0
+#define STM_LCD_FCR_DIV_17 0x1
+#define STM_LCD_FCR_DIV_18 0x2
+#define STM_LCD_FCR_DIV_19 0x3
+#define STM_LCD_FCR_DIV_20 0x4
+#define STM_LCD_FCR_DIV_21 0x5
+#define STM_LCD_FCR_DIV_22 0x6
+#define STM_LCD_FCR_DIV_23 0x7
+#define STM_LCD_FCR_DIV_24 0x8
+#define STM_LCD_FCR_DIV_25 0x9
+#define STM_LCD_FCR_DIV_26 0xa
+#define STM_LCD_FCR_DIV_27 0xb
+#define STM_LCD_FCR_DIV_28 0xc
+#define STM_LCD_FCR_DIV_29 0xd
+#define STM_LCD_FCR_DIV_30 0xe
+#define STM_LCD_FCR_DIV_31 0xf
+#define STM_LCD_FCR_DIV_MASK 0xf
+
+#define STM_LCD_FCR_BLINK (16)
+#define STM_LCD_FCR_BLINK_DISABLE 0
+#define STM_LCD_FCR_BLINK_SEG0_COM0 1
+#define STM_LCD_FCR_BLINK_SEG0_COMALL 2
+#define STM_LCD_FCR_BLINK_SEGALL_COMALL 3
+#define STM_LCD_FCR_BLINK_MASK 3
+
+#define STM_LCD_FCR_BLINKF (13)
+#define STM_LCD_FCR_BLINKF_8 0
+#define STM_LCD_FCR_BLINKF_16 1
+#define STM_LCD_FCR_BLINKF_32 2
+#define STM_LCD_FCR_BLINKF_64 3
+#define STM_LCD_FCR_BLINKF_128 4
+#define STM_LCD_FCR_BLINKF_256 5
+#define STM_LCD_FCR_BLINKF_512 6
+#define STM_LCD_FCR_BLINKF_1024 7
+#define STM_LCD_FCR_BLINKF_MASK 7
+
+#define STM_LCD_FCR_CC (10)
+#define STM_LCD_FCR_CC_MASK 7
+
+#define STM_LCD_FCR_DEAD (7)
+#define STM_LCD_FCR_DEAD_MASK 7
+
+#define STM_LCD_FCR_PON (4)
+#define STM_LCD_FCR_PON_MASK 7
+
+#define STM_LCD_FCR_UDDIE (3)
+#define STM_LCD_FCR_SOFIE (1)
+#define STM_LCD_FCR_HD (0)
+
+#define STM_LCD_SR_FCRSF (5)
+#define STM_LCD_SR_RDY (4)
+#define STM_LCD_SR_UDD (3)
+#define STM_LCD_SR_UDR (2)
+#define STM_LCD_SR_SOF (1)
+#define STM_LCD_SR_ENS (0)
+
+#define STM_LCD_CLR_UDDC (3)
+#define STM_LCD_CLR_SOFC (1)
+
+/* The SYSTICK starts at 0xe000e010 */
+
+struct stm_systick {
+ vuint32_t csr;
+ vuint32_t rvr;
+ vuint32_t cvr;
+ vuint32_t calib;
+};
+
+extern struct stm_systick stm_systick;
+
+#define STM_SYSTICK_CSR_ENABLE 0
+#define STM_SYSTICK_CSR_TICKINT 1
+#define STM_SYSTICK_CSR_CLKSOURCE 2
+#define STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 0
+#define STM_SYSTICK_CSR_CLKSOURCE_HCLK 1
+#define STM_SYSTICK_CSR_COUNTFLAG 16
+
+/* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */
+
+struct stm_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 stm_nvic stm_nvic;
+
+#define IRQ_MASK(irq) (1 << (irq))
+#define IRQ_BOOL(v,irq) (((v) >> (irq)) & 1)
+
+static inline void
+stm_nvic_set_enable(int irq) {
+ stm_nvic.iser = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_enable(int irq) {
+ stm_nvic.icer = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_enabled(int irq) {
+ return IRQ_BOOL(stm_nvic.iser, irq);
+}
+
+static inline void
+stm_nvic_set_pending(int irq) {
+ stm_nvic.ispr = IRQ_MASK(irq);
+}
+
+static inline void
+stm_nvic_clear_pending(int irq) {
+ stm_nvic.icpr = IRQ_MASK(irq);
+}
+
+static inline int
+stm_nvic_pending(int irq) {
+ return IRQ_BOOL(stm_nvic.ispr, irq);
+}
+
+#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
+stm_nvic_set_priority(int irq, uint8_t prio) {
+ int n = IRQ_PRIO_REG(irq);
+ uint32_t v;
+
+ v = stm_nvic.ipr[n];
+ v &= ~IRQ_PRIO_MASK(irq);
+ v |= (prio) << IRQ_PRIO_BIT(irq);
+ stm_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+stm_nvic_get_priority(int irq) {
+ return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
+struct stm_scb {
+ vuint32_t cpuid;
+ vuint32_t icsr;
+ vuint32_t vtor;
+ vuint32_t aircr;
+
+ vuint32_t scr;
+ vuint32_t ccr;
+ vuint32_t shpr1;
+ vuint32_t shpr2;
+
+ vuint32_t shpr3;
+ vuint32_t shcrs;
+ vuint32_t cfsr;
+ vuint32_t hfsr;
+
+ uint32_t unused_30;
+ vuint32_t mmfar;
+ vuint32_t bfar;
+};
+
+extern struct stm_scb stm_scb;
+
+#define STM_SCB_AIRCR_VECTKEY 16
+#define STM_SCB_AIRCR_VECTKEY_KEY 0x05fa
+#define STM_SCB_AIRCR_PRIGROUP 8
+#define STM_SCB_AIRCR_SYSRESETREQ 2
+#define STM_SCB_AIRCR_VECTCLRACTIVE 1
+#define STM_SCB_AIRCR_VECTRESET 0
+
+#define STM_SCB_SCR_SVONPEND 4
+#define STM_SCB_SCR_SLEEPDEEP 2
+#define STM_SCB_SCR_SLEEPONEXIT 1
+
+struct stm_mpu {
+ vuint32_t typer;
+ vuint32_t cr;
+ vuint32_t rnr;
+ vuint32_t rbar;
+
+ vuint32_t rasr;
+ vuint32_t rbar_a1;
+ vuint32_t rasr_a1;
+ vuint32_t rbar_a2;
+ vuint32_t rasr_a2;
+ vuint32_t rbar_a3;
+ vuint32_t rasr_a3;
+};
+
+extern struct stm_mpu stm_mpu;
+
+#define STM_MPU_TYPER_IREGION 16
+#define STM_MPU_TYPER_IREGION_MASK 0xff
+#define STM_MPU_TYPER_DREGION 8
+#define STM_MPU_TYPER_DREGION_MASK 0xff
+#define STM_MPU_TYPER_SEPARATE 0
+
+#define STM_MPU_CR_PRIVDEFENA 2
+#define STM_MPU_CR_HFNMIENA 1
+#define STM_MPU_CR_ENABLE 0
+
+#define STM_MPU_RNR_REGION 0
+#define STM_MPU_RNR_REGION_MASK 0xff
+
+#define STM_MPU_RBAR_ADDR 5
+#define STM_MPU_RBAR_ADDR_MASK 0x7ffffff
+
+#define STM_MPU_RBAR_VALID 4
+#define STM_MPU_RBAR_REGION 0
+#define STM_MPU_RBAR_REGION_MASK 0xf
+
+#define STM_MPU_RASR_XN 28
+#define STM_MPU_RASR_AP 24
+#define STM_MPU_RASR_AP_NONE_NONE 0
+#define STM_MPU_RASR_AP_RW_NONE 1
+#define STM_MPU_RASR_AP_RW_RO 2
+#define STM_MPU_RASR_AP_RW_RW 3
+#define STM_MPU_RASR_AP_RO_NONE 5
+#define STM_MPU_RASR_AP_RO_RO 6
+#define STM_MPU_RASR_AP_MASK 7
+#define STM_MPU_RASR_TEX 19
+#define STM_MPU_RASR_TEX_MASK 7
+#define STM_MPU_RASR_S 18
+#define STM_MPU_RASR_C 17
+#define STM_MPU_RASR_B 16
+#define STM_MPU_RASR_SRD 8
+#define STM_MPU_RASR_SRD_MASK 0xff
+#define STM_MPU_RASR_SIZE 1
+#define STM_MPU_RASR_SIZE_MASK 0x1f
+#define STM_MPU_RASR_ENABLE 0
+
+#define isr_decl(name) void stm_ ## name ## _isr(void)
+
+isr_decl(halt);
+isr_decl(ignore);
+
+isr_decl(nmi);
+isr_decl(hardfault);
+isr_decl(usagefault);
+isr_decl(svc);
+isr_decl(debugmon);
+isr_decl(pendsv);
+isr_decl(systick);
+isr_decl(wwdg);
+isr_decl(pvd);
+isr_decl(rtc);
+isr_decl(flash);
+isr_decl(rcc_crs);
+isr_decl(exti1_0);
+isr_decl(exti3_2);
+isr_decl(exti15_4);
+isr_decl(dma1_channel1);
+isr_decl(dma1_channel3_2);
+isr_decl(dma1_channel7_4);
+isr_decl(adc_comp);
+isr_decl(lptim1);
+isr_decl(usart4_usart5);
+isr_decl(tim2);
+isr_decl(tim3);
+isr_decl(tim4);
+isr_decl(tim6);
+isr_decl(tim7);
+isr_decl(tim21);
+isr_decl(i2c3);
+isr_decl(tim22);
+isr_decl(i2c1);
+isr_decl(i2c2);
+isr_decl(spi1);
+isr_decl(spi2);
+isr_decl(usart1);
+isr_decl(usart2);
+isr_decl(usart3);
+isr_decl(lpuart1_aes);
+
+#undef isr_decl
+
+#define STM_ISR_WWDG_POS 0
+#define STM_ISR_PVD_POS 1
+#define STM_ISR_RTC_POS 2
+#define STM_ISR_FLASH_POS 3
+#define STM_ISR_RCC_CRS_POS 4
+#define STM_ISR_EXTI1_0_POS 5
+#define STM_ISR_EXTI3_2_POS 6
+#define STM_ISR_EXTI15_4_POS 7
+#define STM_ISR_DMA1_CHANNEL1_POS 9
+#define STM_ISR_DMA1_CHANNEL3_2_POS 10
+#define STM_ISR_DMA1_CHANNEL7_4_POS 11
+#define STM_ISR_ADC_COMP_POS 12
+#define STM_ISR_LPTIM1_POS 13
+#define STM_ISR_USART4_USART5_POS 14
+#define STM_ISR_TIM2_POS 15
+#define STM_ISR_TIM3_POS 16
+#define STM_ISR_TIM6_POS 17
+#define STM_ISR_TIM7_POS 18
+#define STM_ISR_TIM21_POS 20
+#define STM_ISR_I2C3_POS 21
+#define STM_ISR_TIM22_POS 22
+#define STM_ISR_I2C1_POS 23
+#define STM_ISR_I2C2_POS 24
+#define STM_ISR_SPI1_POS 25
+#define STM_ISR_SPI2_POS 26
+#define STM_ISR_USART1_POS 27
+#define STM_ISR_USART2_POS 28
+#define STM_ISR_LPUART1_AES_POS 29
+
+struct stm_syscfg {
+ vuint32_t memrmp;
+ vuint32_t pmc;
+ vuint32_t exticr[4];
+};
+
+extern struct stm_syscfg stm_syscfg;
+
+#define STM_SYSCFG_MEMRMP_MEM_MODE 0
+#define STM_SYSCFG_MEMRMP_MEM_MODE_MAIN_FLASH 0
+#define STM_SYSCFG_MEMRMP_MEM_MODE_SYSTEM_FLASH 1
+#define STM_SYSCFG_MEMRMP_MEM_MODE_SRAM 3
+#define STM_SYSCFG_MEMRMP_MEM_MODE_MASK 3
+
+#define STM_SYSCFG_PMC_USB_PU 0
+
+#define STM_SYSCFG_EXTICR_PA 0
+#define STM_SYSCFG_EXTICR_PB 1
+#define STM_SYSCFG_EXTICR_PC 2
+#define STM_SYSCFG_EXTICR_PD 3
+#define STM_SYSCFG_EXTICR_PE 4
+#define STM_SYSCFG_EXTICR_PH 5
+
+static inline void
+stm_exticr_set(struct stm_gpio *gpio, int pin) {
+ uint8_t reg = pin >> 2;
+ uint8_t shift = (pin & 3) << 2;
+ uint8_t val = 0;
+
+ /* Enable SYSCFG */
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGEN);
+
+ if (gpio == &stm_gpioa)
+ val = STM_SYSCFG_EXTICR_PA;
+ else if (gpio == &stm_gpiob)
+ val = STM_SYSCFG_EXTICR_PB;
+ else if (gpio == &stm_gpioc)
+ val = STM_SYSCFG_EXTICR_PC;
+ else if (gpio == &stm_gpiod)
+ val = STM_SYSCFG_EXTICR_PD;
+ else if (gpio == &stm_gpioe)
+ val = STM_SYSCFG_EXTICR_PE;
+
+ stm_syscfg.exticr[reg] = (stm_syscfg.exticr[reg] & ~(0xf << shift)) | val << shift;
+}
+
+struct stm_dma_channel {
+ vuint32_t ccr;
+ vuint32_t cndtr;
+ vvoid_t cpar;
+ vvoid_t cmar;
+ vuint32_t reserved;
+};
+
+#define STM_NUM_DMA 7
+
+struct stm_dma {
+ vuint32_t isr;
+ vuint32_t ifcr;
+ struct stm_dma_channel channel[STM_NUM_DMA];
+ uint8_t unused94[0xa8 - 0x94];
+ vuint32_t cselr;
+};
+
+extern struct stm_dma stm_dma1;
+#define stm_dma1 (*(struct stm_dma *) 0x40020000)
+
+/* DMA channels go from 1 to 7, instead of 0 to 6 (sigh)
+ */
+
+#define STM_DMA_INDEX(channel) ((channel) - 1)
+
+#define STM_DMA_ISR(index) ((index) << 2)
+#define STM_DMA_ISR_MASK 0xf
+#define STM_DMA_ISR_TEIF 3
+#define STM_DMA_ISR_HTIF 2
+#define STM_DMA_ISR_TCIF 1
+#define STM_DMA_ISR_GIF 0
+
+#define STM_DMA_IFCR(index) ((index) << 2)
+#define STM_DMA_IFCR_MASK 0xf
+#define STM_DMA_IFCR_CTEIF 3
+#define STM_DMA_IFCR_CHTIF 2
+#define STM_DMA_IFCR_CTCIF 1
+#define STM_DMA_IFCR_CGIF 0
+
+#define STM_DMA_CCR_MEM2MEM (14)
+
+#define STM_DMA_CCR_PL (12)
+#define STM_DMA_CCR_PL_LOW (0)
+#define STM_DMA_CCR_PL_MEDIUM (1)
+#define STM_DMA_CCR_PL_HIGH (2)
+#define STM_DMA_CCR_PL_VERY_HIGH (3)
+#define STM_DMA_CCR_PL_MASK (3)
+
+#define STM_DMA_CCR_MSIZE (10)
+#define STM_DMA_CCR_MSIZE_8 (0)
+#define STM_DMA_CCR_MSIZE_16 (1)
+#define STM_DMA_CCR_MSIZE_32 (2)
+#define STM_DMA_CCR_MSIZE_MASK (3)
+
+#define STM_DMA_CCR_PSIZE (8)
+#define STM_DMA_CCR_PSIZE_8 (0)
+#define STM_DMA_CCR_PSIZE_16 (1)
+#define STM_DMA_CCR_PSIZE_32 (2)
+#define STM_DMA_CCR_PSIZE_MASK (3)
+
+#define STM_DMA_CCR_MINC (7)
+#define STM_DMA_CCR_PINC (6)
+#define STM_DMA_CCR_CIRC (5)
+#define STM_DMA_CCR_DIR (4)
+#define STM_DMA_CCR_DIR_PER_TO_MEM 0
+#define STM_DMA_CCR_DIR_MEM_TO_PER 1
+#define STM_DMA_CCR_TEIE (3)
+#define STM_DMA_CCR_HTIE (2)
+#define STM_DMA_CCR_TCIE (1)
+#define STM_DMA_CCR_EN (0)
+
+#define STM_DMA_CSELR_C7S_SPI2_TX 0x2
+#define STM_DMA_CSELR_C7S_USART2_TX 0x4
+#define STM_DMA_CSELR_C7S_LPUART1_TX 0x5
+#define STM_DMA_CSELR_C7S_I2C1_RX 0x6
+#define STM_DMA_CSELR_C7S_TIM2_CH2_TIM2_CH4 0x8
+#define STM_DMA_CSELR_C7S_USART4_TX 0xc
+#define STM_DMA_CSELR_C7S_USART5_TX 0xd
+
+#define STM_DMA_CSELR_C6S_SPI2_RX 0x2
+#define STM_DMA_CSELR_C6S_USART2_RX 0x4
+#define STM_DMA_CSELR_C6S_LPUART1_RX 0x5
+#define STM_DMA_CSELR_C6S_I2C1_TX 0x6
+#define STM_DMA_CSELR_C6S_TIM3_TRIG 0xa
+#define STM_DMA_CSELR_C6S_USART4_RX 0xc
+#define STM_DMA_CSELR_C6S_USART5_RX 0xd
+
+#define STM_DMA_CSELR_C5S_SPI2_TX 0x2
+#define STM_DMA_CSELR_C5S_USART1_RX 0x3
+#define STM_DMA_CSELR_C5S_USART2_RX 0x4
+#define STM_DMA_CSELR_C5S_I2C2_RX 0x7
+#define STM_DMA_CSELR_C5S_TIM2_CH1 0x8
+#define STM_DMA_CSELR_C5S_TIM3_CH1 0xa
+#define STM_DMA_CSELR_C5S_AES_IN 0xb
+#define STM_DMA_CSELR_C5S_I2C3_RX 0xe
+
+#define STM_DMA_CSELR_C4S_SPI2_RX 0x2
+#define STM_DMA_CSELR_C4S_USART1_TX 0x3
+#define STM_DMA_CSELR_C4S_USART2_TX 0x4
+#define STM_DMA_CSELR_C4S_I2C2_TX 0x7
+#define STM_DMA_CSELR_C4S_TIM2_CH4 0x8
+#define STM_DMA_CSELR_C4S_I2C3_TX 0xe
+#define STM_DMA_CSELR_C4S_TIM7_UP 0xf
+
+#define STM_DMA_CSELR_C3S_SPI1_TX 0x1
+#define STM_DMA_CSELR_C3S_USART1_RX 0x3
+#define STM_DMA_CSELR_C3S_LPUART1_RX 0x5
+#define STM_DMA_CSELR_C3S_I2C1_RX 0x6
+#define STM_DMA_CSELR_C3S_TIM2_CH2 0x8
+#define STM_DMA_CSELR_C3S_TIM4_CH4_TIM4_UP 0xa
+#define STM_DMA_CSELR_C3S_AES_OUT 0xb
+#define STM_DMA_CSELR_C3S_USART4_TX 0xc
+#define STM_DMA_CSELR_C3S_USART5_TX 0xd
+#define STM_DMA_CSELR_C3S_I2C3_RX 0xe
+
+#define STM_DMA_CSELR_C2S_ADC 0x0
+#define STM_DMA_CSELR_C2S_SPI1_RX 0x1
+#define STM_DMA_CSELR_C2S_USART1_TX 0x3
+#define STM_DMA_CSELR_C2S_LPUART1_TX 0x5
+#define STM_DMA_CSELR_C2S_I2C1_TX 0x6
+#define STM_DMA_CSELR_C2S_TIM2_UP 0x8
+#define STM_DMA_CSELR_C2S_TIM6_UP 0x9
+#define STM_DMA_CSELR_C2S_TIM3_CH3 0xa
+#define STM_DMA_CSELR_C2S_AES_OUT 0xb
+#define STM_DMA_CSELR_C2S_USART4_RX 0xc
+#define STM_DMA_CSELR_C2S_USART5_RX 0xd
+#define STM_DMA_CSELR_C2S_I2C3_TX 0xe
+
+#define STM_DMA_CSELR_C1S_ADC 0x0
+#define STM_DMA_CSELR_C1S_TIM2_CH3 0x8
+#define STM_DMA_CSELR_C1S_AES_IN 0xb
+
+#define STM_NUM_SPI 1
+
+struct stm_spi {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t sr;
+ vuint32_t dr;
+ vuint32_t crcpr;
+ vuint32_t rxcrcr;
+ vuint32_t txcrcr;
+};
+
+extern struct stm_spi stm_spi1;
+#define stm_spi1 (*(struct stm_spi *) 0x40013000)
+
+/* SPI channels go from 1 to 3, instead of 0 to 2 (sigh)
+ */
+
+#define STM_SPI_INDEX(channel) ((channel) - 1)
+
+#define STM_SPI_CR1_BIDIMODE 15
+#define STM_SPI_CR1_BIDIOE 14
+#define STM_SPI_CR1_CRCEN 13
+#define STM_SPI_CR1_CRCNEXT 12
+#define STM_SPI_CR1_DFF 11
+#define STM_SPI_CR1_RXONLY 10
+#define STM_SPI_CR1_SSM 9
+#define STM_SPI_CR1_SSI 8
+#define STM_SPI_CR1_LSBFIRST 7
+#define STM_SPI_CR1_SPE 6
+#define STM_SPI_CR1_BR 3
+#define STM_SPI_CR1_BR_PCLK_2 0
+#define STM_SPI_CR1_BR_PCLK_4 1
+#define STM_SPI_CR1_BR_PCLK_8 2
+#define STM_SPI_CR1_BR_PCLK_16 3
+#define STM_SPI_CR1_BR_PCLK_32 4
+#define STM_SPI_CR1_BR_PCLK_64 5
+#define STM_SPI_CR1_BR_PCLK_128 6
+#define STM_SPI_CR1_BR_PCLK_256 7
+#define STM_SPI_CR1_BR_MASK 7
+
+#define STM_SPI_CR1_MSTR 2
+#define STM_SPI_CR1_CPOL 1
+#define STM_SPI_CR1_CPHA 0
+
+#define STM_SPI_CR2_TXEIE 7
+#define STM_SPI_CR2_RXNEIE 6
+#define STM_SPI_CR2_ERRIE 5
+#define STM_SPI_CR2_SSOE 2
+#define STM_SPI_CR2_TXDMAEN 1
+#define STM_SPI_CR2_RXDMAEN 0
+
+#define STM_SPI_SR_FRE 8
+#define STM_SPI_SR_BSY 7
+#define STM_SPI_SR_OVR 6
+#define STM_SPI_SR_MODF 5
+#define STM_SPI_SR_CRCERR 4
+#define STM_SPI_SR_UDR 3
+#define STM_SPI_SR_CHSIDE 2
+#define STM_SPI_SR_TXE 1
+#define STM_SPI_SR_RXNE 0
+
+struct stm_adc {
+ vuint32_t isr;
+ vuint32_t ier;
+ vuint32_t cr;
+ vuint32_t cfgr1;
+
+ vuint32_t cfgr2;
+ vuint32_t smpr;
+ vuint32_t r_18;
+ vuint32_t r_1c;
+
+ vuint32_t tr;
+ vuint32_t r_24;
+ vuint32_t chselr;
+ vuint32_t r_2c;
+
+ vuint32_t r_30[4];
+
+ vuint32_t dr;
+
+ uint8_t r_44[0xb4 - 0x44];
+
+ vuint32_t calfact;
+
+ uint8_t r_b8[0x308 - 0xb8];
+ vuint32_t ccr;
+};
+
+extern struct stm_adc stm_adc;
+#define stm_adc (*(struct stm_adc *) 0x40012400)
+
+#define STM_ADC_ISR_AWD 7
+#define STM_ADC_ISR_OVR 4
+#define STM_ADC_ISR_EOSEQ 3
+#define STM_ADC_ISR_EOC 2
+#define STM_ADC_ISR_EOSMP 1
+#define STM_ADC_ISR_ADRDY 0
+
+#define STM_ADC_IER_AWDIE 7
+#define STM_ADC_IER_OVRIE 4
+#define STM_ADC_IER_EOSEQIE 3
+#define STM_ADC_IER_EOCIE 2
+#define STM_ADC_IER_EOSMPIE 1
+#define STM_ADC_IER_ADRDYIE 0
+
+#define STM_ADC_CR_ADCAL 31
+#define STM_ADC_CR_ADVREGEN 28
+#define STM_ADC_CR_ADSTP 4
+#define STM_ADC_CR_ADSTART 2
+#define STM_ADC_CR_ADDIS 1
+#define STM_ADC_CR_ADEN 0
+
+#define STM_ADC_CFGR1_AWDCH 26
+#define STM_ADC_CFGR1_AWDEN 23
+#define STM_ADC_CFGR1_AWDSGL 22
+#define STM_ADC_CFGR1_DISCEN 16
+#define STM_ADC_CFGR1_AUTOOFF 15
+#define STM_ADC_CFGR1_WAIT 14
+#define STM_ADC_CFGR1_CONT 13
+#define STM_ADC_CFGR1_OVRMOD 12
+#define STM_ADC_CFGR1_EXTEN 10
+#define STM_ADC_CFGR1_EXTEN_DISABLE 0
+#define STM_ADC_CFGR1_EXTEN_RISING 1
+#define STM_ADC_CFGR1_EXTEN_FALLING 2
+#define STM_ADC_CFGR1_EXTEN_BOTH 3
+#define STM_ADC_CFGR1_EXTEN_MASK 3
+
+#define STM_ADC_CFGR1_EXTSEL 6
+#define STM_ADC_CFGR1_ALIGN 5
+#define STM_ADC_CFGR1_RES 3
+#define STM_ADC_CFGR1_RES_12 0
+#define STM_ADC_CFGR1_RES_10 1
+#define STM_ADC_CFGR1_RES_8 2
+#define STM_ADC_CFGR1_RES_6 3
+#define STM_ADC_CFGR1_RES_MASK 3
+#define STM_ADC_CFGR1_SCANDIR 2
+#define STM_ADC_CFGR1_SCANDIR_UP 0
+#define STM_ADC_CFGR1_SCANDIR_DOWN 1
+#define STM_ADC_CFGR1_DMACFG 1
+#define STM_ADC_CFGR1_DMACFG_ONESHOT 0
+#define STM_ADC_CFGR1_DMACFG_CIRCULAR 1
+#define STM_ADC_CFGR1_DMAEN 0
+
+#define STM_ADC_CFGR2_CKMODE 30
+#define STM_ADC_CFGR2_CKMODE_ADCCLK 0
+#define STM_ADC_CFGR2_CKMODE_PCLK_2 1
+#define STM_ADC_CFGR2_CKMODE_PCLK_4 2
+#define STM_ADC_CFGR2_CKMODE_PCLK 3
+
+#define STM_ADC_SMPR_SMP 0
+#define STM_ADC_SMPR_SMP_1_5 0
+#define STM_ADC_SMPR_SMP_7_5 1
+#define STM_ADC_SMPR_SMP_13_5 2
+#define STM_ADC_SMPR_SMP_28_5 3
+#define STM_ADC_SMPR_SMP_41_5 4
+#define STM_ADC_SMPR_SMP_55_5 5
+#define STM_ADC_SMPR_SMP_71_5 6
+#define STM_ADC_SMPR_SMP_239_5 7
+
+#define STM_ADC_TR_HT 16
+#define STM_ADC_TR_LT 0
+
+#define STM_ADC_CCR_LFMEN 25
+#define STM_ADC_CCR_VLCDEN 24
+#define STM_ADC_CCR_TSEN 23
+#define STM_ADC_CCR_VREFEN 22
+#define STM_ADC_CCR_PRESC 18
+
+#define STM_ADC_CHSEL_TEMP 18
+#define STM_ADC_CHSEL_VREF 17
+#define STM_ADC_CHSEL_VLCD 16
+
+struct stm_cal {
+ uint16_t ts_cal_cold; /* 30°C */
+ uint16_t vrefint_cal;
+ uint16_t unused_c0;
+ uint16_t ts_cal_hot; /* 110°C */
+};
+
+extern struct stm_cal stm_cal;
+
+#define stm_temp_cal_cold 30
+#define stm_temp_cal_hot 110
+
+struct stm_dbg_mcu {
+ uint32_t idcode;
+};
+
+extern struct stm_dbg_mcu stm_dbg_mcu;
+
+static inline uint16_t
+stm_dev_id(void) {
+ return stm_dbg_mcu.idcode & 0xfff;
+}
+
+struct stm_flash_size {
+ uint16_t f_size;
+};
+
+extern struct stm_flash_size stm_flash_size_reg;
+#define stm_flash_size_reg (*((struct stm_flash_size *) 0x1ff8007c))
+
+/* Returns flash size in bytes */
+extern uint32_t
+stm_flash_size(void);
+
+struct stm_device_id {
+ char lot_num_4_6[3];
+ uint8_t waf_num;
+ char lot_num_0_3[4];
+ uint8_t unique_id[4];
+};
+
+extern struct stm_device_id stm_device_id;
+#define stm_device_id (*((struct stm_device_id *) 0x1ff80050))
+
+#define STM_NUM_I2C 2
+
+#define STM_I2C_INDEX(channel) ((channel) - 1)
+
+struct stm_i2c {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t oar1;
+ vuint32_t oar2;
+ vuint32_t dr;
+ vuint32_t sr1;
+ vuint32_t sr2;
+ vuint32_t ccr;
+ vuint32_t trise;
+};
+
+extern struct stm_i2c stm_i2c1, stm_i2c2;
+
+#define STM_I2C_CR1_SWRST 15
+#define STM_I2C_CR1_ALERT 13
+#define STM_I2C_CR1_PEC 12
+#define STM_I2C_CR1_POS 11
+#define STM_I2C_CR1_ACK 10
+#define STM_I2C_CR1_STOP 9
+#define STM_I2C_CR1_START 8
+#define STM_I2C_CR1_NOSTRETCH 7
+#define STM_I2C_CR1_ENGC 6
+#define STM_I2C_CR1_ENPEC 5
+#define STM_I2C_CR1_ENARP 4
+#define STM_I2C_CR1_SMBTYPE 3
+#define STM_I2C_CR1_SMBUS 1
+#define STM_I2C_CR1_PE 0
+
+#define STM_I2C_CR2_LAST 12
+#define STM_I2C_CR2_DMAEN 11
+#define STM_I2C_CR2_ITBUFEN 10
+#define STM_I2C_CR2_ITEVTEN 9
+#define STM_I2C_CR2_ITERREN 8
+#define STM_I2C_CR2_FREQ 0
+#define STM_I2C_CR2_FREQ_2_MHZ 2
+#define STM_I2C_CR2_FREQ_4_MHZ 4
+#define STM_I2C_CR2_FREQ_8_MHZ 8
+#define STM_I2C_CR2_FREQ_16_MHZ 16
+#define STM_I2C_CR2_FREQ_24_MHZ 24
+#define STM_I2C_CR2_FREQ_32_MHZ 32
+#define STM_I2C_CR2_FREQ_MASK 0x3f
+
+#define STM_I2C_SR1_SMBALERT 15
+#define STM_I2C_SR1_TIMEOUT 14
+#define STM_I2C_SR1_PECERR 12
+#define STM_I2C_SR1_OVR 11
+#define STM_I2C_SR1_AF 10
+#define STM_I2C_SR1_ARLO 9
+#define STM_I2C_SR1_BERR 8
+#define STM_I2C_SR1_TXE 7
+#define STM_I2C_SR1_RXNE 6
+#define STM_I2C_SR1_STOPF 4
+#define STM_I2C_SR1_ADD10 3
+#define STM_I2C_SR1_BTF 2
+#define STM_I2C_SR1_ADDR 1
+#define STM_I2C_SR1_SB 0
+
+#define STM_I2C_SR2_PEC 8
+#define STM_I2C_SR2_PEC_MASK 0xff00
+#define STM_I2C_SR2_DUALF 7
+#define STM_I2C_SR2_SMBHOST 6
+#define STM_I2C_SR2_SMBDEFAULT 5
+#define STM_I2C_SR2_GENCALL 4
+#define STM_I2C_SR2_TRA 2
+#define STM_I2C_SR2_BUSY 1
+#define STM_I2C_SR2_MSL 0
+
+#define STM_I2C_CCR_FS 15
+#define STM_I2C_CCR_DUTY 14
+#define STM_I2C_CCR_CCR 0
+#define STM_I2C_CCR_MASK 0x7ff
+
+struct stm_tim234 {
+ vuint32_t cr1;
+ vuint32_t cr2;
+ vuint32_t smcr;
+ vuint32_t dier;
+
+ vuint32_t sr;
+ vuint32_t egr;
+ vuint32_t ccmr1;
+ vuint32_t ccmr2;
+
+ vuint32_t ccer;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+
+ uint32_t reserved_30;
+ vuint32_t ccr1;
+ vuint32_t ccr2;
+ vuint32_t ccr3;
+
+ vuint32_t ccr4;
+ uint32_t reserved_44;
+ vuint32_t dcr;
+ vuint32_t dmar;
+
+ uint32_t reserved_50;
+};
+
+extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4;
+
+#define STM_TIM234_CR1_CKD 8
+#define STM_TIM234_CR1_CKD_1 0
+#define STM_TIM234_CR1_CKD_2 1
+#define STM_TIM234_CR1_CKD_4 2
+#define STM_TIM234_CR1_CKD_MASK 3
+#define STM_TIM234_CR1_ARPE 7
+#define STM_TIM234_CR1_CMS 5
+#define STM_TIM234_CR1_CMS_EDGE 0
+#define STM_TIM234_CR1_CMS_CENTER_1 1
+#define STM_TIM234_CR1_CMS_CENTER_2 2
+#define STM_TIM234_CR1_CMS_CENTER_3 3
+#define STM_TIM234_CR1_CMS_MASK 3
+#define STM_TIM234_CR1_DIR 4
+#define STM_TIM234_CR1_DIR_UP 0
+#define STM_TIM234_CR1_DIR_DOWN 1
+#define STM_TIM234_CR1_OPM 3
+#define STM_TIM234_CR1_URS 2
+#define STM_TIM234_CR1_UDIS 1
+#define STM_TIM234_CR1_CEN 0
+
+#define STM_TIM234_CR2_TI1S 7
+#define STM_TIM234_CR2_MMS 4
+#define STM_TIM234_CR2_MMS_RESET 0
+#define STM_TIM234_CR2_MMS_ENABLE 1
+#define STM_TIM234_CR2_MMS_UPDATE 2
+#define STM_TIM234_CR2_MMS_COMPARE_PULSE 3
+#define STM_TIM234_CR2_MMS_COMPARE_OC1REF 4
+#define STM_TIM234_CR2_MMS_COMPARE_OC2REF 5
+#define STM_TIM234_CR2_MMS_COMPARE_OC3REF 6
+#define STM_TIM234_CR2_MMS_COMPARE_OC4REF 7
+#define STM_TIM234_CR2_MMS_MASK 7
+#define STM_TIM234_CR2_CCDS 3
+
+#define STM_TIM234_SMCR_ETP 15
+#define STM_TIM234_SMCR_ECE 14
+#define STM_TIM234_SMCR_ETPS 12
+#define STM_TIM234_SMCR_ETPS_OFF 0
+#define STM_TIM234_SMCR_ETPS_DIV_2 1
+#define STM_TIM234_SMCR_ETPS_DIV_4 2
+#define STM_TIM234_SMCR_ETPS_DIV_8 3
+#define STM_TIM234_SMCR_ETPS_MASK 3
+#define STM_TIM234_SMCR_ETF 8
+#define STM_TIM234_SMCR_ETF_NONE 0
+#define STM_TIM234_SMCR_ETF_INT_N_2 1
+#define STM_TIM234_SMCR_ETF_INT_N_4 2
+#define STM_TIM234_SMCR_ETF_INT_N_8 3
+#define STM_TIM234_SMCR_ETF_DTS_2_N_6 4
+#define STM_TIM234_SMCR_ETF_DTS_2_N_8 5
+#define STM_TIM234_SMCR_ETF_DTS_4_N_6 6
+#define STM_TIM234_SMCR_ETF_DTS_4_N_8 7
+#define STM_TIM234_SMCR_ETF_DTS_8_N_6 8
+#define STM_TIM234_SMCR_ETF_DTS_8_N_8 9
+#define STM_TIM234_SMCR_ETF_DTS_16_N_5 10
+#define STM_TIM234_SMCR_ETF_DTS_16_N_6 11
+#define STM_TIM234_SMCR_ETF_DTS_16_N_8 12
+#define STM_TIM234_SMCR_ETF_DTS_32_N_5 13
+#define STM_TIM234_SMCR_ETF_DTS_32_N_6 14
+#define STM_TIM234_SMCR_ETF_DTS_32_N_8 15
+#define STM_TIM234_SMCR_ETF_MASK 15
+#define STM_TIM234_SMCR_MSM 7
+#define STM_TIM234_SMCR_TS 4
+#define STM_TIM234_SMCR_TS_ITR0 0
+#define STM_TIM234_SMCR_TS_ITR1 1
+#define STM_TIM234_SMCR_TS_ITR2 2
+#define STM_TIM234_SMCR_TS_ITR3 3
+#define STM_TIM234_SMCR_TS_TI1F_ED 4
+#define STM_TIM234_SMCR_TS_TI1FP1 5
+#define STM_TIM234_SMCR_TS_TI2FP2 6
+#define STM_TIM234_SMCR_TS_ETRF 7
+#define STM_TIM234_SMCR_TS_MASK 7
+#define STM_TIM234_SMCR_OCCS 3
+#define STM_TIM234_SMCR_SMS 0
+#define STM_TIM234_SMCR_SMS_DISABLE 0
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_1 1
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_2 2
+#define STM_TIM234_SMCR_SMS_ENCODER_MODE_3 3
+#define STM_TIM234_SMCR_SMS_RESET_MODE 4
+#define STM_TIM234_SMCR_SMS_GATED_MODE 5
+#define STM_TIM234_SMCR_SMS_TRIGGER_MODE 6
+#define STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK 7
+#define STM_TIM234_SMCR_SMS_MASK 7
+
+#define STM_TIM234_DIER_TDE 14
+#define STM_TIM234_DIER_CC4DE 12
+#define STM_TIM234_DIER_CC3DE 11
+#define STM_TIM234_DIER_CC2DE 10
+#define STM_TIM234_DIER_CC1DE 9
+#define STM_TIM234_DIER_UDE 8
+
+#define STM_TIM234_DIER_TIE 6
+#define STM_TIM234_DIER_CC4IE 4
+#define STM_TIM234_DIER_CC3IE 3
+#define STM_TIM234_DIER_CC2IE 2
+#define STM_TIM234_DIER_CC1IE 1
+#define STM_TIM234_DIER_UIE 0
+
+#define STM_TIM234_SR_CC4OF 12
+#define STM_TIM234_SR_CC3OF 11
+#define STM_TIM234_SR_CC2OF 10
+#define STM_TIM234_SR_CC1OF 9
+#define STM_TIM234_SR_TIF 6
+#define STM_TIM234_SR_CC4IF 4
+#define STM_TIM234_SR_CC3IF 3
+#define STM_TIM234_SR_CC2IF 2
+#define STM_TIM234_SR_CC1IF 1
+#define STM_TIM234_SR_UIF 0
+
+#define STM_TIM234_EGR_TG 6
+#define STM_TIM234_EGR_CC4G 4
+#define STM_TIM234_EGR_CC3G 3
+#define STM_TIM234_EGR_CC2G 2
+#define STM_TIM234_EGR_CC1G 1
+#define STM_TIM234_EGR_UG 0
+
+#define STM_TIM234_CCMR1_OC2CE 15
+#define STM_TIM234_CCMR1_OC2M 12
+#define STM_TIM234_CCMR1_OC2M_FROZEN 0
+#define STM_TIM234_CCMR1_OC2M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR1_OC2M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR1_OC2M_TOGGLE 3
+#define STM_TIM234_CCMR1_OC2M_FORCE_LOW 4
+#define STM_TIM234_CCMR1_OC2M_FORCE_HIGH 5
+#define STM_TIM234_CCMR1_OC2M_PWM_MODE_1 6
+#define STM_TIM234_CCMR1_OC2M_PWM_MODE_2 7
+#define STM_TIM234_CCMR1_OC2M_MASK 7
+#define STM_TIM234_CCMR1_OC2PE 11
+#define STM_TIM234_CCMR1_OC2FE 10
+#define STM_TIM234_CCMR1_CC2S 8
+#define STM_TIM234_CCMR1_CC2S_OUTPUT 0
+#define STM_TIM234_CCMR1_CC2S_INPUT_TI2 1
+#define STM_TIM234_CCMR1_CC2S_INPUT_TI1 2
+#define STM_TIM234_CCMR1_CC2S_INPUT_TRC 3
+#define STM_TIM234_CCMR1_CC2S_MASK 3
+
+#define STM_TIM234_CCMR1_OC1CE 7
+#define STM_TIM234_CCMR1_OC1M 4
+#define STM_TIM234_CCMR1_OC1M_FROZEN 0
+#define STM_TIM234_CCMR1_OC1M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR1_OC1M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM234_CCMR1_OC1M_FORCE_LOW 4
+#define STM_TIM234_CCMR1_OC1M_FORCE_HIGH 5
+#define STM_TIM234_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM234_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM234_CCMR1_OC1M_MASK 7
+#define STM_TIM234_CCMR1_OC1PE 3
+#define STM_TIM234_CCMR1_OC1FE 2
+#define STM_TIM234_CCMR1_CC1S 0
+#define STM_TIM234_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM234_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM234_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM234_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM234_CCMR1_CC1S_MASK 3
+
+#define STM_TIM234_CCMR1_IC2F 12
+#define STM_TIM234_CCMR1_IC2F_NONE 0
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC2F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC2F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC2F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC2F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC2F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC2F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC2PSC 10
+#define STM_TIM234_CCMR1_IC2PSC_NONE 0
+#define STM_TIM234_CCMR1_IC2PSC_2 1
+#define STM_TIM234_CCMR1_IC2PSC_4 2
+#define STM_TIM234_CCMR1_IC2PSC_8 3
+#define STM_TIM234_CCMR1_IC1F 4
+#define STM_TIM234_CCMR1_IC1F_NONE 0
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_2 1
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_4 2
+#define STM_TIM234_CCMR1_IC1F_CK_INT_N_8 3
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_6 4
+#define STM_TIM234_CCMR1_IC1F_DTS_2_N_8 5
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_6 6
+#define STM_TIM234_CCMR1_IC1F_DTS_4_N_8 7
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_6 8
+#define STM_TIM234_CCMR1_IC1F_DTS_8_N_8 9
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_5 10
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_6 11
+#define STM_TIM234_CCMR1_IC1F_DTS_16_N_8 12
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_5 13
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_6 14
+#define STM_TIM234_CCMR1_IC1F_DTS_32_N_8 15
+#define STM_TIM234_CCMR1_IC1PSC 2
+#define STM_TIM234_CCMR1_IC1PSC_NONE 0
+#define STM_TIM234_CCMR1_IC1PSC_2 1
+#define STM_TIM234_CCMR1_IC1PSC_4 2
+#define STM_TIM234_CCMR1_IC1PSC_8 3
+
+#define STM_TIM234_CCMR2_OC4CE 15
+#define STM_TIM234_CCMR2_OC4M 12
+#define STM_TIM234_CCMR2_OC4M_FROZEN 0
+#define STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR2_OC4M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR2_OC4M_TOGGLE 3
+#define STM_TIM234_CCMR2_OC4M_FORCE_LOW 4
+#define STM_TIM234_CCMR2_OC4M_FORCE_HIGH 5
+#define STM_TIM234_CCMR2_OC4M_PWM_MODE_1 6
+#define STM_TIM234_CCMR2_OC4M_PWM_MODE_2 7
+#define STM_TIM234_CCMR2_OC4M_MASK 7
+#define STM_TIM234_CCMR2_OC4PE 11
+#define STM_TIM234_CCMR2_OC4FE 10
+#define STM_TIM234_CCMR2_CC4S 8
+#define STM_TIM234_CCMR2_CC4S_OUTPUT 0
+#define STM_TIM234_CCMR2_CC4S_INPUT_TI4 1
+#define STM_TIM234_CCMR2_CC4S_INPUT_TI3 2
+#define STM_TIM234_CCMR2_CC4S_INPUT_TRC 3
+#define STM_TIM234_CCMR2_CC4S_MASK 3
+
+#define STM_TIM234_CCMR2_OC3CE 7
+#define STM_TIM234_CCMR2_OC3M 4
+#define STM_TIM234_CCMR2_OC3M_FROZEN 0
+#define STM_TIM234_CCMR2_OC3M_SET_HIGH_ON_MATCH 1
+#define STM_TIM234_CCMR2_OC3M_SET_LOW_ON_MATCH 2
+#define STM_TIM234_CCMR2_OC3M_TOGGLE 3
+#define STM_TIM234_CCMR2_OC3M_FORCE_LOW 4
+#define STM_TIM234_CCMR2_OC3M_FORCE_HIGH 5
+#define STM_TIM234_CCMR2_OC3M_PWM_MODE_1 6
+#define STM_TIM234_CCMR2_OC3M_PWM_MODE_2 7
+#define STM_TIM234_CCMR2_OC3M_MASK 7
+#define STM_TIM234_CCMR2_OC3PE 3
+#define STM_TIM234_CCMR2_OC3FE 2
+#define STM_TIM234_CCMR2_CC3S 0
+#define STM_TIM234_CCMR2_CC3S_OUTPUT 0
+#define STM_TIM234_CCMR2_CC3S_INPUT_TI3 1
+#define STM_TIM234_CCMR2_CC3S_INPUT_TI4 2
+#define STM_TIM234_CCMR2_CC3S_INPUT_TRC 3
+#define STM_TIM234_CCMR2_CC3S_MASK 3
+
+#define STM_TIM234_CCER_CC4NP 15
+#define STM_TIM234_CCER_CC4P 13
+#define STM_TIM234_CCER_CC4P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC4P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC4E 12
+#define STM_TIM234_CCER_CC3NP 11
+#define STM_TIM234_CCER_CC3P 9
+#define STM_TIM234_CCER_CC3P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC3P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC3E 8
+#define STM_TIM234_CCER_CC2NP 7
+#define STM_TIM234_CCER_CC2P 5
+#define STM_TIM234_CCER_CC2P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC2P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC2E 4
+#define STM_TIM234_CCER_CC1NP 3
+#define STM_TIM234_CCER_CC1P 1
+#define STM_TIM234_CCER_CC1P_ACTIVE_HIGH 0
+#define STM_TIM234_CCER_CC1P_ACTIVE_LOW 1
+#define STM_TIM234_CCER_CC1E 0
+
+struct stm_exti {
+ vuint32_t imr;
+ vuint32_t emr;
+ vuint32_t rtsr;
+ vuint32_t ftsr;
+
+ vuint32_t swier;
+ vuint32_t pr;
+};
+
+extern struct stm_exti stm_exti;
+#define stm_exti (*(struct stm_exti *) 0x40010400)
+
+struct stm_vrefint_cal {
+ vuint16_t vrefint_cal;
+};
+
+extern struct stm_vrefint_cal stm_vrefint_cal;
+#define stm_vrefint_cal (*(struct stm_vrefint_cal *) 0x1ff80078)
+
+/* Flash interface */
+
+struct stm_flash {
+ vuint32_t acr;
+ vuint32_t pecr;
+ vuint32_t pdkeyr;
+ vuint32_t pekeyr;
+
+ vuint32_t prgkeyr;
+ vuint32_t optkeyr;
+ vuint32_t sr;
+ vuint32_t obr;
+
+ vuint32_t wrpr;
+};
+
+
+extern uint32_t __storage[], __storage_size[];
+
+#define STM_FLASH_PAGE_SIZE 128
+
+#define ao_storage_unit 128
+#define ao_storage_total ((uintptr_t) __storage_size)
+#define ao_storage_block STM_FLASH_PAGE_SIZE
+#define AO_STORAGE_ERASED_BYTE 0x00
+
+extern struct stm_flash stm_flash;
+
+#define STM_FLASH_ACR_PRE_READ (6)
+#define STM_FLASH_ACR_DISAB_BUF (5)
+#define STM_FLASH_ACR_RUN_PD (4)
+#define STM_FLASH_ACR_SLEEP_PD (3)
+#define STM_FLASH_ACR_PRFEN (1)
+#define STM_FLASH_ACR_LATENCY (0)
+
+#define STM_FLASH_PECR_NZDISABLE 23
+#define STM_FLASH_PECR_OBL_LAUNCH 18
+#define STM_FLASH_PECR_ERRIE 17
+#define STM_FLASH_PECR_EOPIE 16
+#define STM_FLASH_PECR_PARRALELLBANK 15
+#define STM_FLASH_PECR_FPRG 10
+#define STM_FLASH_PECR_ERASE 9
+#define STM_FLASH_PECR_FIX 8
+#define STM_FLASH_PECR_DATA 4
+#define STM_FLASH_PECR_PROG 3
+#define STM_FLASH_PECR_OPT_LOCK 2
+#define STM_FLASH_PECR_PRG_LOCK 1
+#define STM_FLASH_PECR_PE_LOCK 0
+
+#define STM_FLASH_SR_OPTVERR 11
+#define STM_FLASH_SR_SIZERR 10
+#define STM_FLASH_SR_PGAERR 9
+#define STM_FLASH_SR_WRPERR 8
+#define STM_FLASH_SR_READY 3
+#define STM_FLASH_SR_ENDHV 2
+#define STM_FLASH_SR_EOP 1
+#define STM_FLASH_SR_BSY 0
+
+#define STM_FLASH_OPTKEYR_OPTKEY1 0xFBEAD9C8
+#define STM_FLASH_OPTKEYR_OPTKEY2 0x24252627
+
+#define STM_FLASH_PEKEYR_PEKEY1 0x89ABCDEF
+#define STM_FLASH_PEKEYR_PEKEY2 0x02030405
+
+#define STM_FLASH_PRGKEYR_PRGKEY1 0x8C9DAEBF
+#define STM_FLASH_PRGKEYR_PRGKEY2 0x13141516
+
+#endif /* _STM32L0_H_ */
--- /dev/null
+/* IOPORT */
+stm_gpioh = 0x50001c00;
+stm_gpioe = 0x50001000;
+stm_gpiod = 0x50000c00;
+stm_gpioc = 0x50000800;
+stm_gpiob = 0x50000400;
+stm_gpioa = 0x50000000;
+
+/* AHB */
+stm_aes = 0x40026000;
+stm_crc = 0x40023000;
+stm_flash = 0x40022000;
+stm_rcc = 0x40021000;
+stm_dma1 = 0x40020000;
+
+/* APB2 */
+stm_dbg = 0x40015800;
+stm_usart1 = 0x40013800;
+stm_spi1 = 0x40013000;
+stm_adc = 0x40012400;
+stm_firewall = 0x40011c00;
+stm_tim22 = 0x40011400;
+stm_tim21 = 0x40010800;
+stm_exti = 0x40010400;
+stm_syscfg = 0x40010000;
+stm_comp = 0x40010000;
+
+/* APB1 */
+stm_lptim1 = 0x40007c00;
+stm_i2c3 = 0x40007800;
+stm_pwr = 0x40007000;
+stm_i2c2 = 0x40005800;
+stm_i2c1 = 0x40005400;
+stm_usart5 = 0x40005000;
+stm_usart4 = 0x40004c00;
+stm_lpuart1 = 0x40004800;
+stm_usart2 = 0x40004400;
+stm_spi2 = 0x40003800;
+stm_iwdg = 0x40003000;
+stm_wwdg = 0x40002c00;
+stm_rtc = 0x40002800;
+stm_timer7 = 0x40001400;
+stm_timer6 = 0x40001000;
+stm_timer3 = 0x40000400;
+stm_timer2 = 0x40000000;
+
+/* ARM */
+stm_systick = 0xe000e010;
+
+stm_nvic = 0xe000e100;
+
+stm_scb = 0xe000ed00;
+
+stm_mpu = 0xe000ed90;
+
+/* ID registers */
+stm_flash_size = 0x1ff8007c;
+stm_device_id = 0x1ff80050;
/* PCLK is set to 48MHz (HCLK 48MHz, HPRE 1, PPRE 1) */
-#define AO_SPI_SPEED_24MHz STM_SPI_CR1_BR_PCLK_2
-#define AO_SPI_SPEED_12MHz STM_SPI_CR1_BR_PCLK_4
-#define AO_SPI_SPEED_6MHz STM_SPI_CR1_BR_PCLK_8
-#define AO_SPI_SPEED_3MHz STM_SPI_CR1_BR_PCLK_16
-#define AO_SPI_SPEED_1500kHz STM_SPI_CR1_BR_PCLK_32
-#define AO_SPI_SPEED_750kHz STM_SPI_CR1_BR_PCLK_64
-#define AO_SPI_SPEED_375kHz STM_SPI_CR1_BR_PCLK_128
-#define AO_SPI_SPEED_187500Hz STM_SPI_CR1_BR_PCLK_256
+#define _AO_SPI_SPEED_24MHz STM_SPI_CR1_BR_PCLK_2
+#define _AO_SPI_SPEED_12MHz STM_SPI_CR1_BR_PCLK_4
+#define _AO_SPI_SPEED_6MHz STM_SPI_CR1_BR_PCLK_8
+#define _AO_SPI_SPEED_3MHz STM_SPI_CR1_BR_PCLK_16
+#define _AO_SPI_SPEED_1500kHz STM_SPI_CR1_BR_PCLK_32
+#define _AO_SPI_SPEED_750kHz STM_SPI_CR1_BR_PCLK_64
+#define _AO_SPI_SPEED_375kHz STM_SPI_CR1_BR_PCLK_128
+#define _AO_SPI_SPEED_187500Hz STM_SPI_CR1_BR_PCLK_256
-#define AO_SPI_SPEED_FAST AO_SPI_SPEED_24MHz
-
-/* Companion bus wants something no faster than 200kHz */
-
-#define AO_SPI_SPEED_200kHz AO_SPI_SPEED_187500Hz
+static inline uint32_t
+ao_spi_speed(uint32_t hz)
+{
+ if (hz >=24000000) return _AO_SPI_SPEED_24MHz;
+ if (hz >=12000000) return _AO_SPI_SPEED_12MHz;
+ if (hz >= 6000000) return _AO_SPI_SPEED_6MHz;
+ if (hz >= 3000000) return _AO_SPI_SPEED_3MHz;
+ if (hz >= 1500000) return _AO_SPI_SPEED_1500kHz;
+ if (hz >= 750000) return _AO_SPI_SPEED_750kHz;
+ if (hz >= 375000) return _AO_SPI_SPEED_375kHz;
+ return _AO_SPI_SPEED_187500Hz;
+}
#define AO_SPI_CONFIG_1 0x00
#define AO_SPI_1_CONFIG_PA5_PA6_PA7 AO_SPI_CONFIG_1
void
ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index);
-extern uint16_t ao_spi_speed[STM_NUM_SPI];
-
void
ao_spi_init(void);
#if HAS_TASK
static inline void
-ao_arch_init_stack(struct ao_task *task, void *start)
+ao_arch_init_stack(struct ao_task *task, uint32_t *sp, void *start)
{
- uint32_t *sp = &task->stack32[AO_STACK_SIZE >> 2];
uint32_t a = (uint32_t) start;
int i;
}
void
-ao_beep_for(uint8_t beep, uint16_t ticks)
+ao_beep_for(uint8_t beep, AO_TICK_TYPE ticks)
{
ao_beep(beep);
ao_delay(ticks);
#if AO_BOOT_CHAIN
if (ao_boot_check_chain()) {
#if AO_BOOT_PIN
- ao_boot_check_pin();
+ if (ao_boot_check_pin())
#endif
+ {
+ ao_boot_chain(AO_BOOT_APPLICATION_BASE);
+ }
}
#endif
/* Turn on syscfg */
ao_led_on(on);
}
-void
-ao_led_toggle(AO_LED_TYPE colors)
-{
-#ifdef LED_PORT
- LED_PORT->odr ^= (colors & LEDS_AVAILABLE);
-#else
-#ifdef LED_PORT_0
- LED_PORT_0->odr ^= ((colors & LEDS_AVAILABLE) & LED_PORT_0_MASK) << LED_PORT_0_SHIFT;
-#endif
-#ifdef LED_PORT_1
- LED_PORT_1->odr ^= ((colors & LEDS_AVAILABLE) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT;
-#endif
-#endif
-}
-
void
ao_led_for(AO_LED_TYPE colors, AO_TICK_TYPE ticks)
{
{
if (stm_systick.csr & (1 << STM_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
+ ao_task_check_alarm();
#if AO_DATA_ALL
if (++ao_data_count == ao_data_interval) {
ao_data_count = 0;
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC1200_SPI_CS_PIN 10
#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#define AO_PA11_PA12_RMP 0
#define IS_FLASH_LOADER 0
-#define HAS_TASK_QUEUE 1
/*
* Serial ports
#define AO_CC1200_SPI_CS_PIN 11
#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_6MHz
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (10)
#define AO_STACK_SIZE 320
-#define HAS_TASK_QUEUE 1
#define IS_FLASH_LOADER 0
#define AO_CC1200_SPI_CS_PIN 3
#define AO_CC1200_SPI_BUS 0
#define AO_CC1200_SPI 0
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_8MHz
#define AO_CC1200_INT_PORT 0
#define AO_CC1200_INT_PIN 2
#define AO_CC1200_SPI_CS_PIN 11
#define AO_CC1200_SPI_BUS AO_SPI_1_PE13_PE14_PE15
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioe)
#define AO_CC1200_INT_PIN (12)
#define AO_CC1200_SPI_CS_PIN 11
#define AO_CC1200_SPI_BUS AO_SPI_1_PE13_PE14_PE15
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioe)
#define AO_CC1200_INT_PIN (12)
#define AO_CC1200_SPI_CS_PIN 7
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#define AO_CC1200_SPI_CS_PIN 3
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#define AO_CC1200_SPI_CS_PIN 7
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#define AO_CC1200_SPI_CS_PIN 7
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC115L_SPI_CS_PIN 12
#define AO_CC115L_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC115L_SPI stm_spi2
-#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_4MHz
#define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2
#define AO_CC115L_FIFO_INT_PORT (&stm_gpioa)
#define AO_CC115L_SPI_CS_PORT 0
#define AO_CC115L_SPI_CS_PIN 3
#define AO_CC115L_SPI_BUS 0
-#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz
#define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2
#define AO_CC115L_FIFO_INT_PORT 0
#define AO_CC115L_SPI_CS_PORT 0
#define AO_CC115L_SPI_CS_PIN 3
#define AO_CC115L_SPI_BUS 0
-#define AO_CC115L_SPI_SPEED AO_SPI_SPEED_6MHz
#define AO_CC115L_FIFO_INT_GPIO_IOCFG CC115L_IOCFG2
#define AO_CC115L_FIFO_INT_PORT 0
#define AO_CC1200_SPI_CS_PIN 1
#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_6MHz
#define AO_CC1200_INT_PORT (&stm_gpioa)
#define AO_CC1200_INT_PIN 4
#define AO_CC1200_SPI_CS_PIN 0
#define AO_CC1200_SPI_BUS AO_SPI_2_PD1_PD3_PD4
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioc)
#define AO_CC1200_INT_PIN (15)
#define AO_CC1200_SPI_CS_PIN 0
#define AO_CC1200_SPI_BUS AO_SPI_2_PD1_PD3_PD4
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioc)
#define AO_CC1200_INT_PIN (15)
#define AO_CC1200_SPI_CS_PIN 0
#define AO_CC1200_SPI_BUS AO_SPI_2_PD1_PD3_PD4
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiod)
#define AO_CC1200_INT_PIN (5)
#define AO_CC1200_SPI_CS_PIN 7
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC1200_SPI_CS_PIN 5
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioe)
#define AO_CC1200_INT_PIN 1
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC1200_SPI_CS_PIN 5
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioe)
#define AO_CC1200_INT_PIN 1
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC1200_SPI_CS_PIN 5
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioe)
#define AO_CC1200_INT_PIN 1
#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
#define AO_ADXL375_CS_PORT (&stm_gpiod)
#define AO_ADXL375_CS_PIN 4
-#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
#define AO_ADXL375_AXIS x
#define AO_ADXL375_INVERT 1
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#define AO_CC1200_SPI_CS_PIN 2
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpioa)
#define AO_CC1200_INT_PIN (3)
#define AO_ADXL375_SPI_INDEX (AO_SPI_1_PB3_PB4_PB5 | AO_SPI_MODE_3)
#define AO_ADXL375_CS_PORT (&stm_gpiob)
#define AO_ADXL375_CS_PIN 9
-#define AO_ADXL375_SPI_SPEED AO_SPI_SPEED_4MHz
#define AO_ADXL375_AXIS x
#define AO_ADXL375_INVERT 1
#define AO_MS5607_MISO_PIN 4
#define AO_MS5607_MISO_MASK (1 << AO_MS5607_MISO_PIN)
#define AO_MS5607_SPI_INDEX AO_SPI_1_PB3_PB4_PB5
-#define AO_MS5607_SPI_SPEED AO_SPI_SPEED_12MHz
/* CC1200 */
#define AO_CC1200_SPI_CS_PIN 0
#define AO_CC1200_SPI_BUS AO_SPI_1_PA5_PA6_PA7
#define AO_CC1200_SPI stm_spi1
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_12MHz
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN 1
#define AO_CC1200_SPI_CS_PIN 3
#define AO_CC1200_SPI_BUS AO_SPI_2_PB13_PB14_PB15
#define AO_CC1200_SPI stm_spi2
-#define AO_CC1200_SPI_SPEED AO_SPI_SPEED_FAST
#define AO_CC1200_INT_PORT (&stm_gpiob)
#define AO_CC1200_INT_PIN (11)
static void ao_led_off(uint8_t led) {
}
-static void ao_delay_until(uint16_t target) {
+static void ao_delay_until(AO_TICK_TYPE target) {
}
-static uint16_t ao_time(void) {
+static AO_TICK_TYPE ao_time(void) {
return 0;
}
#include "ao_microkalman.c"
#include "ao_convert_pa.c"
-uint16_t now;
+AO_TICK_TYPE now;
uint8_t running;
void ao_log_micro_data() {
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
/* 8MHz High speed external crystal */
#define AO_HSE 8000000
#ifndef _AO_PINS_H_
#define _AO_PINS_H_
-#define HAS_TASK_QUEUE 1
#define IS_FLASH_LOADER 0
MACOSX_INFO_PLIST=Info.plist
MACOSX_README=ReadMe-Mac.rtf
-MACOSX_INSTALL=../altosui/install-macosx
+MACOSX_INSTALL=../altosui/install-macosx ../altosui/ask-pass
MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(MACOSX_README) $(DOC) $(MACOSX_ICONS) $(MACOSX_INSTALL)
MACOSX_EXTRA=$(FIRMWARE)
#!/bin/bash
+#
+# Fix fonts. I don't know why the getting the
+# basename of the app set to . matters, but it does
+#
+case "$0" in
+ /*)
+ cd `dirname "$0"`
+ ./`basename "$0"` "$@"
+ exit $?
+ ;;
+esac
+export FREETYPE_PROPERTIES=truetype:interpreter-version=35
##################################################################################
# #
# universalJavaApplicationStub #
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
- pane = getContentPane();
+ pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
/* Product */