+commit 2e26d1ab42163988dc26b06b016c3b05efe17659
+Merge: 639e461 65ed2f5
+Author: Bdale Garbee <bdale@gag.com>
+Date: Mon Jul 4 23:47:24 2016 +0200
+
+ Merge branch 'master' into branch-1.6
+
+commit 65ed2f588ca596fe9aa559bebd590a2a11b9859b
+Author: Keith Packard <keithp@keithp.com>
+Date: Sun Jul 3 12:00:10 2016 +0200
+
+ doc: Build 1.6.5 release notes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d60133c65b4592f0f8c832135664a8e0c922b4f0
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jul 2 22:52:38 2016 +0200
+
+ Credit Chuck Haskin for helping fix the SPI bug.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 14e73d89d7dbb44e9ffab2820aefb693b6e8ef24
+Author: Keith Packard <keithp@keithp.com>
+Date: Sat Jul 2 22:08:58 2016 +0200
+
+ Bump to 1.6.5. Add preliminary release notes
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 8a6a95bb24517af00717fd377bad82ddb2289cf0
+Author: Keith Packard <keithp@keithp.com>
+Date: Thu Jun 30 20:43:03 2016 -0700
+
+ altos/cc1111: Remove 'show tasks' command
+
+ This saves space on cc1111 parts.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit d2e286f66d2b15df128ffe9b40a201242fc4a10a
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 14:22:32 2016 -0700
+
+ Bump to testing version 1.6.4.2
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a04830a636a71808ea8ef5ac5dfa59d6978d9f3b
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 18:41:24 2016 -0700
+
+ altos: Use FIFO_THR pin for cc1120 transmit buffering
+
+ Instead of reading NUM_TXBYTES, set the FIFO_THR pin to indicate when
+ 64 bytes are available in the buffer.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit caf3fc2628c13ff38ffbaabda8aa8d146cda748e
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 18:33:56 2016 -0700
+
+ altos: Leave USB enabled in flight with -DDEBUG=1
+
+ This leaves the command line available for diagnostics when debugging.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit c6c250711355ae8060e956e786702be250ef4527
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 12:55:30 2016 -0700
+
+ altos/stm: clean up ao_exti_enable
+
+ Was computing (1 << pin) twice for no good reason.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a35424cd48205af89ba023db979959dc75b06706
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 12:54:31 2016 -0700
+
+ altos: Make task list output more useful
+
+ Add the timeout value and task id
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6c022e094f6f3c551355742a6f9c3deb6e554fe1
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 16:07:22 2016 -0700
+
+ altos/telemini-v2.0: Remove show tasks command
+
+ There's not enough memory for this command, and it isn't necessary.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 349a63aeed6cdeb89bf18c7b2e2c40782c79cc00
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 12:52:37 2016 -0700
+
+ altos: Make ao_delay(0) not wait forever
+
+ ao_delay() is implemented on top of ao_sleep_for, and ao_sleep_for
+ uses the timeout value of 0 to indicate an infinite timeout. Calls to
+ ao_delay for 0 ticks would unintentionally hit this case and end up
+ waiting forever.x
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3b3a24f5f39a1b72cc8947c33b609f454b46aff8
+Author: Keith Packard <keithp@keithp.com>
+Date: Wed Jun 29 12:49:16 2016 -0700
+
+ altos: cc1200: use FIFO threshold pin output for APRS buffering
+
+ Instead of polling the device for fifo space, just use the available
+ pin configuration to figure out if there is enough space for a single
+ APRS buffer. Then set the APRS buffer size to match the fifo threshold
+ setting in the chip so that we know we can write the whole APRS buffer
+ once the pin says there's space.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 658d8be170f9aea683fe62b68368736a177411a5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:03:34 2016 -0700
+
+ altos: Add debug check for irq block when editing task queues
+
+ List manipulation operations are not atomic, so interrupts need to be
+ blocked while changing them.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 30eb5d2fa77e036690170e7057fa9df669375ae5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 18:40:46 2016 -0700
+
+ altos/drivers: Use more reliable byte interface for CC1120 reception
+
+ This replaces direct register access with function calls to allow that
+ code to respect the hardware requirements.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 61ad8e5bf428246ac89cad7cb9a1edf2ef735fd5
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 18:39:31 2016 -0700
+
+ altos/stm: Add better byte-level SPI api
+
+ This provides inline functions for sending and receiving individual
+ bytes, and setup/finish functions to wrap them in. This make the byte
+ sending respect the SPI hardware interface requirements.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5866d191cee56949ccab4c154a14604e83163d42
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 18:37:49 2016 -0700
+
+ altos/stm: Clean up spi_enable/disable_index functions
+
+ These had an extra level of switch nesting for no good reason.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5ab4a8b911e254dc829b61cb0abc9fd0b46b84b3
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 27 23:25:01 2016 -0700
+
+ altos/stm: move spi execution to common ao_spi_run
+
+ This regularizes SPI hardware use and ensures that the device is
+ turned off after it has been used and that the status register is back
+ to 'normal' the next time through.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 69791ef235161fef404f682fd6955e7eed8dc125
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 27 23:26:20 2016 -0700
+
+ altos: Add STM SPI debugging
+
+ This dumps out the SPI hardware state and history of SPI operations
+ when compiled with -DDEBUG=1. Without that, this patch does nothing.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit f418584d4d225827e08f56de86055eb3f074f8d1
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 27 17:26:19 2016 -0700
+
+ altos: Add STM DMA debugging
+
+ This provides a command that shows current DMA operations when
+ compiled with -DDEBUG=1. Without that, this patch has no effect.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 2e60cd22f6789c94343e6432822cedab028dc1ba
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 18:25:44 2016 -0700
+
+ altos/stm: Change ao_spi_send_sync definition to take const source
+
+ Provides for a bit better error checking.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 21a29c7452398e0cca0fb90f99fa42a2a0684668
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:15:27 2016 -0700
+
+ altos/stm: Add more SPI status register bits
+
+ These weren't the original version of the docs that we had.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 785d2697376ebd20531d22441a60c41bd927b42a
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:12:48 2016 -0700
+
+ altos/stm: use 0xff for dma mutex value for allocated mutexes
+
+ DMA channels which are 'allocated' can't be shared. Instead of using
+ the value '1' in the related 'mutex', use 0xff which won't match any task.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 0dec7d0885970a7d73468dd77220bae78e161b40
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:11:38 2016 -0700
+
+ altos/stm: remove ao_dma_abort
+
+ This function isn't used anywhere.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 974aaf73cbb720f1b1183cc239001528b6c7a5b9
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:09:00 2016 -0700
+
+ altos: Move comment in ao_sleep_for next to related code
+
+ The comment got moved to the wrong place
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit a7e0bb5eb661cfde31c383d605cb9cb8ca568bc7
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 17:04:59 2016 -0700
+
+ altos: Block interrupts while waking tasks sleeping on timers.
+
+ Interrupts may not be blocked in the timer ISR, but they need to be
+ while walking the pending timer list and moving tasks back to the run
+ queue.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 40abb0d1e2f43a60ffa34b055ebb913ee3e20faf
+Author: Keith Packard <keithp@keithp.com>
+Date: Tue Jun 28 00:07:23 2016 -0700
+
+ altosui: Deliver firmware for Tmega 2.0 and TBT 3.0 for Windows too
+
+ 1.6.4 added Tmega 2.0 and TBT 3.0 firmware to linux and mac, but
+ neglected windows.
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 5b7e81628437389014fdd39e323a6f0176e02ba6
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 27 23:28:28 2016 -0700
+
+ Mark testing version 1.6.4.1
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 6d15cf1580563aea90e9c47f5b268c9c7bb9ba26
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 24 12:07:36 2016 -0700
+
+ altosdroid: Deal with multiple installed android SDKs
+
+ Use the latest SDK's zipalign
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 3374a9069618658a33af54472d8670e3086af1e0
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 24 12:06:32 2016 -0700
+
+ ao-tools/ao-chaosread: Document length (-l) option
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit ca59786b5022f592f6516a3ac54708789db14c94
+Author: Keith Packard <keithp@keithp.com>
+Date: Mon Jun 20 10:19:32 2016 -0700
+
+ Bump android version to 13
+
+ Need to update the maps API key in the package
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 10fa950cb9fee0ba28adfc5ead108657655bb289
+Author: Bdale Garbee <bdale@gag.com>
+Date: Wed Jun 22 15:01:09 2016 -0600
+
+ switch libgtk-3-bin build-dep to gtk-update-icon-cache, closes: #825455
+
+commit ed6eb010614b5b27757619fc629d7330fc8c4122
+Author: Keith Packard <keithp@keithp.com>
+Date: Fri Jun 17 10:18:20 2016 -0700
+
+ doc: Add install-html script
+
+ This script strips the XML-ish bits from html files so that ikiwiki
+ can parse them correctly
+
+ Signed-off-by: Keith Packard <keithp@keithp.com>
+
+commit 639e461ded29a48c155afea12171cbfc191ccfd7
+Author: Bdale Garbee <bdale@gag.com>
+Date: Fri Jun 17 10:01:17 2016 -0600
+
+ releasing 1.6.4
+
commit 31cf047113ec72a78f4b500223a2c6be23bc86fd
Merge: 2f0c977 afe74c0
Author: Bdale Garbee <bdale@gag.com>
AAPT=$(SDK)/platform-tools/aapt
APKBUILDER=$(SDK)/tools/apkbuilder
ZIPALIGN_A=$(SDK)/tools/zipalign
-ZIPALIGN_B=$(SDK)/build-tools/*/zipalign
+ZIPALIGN_B=$(shell ls $(SDK)/build-tools/*/zipalign | tail -1)
JAVA_SRC_DIR=src/org/altusmetrum/AltosDroid
EXT_LIBDIR=libs
File "../src/teledongle-v0.2/teledongle-v0.2-${VERSION}.ihx"
File "../src/teledongle-v3.0/teledongle-v3.0-${VERSION}.ihx"
File "../src/telebt-v1.0/telebt-v1.0-${VERSION}.ihx"
+ File "../src/telebt-v3.0/telebt-v3.0-${VERSION}.ihx"
File "../src/telemega-v1.0/telemega-v1.0-${VERSION}.ihx"
+ File "../src/telemega-v2.0/telemega-v2.0-${VERSION}.ihx"
File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx"
\-s serial | --serial serial
This selects a ChaosKey by serial number instead of using the first
one found.
+.TP
+\-l length | --length length
+Set the amount of data to read. Suffixes 'k', 'M' and 'G' are
+supported. The default is 1k.
.SH USAGE
.I ao-chaosread
reads noise data.
dnl Process this file with autoconf to create configure.
AC_PREREQ(2.57)
-AC_INIT([altos], 1.6.4)
-ANDROID_VERSION=12
+AC_INIT([altos], 1.6.5)
+ANDROID_VERSION=13
AC_CONFIG_SRCDIR([src/kernel/ao.h])
AM_INIT_AUTOMAKE([foreign dist-bzip2])
AM_MAINTAINER_MODE
icoutils,
libbluetooth-dev,
libelf-dev,
- libgtk-3-bin,
+ gtk-update-icon-cache,
libjfreechart-java,
libreadline-dev,
librsvg2-bin,
#
RELNOTES_INC=\
+ release-notes-1.6.5.inc \
release-notes-1.6.4.inc \
release-notes-1.6.3.inc \
release-notes-1.6.2.inc \
</legalnotice>
<revhistory>
<?dbhtml filename="altusmetrum-revhistory.html"?>
+ <revision>
+ <revnumber>1.6.5</revnumber>
+ <date>8 Jul 2016</date>
+ <revremark>
+ Minor release fixing TeleMega and TeleMetrum v2.0 bug which
+ would often result in loss of data logging and telemetry in
+ flight. Thanks to Chuck Haskin for help characterizing the bug
+ and testing this release.
+ </revremark>
+ </revision>
<revision>
<revnumber>1.6.4</revnumber>
<date>10 May 2016</date>
--- /dev/null
+#!/bin/sh
+destination=
+state=arg
+for file in "$@"; do
+ case $state in
+ arg)
+ case $file in
+ -d)
+ state=destination
+ ;;
+ *)
+ base=`basename $file`
+ case "$destination" in
+ "")
+ echo "Need -d destination option before files" 1>&2
+ exit 1
+ ;;
+ *)
+ sed \
+ -e 's/<[?]xml [^>]*>//' \
+ -e 's/<!DOCTYPE [^>]*>//' "$file" > "$destination/$base"
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ destination)
+ destination=$file
+ state=arg
+ ;;
+ esac
+done
--- /dev/null
+= Release Notes for Version 1.6.5
+:toc!:
+:doctype: article
+
+ Version 1.6.5 fixes a TeleMega and TeleMetrum v2.0 bug where
+ the device would often stop logging data and transmitting
+ telemetry in flight. All TeleMega v1.0, v2.0 and TeleMetrum
+ v2.0 users should update their flight firmware.
+
+ == AltOS
+
+ AltOS fixes:
+
+ * Fix STM32L SPI driver to prevent lock-up in the logging or
+ radio code, either of which could stop data logging and
+ telemetry. Found and characterized by Chuck Haskin, who also
+ tested the new firmware before release.
+
+ == AltosUI, TeleGPS and AltosDroid Applications
+
+ AltosUI fixes:
+
+ * Deliver firmward for TeleMega v2.0 and TeleBT v3.0 with
+ Windows package.
== Release Notes
:leveloffset: 2
- include::release-notes-1.6.4.raw[]
+ include::release-notes-1.6.5.raw[]
<<<<
+ :leveloffset: 2
+ include::release-notes-1.6.4.raw[]
+ <<<<
:leveloffset: 2
include::release-notes-1.6.3.raw[]
#define HAS_TELEMETRY 1
#define HAS_RADIO_RATE 0 /* not enough space for this */
#define HAS_MUTEX_TRY 0
+ #define HAS_TASK_INFO 0 /* not enough space for this either */
#endif
#if defined(TELEMETRUM_V_1_1)
#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_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_send_sync(d,l) ao_spi_send_sync((d), (l), 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 ao_radio_spi_send_byte(b) ao_spi_send_byte(b, AO_CC1120_SPI_BUS)
+#define ao_radio_spi_recv_byte() ao_spi_recv_byte(AO_CC1120_SPI_BUS)
#define ao_radio_spi_send(d,l) ao_spi_send((d), (l), AO_CC1120_SPI_BUS)
#define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1120_SPI_BUS)
#define ao_radio_spi_recv(d,l) ao_spi_recv((d), (l), AO_CC1120_SPI_BUS)
static void
_ao_radio_burst_read_start (uint16_t addr)
{
- uint8_t data[2];
- uint8_t d;
+ ao_radio_spi_start_bytes();
if (CC1120_IS_EXTENDED(addr)) {
- data[0] = ((1 << CC1120_READ) |
- (1 << CC1120_BURST) |
- CC1120_EXTENDED);
- data[1] = addr;
- d = 2;
+ ao_radio_spi_send_byte((1 << CC1120_READ) |
+ (1 << CC1120_BURST) |
+ CC1120_EXTENDED);
} else {
- data[0] = ((1 << CC1120_READ) |
- (1 << CC1120_BURST) |
- addr);
- d = 1;
+ addr |= ((1 << CC1120_READ) |
+ (1 << CC1120_BURST));
}
-
- ao_radio_spi_send_sync(data, d);
+ ao_radio_spi_send_byte(addr);
}
static void
ao_radio_burst_read_stop (void)
{
+ ao_radio_spi_stop_bytes();
ao_radio_deselect();
}
}
static uint8_t
-ao_radio_tx_fifo_space(void)
+ao_radio_int_pin(void)
{
- return CC1120_FIFO_SIZE - ao_radio_reg_read(CC1120_NUM_TXBYTES);
+ return ao_gpio_get(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, AO_CC1120_INT);
}
#if CC1120_DEBUG
}
static void
-ao_radio_start_tx(void)
+ao_radio_enable_isr(void)
{
- ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
ao_exti_enable(AO_CC1120_MCU_WAKEUP_PORT, AO_CC1120_MCU_WAKEUP_PIN);
+}
+
+static void
+ao_radio_start_tx(void)
+{
+ ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
ao_radio_tx_finished = 0;
ao_radio_strobe(CC1120_STX);
}
CC1120_PA_CFG0, 0x7e,
};
+#define AO_CC1120_TX_BUFFER 64
+
static const uint16_t packet_tx_setup[] = {
CC1120_PKT_CFG2, ((CC1120_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1120_PKT_CFG2_CCA_MODE) |
(CC1120_PKT_CFG2_PKT_FORMAT_NORMAL << CC1120_PKT_CFG2_PKT_FORMAT)),
- AO_CC1120_INT_GPIO_IOCFG, CC1120_IOCFG_GPIO_CFG_RX0TX1_CFG,
+ CC1120_FIFO_CFG, ((0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) |
+ (AO_CC1120_TX_BUFFER << CC1120_FIFO_CFG_FIFO_THR)),
};
static const uint16_t packet_rx_setup[] = {
CC1120_PREAMBLE_CFG1, ((CC1120_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1120_PREAMBLE_CFG1_NUM_PREAMBLE) |
(CC1120_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1120_PREAMBLE_CFG1_PREAMBLE_WORD)),
CC1120_PA_CFG0, 0x7d,
+ CC1120_FIFO_CFG, ((0 << CC1120_FIFO_CFG_CRC_AUTOFLUSH) |
+ (AO_CC1120_TX_BUFFER << CC1120_FIFO_CFG_FIFO_THR)),
};
/*
ao_radio_start_tx();
ao_arch_block_interrupts();
- while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake)
+ while (!ao_radio_wake && !ao_radio_abort && !ao_radio_mcu_wake) {
+ ao_radio_enable_isr();
ao_sleep(&ao_radio_wake);
+ }
ao_arch_release_interrupts();
if (ao_radio_mcu_wake)
ao_radio_check_marc_status();
ao_radio_check_marc_status();
}
-static uint8_t
-ao_radio_wait_tx(uint8_t wait_fifo)
+static void
+ao_radio_wait_fifo(void)
{
- uint8_t fifo_space = 0;
-
- do {
+ while (ao_radio_int_pin() != 0 && !ao_radio_abort) {
+ ao_radio_wake = 0;
+ ao_radio_enable_isr();
ao_radio_wait_isr(0);
- if (!wait_fifo)
- return 0;
- fifo_space = ao_radio_tx_fifo_space();
- } while (!fifo_space && !ao_radio_abort);
- return fifo_space;
+ }
}
static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
uint8_t encode_len;
uint8_t this_len;
uint8_t started = 0;
- uint8_t fifo_space;
encode_len = ao_fec_encode(d, size, tx_data);
/* Flush any pending TX bytes */
ao_radio_strobe(CC1120_SFTX);
- started = 0;
- fifo_space = CC1120_FIFO_SIZE;
while (encode_len) {
this_len = encode_len;
- ao_radio_wake = 0;
- if (this_len > fifo_space) {
- this_len = fifo_space;
+ if (started) {
+ ao_radio_wait_fifo();
+ if (ao_radio_abort)
+ break;
+ }
+
+ if (this_len > AO_CC1120_TX_BUFFER) {
+ this_len = AO_CC1120_TX_BUFFER;
ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_BUF);
} else {
ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX_FINISH);
if (!started) {
ao_radio_start_tx();
started = 1;
- } else {
- ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
- }
-
- fifo_space = ao_radio_wait_tx(encode_len != 0);
- if (ao_radio_abort) {
- ao_radio_idle();
- break;
}
}
- while (started && !ao_radio_abort && !ao_radio_tx_finished)
+ while (started && !ao_radio_abort && !ao_radio_tx_finished) {
+ ao_radio_wake = 0;
+ ao_radio_enable_isr();
ao_radio_wait_isr(0);
+ }
+ if (ao_radio_abort)
+ ao_radio_idle();
ao_radio_put();
}
-#define AO_RADIO_LOTS 64
-
void
ao_radio_send_aprs(ao_radio_fill_func fill)
{
- uint8_t buf[AO_RADIO_LOTS], *b;
+ uint8_t buf[AO_CC1120_TX_BUFFER];
int cnt;
int total = 0;
uint8_t done = 0;
uint8_t started = 0;
- uint8_t fifo_space;
ao_radio_get(0xff);
- fifo_space = CC1120_FIFO_SIZE;
+
+ ao_radio_abort = 0;
+
+ ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_isr);
while (!done) {
cnt = (*fill)(buf, sizeof(buf));
if (cnt < 0) {
}
total += cnt;
- /* At the last buffer, set the total length */
- if (done)
- ao_radio_set_len(total & 0xff);
-
- b = buf;
- while (cnt) {
- uint8_t this_len = cnt;
-
- /* Wait for some space in the fifo */
- while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
- ao_radio_wake = 0;
- ao_radio_wait_isr(0);
- }
+ /* Wait for some space in the fifo */
+ if (started) {
+ ao_radio_wait_fifo();
if (ao_radio_abort)
break;
- if (this_len > fifo_space)
- this_len = fifo_space;
-
- cnt -= this_len;
-
- if (done) {
- if (cnt)
- ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
- else
- ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
- } else
- ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
-
- ao_radio_fifo_write(b, this_len);
- b += this_len;
-
- if (!started) {
- ao_radio_start_tx();
- started = 1;
- } else
- ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN);
}
- if (ao_radio_abort) {
- ao_radio_idle();
- break;
+
+ if (done) {
+ ao_radio_set_len(total & 0xff);
+ ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
+ } else
+ ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
+
+ ao_radio_fifo_write(buf, cnt);
+
+ if (!started) {
+ ao_radio_start_tx();
+ started = 1;
}
- /* Wait for the transmitter to go idle */
+ }
+ /* Wait for the transmitter to go idle */
+ while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) {
ao_radio_wake = 0;
+ ao_radio_enable_isr();
ao_radio_wait_isr(0);
}
+ if (ao_radio_abort)
+ ao_radio_idle();
ao_radio_put();
}
rx_starting = 0;
ao_wakeup(&ao_radio_wake);
}
- d = AO_CC1120_SPI.dr;
- AO_CC1120_SPI.dr = 0;
+ d = ao_radio_spi_recv_byte();
if (rx_ignore == 0) {
if (rx_data_cur < rx_data_count)
rx_data[rx_data_cur++] = d;
rx_data_count = len * 8; /* bytes to bits */
rx_data_cur = 0;
rx_data_consumed = 0;
- rx_ignore = 2;
+ rx_ignore = 1;
/* Must be set before changing the frequency; any abort
* after the frequency is set needs to terminate the read
ao_radio_select();
_ao_radio_burst_read_start(CC1120_SOFT_RX_DATA_OUT);
if (rx_ignore) {
- uint8_t ignore = AO_CC1120_SPI.dr;
- (void) ignore;
- AO_CC1120_SPI.dr = 0;
+ (void) ao_radio_spi_recv_byte();
--rx_ignore;
}
}
}
static uint8_t
-ao_radio_tx_fifo_space(void)
+ao_radio_int_pin(void)
{
- return CC1200_FIFO_SIZE - ao_radio_reg_read(CC1200_NUM_TXBYTES);
+ return ao_gpio_get(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_CC1200_INT);
}
static uint8_t
*/
#define APRS_SYMBOL_RATE_E 6
#define APRS_SYMBOL_RATE_M 1013008
+#define APRS_BUFFER_SIZE 64
static const uint16_t aprs_setup[] = {
CC1200_DEVIATION_M, APRS_DEV_M,
(CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) |
(CC1200_MDMCFG2_UPSAMPLER_P_8 << CC1200_MDMCFG2_UPSAMPLER_P) |
(0 << CC1200_MDMCFG2_CFM_DATA_EN)),
+ CC1200_FIFO_CFG,
+ ((0 << CC1200_FIFO_CFG_CRC_AUTOFLUSH) |
+ (APRS_BUFFER_SIZE << CC1200_FIFO_CFG_FIFO_THR)),
};
/*
ao_radio_run();
}
-
-#define AO_RADIO_LOTS 64
-
void
ao_radio_send_aprs(ao_radio_fill_func fill)
{
- uint8_t buf[AO_RADIO_LOTS], *b;
+ uint8_t buf[APRS_BUFFER_SIZE];
int cnt;
int total = 0;
uint8_t done = 0;
uint8_t started = 0;
- uint8_t fifo_space;
ao_radio_abort = 0;
ao_radio_get(0xff);
- fifo_space = CC1200_FIFO_SIZE;
- while (!done) {
+ ao_radio_wake = 0;
+ while (!done && !ao_radio_abort) {
cnt = (*fill)(buf, sizeof(buf));
if (cnt < 0) {
done = 1;
cnt = -cnt;
}
-#if CC1200_APRS_TRACE
- printf("APRS fill %d bytes done %d\n", cnt, done);
-#endif
total += cnt;
/* At the last buffer, set the total length */
if (done)
ao_radio_set_len(total & 0xff);
- b = buf;
- while (cnt) {
- uint8_t this_len = cnt;
-
- /* Wait for some space in the fifo */
- while (!ao_radio_abort && (fifo_space = ao_radio_tx_fifo_space()) == 0) {
-#if CC1200_APRS_TRACE
- printf("APRS space %d cnt %d\n", fifo_space, cnt); flush();
-#endif
- ao_radio_wake = 0;
- ao_radio_wait_isr(AO_MS_TO_TICKS(1000));
- }
- if (ao_radio_abort)
- break;
- if (this_len > fifo_space)
- this_len = fifo_space;
-
- cnt -= this_len;
-
- if (done) {
- if (cnt)
- ao_radio_set_mode(AO_RADIO_MODE_APRS_LAST_BUF);
- else
- ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
- } else
- ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
-
+ /* Wait for some space in the fifo */
+ while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) {
+ ao_radio_wake = 0;
ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN);
-
- ao_radio_fifo_write(b, this_len);
- b += this_len;
-#if CC1200_APRS_TRACE
- printf("APRS write fifo %d space now %d\n", this_len, ao_radio_tx_fifo_space());
-#endif
- if (!started) {
-#if CC1200_APRS_TRACE
- printf("APRS start\n");
-#endif
- ao_radio_strobe(CC1200_STX);
-#if CC1200_APRS_TRACE
- { int t;
- for (t = 0; t < 20; t++) {
- uint8_t status = ao_radio_status();
- uint8_t space = ao_radio_tx_fifo_space();
- printf ("status: %02x fifo %d\n", status, space);
- if ((status >> 4) == 2)
- break;
- ao_delay(AO_MS_TO_TICKS(0));
- }
- }
-#endif
- started = 1;
- }
+ ao_radio_wait_isr(AO_MS_TO_TICKS(1000));
}
- if (ao_radio_abort) {
- ao_radio_idle();
+ if (ao_radio_abort)
break;
+
+ if (done)
+ ao_radio_set_mode(AO_RADIO_MODE_APRS_FINISH);
+ else
+ ao_radio_set_mode(AO_RADIO_MODE_APRS_BUF);
+
+ ao_radio_fifo_write(buf, cnt);
+ if (!started) {
+ ao_radio_strobe(CC1200_STX);
+ started = 1;
}
}
/* Wait for the transmitter to go idle */
- ao_radio_wake = 0;
-#if CC1200_APRS_TRACE
- printf("APRS wait idle\n"); flush();
-#endif
- ao_radio_wait_isr(AO_MS_TO_TICKS(1000));
-#if CC1200_APRS_TRACE
- printf("APRS abort %d\n", ao_radio_abort);
-#endif
+ while (started && ao_radio_int_pin() != 0 && !ao_radio_abort) {
+ ao_radio_wake = 0;
+ ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN);
+ ao_radio_wait_isr(AO_MS_TO_TICKS(1000));
+ }
+ if (ao_radio_abort)
+ ao_radio_idle();
ao_radio_put();
}
#define AO_PANIC_EXTI 16 /* Mis-using exti API */
#define AO_PANIC_FAST_TIMER 17 /* Mis-using fast timer API */
#define AO_PANIC_ADC 18 /* Mis-using ADC interface */
+#define AO_PANIC_IRQ 19 /* interrupts not blocked */
#define AO_PANIC_SELF_TEST_CC1120 0x40 | 1 /* Self test failure */
#define AO_PANIC_SELF_TEST_HMC5883 0x40 | 2 /* Self test failure */
#define AO_PANIC_SELF_TEST_MPU6000 0x40 | 3 /* Self test failure */
{
/* Set pad mode - we can fly! */
ao_flight_state = ao_flight_pad;
-#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
+#if HAS_USB && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE && !DEBUG
/* Disable the USB controller in flight mode
* to save power
*/
#define ao_check_stack()
#endif
+#if DEBUG
+#define ao_task_irq_check() ao_arch_irq_check()
+#else
+#define ao_task_irq_check()
+#endif
+
#if HAS_TASK_QUEUE
#define SLEEP_HASH_SIZE 17
static void
ao_task_to_run_queue(struct ao_task *task)
{
+ ao_task_irq_check();
ao_list_del(&task->queue);
ao_list_append(&task->queue, &run_queue);
}
static void
ao_task_to_sleep_queue(struct ao_task *task, void *wchan)
{
+ ao_task_irq_check();
ao_list_del(&task->queue);
ao_list_append(&task->queue, ao_task_sleep_queue(wchan));
}
ao_task_to_alarm_queue(struct ao_task *task)
{
struct ao_task *alarm;
+ ao_task_irq_check();
ao_list_for_each_entry(alarm, &alarm_queue, struct ao_task, alarm_queue) {
if ((int16_t) (alarm->alarm - task->alarm) >= 0) {
ao_list_insert(&task->alarm_queue, alarm->alarm_queue.prev);
static void
ao_task_from_alarm_queue(struct ao_task *task)
{
+ ao_task_irq_check();
ao_list_del(&task->alarm_queue);
if (ao_list_is_empty(&alarm_queue))
ao_task_alarm_tick = 0;
static void
ao_task_exit_queue(struct ao_task *task)
{
+ ao_task_irq_check();
ao_list_del(&task->queue);
ao_list_del(&task->alarm_queue);
}
{
struct ao_task *alarm, *next;
- ao_list_for_each_entry_safe(alarm, next, &alarm_queue, struct ao_task, alarm_queue) {
- if ((int16_t) (tick - alarm->alarm) < 0)
- break;
- alarm->alarm = 0;
- ao_task_from_alarm_queue(alarm);
- ao_task_to_run_queue(alarm);
- }
+ 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)
+ break;
+ alarm->alarm = 0;
+ ao_task_from_alarm_queue(alarm);
+ ao_task_to_run_queue(alarm);
+ });
}
void
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
*/
- flags = ao_arch_irqsave();
-#endif
if (!(ao_cur_task->alarm = ao_time() + timeout + 1))
ao_cur_task->alarm = 1;
#if HAS_TASK_QUEUE
void
ao_delay(uint16_t ticks)
{
+ if (!ticks)
+ ticks = 1;
ao_sleep_for(&ao_forever, ticks);
}
{
uint8_t i;
__xdata struct ao_task *task;
+ uint16_t now = ao_time();
for (i = 0; i < ao_num_tasks; i++) {
task = ao_tasks[i];
- printf("%12s: wchan %04x\n",
- task->name,
- (int) task->wchan);
+ printf("%2d: wchan %08x alarm %5d %s\n",
+ task->task_id,
+ (int) task->wchan,
+ task->alarm ? (int16_t) (task->alarm - now) : 9999,
+ task->name);
}
#if HAS_TASK_QUEUE && DEBUG
ao_task_validate();
ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index);
void
-ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index);
+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)
break;
}
- 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 RXNE */
+ 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;
+}
- while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
- stm_spi->dr = byte;
+static inline uint8_t
+ao_spi_recv_byte(uint8_t spi_index)
+{
+ struct stm_spi *stm_spi;
+
+ switch (AO_SPI_INDEX(spi_index)) {
+ case 0:
+ stm_spi = &stm_spi1;
+ break;
+ case 1:
+ stm_spi = &stm_spi2;
+ break;
+ }
+
+ 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
void
ao_dma_done_transfer(uint8_t index);
-void
-ao_dma_abort(uint8_t index);
-
void
ao_dma_alloc(uint8_t index);
asm volatile("" ::: "memory");
}
+static inline void
+ao_arch_irq_check(void) {
+ uint32_t primask;
+ asm("mrs %0,primask" : "=&r" (primask));
+ if ((primask & 1) == 0)
+ ao_panic(AO_PANIC_IRQ);
+}
+
#if HAS_TASK
static inline void
ao_arch_init_stack(struct ao_task *task, void *start)
if (ao_dma_allocated[index]) {
if (ao_dma_mutex[index])
ao_panic(AO_PANIC_DMA);
- ao_dma_mutex[index] = 1;
+ ao_dma_mutex[index] = 0xff;
} else
ao_mutex_get(&ao_dma_mutex[index]);
ao_arch_critical(
ao_mutex_put(&ao_dma_mutex[index]);
}
-void
-ao_dma_abort(uint8_t index)
-{
- stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
- ao_wakeup(&ao_dma_done[index]);
-}
-
void
ao_dma_alloc(uint8_t index)
{
ao_dma_allocated[index] = 1;
}
+#if DEBUG
+void
+ao_dma_dump_cmd(void)
+{
+ int i;
+
+ ao_arch_critical(
+ if (ao_dma_active++ == 0)
+ stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+ );
+ printf ("isr %08x ifcr%08x\n", stm_dma.isr, stm_dma.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_dma.channel[i].ccr,
+ stm_dma.channel[i].cndtr,
+ stm_dma.channel[i].cpar,
+ stm_dma.channel[i].cmar,
+ ao_dma_config[i].isr);
+ ao_arch_critical(
+ if (--ao_dma_active == 0)
+ stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMA1EN);
+ );
+}
+
+static const struct ao_cmds ao_dma_cmds[] = {
+ { ao_dma_dump_cmd, "D\0Dump DMA status" },
+ { 0, NULL }
+};
+#endif
+
void
ao_dma_init(void)
{
ao_dma_allocated[index] = 0;
ao_dma_mutex[index] = 0;
}
-
+#if DEBUG
+ ao_cmd_register(&ao_dma_cmds[0]);
+#endif
}
uint32_t mask = (1 << pin);
(void) gpio;
stm_exti.pr = mask;
- stm_exti.imr |= (1 << pin);
+ stm_exti.imr |= mask;
}
void
static uint8_t spi_dev_null;
+#if DEBUG
+static struct {
+ uint8_t task;
+ uint8_t which;
+ AO_TICK_TYPE tick;
+ uint16_t len;
+} spi_tasks[64];
+static uint8_t spi_task_index;
+
+static void
+validate_spi(struct stm_spi *stm_spi, int which, uint16_t len)
+{
+ uint32_t sr = stm_spi->sr;
+
+ if (stm_spi != &stm_spi2)
+ return;
+ spi_tasks[spi_task_index].task = ao_cur_task ? ao_cur_task->task_id : 0;
+ spi_tasks[spi_task_index].which = which;
+ spi_tasks[spi_task_index].tick = ao_time();
+ spi_tasks[spi_task_index].len = len;
+ spi_task_index = (spi_task_index + 1) & (63);
+ if (sr & (1 << STM_SPI_SR_FRE))
+ ao_panic(0x40 | 1);
+ if (sr & (1 << STM_SPI_SR_BSY))
+ ao_panic(0x40 | 2);
+ if (sr & (1 << STM_SPI_SR_OVR))
+ ao_panic(0x40 | 3);
+ if (sr & (1 << STM_SPI_SR_MODF))
+ ao_panic(0x40 | 4);
+ if (sr & (1 << STM_SPI_SR_UDR))
+ ao_panic(0x40 | 5);
+ if ((sr & (1 << STM_SPI_SR_TXE)) == 0)
+ ao_panic(0x40 | 6);
+ if (sr & (1 << STM_SPI_SR_RXNE))
+ ao_panic(0x40 | 7);
+ if (which != 5 && which != 6 && which != 13)
+ if (ao_cur_task->task_id != ao_spi_mutex[1])
+ ao_panic(0x40 | 8);
+}
+#else
+#define validate_spi(stm_spi, which, len) do { (void) (which); (void) (len); } while (0)
+#endif
+
+static void
+ao_spi_run(uint8_t id, uint8_t which, uint16_t len)
+{
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
+
+ validate_spi(stm_spi, which, len);
+
+ 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));
+
+ validate_spi(stm_spi, which+1, len);
+
+ stm_spi->cr2 = 0;
+
+ ao_dma_done_transfer(mosi_dma_index);
+ ao_dma_done_transfer(miso_dma_index);
+}
+
void
ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
{
- struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
- uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
- uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
/* Set up the transmit DMA to deliver data */
ao_dma_set_transfer(mosi_dma_index,
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
- /* Clear RXNE */
- (void) stm_spi->dr;
-
/* 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
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
- 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]);
- );
- ao_dma_done_transfer(mosi_dma_index);
- ao_dma_done_transfer(miso_dma_index);
+
+ ao_spi_run(id, 1, len);
}
void
ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
{
- struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
- uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
- uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
/* Set up the transmit DMA to deliver data */
ao_dma_set_transfer(mosi_dma_index,
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
- /* Clear RXNE */
- (void) stm_spi->dr;
-
/* 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
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+
+ ao_spi_run(id, 3, len);
+}
+
+void
+ao_spi_start_bytes(uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
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]);
- );
- ao_dma_done_transfer(mosi_dma_index);
- ao_dma_done_transfer(miso_dma_index);
+ (0 << STM_SPI_CR2_TXDMAEN) |
+ (0 << STM_SPI_CR2_RXDMAEN));
+ validate_spi(stm_spi, 5, 0xffff);
}
void
-ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
+ao_spi_stop_bytes(uint8_t spi_index)
{
- uint8_t *b = block;
- struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+ 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;
+ validate_spi(stm_spi, 6, 0xffff);
+ stm_spi->cr2 = 0;
+}
+
+void
+ao_spi_send_sync(const void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ const uint8_t *b = block;
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
(0 << STM_SPI_CR2_RXNEIE) |
(0 << STM_SPI_CR2_SSOE) |
(0 << STM_SPI_CR2_TXDMAEN) |
(0 << STM_SPI_CR2_RXDMAEN));
-
- /* Clear RXNE */
- (void) stm_spi->dr;
-
+ validate_spi(stm_spi, 7, len);
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;
+ validate_spi(stm_spi, 8, len);
}
void
ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
{
- struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
- uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
- uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
spi_dev_null = 0xff;
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
- /* Clear RXNE */
- (void) stm_spi->dr;
-
/* Set up the receive DMA to capture data */
ao_dma_set_transfer(miso_dma_index,
&stm_spi->dr,
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
- 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);
-
- /* Wait until the SPI unit is done */
- ao_arch_critical(
- while (!ao_dma_done[miso_dma_index])
- ao_sleep(&ao_dma_done[miso_dma_index]);
- );
-
- ao_dma_done_transfer(mosi_dma_index);
- ao_dma_done_transfer(miso_dma_index);
+ ao_spi_run(id, 9, len);
}
void
ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
{
- struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
- uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
- uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
+ uint8_t mosi_dma_index = ao_spi_stm_info[id].mosi_dma_index;
+ uint8_t miso_dma_index = ao_spi_stm_info[id].miso_dma_index;
/* Set up transmit DMA to send data */
ao_dma_set_transfer(mosi_dma_index,
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
- /* Clear RXNE */
- (void) stm_spi->dr;
-
/* Set up the receive DMA to capture data */
ao_dma_set_transfer(miso_dma_index,
&stm_spi->dr,
(0 << STM_DMA_CCR_PINC) |
(0 << STM_DMA_CCR_CIRC) |
(STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
-
- 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);
-
- /* Wait until the SPI unit is done */
- ao_arch_critical(
- while (!ao_dma_done[miso_dma_index])
- ao_sleep(&ao_dma_done[miso_dma_index]);
- );
-
- ao_dma_done_transfer(mosi_dma_index);
- ao_dma_done_transfer(miso_dma_index);
+ ao_spi_run(id, 11, len);
}
static void
{
/* Disable current config
*/
- switch (AO_SPI_INDEX(spi_index)) {
- case STM_SPI_INDEX(1):
- switch (spi_index) {
- 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_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;
- case AO_SPI_1_PE13_PE14_PE15:
- stm_gpio_set(&stm_gpioe, 13, 1);
- stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
- stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
- stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
- break;
- }
+ switch (spi_index) {
+ 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 STM_SPI_INDEX(2):
- switch (spi_index) {
- case AO_SPI_2_PB13_PB14_PB15:
- stm_gpio_set(&stm_gpiob, 13, 1);
- stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
- stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
- stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
- break;
- case AO_SPI_2_PD1_PD3_PD4:
- stm_gpio_set(&stm_gpiod, 1, 1);
- stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
- stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
- stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
- 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;
+ case AO_SPI_1_PE13_PE14_PE15:
+ stm_gpio_set(&stm_gpioe, 13, 1);
+ stm_moder_set(&stm_gpioe, 13, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpioe, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpioe, 15, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_gpio_set(&stm_gpiob, 13, 1);
+ stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+ break;
+ case AO_SPI_2_PD1_PD3_PD4:
+ stm_gpio_set(&stm_gpiod, 1, 1);
+ stm_moder_set(&stm_gpiod, 1, STM_MODER_OUTPUT);
+ stm_moder_set(&stm_gpiod, 3, STM_MODER_INPUT);
+ stm_moder_set(&stm_gpiod, 4, STM_MODER_OUTPUT);
break;
}
}
static void
ao_spi_enable_index(uint8_t spi_index)
{
- switch (AO_SPI_INDEX(spi_index)) {
- case STM_SPI_INDEX(1):
- switch (spi_index) {
- case AO_SPI_1_PA5_PA6_PA7:
- stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
- stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
- stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
- break;
- case AO_SPI_1_PB3_PB4_PB5:
- stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
- stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
- stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
- break;
- case AO_SPI_1_PE13_PE14_PE15:
- stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
- stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
- stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
- break;
- }
+ /* Enable new config
+ */
+ switch (spi_index) {
+ case AO_SPI_1_PA5_PA6_PA7:
+ stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
break;
- case STM_SPI_INDEX(2):
- switch (spi_index) {
- case AO_SPI_2_PB13_PB14_PB15:
- stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
- stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
- stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
- break;
- case AO_SPI_2_PD1_PD3_PD4:
- stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
- stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
- stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
- break;
- }
+ case AO_SPI_1_PB3_PB4_PB5:
+ stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
+ break;
+ case AO_SPI_1_PE13_PE14_PE15:
+ stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+ stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
+ break;
+ case AO_SPI_2_PB13_PB14_PB15:
+ stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+ break;
+ case AO_SPI_2_PD1_PD3_PD4:
+ stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
+ stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
break;
}
}
{
uint8_t id = AO_SPI_INDEX(spi_index);
struct stm_spi *stm_spi = ao_spi_stm_info[id].stm_spi;
- 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) |
- (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
- (0 << STM_SPI_CR1_CPHA));
+
if (spi_index != ao_spi_index[id]) {
/* Disable old config
*/
ao_spi_index[id] = spi_index;
}
+ 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) |
+ (0 << STM_SPI_CR1_CPOL) | /* Format 0 */
+ (0 << STM_SPI_CR1_CPHA));
+ validate_spi(stm_spi, 13, 0);
}
uint8_t
ao_spi_get(uint8_t spi_index, uint32_t speed)
{
uint8_t id = AO_SPI_INDEX(spi_index);
+
ao_mutex_get(&ao_spi_mutex[id]);
ao_spi_config(spi_index, speed);
}
ao_spi_disable_index(spi_index);
stm_spi->cr1 = 0;
- (void) stm_spi->sr;
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)
{
ao_spi_index[1] = AO_SPI_CONFIG_NONE;
ao_spi_channel_init(1);
#endif
+#if DEBUG
+ ao_cmd_register(&ao_spi_cmds[0]);
+#endif
}
#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
#define AO_CC1120_SPI_CS_PORT (&stm_gpioc)
#define AO_CC1120_SPI_CS_PIN 5
#define AO_CC1120_SPI_BUS AO_SPI_2_PB13_PB14_PB15
-#define AO_CC1120_SPI stm_spi2
#define AO_CC1120_INT_PORT (&stm_gpioe)
#define AO_CC1120_INT_PIN 1
#define PACKET_HAS_SLAVE 1
#define HAS_RADIO_RATE 1
#define HAS_TELEMETRY 1
+#define HAS_TASK_INFO 0
#define AO_LED_RED 2
#define LEDS_AVAILABLE AO_LED_RED