diff options
| author | Keith Packard <keithp@keithp.com> | 2011-08-26 15:02:43 -0700 | 
|---|---|---|
| committer | Keith Packard <keithp@keithp.com> | 2011-08-26 20:56:25 -0700 | 
| commit | c32893ce79835a8f861d6ef414644c2ff9769ff6 (patch) | |
| tree | a6fd36123685f6880d35612782ddff2ed2d9b18c | |
| parent | 8125acc030574afed6f23aa8aa302d9c768bb04e (diff) | |
altos: Integrate telescience support
Adds a few drivers including an LCD driver
Signed-off-by: Keith Packard <keithp@keithp.com>
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/avr/ao_adc_avr.c | 129 | ||||
| -rw-r--r-- | src/avr/ao_arch.h | 9 | ||||
| -rw-r--r-- | src/avr/ao_spi_slave.c | 142 | ||||
| -rw-r--r-- | src/avr/ao_spi_usart.c | 112 | ||||
| -rw-r--r-- | src/cc1111/ao_arch.h | 12 | ||||
| -rw-r--r-- | src/core/ao.h | 40 | ||||
| -rw-r--r-- | src/core/ao_log_telescience.c | 274 | ||||
| -rw-r--r-- | src/core/ao_panic.c | 4 | ||||
| -rw-r--r-- | src/drivers/ao_companion.c | 2 | ||||
| -rw-r--r-- | src/drivers/ao_lcd.c | 281 | ||||
| -rw-r--r-- | src/drivers/ao_m25.c | 2 | ||||
| -rw-r--r-- | src/product/ao_telescience.c | 39 | ||||
| -rw-r--r-- | src/telescience-v0.1/Makefile | 109 | ||||
| -rw-r--r-- | src/util/check-avr-mem | 9 | 
15 files changed, 1153 insertions, 13 deletions
diff --git a/src/Makefile b/src/Makefile index 4e40c2bf..caa91e83 100644 --- a/src/Makefile +++ b/src/Makefile @@ -18,7 +18,7 @@ SUBDIRS=\  	telemini-v1.0 telenano-v0.1 \  	telebt-v0.0 telebt-v0.1 \  	telemetrum-v0.1-sky telemetrum-v0.1-sirf \ -	tidongle test +	tidongle test telescience-v0.1  all: all-local all-recursive diff --git a/src/avr/ao_adc_avr.c b/src/avr/ao_adc_avr.c new file mode 100644 index 00000000..5afced74 --- /dev/null +++ b/src/avr/ao_adc_avr.c @@ -0,0 +1,129 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +volatile __xdata struct ao_adc	ao_adc_ring[AO_ADC_RING]; +volatile __data uint8_t		ao_adc_head; + +const uint8_t	adc_channels[AO_LOG_TELESCIENCE_NUM_ADC] = { +	0x00, +	0x01, +	0x04, +	0x05, +	0x06, +	0x07, +	0x20, +	0x21, +	0x22, +	0x23, +	0x24, +	0x25, +}; + +static uint8_t	ao_adc_channel; + +#define ADC_CHANNEL_LOW(c)	(((c) & 0x1f) << MUX0) +#define ADC_CHANNEL_HIGH(c)	((((c) & 0x20) >> 5) << MUX5) + +#define ADCSRA_INIT	((1 << ADEN) |		/* Enable ADC */ 		\ +			 (0 << ADATE) |		/* No auto ADC trigger */ 	\ +			 (1 << ADIF) |		/* Clear interrupt */		\ +			 (0 << ADIE) |		/* Enable interrupt */		\ +			 (6 << ADPS0))		/* Prescale clock by 64 */ + +#define ADCSRB_INIT	((0 << ADHSM) |		/* No high-speed mode */ \ +			 (0 << ACME) |		/* Some comparitor thing */ \ +			 (2 << ADTS0))		/* Free running mode (don't care) */ + +static void +ao_adc_start(void) +{ +	uint8_t	channel = adc_channels[ao_adc_channel]; +	ADMUX = ((0 << REFS1) |				/* AVcc reference */ +		 (1 << REFS0) |				/* AVcc reference */ +		 (1 << ADLAR) |				/* Left-shift results */ +		 (ADC_CHANNEL_LOW(channel)));		/* Select channel */ + +	ADCSRB = (ADCSRB_INIT | +		  ADC_CHANNEL_HIGH(channel));		/* High channel bit */ + +	ADCSRA = (ADCSRA_INIT | +		  (1 << ADSC) | +		  (1 << ADIE));				/* Start conversion */ +} + +ISR(ADC_vect) +{ +	uint16_t	value; + +	/* Must read ADCL first or the value there will be lost */ +	value = ADCL; +	value |= (ADCH << 8); +	ao_adc_ring[ao_adc_head].adc[ao_adc_channel] = value; +	if (++ao_adc_channel < AO_TELESCIENCE_NUM_ADC) +		ao_adc_start(); +	else { +		ADCSRA = ADCSRA_INIT; +		ao_adc_ring[ao_adc_head].tick = ao_time(); +		ao_adc_head = ao_adc_ring_next(ao_adc_head); +		ao_wakeup((void *) &ao_adc_head); +		ao_cpu_sleep_disable = 0; +	} +} + +void +ao_adc_poll(void) +{ +	ao_cpu_sleep_disable = 1; +	ao_adc_channel = 0; +	ao_adc_start(); +} + +void +ao_adc_get(__xdata struct ao_adc *packet) +{ +	uint8_t	i = ao_adc_ring_prev(ao_adc_head); +	memcpy(packet, (void *) &ao_adc_ring[i], sizeof (struct ao_adc)); +} + +static void +ao_adc_dump(void) __reentrant +{ +	static __xdata struct ao_adc	packet; +	uint8_t i; +	ao_adc_get(&packet); +	printf("tick: %5u",  packet.tick); +	for (i = 0; i < AO_TELESCIENCE_NUM_ADC; i++) +		printf (" %2d: %5u", i, packet.adc[i]); +	printf ("\n"); +} + +__code struct ao_cmds ao_adc_cmds[] = { +	{ ao_adc_dump,	"a\0Display current ADC values" }, +	{ 0, NULL }, +}; + +void +ao_adc_init(void) +{ +	DIDR0 = 0xf3; +	DIDR2 = 0x3f; +	ADCSRB = ADCSRB_INIT; +	ADCSRA = ADCSRA_INIT; +	ao_cmd_register(&ao_adc_cmds[0]); +} diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index 0ed97361..c695a725 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -145,5 +145,14 @@ extern uint8_t	ao_cpu_sleep_disable;  #define ao_arch_critical(b) do { cli(); b; sei(); } while (0) +#define AO_TELESCIENCE_NUM_ADC	12 + +struct ao_adc { +	uint16_t	tick;		/* tick when the sample was read */ +	uint16_t	adc[AO_TELESCIENCE_NUM_ADC];	/* samples */ +}; + +#define AO_ADC_RING	16 +  #endif /* _AO_ARCH_H_ */ diff --git a/src/avr/ao_spi_slave.c b/src/avr/ao_spi_slave.c new file mode 100644 index 00000000..4dde09f3 --- /dev/null +++ b/src/avr/ao_spi_slave.c @@ -0,0 +1,142 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "ao_product.h" + +struct ao_companion_command	ao_companion_command; + +static const struct ao_companion_setup	ao_telescience_setup = { +	.board_id 		= AO_idProduct_NUMBER, +	.board_id_inverse	= ~AO_idProduct_NUMBER, +	.update_period		= 50, +	.channels		= AO_LOG_TELESCIENCE_NUM_ADC, +}; + +static uint8_t +ao_spi_read(uint8_t *buf, uint8_t len) +{ +	while (len--) { +		while (!(SPSR & (1 << SPIF))) +			if ((PINB & (1 << PINB0))) +				return 0; +		*buf++ = SPDR; +	} +	return 1; +} + +static void +ao_spi_write(uint8_t *buf, uint8_t len) +{ +	while (len--) { +		SPDR = *buf++; +		while (!(SPSR & (1 << SPIF))) +			if ((PINB & (1 << PINB0))) +				return; +	} +	/* Clear pending SPIF bit by reading */ +	(void) SPDR; +} + +static uint8_t ao_spi_slave_recv(void) +{ +	if (!ao_spi_read((uint8_t *) &ao_companion_command, +			 sizeof (ao_companion_command))) +		return 0; + +	/* Figure out the outbound data */ +	switch (ao_companion_command.command) { +	case AO_COMPANION_SETUP: +		ao_spi_write((uint8_t *) &ao_telescience_setup, +			     sizeof (ao_telescience_setup)); +		break; +	case AO_COMPANION_FETCH: +		ao_spi_write((uint8_t *) &ao_adc_ring[ao_adc_ring_prev(ao_adc_head)].adc, +			     AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t)); +		break; +	case AO_COMPANION_NOTIFY: +		break; +	default: +		return 0; +	} + +	ao_log_store.tm_tick = ao_companion_command.tick; +	if (ao_log_store.tm_state != ao_companion_command.flight_state) { +		ao_log_store.tm_state = ao_companion_command.flight_state; +		return 1; +	} +	return 0; +} + +static uint8_t ao_spi_slave_running; + +ISR(PCINT0_vect) +{ +	if ((PINB & (1 << PINB0)) == 0) { +		if (!ao_spi_slave_running) { +			uint8_t	changed; +			ao_spi_slave_running = 1; +			cli(); +			changed = ao_spi_slave_recv(); +			sei(); +			if (changed && ao_flight_boost <= ao_log_store.tm_state) { +				if (ao_log_store.tm_state < ao_flight_landed) +					ao_log_start(); +				else +					ao_log_stop(); +			} +		} +	} else { +		ao_spi_slave_running = 0; +	} +} + +void ao_spi_slave_debug(void) { +	printf ("slave running %d\n", ao_spi_slave_running); +} + +void +ao_spi_slave_init(void) +{ +	PCMSK0 |= (1 << PCINT0);	/* Enable PCINT0 pin change */ +	PCICR |= (1 << PCIE0);		/* Enable pin change interrupt */ + +	DDRB = ((DDRB & 0xf0) | +		(1 << 3) |		/* MISO, output */ +		(0 << 2) |		/* MOSI, input */ +		(0 << 1) |		/* SCK, input */ +		(0 << 0));		/* SS, input */ + +	/* We'd like to have a pull-up on SS so that disconnecting the +	 * TM would cause any SPI transaction to abort. However, when +	 * I tried that, SPI transactions would spontaneously abort, +	 * making me assume that we needed a less aggressive pull-up +	 * than is offered inside the AVR +	 */ +	PORTB = ((PORTB & 0xf0) | +		 (1 << 3) |		/* MISO, output */ +		 (0 << 2) |		/* MOSI, no pull-up */ +		 (0 << 1) |		/* SCK, no pull-up */ +		 (0 << 0));		/* SS, no pull-up */ + +	SPCR = (0 << SPIE) |		/* Disable SPI interrupts */ +		(1 << SPE) |		/* Enable SPI */ +		(0 << DORD) |		/* MSB first */ +		(0 << MSTR) |		/* Slave mode */ +		(0 << CPOL) |		/* Clock low when idle */ +		(0 << CPHA);		/* Sample at leading clock edge */ +} diff --git a/src/avr/ao_spi_usart.c b/src/avr/ao_spi_usart.c new file mode 100644 index 00000000..6ed708ff --- /dev/null +++ b/src/avr/ao_spi_usart.c @@ -0,0 +1,112 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +/* + * Atmega32u4 USART in MSPIM (master SPI mode) + */ + +__xdata uint8_t	ao_spi_mutex; + +/* Send bytes over SPI. + * + * This just polls; the SPI is set to go as fast as possible, + * so using interrupts would take way too long + */ +void +ao_spi_send(void __xdata *block, uint16_t len) __reentrant +{ +	uint8_t	*d = block; + +	ao_mutex_get(&ao_spi_mutex); +	while (len--) { +		while (!(UCSR1A & (1 << UDRE1))); +		UDR1 = *d++; +		while (!(UCSR1A & (1 << RXC1))); +		(void) UDR1; +	} +	ao_mutex_put(&ao_spi_mutex); +} + +/* Receive bytes over SPI. + * + * This sets up tow DMA engines, one reading the data and another + * writing constant values to the SPI transmitter as that is what + * clocks the data coming in. + */ +void +ao_spi_recv(void __xdata *block, uint16_t len) __reentrant +{ +	uint8_t	*d = block; + +	ao_mutex_get(&ao_spi_mutex); +	while (len--) { +		while (!(UCSR1A & (1 << UDRE1))); +		UDR1 = 0; +		while (!(UCSR1A & (1 << RXC1))); +		*d++ = UDR1; +	} +	ao_mutex_put(&ao_spi_mutex); +} + +/* + * Initialize USART0 for SPI using config alt 2 + * + * 	MO	P1_5 + * 	MI	P1_4 + * 	CLK	P1_3 + * + * Chip select is the responsibility of the caller + */ + +#define XCK1_DDR	DDRD +#define XCK1_PORT	PORTD +#define XCK1		PORTD5 +#define XMS1_DDR	DDRE +#define XMS1_PORT	PORTE +#define XMS1		PORTE6 + +void +ao_spi_init(void) +{ +	/* Ensure the USART is powered */ +	PRR1 &= ~(1 << PRUSART1); + +	/* +	 * Set pin directions +	 */ +	XCK1_DDR |= (1 << XCK1); + +	/* Clear chip select (which is negated) */ +	XMS1_PORT |= (1 < XMS1); +	XMS1_DDR |= (1 << XMS1); + +	/* Set baud register to zero (required before turning transmitter on) */ +	UBRR1 = 0; + +	UCSR1C = ((0x3 << UMSEL10) |	/* Master SPI mode */ +		  (0 << UCSZ10) |	/* SPI mode 0 */ +		  (0 << UCPOL1));	/* SPI mode 0 */ + +	/* Enable transmitter and receiver */ +	UCSR1B = ((1 << RXEN1) | +		  (1 << TXEN1)); + +	/* It says that 0 is a legal value; we'll see... */ +	UBRR1 = 0; +} diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index c4972819..8a41791f 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -192,4 +192,16 @@ extern __code __at (0x00a6) uint32_t ao_radio_cal;  #define ao_arch_critical(b) __critical { b } +struct ao_adc { +	uint16_t	tick;		/* tick when the sample was read */ +	int16_t		accel;		/* accelerometer */ +	int16_t		pres;		/* pressure sensor */ +	int16_t		temp;		/* temperature sensor */ +	int16_t		v_batt;		/* battery voltage */ +	int16_t		sense_d;	/* drogue continuity sense */ +	int16_t		sense_m;	/* main continuity sense */ +}; + +#define AO_ADC_RING	32 +  #endif /* _AO_ARCH_H_ */ diff --git a/src/core/ao.h b/src/core/ao.h index 98a01a4a..05f056fd 100644 --- a/src/core/ao.h +++ b/src/core/ao.h @@ -144,15 +144,6 @@ ao_clock_init(void);  /*   * One set of samples read from the A/D converter or telemetry   */ -struct ao_adc { -	uint16_t	tick;		/* tick when the sample was read */ -	int16_t		accel;		/* accelerometer */ -	int16_t		pres;		/* pressure sensor */ -	int16_t		temp;		/* temperature sensor */ -	int16_t		v_batt;		/* battery voltage */ -	int16_t		sense_d;	/* drogue continuity sense */ -	int16_t		sense_m;	/* main continuity sense */ -};  #if HAS_ADC @@ -160,7 +151,6 @@ struct ao_adc {   * ao_adc.c   */ -#define AO_ADC_RING	32  #define ao_adc_ring_next(n)	(((n) + 1) & (AO_ADC_RING - 1))  #define ao_adc_ring_prev(n)	(((n) - 1) & (AO_ADC_RING - 1)) @@ -505,6 +495,23 @@ extern __pdata uint32_t ao_log_start_pos;  extern __xdata uint8_t	ao_log_running;  extern __pdata enum flight_state ao_log_state; +#define AO_LOG_TELESCIENCE_START	((uint8_t) 's') +#define AO_LOG_TELESCIENCE_DATA		((uint8_t) 'd') + +#define AO_LOG_TELESCIENCE_NUM_ADC	12 + +struct ao_log_telescience { +	uint8_t		type; +	uint8_t		csum; +	uint16_t	tick; +	uint16_t	tm_tick; +	uint8_t		tm_state; +	uint8_t		unused; +	uint16_t	adc[AO_LOG_TELESCIENCE_NUM_ADC]; +}; + +extern struct ao_log_telescience ao_log_store; +  /* required functions from the underlying log system */  #define AO_LOG_FORMAT_UNKNOWN		0	/* unknown; altosui will have to guess */ @@ -971,6 +978,16 @@ void  ao_spi_init(void);  /* + * ao_spi_slave.c + */ + +void +ao_spi_slave_debug(void); + +void +ao_spi_slave_init(void); + +/*   * ao_telemetry.c   */  #define AO_MAX_CALLSIGN			8 @@ -1568,8 +1585,9 @@ struct ao_companion_setup {  };  extern __pdata uint8_t				ao_companion_running; -extern __xdata struct ao_companion_setup	ao_companion_setup;  extern __xdata uint8_t				ao_companion_mutex; +extern __xdata struct ao_companion_command	ao_companion_command; +extern __xdata struct ao_companion_setup	ao_companion_setup;  extern __xdata uint16_t				ao_companion_data[AO_COMPANION_MAX_CHANNELS];  void diff --git a/src/core/ao_log_telescience.c b/src/core/ao_log_telescience.c new file mode 100644 index 00000000..aac780fa --- /dev/null +++ b/src/core/ao_log_telescience.c @@ -0,0 +1,274 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" +#include "ao_product.h" + +static struct ao_task ao_log_task; +//static struct ao_task ao_spi_task; + +uint8_t 	ao_log_running; +uint8_t		ao_log_mutex; +uint32_t	ao_log_start_pos; +uint32_t	ao_log_end_pos; +uint32_t	ao_log_current_pos; + +#define AO_LOG_TELESCIENCE_START	((uint8_t) 's') +#define AO_LOG_TELESCIENCE_DATA		((uint8_t) 'd') + +struct ao_log_telescience ao_log_store; +struct ao_log_telescience ao_log_fetch; + +static uint8_t	ao_log_adc_pos; + +__code uint8_t ao_log_format = AO_LOG_FORMAT_TELESCIENCE; + +static uint8_t +ao_log_csum(__xdata uint8_t *b) __reentrant +{ +	uint8_t	sum = 0x5a; +	uint8_t	i; + +	for (i = 0; i < sizeof (struct ao_log_telescience); i++) +		sum += *b++; +	return -sum; +} + +static uint8_t +ao_log_telescience_write(void) +{ +	uint8_t wrote = 0; + +	ao_log_store.csum = 0; +	ao_log_store.csum = ao_log_csum((__xdata uint8_t *) &ao_log_store); +	ao_mutex_get(&ao_log_mutex); { +		if (ao_log_current_pos >= ao_log_end_pos && ao_log_running) +			ao_log_stop(); +		if (ao_log_running) { +			wrote = 1; +			ao_storage_write(ao_log_current_pos, +					 (__xdata uint8_t *) &ao_log_store, +					 sizeof (struct ao_log_telescience)); +			ao_log_current_pos += sizeof (struct ao_log_telescience); +		} +	} ao_mutex_put(&ao_log_mutex); +	return wrote; +} + +static uint8_t +ao_log_valid(struct ao_log_telescience *log) +{ +	uint8_t	*d; +	uint8_t	i; +	d = (uint8_t *) log; +	for (i = 0; i < sizeof (struct ao_log_telescience); i++) +		if (d[i] != 0xff) +			return 1; +	return 0; +} + +static uint8_t +ao_log_telescience_read(uint32_t pos) +{ +	if (!ao_storage_read(pos, &ao_log_fetch, sizeof (struct ao_log_telescience))) +		return 0; +	return ao_log_valid(&ao_log_fetch); +} + +void +ao_log_start(void) +{ +	if (!ao_log_running) { +		ao_log_running = 1; +		ao_wakeup(&ao_log_running); +	} +} + +void +ao_log_stop(void) +{ +	if (ao_log_running) { +		ao_log_running = 0; +	} +} + +void +ao_log_restart(void) +{ +	/* Find end of data */ +	ao_log_end_pos = ao_storage_config; +	for (ao_log_current_pos = 0; +	     ao_log_current_pos < ao_storage_config; +	     ao_log_current_pos += ao_storage_block) +	{ +		if (!ao_log_telescience_read(ao_log_current_pos)) +			break; +	} +	if (ao_log_current_pos > 0) { +		ao_log_current_pos -= ao_storage_block; +		for (; ao_log_current_pos < ao_storage_config; +		     ao_log_current_pos += sizeof (struct ao_log_telescience)) +		{ +			if (!ao_log_telescience_read(ao_log_current_pos)) +				break; +		} +	} +} + +void +ao_log_telescience(void) +{ +	ao_storage_setup(); + +	/* This can take a while, so let the rest +	 * of the system finish booting before we start +	 */ +	ao_delay(AO_SEC_TO_TICKS(10)); + +	ao_log_restart(); +	for (;;) { +		while (!ao_log_running) +			ao_sleep(&ao_log_running); + +		ao_log_start_pos = ao_log_current_pos; +		ao_log_store.type = AO_LOG_TELESCIENCE_START; +		ao_log_store.tick = ao_time(); +		ao_log_store.adc[0] = ao_companion_command.serial; +		ao_log_store.adc[1] = ao_companion_command.flight; +		ao_log_telescience_write(); +		/* Write the whole contents of the ring to the log +		 * when starting up. +		 */ +		ao_log_adc_pos = ao_adc_ring_next(ao_adc_head); +		ao_log_store.type = AO_LOG_TELESCIENCE_DATA; +		while (ao_log_running) { +			/* Write samples to EEPROM */ +			while (ao_log_adc_pos != ao_adc_head) { +				ao_log_store.tick = ao_adc_ring[ao_log_adc_pos].tick; +				memcpy(&ao_log_store.adc, (void *) ao_adc_ring[ao_log_adc_pos].adc, +				       AO_LOG_TELESCIENCE_NUM_ADC * sizeof (uint16_t)); +				ao_log_telescience_write(); +				ao_log_adc_pos = ao_adc_ring_next(ao_log_adc_pos); +			} +			/* Wait for more ADC data to arrive */ +			ao_sleep((void *) &ao_adc_head); +		} +		memset(&ao_log_store.adc, '\0', sizeof (ao_log_store.adc)); +	} +} + +void +ao_log_set(void) +{ +	printf("Logging currently %s\n", ao_log_running ? "on" : "off"); +	ao_cmd_hex(); +	if (ao_cmd_status == ao_cmd_success) { +		if (ao_cmd_lex_i) { +			printf("Logging from %ld to %ld\n", ao_log_current_pos, ao_log_end_pos); +			ao_log_start(); +		} else { +			printf ("Log stopped at %ld\n", ao_log_current_pos); +			ao_log_stop(); +		} +	} +	ao_cmd_status = ao_cmd_success; +} + +void +ao_log_list(void) +{ +	uint32_t	pos; +	uint32_t	start = 0; +	uint8_t		flight = 0; + +	for (pos = 0; ; pos += sizeof (struct ao_log_telescience)) { +		if (pos >= ao_storage_config || +		    !ao_log_telescience_read(pos) || +		    ao_log_fetch.type == AO_LOG_TELESCIENCE_START) +		{ +			if (pos != start) { +				printf("flight %d start %x end %x\n", +				       flight, +				       (uint16_t) (start >> 8), +				       (uint16_t) ((pos + 0xff) >> 8)); flush(); +			} +			if (ao_log_fetch.type != AO_LOG_TELESCIENCE_START) +				break; +			start = pos; +			flight++; +		} +	} +	printf ("done\n"); +} + +void +ao_log_delete(void) +{ +	uint32_t	pos; + +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	if (ao_cmd_lex_i != 1) { +		ao_cmd_status = ao_cmd_syntax_error; +		printf("No such flight: %d\n", ao_cmd_lex_i); +		return; +	} +	ao_log_stop(); +	for (pos = 0; pos < ao_storage_config; pos += ao_storage_block) { +		if (!ao_log_telescience_read(pos)) +			break; +		ao_storage_erase(pos); +	} +	ao_log_current_pos = ao_log_start_pos = 0; +	if (pos == 0) +		printf("No such flight: %d\n", ao_cmd_lex_i); +	else +		printf ("Erased\n"); +} + +static void +ao_log_query(void) +{ +	printf("Logging enabled: %d\n", ao_log_running); +	printf("Log start: %ld\n", ao_log_start_pos); +	printf("Log cur: %ld\n", ao_log_current_pos); +	printf("Log end: %ld\n", ao_log_end_pos); +	printf("log data tick: %04x\n", ao_log_store.tick); +	printf("TM data tick: %04x\n", ao_log_store.tm_tick); +	printf("TM state: %d\n", ao_log_store.tm_state); +	printf("TM serial: %d\n", ao_companion_command.serial); +	printf("TM flight: %d\n", ao_companion_command.flight); +} + +const struct ao_cmds ao_log_cmds[] = { +	{ ao_log_set,	"L <0 off, 1 on>\0Set logging mode" }, +	{ ao_log_list,	"l\0List stored flight logs" }, +	{ ao_log_delete, "d 1\0Delete all stored flights" }, +	{ ao_log_query, "q\0Query log status" }, +	{ 0,	NULL }, +}; + +void +ao_log_init(void) +{ +	ao_log_running = 0; + +	ao_cmd_register(&ao_log_cmds[0]); + +	ao_add_task(&ao_log_task, ao_log_telescience, "log"); +} diff --git a/src/core/ao_panic.c b/src/core/ao_panic.c index 0668dad2..b6ff65cc 100644 --- a/src/core/ao_panic.c +++ b/src/core/ao_panic.c @@ -24,6 +24,10 @@  #if !HAS_BEEP  #define ao_beep(x)  #endif +#if !LEDS_AVAILABLE +#define ao_led_on(x) +#define ao_led_off(x) +#endif  static void  ao_panic_delay(uint8_t n) diff --git a/src/drivers/ao_companion.c b/src/drivers/ao_companion.c index 4c8f4269..2e587f8e 100644 --- a/src/drivers/ao_companion.c +++ b/src/drivers/ao_companion.c @@ -30,7 +30,7 @@  #define COMPANION_SELECT()	do { ao_spi_get_bit(COMPANION_CS); ao_spi_slow(); } while (0)  #define COMPANION_DESELECT()	do { ao_spi_fast(); ao_spi_put_bit(COMPANION_CS); } while (0) -static __xdata struct ao_companion_command	ao_companion_command; +__xdata struct ao_companion_command		ao_companion_command;  __xdata struct ao_companion_setup		ao_companion_setup;  __xdata uint16_t	ao_companion_data[AO_COMPANION_MAX_CHANNELS]; diff --git a/src/drivers/ao_lcd.c b/src/drivers/ao_lcd.c new file mode 100644 index 00000000..5bc89bbd --- /dev/null +++ b/src/drivers/ao_lcd.c @@ -0,0 +1,281 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +#define LCD_PORT	PORTB +#define LCD_DDR		DDRB + +#define PIN_RS		4 +#define PIN_E		5 +#define PIN_RW		6 + +void +ao_lcd_set_bits(uint8_t bits) +{ +#if 0 +	printf("\tLCD data %x RS %d R/W %d E %d\n", +	       bits & 0xf, +	       (bits & (1 << PIN_RS)) ? 1 : 0, +	       (bits & (1 << PIN_RW)) ? 1 : 0, +	       (bits & (1 << PIN_E)) ? 1 : 0); +#endif +	LCD_PORT = bits; +#if 0 +	ao_delay(1); +	if (bits & (1 << PIN_RW)) +		printf("\tLCD input %x\n", PINB); +#endif +} + +uint8_t +ao_lcd_get_nibble(uint8_t rs) +{ +	uint8_t	data = (rs ? (1 << PIN_RS) : 0) | (1 << PIN_RW); +	uint8_t n; + +	DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW); +	ao_lcd_set_bits(data); +	ao_lcd_set_bits(data | (1 << PIN_E)); +	n = PINB & 0xf; +	ao_lcd_set_bits(data); +	return n; +} + +uint8_t +ao_lcd_get_status(void) +{ +	uint8_t	high, low; +	uint8_t data; + +	high = ao_lcd_get_nibble(0); +	low = ao_lcd_get_nibble(0); +	data = (high << 4) | low; +	printf ("\tLCD status %02x\n", data); +	return data; +} + +uint8_t +ao_lcd_get_data(void) +{ +	uint8_t	high, low; +	uint8_t data; + +	high = ao_lcd_get_nibble(1); +	low = ao_lcd_get_nibble(1); +	data = (high << 4) | low; +	printf ("\tLCD data %02x\n", data); +	return data; +} + +void +ao_lcd_wait_idle(void) +{ +	uint8_t	status; +	uint8_t	count = 0; + +	do { +		status = ao_lcd_get_status(); +		count++; +		if (count > 100) { +			printf("idle timeout\n"); +			break; +		} +	} while (0);	/* status & 0x80); */ +} + +void +ao_lcd_send_nibble(uint8_t rs, uint8_t data) +{ +	data = (data & 0xf) | (rs ? (1 << PIN_RS) : 0); +	DDRB = (0xf) | (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW); +	ao_lcd_set_bits(data); +	ao_lcd_set_bits(data | (1 << PIN_E)); +	ao_lcd_set_bits(data); +} + +static uint16_t	ao_lcd_time = 3; + +void +ao_lcd_delay(void) +{ +	volatile uint16_t	count; + +	for (count = 0; count < ao_lcd_time; count++) +		; +} + +void +ao_lcd_send_ins(uint8_t data) +{ +//	printf("send ins %02x\n", data); +//	ao_lcd_wait_idle(); +//	ao_delay(1); +	ao_lcd_delay(); +	ao_lcd_send_nibble(0, data >> 4); +	ao_lcd_send_nibble(0, data & 0xf); +} + +void +ao_lcd_send_data(uint8_t data) +{ +//	printf ("send data %02x\n", data); +//	ao_lcd_wait_idle(); +	ao_lcd_delay(); +	ao_lcd_send_nibble(1, data >> 4); +	ao_lcd_send_nibble(1, data & 0x0f); +} + +void +ao_lcd_send_string(char *string) +{ +	uint8_t	c; + +	while ((c = (uint8_t) *string++)) +		ao_lcd_send_data(c); +} + +#define AO_LCD_POWER_CONTROL	0x54 + +void +ao_lcd_contrast_set(uint8_t contrast) +{ +	ao_lcd_send_ins(AO_LCD_POWER_CONTROL | ((contrast >> 4) & 0x3)); +	ao_lcd_send_ins(0x70 | (contrast & 0xf)); +} + +void +ao_lcd_clear(void) +{ +	ao_lcd_send_ins(0x01); +	ao_delay(1); +	/* Entry mode */ +	ao_lcd_send_ins(0x04 | 0x02); +} + +void +ao_lcd_start(void) +{ +	/* get to 4bit mode */ +	ao_lcd_send_nibble(0, 0x3); +	ao_lcd_send_nibble(0, 0x3); +	ao_lcd_send_nibble(0, 0x3); +	ao_lcd_send_nibble(0, 0x2); + +	/* function set */ +	ao_lcd_send_ins(0x28); +	/* function set, instruction table 1 */ +	ao_lcd_send_ins(0x29); + +	/* freq set */ +	ao_lcd_send_ins(0x14); + +	/* Power/icon/contrast control*/ +	ao_lcd_send_ins(AO_LCD_POWER_CONTROL); + +	/* Follower control */ +	ao_lcd_send_ins(0x6d); +	ao_delay(AO_MS_TO_TICKS(200)); + +	/* contrast set */ +	ao_lcd_contrast_set(0x18); + +	/* Display on */ +	ao_lcd_send_ins(0x08 | 0x04); + +	/* Clear */ +	ao_lcd_clear(); + +} + +void +ao_lcd_contrast(void) +{ +	ao_cmd_hex(); +	if (ao_cmd_status == ao_cmd_success) { +		printf("setting contrast to %02x\n", ao_cmd_lex_i); +		ao_lcd_contrast_set(ao_cmd_lex_i & 0x3f); +	} +} + +static uint8_t +ao_cmd_hex_nibble(void) +{ +	if ('0' <= ao_cmd_lex_c && ao_cmd_lex_c <= '9') +		return ao_cmd_lex_c - '0'; +	if ('a' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'f') +		return ao_cmd_lex_c - ('a' - 10); +	if ('A' <= ao_cmd_lex_c && ao_cmd_lex_c <= 'F') +		return ao_cmd_lex_c - ('A' - 10); +	ao_cmd_status = ao_cmd_syntax_error; +	return 0; +} + +void +ao_lcd_string(void) +{ +	uint8_t	col = 0; +	uint8_t	c; + +	ao_cmd_decimal(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	ao_lcd_send_ins(0x80 | (ao_cmd_lex_i ? 0x40 : 0x00)); +	ao_cmd_white(); +	while (ao_cmd_lex_c != '\n') { +		c = ao_cmd_lex_c; +		if (c == '\\') { +			ao_cmd_lex(); +			c = ao_cmd_hex_nibble() << 4; +			ao_cmd_lex(); +			c |= ao_cmd_hex_nibble(); +		} +		ao_lcd_send_data(c); +		ao_cmd_lex(); +		col++; +	} +	while (col < 16) { +		ao_lcd_send_data(' '); +		col++; +	} +} + +void +ao_lcd_delay_set(void) +{ +	ao_cmd_decimal(); +	if (ao_cmd_status == ao_cmd_success) { +		printf("setting LCD delay to %d\n", ao_cmd_lex_i); +		ao_lcd_time = ao_cmd_lex_i; +	} +} + +__code struct ao_cmds ao_lcd_cmds[] = { +	{ ao_lcd_start, "S\0Start LCD" }, +	{ ao_lcd_contrast, "C <contrast>\0Set LCD contrast" }, +	{ ao_lcd_string, "s <line> <string>\0Send string to LCD" }, +	{ ao_lcd_delay_set, "t <delay>\0Set LCD delay" }, +	{ 0, NULL }, +}; + +void +ao_lcd_init(void) +{ +	DDRB = (1 << PIN_RS) | (1 << PIN_E) | (1 << PIN_RW); +	PORTB = 0; +	ao_cmd_register(&ao_lcd_cmds[0]); +} diff --git a/src/drivers/ao_m25.c b/src/drivers/ao_m25.c index d7208273..28cb1dd7 100644 --- a/src/drivers/ao_m25.c +++ b/src/drivers/ao_m25.c @@ -376,5 +376,7 @@ ao_storage_device_init(void)  	/* Set up chip select wires */  	SPI_CS_PORT |= M25_CS_MASK;	/* raise all CS pins */  	SPI_CS_DIR |= M25_CS_MASK;	/* set CS pins as outputs */ +#ifdef SPI_CS_SEL  	SPI_CS_SEL &= ~M25_CS_MASK;	/* set CS pins as GPIO */ +#endif  } diff --git a/src/product/ao_telescience.c b/src/product/ao_telescience.c new file mode 100644 index 00000000..4dec3a18 --- /dev/null +++ b/src/product/ao_telescience.c @@ -0,0 +1,39 @@ +/* + * Copyright © 2011 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include "ao.h" + +int +main(void) +{ +	ao_clock_init(); + +	PORTE |= (1 << 6); +	DDRE |= (1 << 6); + +	ao_avr_stdio_init(); +	ao_timer_init(); +	ao_cmd_init(); +	ao_spi_init(); +	ao_spi_slave_init(); +	ao_storage_init(); +	ao_usb_init(); +	ao_adc_init(); +	ao_log_init(); +	ao_start_scheduler(); +	return 0; +} diff --git a/src/telescience-v0.1/Makefile b/src/telescience-v0.1/Makefile new file mode 100644 index 00000000..3ccbb787 --- /dev/null +++ b/src/telescience-v0.1/Makefile @@ -0,0 +1,109 @@ +# +# AltOS build +# +# +vpath % ..:../core:../product:../drivers:../avr +vpath ao-make-product.5c ../util + +MCU=atmega32u4 +DUDECPUTYPE=m32u4 +#PROGRAMMER=stk500v2 -P usb +PROGRAMMER=usbtiny +LOADCMD=avrdude +LOADARG=-p $(DUDECPUTYPE) -c $(PROGRAMMER) -e -U flash:w: +CC=avr-gcc +OBJCOPY=avr-objcopy + +ifndef VERSION +include ../Version +endif + +INC = \ +	ao.h \ +	ao_usb.h \ +	ao_pins.h \ +	altitude.h + +# +# Common AltOS sources +# +TELESCIENCE_STORAGE= \ +	ao_m25.c \ +	ao_spi_usart.c \ +	ao_storage.c \ + +ALTOS_SRC = \ +	ao_cmd.c \ +	ao_mutex.c \ +	ao_panic.c \ +	ao_product.c \ +	ao_stdio.c \ +	ao_task.c \ +	ao_timer.c \ +	ao_led.c \ +	ao_avr_stdio.c \ +	ao_romconfig.c \ +	ao_usb_avr.c \ +	ao_adc_avr.c \ +	ao_spi_slave.c \ +	ao_log_telescience.c \ +	$(TELESCIENCE_STORAGE) + +PRODUCT=TeleScience-v0.1 +MCU=atmega32u4 +PRODUCT_DEF=-DTELESCIENCE +IDPRODUCT=0x0011 +CFLAGS = $(PRODUCT_DEF) -I. -I../avr -I../core -I.. +CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O3 -mcall-prologues -DAVR + +NICKLE=nickle + +PROG=telescience-v0.1 + +SRC=$(ALTOS_SRC) ao_telescience.c +OBJ=$(SRC:.c=.o) + +V=0 +# The user has explicitly enabled quiet compilation. +ifeq ($(V),0) +quiet = @printf "  $1 $2 $@\n"; $($1) +endif +# Otherwise, print the full command line. +quiet ?= $($1) + +all: $(PROG) + +CHECK=sh ../util/check-avr-mem + +$(PROG): Makefile $(OBJ) +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) +	$(call quiet,CHECK) $(PROG) || ($(RM) -f $(PROG); exit 1) + +$(PROG).hex: $(PROG) +	avr-size $(PROG) +	$(OBJCOPY) -R .eeprom -O ihex $(PROG) $@ + + +load: $(PROG).hex +	$(LOADCMD) $(LOADARG)$(PROG).hex + +../altitude.h: make-altitude +	nickle $< > $@ + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +ao_product.rel: ao_product.c ao_product.h +	$(call quiet,CC) -c $(CFLAGS) -D PRODUCT_DEFS='\"ao_product.h\"' -o$@ $< + +distclean:	clean + +clean: +	rm -f $(OBJ) +	rm -f ao_product.h + +install: + +uninstall: + +$(OBJ): ao.h ao_product.h ao_usb.h diff --git a/src/util/check-avr-mem b/src/util/check-avr-mem new file mode 100644 index 00000000..c73edbd1 --- /dev/null +++ b/src/util/check-avr-mem @@ -0,0 +1,9 @@ +#!/bin/sh +nm "$@" | +grep ' N _end' | +awk '{ iram = strtonum("0x" $1) % 0x10000; +if ( iram > 0xaff) { +	printf ("%d bytes of ram more than %d available\n", iram, 0xaff); +	exit(1); +} else +	exit(0); }'  | 
