diff options
| -rw-r--r-- | altosdroid/Makefile.am | 2 | ||||
| -rw-r--r-- | altosui/altos-windows.nsi.in | 2 | ||||
| -rw-r--r-- | ao-tools/ao-chaosread/ao-chaosread.1 | 4 | ||||
| -rw-r--r-- | configure.ac | 4 | ||||
| -rw-r--r-- | debian/control | 2 | ||||
| -rw-r--r-- | doc/Makefile | 1 | ||||
| -rw-r--r-- | doc/altusmetrum-docinfo.xml | 10 | ||||
| -rwxr-xr-x | doc/install-html | 32 | ||||
| -rw-r--r-- | doc/release-notes-1.6.5.inc | 24 | ||||
| -rw-r--r-- | doc/release-notes.inc | 5 | ||||
| -rw-r--r-- | src/cc1111/ao_pins.h | 1 | ||||
| -rw-r--r-- | src/drivers/ao_cc1120.c | 173 | ||||
| -rw-r--r-- | src/drivers/ao_cc1200.c | 105 | ||||
| -rw-r--r-- | src/kernel/ao.h | 1 | ||||
| -rw-r--r-- | src/kernel/ao_flight.c | 2 | ||||
| -rw-r--r-- | src/kernel/ao_task.c | 41 | ||||
| -rw-r--r-- | src/stm/ao_arch_funcs.h | 55 | ||||
| -rw-r--r-- | src/stm/ao_dma_stm.c | 47 | ||||
| -rw-r--r-- | src/stm/ao_exti_stm.c | 2 | ||||
| -rw-r--r-- | src/stm/ao_spi_stm.c | 438 | ||||
| -rw-r--r-- | src/stm/stm32l.h | 3 | ||||
| -rw-r--r-- | src/telemega-v1.0/ao_pins.h | 1 | ||||
| -rw-r--r-- | src/telemini-v2.0/ao_pins.h | 1 | 
23 files changed, 571 insertions, 385 deletions
| diff --git a/altosdroid/Makefile.am b/altosdroid/Makefile.am index 295abbc5..686aeabf 100644 --- a/altosdroid/Makefile.am +++ b/altosdroid/Makefile.am @@ -15,7 +15,7 @@ ADB=$(SDK)/platform-tools/adb  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 diff --git a/altosui/altos-windows.nsi.in b/altosui/altos-windows.nsi.in index c88b9e34..c85e2ac8 100644 --- a/altosui/altos-windows.nsi.in +++ b/altosui/altos-windows.nsi.in @@ -129,7 +129,9 @@ Section "Firmware"  	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" diff --git a/ao-tools/ao-chaosread/ao-chaosread.1 b/ao-tools/ao-chaosread/ao-chaosread.1 index d8ed6cb3..ead8afb2 100644 --- a/ao-tools/ao-chaosread/ao-chaosread.1 +++ b/ao-tools/ao-chaosread/ao-chaosread.1 @@ -29,6 +29,10 @@ reads ADC values from the noise source on the attached ChaosKey device.  \-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. diff --git a/configure.ac b/configure.ac index 6745b012..001449a7 100644 --- a/configure.ac +++ b/configure.ac @@ -18,8 +18,8 @@ dnl  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 diff --git a/debian/control b/debian/control index 426fb777..e20a54a2 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,7 @@ Build-Depends: asciidoc,                 icoutils,                 libbluetooth-dev,                 libelf-dev, -               libgtk-3-bin, +               gtk-update-icon-cache,                 libjfreechart-java,                 libreadline-dev,                 librsvg2-bin, diff --git a/doc/Makefile b/doc/Makefile index 31bc08d8..707a4428 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -3,6 +3,7 @@  #  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 \ diff --git a/doc/altusmetrum-docinfo.xml b/doc/altusmetrum-docinfo.xml index 1b8ff68d..fbd14c5a 100644 --- a/doc/altusmetrum-docinfo.xml +++ b/doc/altusmetrum-docinfo.xml @@ -47,6 +47,16 @@  <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>      <revremark> diff --git a/doc/install-html b/doc/install-html new file mode 100755 index 00000000..71c7933c --- /dev/null +++ b/doc/install-html @@ -0,0 +1,32 @@ +#!/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 diff --git a/doc/release-notes-1.6.5.inc b/doc/release-notes-1.6.5.inc new file mode 100644 index 00000000..9f3ae281 --- /dev/null +++ b/doc/release-notes-1.6.5.inc @@ -0,0 +1,24 @@ += 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. diff --git a/doc/release-notes.inc b/doc/release-notes.inc index 6ac90cfd..b8b34e7b 100644 --- a/doc/release-notes.inc +++ b/doc/release-notes.inc @@ -2,10 +2,13 @@  == 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[] diff --git a/src/cc1111/ao_pins.h b/src/cc1111/ao_pins.h index e12f813f..9cbb0a7b 100644 --- a/src/cc1111/ao_pins.h +++ b/src/cc1111/ao_pins.h @@ -61,6 +61,7 @@  	#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) diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 5b814667..6b800585 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -44,7 +44,10 @@ extern const uint32_t	ao_radio_cal;  #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) @@ -111,28 +114,23 @@ ao_radio_reg_write(uint16_t addr, uint8_t value)  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();  } @@ -206,9 +204,9 @@ ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)  }  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 @@ -264,11 +262,16 @@ ao_radio_isr(void)  }  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);  } @@ -424,10 +427,13 @@ static const uint16_t packet_setup_24[] = {  	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[] = { @@ -534,6 +540,8 @@ static const uint16_t aprs_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)),  };  /* @@ -739,8 +747,10 @@ ao_rdf_run(void)  	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(); @@ -846,18 +856,14 @@ ao_radio_wait_isr(uint16_t timeout)  		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]; @@ -869,7 +875,6 @@ ao_radio_send(const void *d, uint8_t size)  	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); @@ -880,14 +885,17 @@ ao_radio_send(const void *d, uint8_t size)  	/* 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); @@ -900,35 +908,32 @@ ao_radio_send(const void *d, uint8_t size)  		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) { @@ -937,51 +942,34 @@ ao_radio_send_aprs(ao_radio_fill_func fill)  		}  		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();  } @@ -1029,8 +1017,7 @@ ao_radio_rx_isr(void)  		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; @@ -1099,7 +1086,7 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)  	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 @@ -1149,9 +1136,7 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)  		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;  		}  	} diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c index 6bccb188..cd85f208 100644 --- a/src/drivers/ao_cc1200.c +++ b/src/drivers/ao_cc1200.c @@ -185,9 +185,9 @@ ao_radio_fifo_write_fixed(uint8_t data, uint8_t len)  }  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 @@ -482,6 +482,7 @@ static const uint16_t rdf_setup[] = {   */  #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, @@ -516,6 +517,9 @@ static const uint16_t aprs_setup[] = {  		 (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)),  };  /* @@ -861,105 +865,58 @@ ao_radio_send(const void *d, uint8_t size)  	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();  } diff --git a/src/kernel/ao.h b/src/kernel/ao.h index 6ed0299e..27a16606 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -73,6 +73,7 @@ typedef AO_PORT_TYPE ao_port_t;  #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 */ diff --git a/src/kernel/ao_flight.c b/src/kernel/ao_flight.c index 9ba02bb8..9031a54a 100644 --- a/src/kernel/ao_flight.c +++ b/src/kernel/ao_flight.c @@ -130,7 +130,7 @@ ao_flight(void)   			{  				/* 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  				 */ diff --git a/src/kernel/ao_task.c b/src/kernel/ao_task.c index e430edc6..cf0b58ed 100644 --- a/src/kernel/ao_task.c +++ b/src/kernel/ao_task.c @@ -54,6 +54,12 @@ static inline void ao_check_stack(void) {  #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 @@ -65,6 +71,7 @@ static struct ao_list	sleep_queue[SLEEP_HASH_SIZE];  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);  } @@ -78,6 +85,7 @@ ao_task_sleep_queue(void *wchan)  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));  } @@ -122,6 +130,7 @@ static void  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); @@ -138,6 +147,7 @@ ao_task_to_alarm_queue(struct ao_task *task)  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; @@ -156,6 +166,7 @@ ao_task_init_queue(struct ao_task *task)  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);  } @@ -165,13 +176,14 @@ ao_task_check_alarm(uint16_t tick)  {  	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 @@ -459,11 +471,11 @@ ao_sleep_for(__xdata void *wchan, uint16_t timeout)  	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 @@ -492,6 +504,8 @@ static __xdata uint8_t ao_forever;  void  ao_delay(uint16_t ticks)  { +	if (!ticks) +		ticks = 1;  	ao_sleep_for(&ao_forever, ticks);  } @@ -523,12 +537,15 @@ ao_task_info(void)  {  	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(); diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 2c017c79..a796891d 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -80,7 +80,13 @@ void  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) @@ -96,18 +102,34 @@ 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 @@ -250,9 +272,6 @@ void  ao_dma_done_transfer(uint8_t index);  void -ao_dma_abort(uint8_t index); - -void  ao_dma_alloc(uint8_t index);  void @@ -343,6 +362,14 @@ ao_arch_memory_barrier() {  	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) diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c index 8379a1a5..0135de48 100644 --- a/src/stm/ao_dma_stm.c +++ b/src/stm/ao_dma_stm.c @@ -64,7 +64,7 @@ ao_dma_set_transfer(uint8_t 		index,  	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( @@ -106,13 +106,6 @@ ao_dma_done_transfer(uint8_t 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)  {  	if (ao_dma_allocated[index]) @@ -120,6 +113,40 @@ 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)  { @@ -131,5 +158,7 @@ ao_dma_init(void)  		ao_dma_allocated[index] = 0;  		ao_dma_mutex[index] = 0;  	} -	 +#if DEBUG +	ao_cmd_register(&ao_dma_cmds[0]); +#endif  } diff --git a/src/stm/ao_exti_stm.c b/src/stm/ao_exti_stm.c index 35958cf8..925f9a22 100644 --- a/src/stm/ao_exti_stm.c +++ b/src/stm/ao_exti_stm.c @@ -144,7 +144,7 @@ ao_exti_enable(struct stm_gpio *gpio, uint8_t pin) {  	uint32_t	mask = (1 << pin);  	(void) gpio;  	stm_exti.pr = mask; -	stm_exti.imr |= (1 << pin); +	stm_exti.imr |= mask;  }  void diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c index 7eaa3924..214092f6 100644 --- a/src/stm/ao_spi_stm.c +++ b/src/stm/ao_spi_stm.c @@ -41,12 +41,91 @@ static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {  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, @@ -62,9 +141,6 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_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 @@ -81,28 +157,17 @@ ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)  			    (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, @@ -118,9 +183,6 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_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 @@ -137,27 +199,48 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)  			    (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) | @@ -165,22 +248,28 @@ ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)  			(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; @@ -198,9 +287,6 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_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, @@ -215,31 +301,16 @@ ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)  			    (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, @@ -255,9 +326,6 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_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, @@ -271,24 +339,7 @@ ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)  			    (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 @@ -296,44 +347,36 @@ ao_spi_disable_index(uint8_t spi_index)  {  	/* 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;  	}  } @@ -341,39 +384,33 @@ ao_spi_disable_index(uint8_t spi_index)  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;  	}  } @@ -383,20 +420,7 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)  {  	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 @@ -411,6 +435,21 @@ ao_spi_config(uint8_t spi_index, uint32_t speed)  		 */  		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 @@ -428,6 +467,7 @@ void  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);  } @@ -451,15 +491,62 @@ ao_spi_channel_init(uint8_t spi_index)  	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)  { @@ -504,4 +591,7 @@ 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  } diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h index 0b6b2798..352214ff 100644 --- a/src/stm/stm32l.h +++ b/src/stm/stm32l.h @@ -1359,10 +1359,13 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;  #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 diff --git a/src/telemega-v1.0/ao_pins.h b/src/telemega-v1.0/ao_pins.h index b81e59a9..58b4d61a 100644 --- a/src/telemega-v1.0/ao_pins.h +++ b/src/telemega-v1.0/ao_pins.h @@ -307,7 +307,6 @@ struct ao_adc {  #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 diff --git a/src/telemini-v2.0/ao_pins.h b/src/telemini-v2.0/ao_pins.h index ed911798..e75adc07 100644 --- a/src/telemini-v2.0/ao_pins.h +++ b/src/telemini-v2.0/ao_pins.h @@ -44,6 +44,7 @@  #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 | 
