diff options
| author | Bdale Garbee <bdale@gag.com> | 2015-02-07 22:39:54 -0700 | 
|---|---|---|
| committer | Bdale Garbee <bdale@gag.com> | 2015-02-07 22:39:54 -0700 | 
| commit | f766a457323268857b3f2dfc7f42427437b71cb7 (patch) | |
| tree | 8afc8a661d682fc34b16fc0b1b44f2844d34f336 /src | |
| parent | db51224af01731e7323f6f696a7397d64eb80b92 (diff) | |
| parent | e2cefd8593d269ce603aaf33f4a53a5c2dcb3350 (diff) | |
Merge branch 'branch-1.6' into debian
Conflicts:
	ChangeLog
	altoslib/AltosTelemetryReader.java
	configure.ac
Diffstat (limited to 'src')
86 files changed, 9328 insertions, 277 deletions
diff --git a/src/.gitignore b/src/.gitignore index a8628fae..aad18d4c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,4 +1,5 @@  Makedefs  altitude.h  altitude-pa.h +altitude-pa-small.h  ao_whiten.h diff --git a/src/Makefile b/src/Makefile index 20126de6..05e99c7f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -35,7 +35,9 @@ ARMM3DIRS=\  	telegps-v1.0 telegps-v1.0/flash-loader \  	telelco-v0.2 telelco-v0.2/flash-loader \  	telescience-v0.2 telescience-v0.2/flash-loader \ -	teleballoon-v2.0 +	teledongle-v3.0 teledongle-v3.0/flash-loader \ +	teleballoon-v2.0 \ +	telebt-v3.0 telebt-v3.0/flash-loader  ARMM0DIRS=\  	easymini-v1.0 easymini-v1.0/flash-loader diff --git a/src/attiny/ao_arch.h b/src/attiny/ao_arch.h index 8140dd30..6ca12af6 100644 --- a/src/attiny/ao_arch.h +++ b/src/attiny/ao_arch.h @@ -31,6 +31,8 @@  #define AO_STACK_SIZE	116 +#define AO_PORT_TYPE	uint8_t +  /* Various definitions to make GCC look more like SDCC */  #define ao_arch_naked_declare	__attribute__((naked)) diff --git a/src/avr/ao_arch.h b/src/avr/ao_arch.h index d626e830..f8c7f042 100644 --- a/src/avr/ao_arch.h +++ b/src/avr/ao_arch.h @@ -41,6 +41,8 @@  #define AO_STACK_SIZE	116  #endif +#define AO_PORT_TYPE	uint8_t +  /* Various definitions to make GCC look more like SDCC */  #define ao_arch_naked_declare	__attribute__((naked)) diff --git a/src/cc1111/ao_arch.h b/src/cc1111/ao_arch.h index fcac331b..b3c6b5dc 100644 --- a/src/cc1111/ao_arch.h +++ b/src/cc1111/ao_arch.h @@ -40,6 +40,8 @@  #define AO_STACK_END	0xfe  #define AO_STACK_SIZE	(AO_STACK_END - AO_STACK_START + 1) +#define AO_PORT_TYPE	uint8_t +  #define ao_arch_reboot() do {					\  	WDCTL = WDCTL_EN | WDCTL_MODE_WATCHDOG | WDCTL_INT_64;	\  	ao_delay(AO_SEC_TO_TICKS(2));				\ diff --git a/src/drivers/ao_btm.c b/src/drivers/ao_btm.c index 3b6028a0..e6b28688 100644 --- a/src/drivers/ao_btm.c +++ b/src/drivers/ao_btm.c @@ -16,13 +16,16 @@   */  #include "ao.h" +#ifdef AO_BTM_INT_PORT +#include <ao_exti.h> +#endif  #ifndef ao_serial_btm_getchar  #define ao_serial_btm_putchar	ao_serial1_putchar  #define _ao_serial_btm_pollchar	_ao_serial1_pollchar +#define _ao_serial_btm_sleep()	ao_sleep((void *) &ao_serial1_rx_fifo)  #define ao_serial_btm_set_speed ao_serial1_set_speed  #define ao_serial_btm_drain	ao_serial1_drain -#define ao_serial_btm_rx_fifo	ao_serial1_rx_fifo  #endif  int8_t			ao_btm_stdio; @@ -32,7 +35,7 @@ __xdata uint8_t		ao_btm_connected;  #if BT_DEBUG  __xdata char		ao_btm_buffer[256]; -int			ao_btm_ptr; +uint16_t		ao_btm_ptr;  char			ao_btm_dir;  static void @@ -81,6 +84,10 @@ ao_btm_dump(void)  			putchar(ao_btm_buffer[i]);  	}  	putchar('\n'); +	ao_cmd_decimal(); +	if (ao_cmd_status == ao_cmd_success && ao_cmd_lex_i) +		ao_btm_ptr = 0; +	ao_cmd_status = ao_cmd_success;  }  static void @@ -95,9 +102,44 @@ ao_btm_speed(void)  		ao_cmd_status = ao_cmd_syntax_error;  } +static uint8_t	ao_btm_enable; + +static void +ao_btm_do_echo(void) +{ +	int	c; +	while (ao_btm_enable) { +		ao_arch_block_interrupts(); +		while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN && ao_btm_enable) +			_ao_serial_btm_sleep(); +		ao_arch_release_interrupts(); +		if (c != AO_READ_AGAIN) { +			putchar(c); +			flush(); +		} +	} +	ao_exit(); +} + +static struct ao_task ao_btm_echo_task; + +static void +ao_btm_send(void) +{ +	int c; +	ao_btm_enable = 1; +	ao_add_task(&ao_btm_echo_task, ao_btm_do_echo, "btm-echo"); +	while ((c = getchar()) != '~') { +		ao_serial_btm_putchar(c); +	} +	ao_btm_enable = 0; +	ao_wakeup((void *) &ao_serial_btm_rx_fifo); +} +  __code struct ao_cmds ao_btm_cmds[] = {  	{ ao_btm_dump,		"d\0Dump btm buffer." },  	{ ao_btm_speed,		"s <19200,57600>\0Set btm serial speed." }, +	{ ao_btm_send,		"S\0BTM interactive mode. ~ to exit." },  	{ 0, NULL },  }; @@ -125,7 +167,7 @@ ao_btm_getchar(void)  	ao_arch_block_interrupts();  	while ((c = _ao_serial_btm_pollchar()) == AO_READ_AGAIN) {  		ao_alarm(AO_MS_TO_TICKS(10)); -		c = ao_sleep(&ao_serial_btm_rx_fifo); +		c = _ao_serial_btm_sleep();  		ao_clear_alarm();  		if (c) {  			c = AO_READ_AGAIN; @@ -146,6 +188,7 @@ ao_btm_get_line(void)  {  	uint8_t ao_btm_reply_len = 0;  	int c; +	uint8_t l;  	while ((c = ao_btm_getchar()) != AO_READ_AGAIN) {  		ao_btm_log_in_char(c); @@ -154,8 +197,8 @@ ao_btm_get_line(void)  		if (c == '\r' || c == '\n')  			break;  	} -	for (c = ao_btm_reply_len; c < sizeof (ao_btm_reply);) -		ao_btm_reply[c++] = '\0'; +	for (l = ao_btm_reply_len; l < sizeof (ao_btm_reply);) +		ao_btm_reply[l++] = '\0';  	return ao_btm_reply_len;  } @@ -214,7 +257,7 @@ ao_btm_string(__code char *cmd)  {  	char	c; -	while (c = *cmd++) +	while ((c = *cmd++) != '\0')  		ao_btm_putchar(c);  } @@ -256,6 +299,52 @@ ao_btm_try_speed(uint8_t speed)  	return 0;  } +#if BT_LINK_ON_P2 +#define BT_PICTL_ICON	PICTL_P2ICON +#define BT_PIFG		P2IFG +#define BT_PDIR		P2DIR +#define BT_PINP		P2INP +#define BT_IEN2_PIE	IEN2_P2IE +#define BT_CC1111	1 +#endif +#if BT_LINK_ON_P1 +#define BT_PICTL_ICON	PICTL_P1ICON +#define BT_PIFG		P1IFG +#define BT_PDIR		P1DIR +#define BT_PINP		P1INP +#define BT_IEN2_PIE	IEN2_P1IE +#define BT_CC1111	1 +#endif + +void +ao_btm_check_link() +{ +#if BT_CC1111 +	ao_arch_critical( +		/* Check the pin and configure the interrupt detector to wait for the +		 * pin to flip the other way +		 */ +		if (BT_LINK_PIN) { +			ao_btm_connected = 0; +			PICTL |= BT_PICTL_ICON; +		} else { +			ao_btm_connected = 1; +			PICTL &= ~BT_PICTL_ICON; +		} +		); +#else +	ao_arch_block_interrupts(); +	if (ao_gpio_get(AO_BTM_INT_PORT, AO_BTM_INT_PIN, AO_BTM_INT) == 0) { +		ao_btm_connected = 1; +	} else { +		ao_btm_connected = 0; +	} +	ao_arch_release_interrupts(); +#endif +} + +__xdata struct ao_task ao_btm_task; +  /*   * A thread to initialize the bluetooth device and   * hang around to blink the LED when connected @@ -298,6 +387,13 @@ ao_btm(void)  				    NULL);  	ao_btm_echo(0); +	/* Check current pin state */ +	ao_btm_check_link(); + +#ifdef AO_BTM_INT_PORT +	ao_exti_enable(AO_BTM_INT_PORT, AO_BTM_INT_PIN); +#endif +  	for (;;) {  		while (!ao_btm_connected)  			ao_sleep(&ao_btm_connected); @@ -308,40 +404,8 @@ ao_btm(void)  	}  } -__xdata struct ao_task ao_btm_task; - -#if BT_LINK_ON_P2 -#define BT_PICTL_ICON	PICTL_P2ICON -#define BT_PIFG		P2IFG -#define BT_PDIR		P2DIR -#define BT_PINP		P2INP -#define BT_IEN2_PIE	IEN2_P2IE -#endif -#if BT_LINK_ON_P1 -#define BT_PICTL_ICON	PICTL_P1ICON -#define BT_PIFG		P1IFG -#define BT_PDIR		P1DIR -#define BT_PINP		P1INP -#define BT_IEN2_PIE	IEN2_P1IE -#endif - -void -ao_btm_check_link() -{ -	ao_arch_critical( -		/* Check the pin and configure the interrupt detector to wait for the -		 * pin to flip the other way -		 */ -		if (BT_LINK_PIN) { -			ao_btm_connected = 0; -			PICTL |= BT_PICTL_ICON; -		} else { -			ao_btm_connected = 1; -			PICTL &= ~BT_PICTL_ICON; -		} -		); -} +#if BT_CC1111  void  ao_btm_isr(void)  #if BT_LINK_ON_P1 @@ -357,6 +421,16 @@ ao_btm_isr(void)  	}  	BT_PIFG = 0;  } +#endif + +#ifdef AO_BTM_INT_PORT +void +ao_btm_isr(void) +{ +	ao_btm_check_link(); +	ao_wakeup(&ao_btm_connected); +} +#endif  void  ao_btm_init (void) @@ -365,6 +439,18 @@ ao_btm_init (void)  	ao_serial_btm_set_speed(AO_SERIAL_SPEED_19200); +#ifdef AO_BTM_RESET_PORT +	ao_enable_output(AO_BTM_RESET_PORT,AO_BTM_RESET_PIN,AO_BTM_RESET,0); +#endif + +#ifdef AO_BTM_INT_PORT +	ao_enable_port(AO_BTM_INT_PORT); +	ao_exti_setup(AO_BTM_INT_PORT, AO_BTM_INT_PIN, +		      AO_EXTI_MODE_FALLING|AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_LOW, +		      ao_btm_isr); +#endif + +#if BT_CC1111  #if BT_LINK_ON_P1  	/*  	 * Configure ser reset line @@ -386,9 +472,7 @@ ao_btm_init (void)  	/* Enable interrupts */  	IEN2 |= BT_IEN2_PIE; - -	/* Check current pin state */ -	ao_btm_check_link(); +#endif  #if BT_LINK_ON_P2  	/* Eable the pin interrupt */ diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c index 3ea8b704..90d6cc75 100644 --- a/src/drivers/ao_cc1120.c +++ b/src/drivers/ao_cc1120.c @@ -1125,12 +1125,12 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)  	ao_exti_set_mode(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN,  			 AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); -	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); -	ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); -  	rx_starting = 1;  	rx_task_id = ao_cur_task->task_id; +	ao_exti_set_callback(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN, ao_radio_rx_isr); +	ao_exti_enable(AO_CC1120_INT_PORT, AO_CC1120_INT_PIN); +  	ao_radio_strobe(CC1120_SRX);  	if (timeout) @@ -1148,8 +1148,9 @@ ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout)  		ao_clear_alarm();  	if (ao_radio_abort) { +		if (rx_task_id_save == 0) +			ao_radio_burst_read_stop();  		ret = 0; -		rx_task_id = 0;  		goto abort;  	} diff --git a/src/drivers/ao_cc115l.c b/src/drivers/ao_cc115l.c index cf61acfe..0246ba02 100644 --- a/src/drivers/ao_cc115l.c +++ b/src/drivers/ao_cc115l.c @@ -38,7 +38,7 @@ static uint8_t ao_radio_abort;		/* radio operation should abort */  #define FOSC	26000000 -#define ao_radio_select()	ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_1MHz) +#define ao_radio_select()	ao_spi_get_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS,AO_SPI_SPEED_6MHz)  #define ao_radio_deselect()	ao_spi_put_mask(AO_CC115L_SPI_CS_PORT,(1 << AO_CC115L_SPI_CS_PIN),AO_CC115L_SPI_BUS)  #define ao_radio_spi_send(d,l)	ao_spi_send((d), (l), AO_CC115L_SPI_BUS)  #define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC115L_SPI_BUS) @@ -246,6 +246,8 @@ ao_radio_idle(void)  	}  	/* Flush any pending TX bytes */  	ao_radio_strobe(CC115L_SFTX); +	/* Make sure the RF calibration is current */ +	ao_radio_strobe(CC115L_SCAL);  }  /* @@ -325,23 +327,22 @@ static const struct {  static const uint16_t packet_setup[] = {  	CC115L_MDMCFG3,		(PACKET_DRATE_M), -	CC115L_MDMCFG2,		(0x00 | -				 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | +	CC115L_MDMCFG2,		((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |  				 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |  				 (CC115L_MDMCFG2_SYNC_MODE_16BITS << CC115L_MDMCFG2_SYNC_MODE)),  };  /* - * RDF deviation is 5kHz + * RDF deviation is 3kHz   *   *	fdev = fosc >> 17 * (8 + dev_m) << dev_e   * - *     	26e6 / (2 ** 17) * (8 + 4) * (2 ** 1) = 4761Hz + *     	26e6 / (2 ** 17) * (8 + 7) * (2 ** 0) = 2975   */ -#define RDF_DEV_E	1 -#define RDF_DEV_M	4 +#define RDF_DEV_E	0 +#define RDF_DEV_M	7  /*   * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone) @@ -364,8 +365,7 @@ static const uint16_t rdf_setup[] = {  	CC115L_MDMCFG4,		((0xf << 4) |  				 (RDF_DRATE_E << CC115L_MDMCFG4_DRATE_E)),  	CC115L_MDMCFG3,		(RDF_DRATE_M), -	CC115L_MDMCFG2,		(0x00 | -				 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | +	CC115L_MDMCFG2,		((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |  				 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |  				 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),  }; @@ -401,8 +401,7 @@ static const uint16_t aprs_setup[] = {  	CC115L_MDMCFG4,		((0xf << 4) |  				 (APRS_DRATE_E << CC115L_MDMCFG4_DRATE_E)),  	CC115L_MDMCFG3,		(APRS_DRATE_M), -	CC115L_MDMCFG2,		(0x00 | -				 (CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) | +	CC115L_MDMCFG2,		((CC115L_MDMCFG2_MOD_FORMAT_GFSK << CC115L_MDMCFG2_MOD_FORMAT) |  				 (0 << CC115L_MDMCFG2_MANCHESTER_EN) |  				 (CC115L_MDMCFG2_SYNC_MODE_NONE << CC115L_MDMCFG2_SYNC_MODE)),  }; @@ -491,16 +490,21 @@ static const uint16_t radio_setup[] = {  	AO_CC115L_DONE_INT_GPIO_IOCFG,	    CC115L_IOCFG_GPIO_CFG_PA_PD | (1 << CC115L_IOCFG_GPIO_INV),          CC115L_FIFOTHR,                     0x47,       /* TX FIFO Thresholds */ -	CC115L_MDMCFG1,			    (0x00 | -					     (CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) | -					     (1 << CC115L_MDMCFG1_CHANSPC_E)), +	CC115L_MDMCFG1,					/* Modem Configuration */ +		((CC115L_MDMCFG1_NUM_PREAMBLE_4 << CC115L_MDMCFG1_NUM_PREAMBLE) | +		 (1 << CC115L_MDMCFG1_CHANSPC_E)),  	CC115L_MDMCFG0,			    248,	/* Channel spacing M value (100kHz channels) */ +	CC115L_MCSM1,			    0x30,	/* Main Radio Control State Machine Configuration */          CC115L_MCSM0,                       0x38,       /* Main Radio Control State Machine Configuration */          CC115L_RESERVED_0X20,               0xfb,       /* Use setting from SmartRF Studio */ +	CC115L_FREND0,			    0x10,	/* Front End TX Configuration */          CC115L_FSCAL3,                      0xe9,       /* Frequency Synthesizer Calibration */          CC115L_FSCAL2,                      0x2a,       /* Frequency Synthesizer Calibration */          CC115L_FSCAL1,                      0x00,       /* Frequency Synthesizer Calibration */          CC115L_FSCAL0,                      0x1f,       /* Frequency Synthesizer Calibration */ +	CC115L_RESERVED_0X29,		    0x59,	/* RESERVED */ +	CC115L_RESERVED_0X2A,		    0x7f,	/* RESERVED */ +	CC115L_RESERVED_0X2B,		    0x3f,	/* RESERVED */          CC115L_TEST2,                       0x81,       /* Various Test Settings */          CC115L_TEST1,                       0x35,       /* Various Test Settings */          CC115L_TEST0,                       0x09,       /* Various Test Settings */ @@ -508,6 +512,18 @@ static const uint16_t radio_setup[] = {  static uint8_t	ao_radio_configured = 0; +#if HAS_RADIO_POWER +#define RADIO_POWER	ao_config.radio_power +#else + +#if 0 +#define RADIO_POWER	0x03	/* -31.75dBm on the test board */ +#endif + +#define RADIO_POWER	0xc0	/* full power */ + +#endif +  static void  ao_radio_setup(void)  { @@ -523,6 +539,8 @@ ao_radio_setup(void)  	ao_config_get(); +	ao_radio_reg_write(CC115L_PA, RADIO_POWER); +  	ao_radio_strobe(CC115L_SCAL);  	ao_radio_configured = 1; @@ -553,6 +571,8 @@ ao_radio_get(void)  		ao_radio_reg_write(CC115L_FREQ1, ao_config.radio_setting >> 8);  		ao_radio_reg_write(CC115L_FREQ0, ao_config.radio_setting);  		last_radio_setting = ao_config.radio_setting; +		/* Make sure the RF calibration is current */ +		ao_radio_strobe(CC115L_SCAL);  	}  	if (ao_config.radio_rate != last_radio_rate) {  		ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET_TX; @@ -666,23 +686,11 @@ ao_radio_rdf_abort(void)  #define POWER_STEP	0x08 -#if HAS_RADIO_POWER -#define RADIO_POWER	ao_config.radio_power -#else -#define RADIO_POWER	0xc0 -#endif -  static void  ao_radio_stx(void)  { -	uint8_t	power;  	ao_radio_pa_on(); -	ao_radio_reg_write(CC115L_PA, 0);  	ao_radio_strobe(CC115L_STX); -	for (power = POWER_STEP; power < RADIO_POWER; power += POWER_STEP) -		ao_radio_reg_write(CC115L_PA, power); -	if (power != RADIO_POWER) -		ao_radio_reg_write(CC115L_PA, RADIO_POWER);  }  static void diff --git a/src/drivers/ao_cc1200.c b/src/drivers/ao_cc1200.c new file mode 100644 index 00000000..8546900e --- /dev/null +++ b/src/drivers/ao_cc1200.c @@ -0,0 +1,1462 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_cc1200.h> +#include <ao_exti.h> +#include <ao_fec.h> +#include <ao_packet.h> + +static uint8_t ao_radio_mutex; + +static uint8_t ao_radio_wake;		/* radio ready. Also used as sleep address */ +static uint8_t ao_radio_abort;		/* radio operation should abort */ + +int8_t	ao_radio_rssi;			/* Last received RSSI value */ + +#ifndef CC1200_DEBUG +#define CC1200_DEBUG		0 +#endif + +#ifndef CC1200_LOW_LEVEL_DEBUG +#define CC1200_LOW_LEVEL_DEBUG	0 +#endif + +#define CC1200_TRACE		0 +#define CC1200_APRS_TRACE	0 + +extern const uint32_t	ao_radio_cal; + +#define FOSC	40000000 + +#define ao_radio_select()	ao_spi_get_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS,AO_SPI_SPEED_FAST) +#define ao_radio_deselect()	ao_spi_put_mask(AO_CC1200_SPI_CS_PORT,(1 << AO_CC1200_SPI_CS_PIN),AO_CC1200_SPI_BUS) +#define ao_radio_spi_send(d,l)	ao_spi_send((d), (l), AO_CC1200_SPI_BUS) +#define ao_radio_spi_send_fixed(d,l) ao_spi_send_fixed((d), (l), AO_CC1200_SPI_BUS) +#define ao_radio_spi_recv(d,l)	ao_spi_recv((d), (l), AO_CC1200_SPI_BUS) +#define ao_radio_duplex(o,i,l)	ao_spi_duplex((o), (i), (l), AO_CC1200_SPI_BUS) + +static uint8_t +ao_radio_reg_read(uint16_t addr) +{ +	uint8_t	data[2]; +	uint8_t	d; + +#if CC1200_TRACE +	printf("\t\tao_radio_reg_read (%04x): ", addr); flush(); +#endif +	if (CC1200_IS_EXTENDED(addr)) { +		data[0] = ((1 << CC1200_READ)  | +			   (0 << CC1200_BURST) | +			   CC1200_EXTENDED); +		data[1] = addr; +		d = 2; +	} else { +		data[0] = ((1 << CC1200_READ)  | +			   (0 << CC1200_BURST) | +			   addr); +		d = 1; +	} +	ao_radio_select(); +	ao_radio_spi_send(data, d); +	ao_radio_spi_recv(data, 1); +	ao_radio_deselect(); +#if CC1200_TRACE +	printf (" %02x\n", data[0]); +#endif +	return data[0]; +} + +static void +ao_radio_reg_write(uint16_t addr, uint8_t value) +{ +	uint8_t	data[3]; +	uint8_t	d; + +#if CC1200_TRACE +	printf("\t\tao_radio_reg_write (%04x): %02x\n", addr, value); +#endif +	if (CC1200_IS_EXTENDED(addr)) { +		data[0] = ((0 << CC1200_READ)  | +			   (0 << CC1200_BURST) | +			   CC1200_EXTENDED); +		data[1] = addr; +		d = 2; +	} else { +		data[0] = ((0 << CC1200_READ)  | +			   (0 << CC1200_BURST) | +			   addr); +		d = 1; +	} +	data[d] = value; +	ao_radio_select(); +	ao_radio_spi_send(data, d+1); +	ao_radio_deselect(); +#if CC1200_TRACE +	(void) ao_radio_reg_read(addr); +#endif +} + +static uint8_t +ao_radio_strobe(uint8_t addr) +{ +	uint8_t	in; + +#if CC1200_TRACE +	printf("\t\tao_radio_strobe (%02x): ", addr); flush(); +#endif +	ao_radio_select(); +	ao_radio_duplex(&addr, &in, 1); +	ao_radio_deselect(); +#if CC1200_TRACE +	printf("%02x\n", in); flush(); +#endif +	return in; +} + +static uint8_t +ao_radio_fifo_read(uint8_t *data, uint8_t len) +{ +	uint8_t	addr = ((1 << CC1200_READ)  | +			(1 << CC1200_BURST) | +			CC1200_FIFO); +	uint8_t status; + +	ao_radio_select(); +	ao_radio_duplex(&addr, &status, 1); +	ao_radio_spi_recv(data, len); +	ao_radio_deselect(); +	return status; +} + +static uint8_t +ao_radio_fifo_write_start(void) +{ +	uint8_t	addr = ((0 << CC1200_READ)  | +			(1 << CC1200_BURST) | +			CC1200_FIFO); +	uint8_t status; + +	ao_radio_select(); +	ao_radio_duplex(&addr, &status, 1); +	return status; +} + +static inline uint8_t ao_radio_fifo_write_stop(uint8_t status) { +	ao_radio_deselect(); +	return status; +} + +static uint8_t +ao_radio_fifo_write(const uint8_t *data, uint8_t len) +{ +	uint8_t	status = ao_radio_fifo_write_start(); +	ao_radio_spi_send(data, len); +	return ao_radio_fifo_write_stop(status); +} + +static uint8_t +ao_radio_fifo_write_fixed(uint8_t data, uint8_t len) +{ +	uint8_t status = ao_radio_fifo_write_start(); +	ao_radio_spi_send_fixed(data, len); +	return ao_radio_fifo_write_stop(status); +} + +static uint8_t +ao_radio_tx_fifo_space(void) +{ +	return CC1200_FIFO_SIZE - ao_radio_reg_read(CC1200_NUM_TXBYTES); +} + +static uint8_t +ao_radio_status(void) +{ +	return ao_radio_strobe (CC1200_SNOP); +} + +void +ao_radio_recv_abort(void) +{ +	ao_radio_abort = 1; +	ao_wakeup(&ao_radio_wake); +} + +#define ao_radio_rdf_value 0x55 + +static void +ao_radio_isr(void) +{ +	ao_exti_disable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); +	ao_radio_wake = 1; +	ao_wakeup(&ao_radio_wake); +} + +static void +ao_radio_start_tx(void) +{ +	ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); +	ao_radio_strobe(CC1200_STX); +} + +static void +ao_radio_start_rx(void) +{ +	ao_exti_enable(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN); +	ao_radio_strobe(CC1200_SRX); +} + +static void +ao_radio_idle(void) +{ +	for (;;) { +		uint8_t	state = (ao_radio_strobe(CC1200_SIDLE) >> CC1200_STATUS_STATE) & CC1200_STATUS_STATE_MASK; +		if (state == CC1200_STATUS_STATE_IDLE) +			break; +		if (state == CC1200_STATUS_STATE_TX_FIFO_ERROR) +			ao_radio_strobe(CC1200_SFTX); +		if (state == CC1200_STATUS_STATE_RX_FIFO_ERROR) +			ao_radio_strobe(CC1200_SFRX); +	} +	/* Flush any pending data in the fifos */ +	ao_radio_strobe(CC1200_SFTX); +	ao_radio_strobe(CC1200_SFRX); +	/* Make sure the RF calibration is current */ +	ao_radio_strobe(CC1200_SCAL); +} + +/* + * Packet deviation + * + *	fdev = fosc >> 22 * (256 + dev_m) << dev_e + * + * Deviation for 38400 baud should be 20.5kHz: + * + *     	40e6 / (2 ** 22) * (256 + 13) * (2 ** 3) = 20523Hz + * + * Deviation for 9600 baud should be 5.125kHz: + * + *     	40e6 / (2 ** 22) * (256 + 13) * (2 ** 1) = 5131Hz + * + * Deviation for 2400 baud should be 1.28125kHz, but cc1111 and + * cc115l can't do that, so we'll use 1.5kHz instead: + * + *     	40e6 / (2 ** 21) * (79) = 1506Hz + */ + +#define PACKET_DEV_M_384	13 +#define PACKET_DEV_E_384	3 + +#define PACKET_DEV_M_96		13 +#define PACKET_DEV_E_96		1 + +#define PACKET_DEV_M_24		79 +#define PACKET_DEV_E_24		0 + +/* + * For our packet data + * + *              (2**20 + DATARATE_M) * 2 ** DATARATE_E + *	Rdata = -------------------------------------- * fosc + *		             2 ** 39 + * + * Given the bit period of the baseband, T, the bandwidth of the + * baseband signal is B = 1/(2T).  The overall bandwidth of the + * modulated signal is then Channel bandwidth = 2Δf + 2B. + * + * 38400 -- 2 * 20500 + 38400 = 79.4 kHz + *  9600 -- 2 * 5.125 +  9600 = 19.9 kHz + *  2400 -- 2 * 1.5   +  2400 =  5.4 khz + * + * Symbol rate 38400 Baud: + * + *	DATARATE_M = 1013008 + *	DATARATE_E = 8 + *	CHANBW = 104.16667 + * + * Symbol rate 9600 Baud: + * + *	DATARATE_M = 1013008 + *	DATARATE_E = 6 + *	CHANBW = 26.042 (round to 19.8) + * + * Symbol rate 2400 Baud: + * + *	DATARATE_M = 1013008 + *	DATARATE_E = 4 + *	CHANBW = 5.0 (round to 9.5) + */ + +#define PACKET_SYMBOL_RATE_M		1013008 + +#define PACKET_SYMBOL_RATE_E_384	8 + +/* 200 / 2 = 100 */ +#define PACKET_CHAN_BW_384	((CC1200_CHAN_BW_ADC_CIC_DECFACT_12 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ +				 (16 << CC1200_CHAN_BW_BB_CIC_DECFACT)) + +#define PACKET_SYMBOL_RATE_E_96		6 +/* 200 / 10 = 20 */ +#define PACKET_CHAN_BW_96	((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ +				 (16 << CC1200_CHAN_BW_BB_CIC_DECFACT)) + +#define PACKET_SYMBOL_RATE_E_24		4 +/* 200 / 25 = 8 */ +#define PACKET_CHAN_BW_24	((CC1200_CHAN_BW_ADC_CIC_DECFACT_48 << CC1200_CHAN_BW_ADC_CIC_DECFACT) | \ +				 (44 << CC1200_CHAN_BW_BB_CIC_DECFACT)) + +static const uint16_t packet_setup[] = { +	CC1200_SYMBOL_RATE1,		((PACKET_SYMBOL_RATE_M >> 8) & 0xff), +	CC1200_SYMBOL_RATE0,		((PACKET_SYMBOL_RATE_M >> 0) & 0xff), +        CC1200_PKT_CFG2,                            	 /* Packet Configuration Reg. 2 */ +		((0 << CC1200_PKT_CFG2_FG_MODE_EN) | +		 (CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1200_PKT_CFG2_CCA_MODE) | +		 (CC1200_PKT_CFG2_PKT_FORMAT_NORMAL << CC1200_PKT_CFG2_PKT_FORMAT)), +        CC1200_PKT_CFG1,                                 /* Packet Configuration Reg. 1 */ +		((1 << CC1200_PKT_CFG1_FEC_EN) | +		 (1 << CC1200_PKT_CFG1_WHITE_DATA) | +		 (0 << CC1200_PKT_CFG1_PN9_SWAP_EN) | +		 (CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1200_PKT_CFG1_ADDR_CHECK_CFG) | +		 (CC1200_PKT_CFG1_CRC_CFG_CRC16_INIT_ONES << CC1200_PKT_CFG1_CRC_CFG) | +		 (1 << CC1200_PKT_CFG1_APPEND_STATUS)), +        CC1200_PREAMBLE_CFG1,	((CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1200_PREAMBLE_CFG1_NUM_PREAMBLE) | +				 (CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1200_PREAMBLE_CFG1_PREAMBLE_WORD)), +}; + +static const uint16_t packet_setup_384[] = { +	CC1200_DEVIATION_M,	PACKET_DEV_M_384, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (PACKET_DEV_E_384 << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,	((PACKET_SYMBOL_RATE_E_384 << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((PACKET_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_CHAN_BW,		PACKET_CHAN_BW_384, +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (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)), +}; + +static const uint16_t packet_setup_96[] = { +	CC1200_DEVIATION_M,	PACKET_DEV_M_96, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (PACKET_DEV_E_96 << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,	((PACKET_SYMBOL_RATE_E_96 << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((PACKET_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_CHAN_BW,		PACKET_CHAN_BW_96, +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) | +		 (CC1200_MDMCFG2_UPSAMPLER_P_32 << CC1200_MDMCFG2_UPSAMPLER_P) | +		 (0 << CC1200_MDMCFG2_CFM_DATA_EN)), +}; + +static const uint16_t packet_setup_24[] = { +	CC1200_DEVIATION_M,	PACKET_DEV_M_24, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (PACKET_DEV_E_24 << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,	((PACKET_SYMBOL_RATE_E_24 << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((PACKET_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_CHAN_BW,		PACKET_CHAN_BW_24, +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) | +		 (CC1200_MDMCFG2_UPSAMPLER_P_64 << CC1200_MDMCFG2_UPSAMPLER_P) | +		 (0 << CC1200_MDMCFG2_CFM_DATA_EN)), +}; + +/* + * RDF deviation is 3kHz + * + *	fdev = fosc >> 22 * (256 + dev_m) << dev_e	dev_e != 0 + *	fdev = fosc >> 21 * dev_m			dev_e == 0 + * + *     	40e6 / (2 ** 21) * 157 = 2995Hz + */ + +#define RDF_DEV_E	0 +#define RDF_DEV_M	157 + +/* + * For our RDF beacon, set the symbol rate to 2kBaud (for a 1kHz tone) + * + *              (2**20 + DATARATE_M) * 2 ** DATARATE_E + *	Rdata = -------------------------------------- * fosc + *		             2 ** 39 + * + *	DATARATE_M = 669411 + *	DATARATE_E = 4 + * + * To make the tone last for 200ms, we need 2000 * .2 = 400 bits or 50 bytes + */ +#define RDF_SYMBOL_RATE_E	4 +#define RDF_SYMBOL_RATE_M	669411 +#define RDF_PACKET_LEN	50 + +static const uint16_t rdf_setup[] = { +	CC1200_DEVIATION_M,	RDF_DEV_M, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (RDF_DEV_E << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,	((RDF_SYMBOL_RATE_E << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((RDF_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_SYMBOL_RATE1,	((RDF_SYMBOL_RATE_M >> 8) & 0xff), +	CC1200_SYMBOL_RATE0,	((RDF_SYMBOL_RATE_M >> 0) & 0xff), +        CC1200_PKT_CFG2,                            	 /* Packet Configuration Reg. 2 */ +		((0 << CC1200_PKT_CFG2_FG_MODE_EN) | +		 (CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1200_PKT_CFG2_CCA_MODE) | +		 (CC1200_PKT_CFG2_PKT_FORMAT_NORMAL << CC1200_PKT_CFG2_PKT_FORMAT)), +        CC1200_PKT_CFG1,                                 /* Packet Configuration Reg. 1 */ +		((0 << CC1200_PKT_CFG1_FEC_EN) | +		 (0 << CC1200_PKT_CFG1_WHITE_DATA) | +		 (0 << CC1200_PKT_CFG1_PN9_SWAP_EN) | +		 (CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1200_PKT_CFG1_ADDR_CHECK_CFG) | +		 (CC1200_PKT_CFG1_CRC_CFG_DISABLED << CC1200_PKT_CFG1_CRC_CFG) | +		 (0 << CC1200_PKT_CFG1_APPEND_STATUS)), +        CC1200_PREAMBLE_CFG1, +		((CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1200_PREAMBLE_CFG1_NUM_PREAMBLE) | +		 (CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1200_PREAMBLE_CFG1_PREAMBLE_WORD)), +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((0 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (0 << CC1200_MDMCFG2_SYMBOL_MAP_CFG) | +		 (12 << CC1200_MDMCFG2_UPSAMPLER_P) | +		 (0 << CC1200_MDMCFG2_CFM_DATA_EN)), +}; + +/* + * APRS deviation is 3kHz + * + *	fdev = fosc >> 22 * (256 + dev_m) << dev_e	dev_e != 0 + *	fdev = fosc >> 21 * dev_m			dev_e == 0 + * + *     	40e6 / (2 ** 21) * 157 = 2995Hz + */ + +#define APRS_DEV_E	0 +#define APRS_DEV_M	157 + +/* + * For our APRS beacon, set the symbol rate to 9.6kBaud (8x oversampling for 1200 baud data rate) + * + *              (2**20 + DATARATE_M) * 2 ** DATARATE_E + *	Rdata = -------------------------------------- * fosc + *		             2 ** 39 + * + *	DATARATE_M = 1013008 + *	DATARATE_E = 6 + * + *	Rdata = 9599.998593330383301 + * + */ +#define APRS_SYMBOL_RATE_E	6 +#define APRS_SYMBOL_RATE_M	1013008 + +static const uint16_t aprs_setup[] = { +	CC1200_DEVIATION_M,	APRS_DEV_M, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (APRS_DEV_E << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,	((APRS_SYMBOL_RATE_E << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((APRS_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_SYMBOL_RATE1,	((APRS_SYMBOL_RATE_M >> 8) & 0xff), +	CC1200_SYMBOL_RATE0,	((APRS_SYMBOL_RATE_M >> 0) & 0xff), +        CC1200_PKT_CFG2,                            	 /* Packet Configuration Reg. 2 */ +		((0 << CC1200_PKT_CFG2_FG_MODE_EN) | +		 (CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1200_PKT_CFG2_CCA_MODE) | +		 (CC1200_PKT_CFG2_PKT_FORMAT_NORMAL << CC1200_PKT_CFG2_PKT_FORMAT)), +        CC1200_PKT_CFG1,                                 /* Packet Configuration Reg. 1 */ +		((0 << CC1200_PKT_CFG1_FEC_EN) | +		 (0 << CC1200_PKT_CFG1_WHITE_DATA) | +		 (0 << CC1200_PKT_CFG1_PN9_SWAP_EN) | +		 (CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1200_PKT_CFG1_ADDR_CHECK_CFG) | +		 (CC1200_PKT_CFG1_CRC_CFG_DISABLED << CC1200_PKT_CFG1_CRC_CFG) | +		 (0 << CC1200_PKT_CFG1_APPEND_STATUS)), +        CC1200_PKT_CFG0,                                 /* Packet Configuration Reg. 0 */ +		((CC1200_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1200_PKT_CFG0_LENGTH_CONFIG) | +		 (0 << CC1200_PKT_CFG0_PKG_BIT_LEN) | +		 (0 << CC1200_PKT_CFG0_UART_MODE_EN) | +		 (0 << CC1200_PKT_CFG0_UART_SWAP_EN)), +        CC1200_PREAMBLE_CFG1, +		((CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_NONE << CC1200_PREAMBLE_CFG1_NUM_PREAMBLE) | +		 (CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1200_PREAMBLE_CFG1_PREAMBLE_WORD)), +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (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)), +}; + +/* + * For Test mode, we want an unmodulated carrier. To do that, we + * set the deviation to zero and enable a preamble so that the radio + * turns on before we send any data + */ + +static const uint16_t test_setup[] = { +	CC1200_DEVIATION_M,	0, +	CC1200_MODCFG_DEV_E,	((CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL << CC1200_MODCFG_DEV_E_MODEM_MODE) | +				 (CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK << CC1200_MODCFG_DEV_E_MOD_FORMAT) | +				 (0 << CC1200_MODCFG_DEV_E_DEV_E)), +	CC1200_SYMBOL_RATE2,		((APRS_SYMBOL_RATE_E << CC1200_SYMBOL_RATE2_DATARATE_E) | +				 (((APRS_SYMBOL_RATE_M >> 16) & CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK) << CC1200_SYMBOL_RATE2_DATARATE_M_19_16)), +	CC1200_SYMBOL_RATE1,		((APRS_SYMBOL_RATE_M >> 8) & 0xff), +	CC1200_SYMBOL_RATE0,		((APRS_SYMBOL_RATE_M >> 0) & 0xff), +	CC1200_PKT_CFG2,	((CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1200_PKT_CFG2_CCA_MODE) | +				 (CC1200_PKT_CFG2_PKT_FORMAT_NORMAL << CC1200_PKT_CFG2_PKT_FORMAT)), +	CC1200_PKT_CFG1,	((0 << CC1200_PKT_CFG1_WHITE_DATA) | +				 (CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1200_PKT_CFG1_ADDR_CHECK_CFG) | +				 (CC1200_PKT_CFG1_CRC_CFG_DISABLED << CC1200_PKT_CFG1_CRC_CFG) | +				 (0 << CC1200_PKT_CFG1_APPEND_STATUS)), +        CC1200_PREAMBLE_CFG1,	((CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES << CC1200_PREAMBLE_CFG1_NUM_PREAMBLE) | +				 (CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_AA << CC1200_PREAMBLE_CFG1_PREAMBLE_WORD)), +}; + +#define AO_PKT_CFG0_INFINITE ((CC1200_PKT_CFG0_LENGTH_CONFIG_INFINITE << CC1200_PKT_CFG0_LENGTH_CONFIG) | \ +			      (0 << CC1200_PKT_CFG0_PKG_BIT_LEN) |	\ +			      (0 << CC1200_PKT_CFG0_UART_MODE_EN) |	\ +			      (0 << CC1200_PKT_CFG0_UART_SWAP_EN)) + +#define AO_PKT_CFG0_FIXED ((CC1200_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1200_PKT_CFG0_LENGTH_CONFIG) | \ +			   (0 << CC1200_PKT_CFG0_PKG_BIT_LEN) |		\ +			   (0 << CC1200_PKT_CFG0_UART_MODE_EN) |	\ +			   (0 << CC1200_PKT_CFG0_UART_SWAP_EN)) + +static uint16_t ao_radio_mode; + +#define AO_RADIO_MODE_BITS_PACKET	1 +#define AO_RADIO_MODE_BITS_TX_BUF	4 +#define AO_RADIO_MODE_BITS_TX_FINISH	8 +#define AO_RADIO_MODE_BITS_RX		16 +#define AO_RADIO_MODE_BITS_RDF		32 +#define AO_RADIO_MODE_BITS_APRS		64 +#define AO_RADIO_MODE_BITS_TEST		128 +#define AO_RADIO_MODE_BITS_INFINITE	256 +#define AO_RADIO_MODE_BITS_FIXED	512 + +#define AO_RADIO_MODE_NONE		0 +#define AO_RADIO_MODE_PACKET_TX		(AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_FIXED    | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_PACKET_RX		(AO_RADIO_MODE_BITS_PACKET | AO_RADIO_MODE_BITS_FIXED    | AO_RADIO_MODE_BITS_RX) +#define AO_RADIO_MODE_RDF		(AO_RADIO_MODE_BITS_RDF    | AO_RADIO_MODE_BITS_FIXED    | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_APRS_BUF		(AO_RADIO_MODE_BITS_APRS   | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_LAST_BUF	(AO_RADIO_MODE_BITS_APRS   | AO_RADIO_MODE_BITS_FIXED    | AO_RADIO_MODE_BITS_TX_BUF) +#define AO_RADIO_MODE_APRS_FINISH	(AO_RADIO_MODE_BITS_APRS   | AO_RADIO_MODE_BITS_FIXED    | AO_RADIO_MODE_BITS_TX_FINISH) +#define AO_RADIO_MODE_TEST		(AO_RADIO_MODE_BITS_TEST   | AO_RADIO_MODE_BITS_INFINITE | AO_RADIO_MODE_BITS_TX_BUF) + +static void +_ao_radio_set_regs(const uint16_t *regs, int nreg) +{ +	int i; + +	for (i = 0; i < nreg; i++) { +		ao_radio_reg_write(regs[0], regs[1]); +		regs += 2; +	} +} + +#define ao_radio_set_regs(setup) _ao_radio_set_regs(setup, (sizeof (setup) / sizeof(setup[0])) >> 1) + +static void +ao_radio_set_mode(uint16_t new_mode) +{ +	uint16_t changes; + +	if (new_mode == ao_radio_mode) +		return; + +	changes = new_mode & (~ao_radio_mode); + +	if (changes & AO_RADIO_MODE_BITS_PACKET) { +		ao_radio_set_regs(packet_setup); + +		switch (ao_config.radio_rate) { +		default: +		case AO_RADIO_RATE_38400: +			ao_radio_set_regs(packet_setup_384); +			break; +		case AO_RADIO_RATE_9600: +			ao_radio_set_regs(packet_setup_96); +			break; +		case AO_RADIO_RATE_2400: +			ao_radio_set_regs(packet_setup_24); +			break; +		} +	} + +	if (changes & AO_RADIO_MODE_BITS_TX_BUF) { +		ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_TXFIFO_THR); +		ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); +	} + +	if (changes & AO_RADIO_MODE_BITS_TX_FINISH) { +		ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_PKT_SYNC_RXTX); +		ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH); +	} + +	if (changes & AO_RADIO_MODE_BITS_RX) { +		ao_radio_reg_write(AO_CC1200_INT_GPIO_IOCFG, CC1200_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP); +		ao_exti_set_mode(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, AO_EXTI_MODE_RISING|AO_EXTI_PRIORITY_HIGH); +	} + +	if (changes & AO_RADIO_MODE_BITS_RDF) +		ao_radio_set_regs(rdf_setup); + +	if (changes & AO_RADIO_MODE_BITS_APRS) +		ao_radio_set_regs(aprs_setup); + +	if (changes & AO_RADIO_MODE_BITS_TEST) +		ao_radio_set_regs(test_setup); + +	if (changes & AO_RADIO_MODE_BITS_INFINITE) +		ao_radio_reg_write(CC1200_PKT_CFG0, AO_PKT_CFG0_INFINITE); + +	if (changes & AO_RADIO_MODE_BITS_FIXED) +		ao_radio_reg_write(CC1200_PKT_CFG0, AO_PKT_CFG0_FIXED); + +	ao_radio_mode = new_mode; +} + +static const uint16_t radio_setup[] = { +#include "ao_cc1200_CC1200.h" +}; + +static uint8_t	ao_radio_configured = 0; + +static void +ao_radio_setup(void) +{ +	ao_radio_strobe(CC1200_SRES); + +	ao_radio_set_regs(radio_setup); + +	ao_radio_mode = 0; + +	ao_radio_idle(); + +	ao_config_get(); + +	ao_radio_configured = 1; +} + +static void +ao_radio_set_len(uint8_t len) +{ +	static uint8_t	last_len; + +	if (len != last_len) { +		ao_radio_reg_write(CC1200_PKT_LEN, len); +		last_len = len; +	} +} + +static void +ao_radio_get(uint8_t len) +{ +	static uint32_t	last_radio_setting; +	static uint8_t	last_radio_rate; + +	ao_mutex_get(&ao_radio_mutex); + +	if (!ao_radio_configured) +		ao_radio_setup(); +	if (ao_config.radio_setting != last_radio_setting) { +		ao_radio_reg_write(CC1200_FREQ2, ao_config.radio_setting >> 16); +		ao_radio_reg_write(CC1200_FREQ1, ao_config.radio_setting >> 8); +		ao_radio_reg_write(CC1200_FREQ0, ao_config.radio_setting); +		last_radio_setting = ao_config.radio_setting; +		ao_radio_strobe(CC1200_SCAL); +	} +	if (ao_config.radio_rate != last_radio_rate) { +		ao_radio_mode &= ~AO_RADIO_MODE_BITS_PACKET; +		last_radio_rate = ao_config.radio_rate; +	} +	ao_radio_set_len(len); +} + +#define ao_radio_put()	ao_mutex_put(&ao_radio_mutex) + +static inline uint8_t +ao_radio_state(void) +{ +	return (ao_radio_status() >> CC1200_STATUS_STATE) & CC1200_STATUS_STATE_MASK; +} + +#if CC1200_DEBUG +void +ao_radio_show_state(char *where) +{ +	printf("%s: state %d len %d rxbytes %d\n", +	       where, ao_radio_state(), +	       ao_radio_reg_read(CC1200_PKT_LEN), +	       ao_radio_reg_read(CC1200_NUM_RXBYTES)); +} +#else +#define ao_radio_show_state(where) +#endif + +/* Wait for the radio to signal an interrupt + */ +static void +ao_radio_wait_isr(uint16_t timeout) +{ +	if (timeout) +		ao_alarm(timeout); + +	ao_arch_block_interrupts(); +	while (!ao_radio_wake && !ao_radio_abort) +		if (ao_sleep(&ao_radio_wake)) +			ao_radio_abort = 1; +	ao_arch_release_interrupts(); + +	if (timeout) +		ao_clear_alarm(); +} + +static void +ao_rdf_start(uint8_t len) +{ +	ao_radio_abort = 0; +	ao_radio_get(len); + +	ao_radio_set_mode(AO_RADIO_MODE_RDF); +	ao_radio_wake = 0; +} + +static void +ao_radio_run(void) +{ +	ao_radio_wake = 0; +	ao_radio_abort = 0; +	ao_radio_start_tx(); +	ao_radio_wait_isr(0); +	if (!ao_radio_wake) +		ao_radio_idle(); +	ao_radio_put(); +} + +void +ao_radio_rdf(void) +{ +	ao_rdf_start(AO_RADIO_RDF_LEN); + +	ao_radio_fifo_write_fixed(ao_radio_rdf_value, AO_RADIO_RDF_LEN); + +	ao_radio_run(); +} + +void +ao_radio_continuity(uint8_t c) +{ +	uint8_t	i; +	uint8_t status; + +	ao_rdf_start(AO_RADIO_CONT_TOTAL_LEN); + +	status = ao_radio_fifo_write_start(); +	for (i = 0; i < 3; i++) { +		ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); +		if (i < c) +			ao_radio_spi_send_fixed(ao_radio_rdf_value, AO_RADIO_CONT_TONE_LEN); +		else +			ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_TONE_LEN); +	} +	ao_radio_spi_send_fixed(0x00, AO_RADIO_CONT_PAUSE_LEN); +	status = ao_radio_fifo_write_stop(status); +	(void) status; +	ao_radio_run(); +} + +void +ao_radio_rdf_abort(void) +{ +	ao_radio_abort = 1; +	ao_wakeup(&ao_radio_wake); +} + +static void +ao_radio_test_cmd(void) +{ +	uint8_t	mode = 2; +	static uint8_t radio_on; +	ao_cmd_white(); +	if (ao_cmd_lex_c != '\n') { +		ao_cmd_decimal(); +		mode = (uint8_t) ao_cmd_lex_u32; +	} +	mode++; +	if ((mode & 2) && !radio_on) { +#if HAS_MONITOR +		ao_monitor_disable(); +#endif +#if PACKET_HAS_SLAVE +		ao_packet_slave_stop(); +#endif +		ao_radio_get(0xff); +		ao_radio_set_mode(AO_RADIO_MODE_TEST); +		ao_radio_strobe(CC1200_STX); +#if CC1200_TRACE +		{ int t; +			for (t = 0; t < 10; t++) { +				printf ("status: %02x\n", ao_radio_status()); +				ao_delay(AO_MS_TO_TICKS(100)); +			} +		} +#endif +		radio_on = 1; +	} +	if (mode == 3) { +		printf ("Hit a character to stop..."); flush(); +		getchar(); +		putchar('\n'); +	} +	if ((mode & 1) && radio_on) { +		ao_radio_idle(); +		ao_radio_put(); +		radio_on = 0; +#if HAS_MONITOR +		ao_monitor_enable(); +#endif +	} +} + +void +ao_radio_send(const void *d, uint8_t size) +{ +	ao_radio_get(size); +	ao_radio_set_mode(AO_RADIO_MODE_PACKET_TX); + +	ao_radio_fifo_write(d, 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; +	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) { +		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); + +			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; +			} +		} +		if (ao_radio_abort) { +			ao_radio_idle(); +			break; +		} +	} +	/* 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 +	ao_radio_put(); +} + +#if 0 +static uint8_t +ao_radio_marc_state(void) +{ +	return ao_radio_reg_read(CC1200_MARCSTATE); +} + +static uint8_t +ao_radio_modem_status1(void) +{ +	return ao_radio_reg_read(CC1200_MODEM_STATUS1); +} + +static uint8_t +ao_radio_modem_status0(void) +{ +	return ao_radio_reg_read(CC1200_MODEM_STATUS0); +} + +struct ao_radio_state { +	char	where[4]; +	uint8_t	marc_state; +	uint8_t marc_status1; +	uint8_t marc_status0; +	uint8_t	modem_status1; +	uint8_t	modem_status0; +}; + +static void +ao_radio_fill_state(char *where, struct ao_radio_state *s) +{ +	strcpy(s->where, where); +	s->marc_state = ao_radio_marc_state(); +	s->marc_status1 = ao_radio_reg_read(CC1200_MARC_STATUS1); +	s->marc_status0 = ao_radio_reg_read(CC1200_MARC_STATUS0); +	s->modem_status1 = ao_radio_modem_status1(); +	s->modem_status0 = ao_radio_modem_status0(); +} + +static void +ao_radio_dump_state(struct ao_radio_state *s) +{ +	printf ("%s: marc %2x marc1 %2x marc0 %2x modem1 %2x modem0 %2x\n", +		s->where, s->marc_state, s->marc_status1, s->marc_status0, s->modem_status1, s->modem_status0); +} +#endif + +uint8_t +ao_radio_recv(__xdata void *d, uint8_t size, uint8_t timeout) +{ +	uint8_t	success = 0; + +	ao_radio_abort = 0; +	ao_radio_get(size - 2); +	ao_radio_set_mode(AO_RADIO_MODE_PACKET_RX); +	ao_radio_wake = 0; +	ao_radio_start_rx(); + +	while (!ao_radio_abort) { +		ao_radio_wait_isr(timeout); +		if (ao_radio_wake) { +			uint8_t		marc_status1 = ao_radio_reg_read(CC1200_MARC_STATUS1); + +			/* Check the receiver status to see what happened +			 */ +			switch (marc_status1) { +			case CC1200_MARC_STATUS1_RX_FINISHED: +			case CC1200_MARC_STATUS1_ADDRESS: +			case CC1200_MARC_STATUS1_CRC: +				/* Normal return, go fetch the bytes from the FIFO +				 * and give them back to the caller +				 */ +				success = 1; +				break; +			case CC1200_MARC_STATUS1_RX_TIMEOUT: +			case CC1200_MARC_STATUS1_RX_TERMINATION: +			case CC1200_MARC_STATUS1_EWOR_SYNC_LOST: +			case CC1200_MARC_STATUS1_MAXIMUM_LENGTH: +			case CC1200_MARC_STATUS1_RX_FIFO_OVERFLOW: +			case CC1200_MARC_STATUS1_RX_FIFO_UNDERFLOW: +				/* Something weird happened; reset the radio and +				 * return failure +				 */ +				success = 0; +				break; +			default: +				/* some other status; go wait for the radio to do something useful +				 */ +				continue; +			} +			break; +		} else { +			uint8_t modem_status1 = ao_radio_reg_read(CC1200_MODEM_STATUS1); + +			/* Check to see if the packet header has been seen, in which case we'll +			 * want to keep waiting for the rest of the packet to appear +			 */ +			if (modem_status1 & (1 << CC1200_MODEM_STATUS1_SYNC_FOUND)) +			{ +				ao_radio_abort = 0; + +				/* Set a timeout based on the packet length so that we make sure to +				 * wait long enough to receive the whole thing. +				 * +				 * timeout = bits * FEC expansion / rate +				 */ +				switch (ao_config.radio_rate) { +				default: +				case AO_RADIO_RATE_38400: +					timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 384) + 1; +					break; +				case AO_RADIO_RATE_9600: +					timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 96) + 1; +					break; +				case AO_RADIO_RATE_2400: +					timeout = AO_MS_TO_TICKS(size * (8 * 2 * 10) / 24) + 1; +					break; +				} +			} +		} +	} + +	if (success) { +		int8_t	rssi; +		uint8_t	status; + +		status = ao_radio_fifo_read(d, size); +		(void) status; +		rssi = ((int8_t *) d)[size - 2]; +		ao_radio_rssi = rssi; + +		/* Bound it to the representable range */ +		if (rssi > -11) +			rssi = -11; + +		/* Write it back to the packet */ +		((int8_t *) d)[size-2] = AO_RADIO_FROM_RSSI(rssi); +	} else { +		ao_radio_idle(); +		ao_radio_rssi = 0; +	} + +	ao_radio_put(); +	return success; +} + + +#if CC1200_DEBUG +static char *cc1200_state_name[] = { +	[CC1200_STATUS_STATE_IDLE] = "IDLE", +	[CC1200_STATUS_STATE_RX] = "RX", +	[CC1200_STATUS_STATE_TX] = "TX", +	[CC1200_STATUS_STATE_FSTXON] = "FSTXON", +	[CC1200_STATUS_STATE_CALIBRATE] = "CALIBRATE", +	[CC1200_STATUS_STATE_SETTLING] = "SETTLING", +	[CC1200_STATUS_STATE_RX_FIFO_ERROR] = "RX_FIFO_ERROR", +	[CC1200_STATUS_STATE_TX_FIFO_ERROR] = "TX_FIFO_ERROR", +}; + +struct ao_cc1200_reg { +	uint16_t	addr; +	char		*name; +}; + +static const struct ao_cc1200_reg ao_cc1200_reg[] = { +	{ .addr = CC1200_IOCFG3,	.name = "IOCFG3" }, +	{ .addr = CC1200_IOCFG2,	.name = "IOCFG2" }, +	{ .addr = CC1200_IOCFG1,	.name = "IOCFG1" }, +	{ .addr = CC1200_IOCFG0,	.name = "IOCFG0" }, +	{ .addr = CC1200_SYNC3,	.name = "SYNC3" }, +	{ .addr = CC1200_SYNC2,	.name = "SYNC2" }, +	{ .addr = CC1200_SYNC1,	.name = "SYNC1" }, +	{ .addr = CC1200_SYNC0,	.name = "SYNC0" }, +	{ .addr = CC1200_SYNC_CFG1,	.name = "SYNC_CFG1" }, +	{ .addr = CC1200_SYNC_CFG0,	.name = "SYNC_CFG0" }, +	{ .addr = CC1200_DEVIATION_M,	.name = "DEVIATION_M" }, +	{ .addr = CC1200_MODCFG_DEV_E,	.name = "MODCFG_DEV_E" }, +	{ .addr = CC1200_DCFILT_CFG,	.name = "DCFILT_CFG" }, +	{ .addr = CC1200_PREAMBLE_CFG1,	.name = "PREAMBLE_CFG1" }, +	{ .addr = CC1200_PREAMBLE_CFG0,	.name = "PREAMBLE_CFG0" }, +	{ .addr = CC1200_IQIC,	.name = "IQIC" }, +	{ .addr = CC1200_CHAN_BW,	.name = "CHAN_BW" }, +	{ .addr = CC1200_MDMCFG2,	.name = "MDMCFG2" }, +	{ .addr = CC1200_MDMCFG1,	.name = "MDMCFG1" }, +	{ .addr = CC1200_MDMCFG0,	.name = "MDMCFG0" }, +	{ .addr = CC1200_SYMBOL_RATE2,	.name = "SYMBOL_RATE2" }, +	{ .addr = CC1200_SYMBOL_RATE1,	.name = "SYMBOL_RATE1" }, +	{ .addr = CC1200_SYMBOL_RATE0,	.name = "SYMBOL_RATE0" }, +	{ .addr = CC1200_AGC_REF,	.name = "AGC_REF" }, +	{ .addr = CC1200_AGC_CS_THR,	.name = "AGC_CS_THR" }, +	{ .addr = CC1200_AGC_GAIN_ADJUST,	.name = "AGC_GAIN_ADJUST" }, +	{ .addr = CC1200_AGC_CFG3,	.name = "AGC_CFG3" }, +	{ .addr = CC1200_AGC_CFG2,	.name = "AGC_CFG2" }, +	{ .addr = CC1200_AGC_CFG1,	.name = "AGC_CFG1" }, +	{ .addr = CC1200_AGC_CFG0,	.name = "AGC_CFG0" }, +	{ .addr = CC1200_FIFO_CFG,	.name = "FIFO_CFG" }, +	{ .addr = CC1200_DEV_ADDR,	.name = "DEV_ADDR" }, +	{ .addr = CC1200_SETTLING_CFG,	.name = "SETTLING_CFG" }, +	{ .addr = CC1200_FS_CFG,	.name = "FS_CFG" }, +	{ .addr = CC1200_WOR_CFG1,	.name = "WOR_CFG1" }, +	{ .addr = CC1200_WOR_CFG0,	.name = "WOR_CFG0" }, +	{ .addr = CC1200_WOR_EVENT0_MSB,	.name = "WOR_EVENT0_MSB" }, +	{ .addr = CC1200_WOR_EVENT0_LSB,	.name = "WOR_EVENT0_LSB" }, +	{ .addr = CC1200_RXDCM_TIME,		.name = "RXDCM_TIME" }, +	{ .addr = CC1200_PKT_CFG2,	.name = "PKT_CFG2" }, +	{ .addr = CC1200_PKT_CFG1,	.name = "PKT_CFG1" }, +	{ .addr = CC1200_PKT_CFG0,	.name = "PKT_CFG0" }, +	{ .addr = CC1200_RFEND_CFG1,	.name = "RFEND_CFG1" }, +	{ .addr = CC1200_RFEND_CFG0,	.name = "RFEND_CFG0" }, +	{ .addr = CC1200_PA_CFG1,	.name = "PA_CFG1" }, +	{ .addr = CC1200_PA_CFG0,	.name = "PA_CFG0" }, +	{ .addr = CC1200_PKT_LEN,	.name = "PKT_LEN" }, +	{ .addr = CC1200_IF_MIX_CFG,	.name = "IF_MIX_CFG" }, +	{ .addr = CC1200_FREQOFF_CFG,	.name = "FREQOFF_CFG" }, +	{ .addr = CC1200_TOC_CFG,	.name = "TOC_CFG" }, +	{ .addr = CC1200_MARC_SPARE,	.name = "MARC_SPARE" }, +	{ .addr = CC1200_ECG_CFG,	.name = "ECG_CFG" }, +	{ .addr = CC1200_EXT_CTRL,	.name = "EXT_CTRL" }, +	{ .addr = CC1200_RCCAL_FINE,	.name = "RCCAL_FINE" }, +	{ .addr = CC1200_RCCAL_COARSE,	.name = "RCCAL_COARSE" }, +	{ .addr = CC1200_RCCAL_OFFSET,	.name = "RCCAL_OFFSET" }, +	{ .addr = CC1200_FREQOFF1,	.name = "FREQOFF1" }, +	{ .addr = CC1200_FREQOFF0,	.name = "FREQOFF0" }, +	{ .addr = CC1200_FREQ2,	.name = "FREQ2" }, +	{ .addr = CC1200_FREQ1,	.name = "FREQ1" }, +	{ .addr = CC1200_FREQ0,	.name = "FREQ0" }, +	{ .addr = CC1200_IF_ADC2,	.name = "IF_ADC2" }, +	{ .addr = CC1200_IF_ADC1,	.name = "IF_ADC1" }, +	{ .addr = CC1200_IF_ADC0,	.name = "IF_ADC0" }, +	{ .addr = CC1200_FS_DIG1,	.name = "FS_DIG1" }, +	{ .addr = CC1200_FS_DIG0,	.name = "FS_DIG0" }, +	{ .addr = CC1200_FS_CAL3,	.name = "FS_CAL3" }, +	{ .addr = CC1200_FS_CAL2,	.name = "FS_CAL2" }, +	{ .addr = CC1200_FS_CAL1,	.name = "FS_CAL1" }, +	{ .addr = CC1200_FS_CAL0,	.name = "FS_CAL0" }, +	{ .addr = CC1200_FS_CHP,	.name = "FS_CHP" }, +	{ .addr = CC1200_FS_DIVTWO,	.name = "FS_DIVTWO" }, +	{ .addr = CC1200_FS_DSM1,	.name = "FS_DSM1" }, +	{ .addr = CC1200_FS_DSM0,	.name = "FS_DSM0" }, +	{ .addr = CC1200_FS_DVC1,	.name = "FS_DVC1" }, +	{ .addr = CC1200_FS_DVC0,	.name = "FS_DVC0" }, +	{ .addr = CC1200_FS_LBI,	.name = "FS_LBI" }, +	{ .addr = CC1200_FS_PFD,	.name = "FS_PFD" }, +	{ .addr = CC1200_FS_PRE,	.name = "FS_PRE" }, +	{ .addr = CC1200_FS_REG_DIV_CML,	.name = "FS_REG_DIV_CML" }, +	{ .addr = CC1200_FS_SPARE,	.name = "FS_SPARE" }, +	{ .addr = CC1200_FS_VCO4,	.name = "FS_VCO4" }, +	{ .addr = CC1200_FS_VCO3,	.name = "FS_VCO3" }, +	{ .addr = CC1200_FS_VCO2,	.name = "FS_VCO2" }, +	{ .addr = CC1200_FS_VCO1,	.name = "FS_VCO1" }, +	{ .addr = CC1200_FS_VCO0,	.name = "FS_VCO0" }, +	{ .addr = CC1200_GBIAS6,	.name = "GBIAS6" }, +	{ .addr = CC1200_GBIAS5,	.name = "GBIAS5" }, +	{ .addr = CC1200_GBIAS4,	.name = "GBIAS4" }, +	{ .addr = CC1200_GBIAS3,	.name = "GBIAS3" }, +	{ .addr = CC1200_GBIAS2,	.name = "GBIAS2" }, +	{ .addr = CC1200_GBIAS1,	.name = "GBIAS1" }, +	{ .addr = CC1200_GBIAS0,	.name = "GBIAS0" }, +	{ .addr = CC1200_IFAMP,	.name = "IFAMP" }, +	{ .addr = CC1200_LNA,	.name = "LNA" }, +	{ .addr = CC1200_RXMIX,	.name = "RXMIX" }, +	{ .addr = CC1200_XOSC5,	.name = "XOSC5" }, +	{ .addr = CC1200_XOSC4,	.name = "XOSC4" }, +	{ .addr = CC1200_XOSC3,	.name = "XOSC3" }, +	{ .addr = CC1200_XOSC2,	.name = "XOSC2" }, +	{ .addr = CC1200_XOSC1,	.name = "XOSC1" }, +	{ .addr = CC1200_XOSC0,	.name = "XOSC0" }, +	{ .addr = CC1200_ANALOG_SPARE,	.name = "ANALOG_SPARE" }, +	{ .addr = CC1200_PA_CFG3,	.name = "PA_CFG3" }, +	{ .addr = CC1200_WOR_TIME1,	.name = "WOR_TIME1" }, +	{ .addr = CC1200_WOR_TIME0,	.name = "WOR_TIME0" }, +	{ .addr = CC1200_WOR_CAPTURE1,	.name = "WOR_CAPTURE1" }, +	{ .addr = CC1200_WOR_CAPTURE0,	.name = "WOR_CAPTURE0" }, +	{ .addr = CC1200_BIST,	.name = "BIST" }, +	{ .addr = CC1200_DCFILTOFFSET_I1,	.name = "DCFILTOFFSET_I1" }, +	{ .addr = CC1200_DCFILTOFFSET_I0,	.name = "DCFILTOFFSET_I0" }, +	{ .addr = CC1200_DCFILTOFFSET_Q1,	.name = "DCFILTOFFSET_Q1" }, +	{ .addr = CC1200_DCFILTOFFSET_Q0,	.name = "DCFILTOFFSET_Q0" }, +	{ .addr = CC1200_IQIE_I1,	.name = "IQIE_I1" }, +	{ .addr = CC1200_IQIE_I0,	.name = "IQIE_I0" }, +	{ .addr = CC1200_IQIE_Q1,	.name = "IQIE_Q1" }, +	{ .addr = CC1200_IQIE_Q0,	.name = "IQIE_Q0" }, +	{ .addr = CC1200_RSSI1,	.name = "RSSI1" }, +	{ .addr = CC1200_RSSI0,	.name = "RSSI0" }, +	{ .addr = CC1200_MARCSTATE,	.name = "MARCSTATE" }, +	{ .addr = CC1200_LQI_VAL,	.name = "LQI_VAL" }, +	{ .addr = CC1200_PQT_SYNC_ERR,	.name = "PQT_SYNC_ERR" }, +	{ .addr = CC1200_DEM_STATUS,	.name = "DEM_STATUS" }, +	{ .addr = CC1200_FREQOFF_EST1,	.name = "FREQOFF_EST1" }, +	{ .addr = CC1200_FREQOFF_EST0,	.name = "FREQOFF_EST0" }, +	{ .addr = CC1200_AGC_GAIN3,	.name = "AGC_GAIN3" }, +	{ .addr = CC1200_AGC_GAIN2,	.name = "AGC_GAIN2" }, +	{ .addr = CC1200_AGC_GAIN1,	.name = "AGC_GAIN1" }, +	{ .addr = CC1200_AGC_GAIN0,	.name = "AGC_GAIN0" }, +	{ .addr = CC1200_SOFT_RX_DATA_OUT,	.name = "SOFT_RX_DATA_OUT" }, +	{ .addr = CC1200_SOFT_TX_DATA_IN,	.name = "SOFT_TX_DATA_IN" }, +	{ .addr = CC1200_ASK_SOFT_RX_DATA,	.name = "ASK_SOFT_RX_DATA" }, +	{ .addr = CC1200_RNDGEN,	.name = "RNDGEN" }, +	{ .addr = CC1200_MAGN2,	.name = "MAGN2" }, +	{ .addr = CC1200_MAGN1,	.name = "MAGN1" }, +	{ .addr = CC1200_MAGN0,	.name = "MAGN0" }, +	{ .addr = CC1200_ANG1,	.name = "ANG1" }, +	{ .addr = CC1200_ANG0,	.name = "ANG0" }, +	{ .addr = CC1200_CHFILT_I2,	.name = "CHFILT_I2" }, +	{ .addr = CC1200_CHFILT_I1,	.name = "CHFILT_I1" }, +	{ .addr = CC1200_CHFILT_I0,	.name = "CHFILT_I0" }, +	{ .addr = CC1200_CHFILT_Q2,	.name = "CHFILT_Q2" }, +	{ .addr = CC1200_CHFILT_Q1,	.name = "CHFILT_Q1" }, +	{ .addr = CC1200_CHFILT_Q0,	.name = "CHFILT_Q0" }, +	{ .addr = CC1200_GPIO_STATUS,	.name = "GPIO_STATUS" }, +	{ .addr = CC1200_FSCAL_CTRL,	.name = "FSCAL_CTRL" }, +	{ .addr = CC1200_PHASE_ADJUST,	.name = "PHASE_ADJUST" }, +	{ .addr = CC1200_PARTNUMBER,	.name = "PARTNUMBER" }, +	{ .addr = CC1200_PARTVERSION,	.name = "PARTVERSION" }, +	{ .addr = CC1200_SERIAL_STATUS,	.name = "SERIAL_STATUS" }, +	{ .addr = CC1200_MODEM_STATUS1,	.name = "MODEM_STATUS1" }, +	{ .addr = CC1200_MODEM_STATUS0,	.name = "MODEM_STATUS0" }, +	{ .addr = CC1200_MARC_STATUS1,	.name = "MARC_STATUS1" }, +	{ .addr = CC1200_MARC_STATUS0,	.name = "MARC_STATUS0" }, +	{ .addr = CC1200_PA_IFAMP_TEST,	.name = "PA_IFAMP_TEST" }, +	{ .addr = CC1200_FSRF_TEST,	.name = "FSRF_TEST" }, +	{ .addr = CC1200_PRE_TEST,	.name = "PRE_TEST" }, +	{ .addr = CC1200_PRE_OVR,	.name = "PRE_OVR" }, +	{ .addr = CC1200_ADC_TEST,	.name = "ADC_TEST" }, +	{ .addr = CC1200_DVC_TEST,	.name = "DVC_TEST" }, +	{ .addr = CC1200_ATEST,	.name = "ATEST" }, +	{ .addr = CC1200_ATEST_LVDS,	.name = "ATEST_LVDS" }, +	{ .addr = CC1200_ATEST_MODE,	.name = "ATEST_MODE" }, +	{ .addr = CC1200_XOSC_TEST1,	.name = "XOSC_TEST1" }, +	{ .addr = CC1200_XOSC_TEST0,	.name = "XOSC_TEST0" }, +	{ .addr = CC1200_RXFIRST,	.name = "RXFIRST" }, +	{ .addr = CC1200_TXFIRST,	.name = "TXFIRST" }, +	{ .addr = CC1200_RXLAST,	.name = "RXLAST" }, +	{ .addr = CC1200_TXLAST,	.name = "TXLAST" }, +	{ .addr = CC1200_NUM_TXBYTES,	.name = "NUM_TXBYTES" }, +	{ .addr = CC1200_NUM_RXBYTES,	.name = "NUM_RXBYTES" }, +	{ .addr = CC1200_FIFO_NUM_TXBYTES,	.name = "FIFO_NUM_TXBYTES" }, +	{ .addr = CC1200_FIFO_NUM_RXBYTES,	.name = "FIFO_NUM_RXBYTES" }, +}; + +#define AO_NUM_CC1200_REG	(sizeof ao_cc1200_reg / sizeof ao_cc1200_reg[0]) + +static uint8_t +ao_radio_get_marc_status(void) +{ +	return ao_radio_reg_read(CC1200_MARC_STATUS1); +} + +static void ao_radio_show(void) { +	uint8_t	status; +	unsigned int	i; + +	ao_mutex_get(&ao_radio_mutex); +	status = ao_radio_status(); +	printf ("Status:   %02x\n", status); +	printf ("CHIP_RDY: %d\n", (status >> CC1200_STATUS_CHIP_RDY) & 1); +	printf ("STATE:    %s\n", cc1200_state_name[(status >> CC1200_STATUS_STATE) & CC1200_STATUS_STATE_MASK]); +	printf ("MARC:     %02x\n", ao_radio_get_marc_status()); + +	for (i = 0; i < AO_NUM_CC1200_REG; i++) +		printf ("\t%02x %-20.20s\n", ao_radio_reg_read(ao_cc1200_reg[i].addr), ao_cc1200_reg[i].name); + +	ao_radio_put(); +} + +static void ao_radio_beep(void) { +	ao_radio_rdf(); +} + +static void ao_radio_packet(void) { +	static const uint8_t packet[] = { +#if 1 +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +#else +		3, 1, 2, 3 +#endif +	}; + +	ao_radio_send(packet, sizeof (packet)); +} + +void +ao_radio_test_recv(void) +{ +	uint8_t	bytes[34]; +	uint8_t	b; + +	if (ao_radio_recv(bytes, 34, 0)) { +		if (bytes[33] & 0x80) +			printf ("CRC OK"); +		else +			printf ("CRC BAD"); +		printf (" RSSI %d", AO_RSSI_FROM_RADIO(bytes[32])); +		for (b = 0; b < 32; b++) +			printf (" %02x", bytes[b]); + +		printf (" RSSI %02x LQI %02x", bytes[32], bytes[33]); +		printf ("\n"); +	} +} + +#if HAS_APRS +#include <ao_aprs.h> + +static void +ao_radio_aprs(void) +{ +#if PACKET_HAS_SLAVE +	ao_packet_slave_stop(); +#endif +	ao_aprs_send(); +} +#endif +#endif + +#if CC1200_LOW_LEVEL_DEBUG +static void +ao_radio_strobe_test(void) +{ +	uint8_t	r; + +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	r = ao_radio_strobe(ao_cmd_lex_i); +	printf ("Strobe %02x -> %02x (rdy %d state %d)\n", +		ao_cmd_lex_i, +		r, +		r >> 7, +		(r >> 4) & 0x7); +} + +static void +ao_radio_write_test(void) +{ +	uint16_t	addr; +	uint8_t		data; + +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	addr = ao_cmd_lex_i; +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	data = ao_cmd_lex_i; +	printf ("Write %04x = %02x\n", addr, data); +	ao_radio_reg_write(addr, data); +} + +static void +ao_radio_read_test(void) +{ +	uint16_t	addr; +	uint8_t		data; + +	ao_cmd_hex(); +	if (ao_cmd_status != ao_cmd_success) +		return; +	addr = ao_cmd_lex_i; +	data = ao_radio_reg_read(addr); +	printf ("Read %04x = %02x\n", addr, data); +} +#endif + +static const struct ao_cmds ao_radio_cmds[] = { +	{ ao_radio_test_cmd,	"C <1 start, 0 stop, none both>\0Radio carrier test" }, +#if CC1200_DEBUG +#if HAS_APRS +	{ ao_radio_aprs,	"G\0Send APRS packet" }, +#endif +	{ ao_radio_show,	"R\0Show CC1200 status" }, +	{ ao_radio_beep,	"b\0Emit an RDF beacon" }, +	{ ao_radio_packet,	"p\0Send a test packet" }, +	{ ao_radio_test_recv,	"q\0Recv a test packet" }, +#endif +#if CC1200_LOW_LEVEL_DEBUG +	{ ao_radio_strobe_test,	"A <value>\0Strobe radio" }, +	{ ao_radio_write_test,	"W <addr> <value>\0Write radio reg" }, +	{ ao_radio_read_test,	"B <addr>\0Read radio reg" }, +#endif +	{ 0, NULL } +}; + +void +ao_radio_init(void) +{ +	ao_radio_configured = 0; +	ao_spi_init_cs (AO_CC1200_SPI_CS_PORT, (1 << AO_CC1200_SPI_CS_PIN)); + +#if 0 +	AO_CC1200_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1200_SPI_CS_PIN)); +	for (i = 0; i < 10000; i++) { +		if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0) +			break; +	} +	AO_CC1200_SPI_CS_PORT->bsrr = (1 << AO_CC1200_SPI_CS_PIN); +	if (i == 10000) +		ao_panic(AO_PANIC_SELF_TEST_CC1200); +#endif + +	/* Enable the EXTI interrupt for the appropriate pin */ +	ao_enable_port(AO_CC1200_INT_PORT); +	ao_exti_setup(AO_CC1200_INT_PORT, AO_CC1200_INT_PIN, +		      AO_EXTI_MODE_FALLING|AO_EXTI_PRIORITY_HIGH, +		      ao_radio_isr); + +	ao_cmd_register(&ao_radio_cmds[0]); +} diff --git a/src/drivers/ao_cc1200.h b/src/drivers/ao_cc1200.h new file mode 100644 index 00000000..b04775fd --- /dev/null +++ b/src/drivers/ao_cc1200.h @@ -0,0 +1,632 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_CC1200_H_ +#define _AO_CC1200_H_ + +#define CC1200_READ	(7) +#define CC1200_BURST	(6) + +/* Register space */ +#define CC1200_IOCFG3		0x00 +#define  CC1200_IOCFG_GPIO_ATRAN	7 +#define  CC1200_IOCFG_GPIO_INV		6 +#define  CC1200_IOCFG_GPIO_CFG		0 +#define  CC1200_IOCFG_GPIO_CFG_RXFIFO_THR	0 +#define  CC1200_IOCFG_GPIO_CFG_RXFIFO_THR_PKT	1 +#define  CC1200_IOCFG_GPIO_CFG_TXFIFO_THR	2 +#define  CC1200_IOCFG_GPIO_CFG_TXFIFO_THR_PKT	3 +#define  CC1200_IOCFG_GPIO_CFG_RXFIFO_OVERFLOW	4 +#define  CC1200_IOCFG_GPIO_CFG_TXFIFO_UNDERFLOW	5 +#define  CC1200_IOCFG_GPIO_CFG_PKT_SYNC_RXTX	6 +#define  CC1200_IOCFG_GPIO_CFG_CRC_OK		7 +#define  CC1200_IOCFG_GPIO_CFG_SERIAL_CLK	8 +#define  CC1200_IOCFG_GPIO_CFG_SERIAL_RX	9 +#define  CC1200_IOCFG_GPIO_CFG_PQT_REACHED	11 +#define  CC1200_IOCFG_GPIO_CFG_PQT_VALID	12 +#define  CC1200_IOCFG_GPIO_CFG_RSSI_VALID	13 +#define  CC1200_IOCFG_GPIO3_CFG_RSSI_UPDATE	14 +#define  CC1200_IOCFG_GPIO2_CFG_RSSI_UPDATE	14 +#define  CC1200_IOCFG_GPIO1_CFG_AGC_HOLD	14 +#define  CC1200_IOCFG_GPIO0_CFG_AGC_UPDATE	14 +#define  CC1200_IOCFG_GPIO3_CFG_CGA_STATUS	15 +#define  CC1200_IOCFG_GPIO2_CFG_TXONCCA_DONE	15 +#define  CC1200_IOCFG_GPIO1_CFG_CCA_STATUS	15 +#define  CC1200_IOCFG_GPIO0_CFG_TXONCCA_FAILED	15 +#define  CC1200_IOCFG_GPIO_CFG_CARRIER_SENSE_VALID	16 +#define  CC1200_IOCFG_GPIO_CFG_CARRIER_SENSE	17 +#define  CC1200_IOCFG_GPIO3_CFG_DSSS_CLK	18 +#define  CC1200_IOCFG_GPIO2_CFG_DSSS_DATA0	18 +#define  CC1200_IOCFG_GPIO1_CFG_DSSS_CLK	18 +#define  CC1200_IOCFG_GPIO0_CFG_DSSS_DATA1	18 +#define  CC1200_IOCFG_GPIO_CFG_PKT_CRC_OK	19 +#define  CC1200_IOCFG_GPIO_CFG_MARC_MCU_WAKEUP	20 +#define  CC1200_IOCFG_GPIO_CFG_SYNC_LOW0_HIGH1	21 +#define  CC1200_IOCFG_GPIO_CFG_LNA_PA_REG_PD	23 +#define  CC1200_IOCFG_GPIO_CFG_LNA_PD		24 +#define  CC1200_IOCFG_GPIO_CFG_PA_RD		25 +#define  CC1200_IOCFG_GPIO_CFG_RX0TX1_CFG	26 +#define  CC1200_IOCFG_GPIO_CFG_IMAGE_FOUND	28 +#define  CC1200_IOCFG_GPIO_CFG_CLKEN_SOFT	29 +#define  CC1200_IOCFG_GPIO_CFG_SOFT_TX_DATA_CLK	30 +#define  CC1200_IOCFG_GPIO_CFG_RSSI_STEP_FOUND	33 +#define  CC1200_IOCFG_GPIO_CFG_RSSI_STEP_EVENT	34 +#define  CC1200_IOCFG_GPIO_CFG_ANTENNA_SELECT	36 +#define  CC1200_IOCFG_GPIO_CFG_MARC_2PIN_STATUS1	37 +#define  CC1200_IOCFG_GPIO_CFG_MARC_2PIN_STATUS0	38 +#define  CC1200_IOCFG_GPIO2_CFG_TXFIFO_OVERFLOW		39 +#define  CC1200_IOCFG_GPIO0_CFG_RXFIFO_UNDERFLOW	39 +#define  CC1200_IOCFG_GPIO3_CFG_MAGN_VALID	40 +#define  CC1200_IOCFG_GPIO2_CFG_CHFILT_VALID	40 +#define  CC1200_IOCFG_GPIO1_CFG_RCC_CAL_VALID	40 +#define  CC1200_IOCFG_GPIO0_CFG_CHFILTER_STARTUP_VALID	40 +#define  CC1200_IOCFG_GPIO3_CFG_COLLISION_FOUND		41 +#define  CC1200_IOCFG_GPIO2_CFG_SYNC_EVENT		41 +#define  CC1200_IOCFG_GPIO1_CFG_COLLISION_FOUND		41 +#define  CC1200_IOCFG_GPIO0_CFG_COLLISION_EVENT		41 +#define  CC1200_IOCFG_GPIO_CFG_PA_RAMP_UP		42 +#define  CC1200_IOCFG_GPIO3_CFG_CRC_FAILED		43 +#define  CC1200_IOCFG_GPIO2_CFG_LENGTH_FAILED		43 +#define  CC1200_IOCFG_GPIO1_CFG_ADDR_FAILED		43 +#define  CC1200_IOCFG_GPIO0_CFG_UART_FRAMING_ERROR	43 +#define  CC1200_IOCFG_GPIO_CFG_AGC_STABLE_GAIN		44 +#define  CC1200_IOCFG_GPIO_CFG_AGC_UPDATE		45 +#define  CC1200_IOCFG_GPIO3_CFG_ADC_CLOCK		46 +#define  CC1200_IOCFG_GPIO2_CFG_ADC_Q_DATA_SAMPLE	46 +#define  CC1200_IOCFG_GPIO1_CFG_ADC_CLOCK		46 +#define  CC1200_IOCFG_GPIO0_CFG_ADC_I_DATA_SAMPLE	46 +#define  CC1200_IOCFG_GPIO_CFG_HIGHZ			48 +#define  CC1200_IOCFG_GPIO_CFG_EXT_CLOCK		49 +#define  CC1200_IOCFG_GPIO_CFG_CHIP_RDY			50 +#define  CC1200_IOCFG_GPIO_CFG_HW0			51 +#define  CC1200_IOCFG_GPIO_CFG_CLOCK_32K		54 +#define  CC1200_IOCFG_GPIO_CFG_WOR_EVENT0		55 +#define  CC1200_IOCFG_GPIO_CFG_WOR_EVENT1		56 +#define  CC1200_IOCFG_GPIO_CFG_WOR_EVENT2		57 +#define  CC1200_IOCFG_GPIO_CFG_XOSC_STABLE		59 +#define  CC1200_IOCFG_GPIO_CFG_EXT_OSC_EN		60 +#define  CC1200_IOCFG_GPIO_CFG_MASK	0x3f + +#define CC1200_IOCFG2		0x01 +#define CC1200_IOCFG1		0x02 +#define CC1200_IOCFG0		0x03 +#define CC1200_SYNC3		0x04 +#define CC1200_SYNC2		0x05 +#define CC1200_SYNC1		0x06 +#define CC1200_SYNC0		0x07 + +#define CC1200_SYNC_CFG1	0x08 + +#define  CC1200_SYNC_CFG1_SYNC_MODE	5 +#define  CC1200_SYNC_CFG1_SYNC_MODE_NONE		0 +#define  CC1200_SYNC_CFG1_SYNC_MODE_11_BITS		1 +#define  CC1200_SYNC_CFG1_SYNC_MODE_16_BITS		2 +#define  CC1200_SYNC_CFG1_SYNC_MODE_18_BITS		3 +#define  CC1200_SYNC_CFG1_SYNC_MODE_24_BITS		4 +#define  CC1200_SYNC_CFG1_SYNC_MODE_32_BITS		5 +#define  CC1200_SYNC_CFG1_SYNC_MODE_16H_BITS		6 +#define  CC1200_SYNC_CFG1_SYNC_MODE_16D_BITS		7 +#define  CC1200_SYNC_CFG1_SYNC_MODE_MASK		7 + +#define  CC1200_SYNC_CFG1_SYNC_THR	0 +#define  CC1200_SYNC_CFG1_SYNC_MASK			0x1f + +#define CC1200_SYNC_CFG0	0x09 +#define  CC1200_SYNC_CFG0_AUTO_CLEAR		5 +#define  CC1200_SYNC_CFG0_RX_CONFIG_LIMITATION	4 +#define  CC1200_SYNC_CFG0_PQT_GATING_EN		3 +#define  CC1200_SYNC_CFG0_EXT_SYNC_DETECT	2 + +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK	0 +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_LEVEL_1	0 +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_LEVEL_2	1 +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_LEVEL_3	2 +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_DISABLED	3 +#define  CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_MASK		3 + +#define CC1200_DEVIATION_M	0x0a +#define CC1200_MODCFG_DEV_E	0x0b +#define  CC1200_MODCFG_DEV_E_MODEM_MODE		6 +#define  CC1200_MODCFG_DEV_E_MODEM_MODE_NORMAL		0 +#define  CC1200_MODCFG_DEV_E_MODEM_MODE_DSSS_REPEAT	1 +#define  CC1200_MODCFG_DEV_E_MODEM_MODE_DSSS_PN		2 +#define  CC1200_MODCFG_DEV_E_MODEM_MODE_CARRIER_SENSE	3 +#define  CC1200_MODCFG_DEV_E_MODEM_MODE_MASK		3 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT		3 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_2_FSK		0 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_2_GFSK		1 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_ASK_OOK		3 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_4_FSK		4 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_4_GFSK		5 +#define  CC1200_MODCFG_DEV_E_MOD_FORMAT_MASK		7 +#define  CC1200_MODCFG_DEV_E_DEV_E		0 +#define  CC1200_MODCFG_DEV_E_DEV_E_MASK		7 + +#define CC1200_DCFILT_CFG	0x0c +#define CC1200_PREAMBLE_CFG1	0x0d +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE	2 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_NONE		0 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_0_5_BYTE	1 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_1_BYTE	2 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_1_5_BYTE	3 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_2_BYTES	4 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_3_BYTES	5 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_4_BYTES	6 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_5_BYTES	7 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_6_BYTES	8 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_7_BYTES	9 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_8_BYTES	10 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_12_BYTES	11 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_24_BYTES	12 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_30_BYTES	13 +#define  CC1200_PREAMBLE_CFG1_NUM_PREAMBLE_MASK		0xf + +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD	0 +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_AA		0 +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_55		1 +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_33		2 +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_CC		3 +#define  CC1200_PREAMBLE_CFG1_PREAMBLE_WORD_MASK	3 + +#define CC1200_PREAMBLE_CFG0	0x0e +#define  CC1200_PREAMBLE_CFG0_PQT_EN		7 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT	4 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_11	0 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_12	1 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_13	2 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_15	3 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_16	4 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_17	5 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_24	6 +#define  CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_32	7 +#define  CC1200_PREAMBLE_CFG0_PQT		0 +#define  CC1200_PREAMBLE_CFG0_PQT_MASK			0xf + +#define CC1200_IQIC		0x0f +#define CC1200_CHAN_BW		0x10 +#define  CC1200_CHAN_BW_ADC_CIC_DECFACT		6 +#define  CC1200_CHAN_BW_ADC_CIC_DECFACT_12		0 +#define  CC1200_CHAN_BW_ADC_CIC_DECFACT_24		1 +#define  CC1200_CHAN_BW_ADC_CIC_DECFACT_48		2 +#define  CC1200_CHAN_BW_BB_CIC_DECFACT		0 + +#define CC1200_MDMCFG1		0x11 +#define  CC1200_MDMCFG1_CARRIER_SENSE_GATE	7 +#define  CC1200_MDMCFG1_FIFO_EN			6 +#define  CC1200_MDMCFG1_MANCHESTER_EN		5 +#define  CC1200_MDMCFG1_INVERT_DATA_EN		4 +#define  CC1200_MDMCFG1_COLLISION_DETECT_EN	3 +#define  CC1200_MDMCFG1_DVGA_GAIN		1 +#define  CC1200_MDMCFG1_DVGA_GAIN_0			0 +#define  CC1200_MDMCFG1_DVGA_GAIN_3			1 +#define  CC1200_MDMCFG1_DVGA_GAIN_6			2 +#define  CC1200_MDMCFG1_DVGA_GAIN_9			3 +#define  CC1200_MDMCFG1_DVGA_GAIN_MASK			3 +#define  CC1200_MDMCFG1_SINGLE_ADC_EN		0 + +#define CC1200_MDMCFG0		0x12 +#define  CC1200_MDMCFG0_TRANSPARENT_MODE_EN	6 +#define  CC1200_MDMCFG0_TRANSPARENT_INTFACT	4 +#define  CC1200_MDMCFG0_DATA_FILTER_EN		3 +#define  CC1200_MDMCFG0_VITERBI_EN		2 + +#define CC1200_SYMBOL_RATE2	0x13 +#define  CC1200_SYMBOL_RATE2_DATARATE_E			4 +#define  CC1200_SYMBOL_RATE2_DATARATE_E_MASK		0xf +#define  CC1200_SYMBOL_RATE2_DATARATE_M_19_16		0 +#define  CC1200_SYMBOL_RATE2_DATARATE_M_19_16_MASK	0xf + +#define CC1200_SYMBOL_RATE1	0x14 +#define CC1200_SYMBOL_RATE0	0x15 +#define CC1200_AGC_REF		0x16 +#define CC1200_AGC_CS_THR	0x17 +#define CC1200_AGC_GAIN_ADJUST	0x18 + +#define CC1200_AGC_CFG3		0x19 +#define  CC1200_AGC_CFG3_RSSI_STEP_THR		7 +#define  CC1200_AGC_CFG3_AGC_MIN_GAIN		0 +#define  CC1200_AGC_CFG3_AGC_MIN_GAIN_MASK	0x1f + +#define CC1200_AGC_CFG2		0x1a +#define  CC1200_AGC_CFG2_START_PREVIOUS_GAIN_EN	7 +#define  CC1200_AGC_CFG2_FE_PERFORMANCE_MODE	5 +#define  CC1200_AGC_CFG2_FE_PERFORMANCE_MODE_OPTIMIZE_LINEARITY	0 +#define  CC1200_AGC_CFG2_FE_PERFORMANCE_MODE_NORMAL		1 +#define  CC1200_AGC_CFG2_FE_PERFORMANCE_MODE_LOW_POWER		2 +#define  CC1200_AGC_CFG2_FE_PERFORMANCE_MODE_MASK		3 +#define  CC1200_AGC_CFG2_AGC_MAX_GAIN		0 +#define  CC1200_AGC_CFG2_AGC_MAX_MASK		0x1f + +#define CC1200_AGC_CFG1		0x1b +#define  CC1200_AGC_CFG1_RSSI_STEP_THR		6 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE		3 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_8			0 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_16		1 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_32		2 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_64		3 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_128		4 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_256		5 +#define  CC1200_AGC_CFG1_AGC_WIN_SIZE_MASK		7 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT	0 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_24		0 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_32		1 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_40		2 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_48		3 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_64		4 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_80		5 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_96		6 +#define  CC1200_AGC_CFG1_AGC_SETTLE_WAIT_127		7 + +#define CC1200_AGC_CFG0		0x1c + +#define  CC1200_AGC_CFG0_AGC_HYST_LEVEL		6 +#define   CC1200_AGC_CFG0_AGC_HYST_LEVEL_2		0 +#define   CC1200_AGC_CFG0_AGC_HYST_LEVEL_4		1 +#define   CC1200_AGC_CFG0_AGC_HYST_LEVEL_7		2 +#define   CC1200_AGC_CFG0_AGC_HYST_LEVEL_10		3 + +#define  CC1200_AGC_CFG0_AGC_SLEWRATE_LIMIT	4 +#define   CC1200_AGC_CFG0_AGC_SLEWRATE_LIMIT_60		0 +#define   CC1200_AGC_CFG0_AGC_SLEWRATE_LIMIT_30		1 +#define   CC1200_AGC_CFG0_AGC_SLEWRATE_LIMIT_18		2 +#define   CC1200_AGC_CFG0_AGC_SLEWRATE_LIMIT_9		3 + +#define  CC1200_AGC_CFG0_RSSI_VALID_CNT		2 +#define   CC1200_AGC_CFG0_RSSI_VALID_CNT_2		0 +#define   CC1200_AGC_CFG0_RSSI_VALID_CNT_3		1 +#define   CC1200_AGC_CFG0_RSSI_VALID_CNT_5		2 +#define   CC1200_AGC_CFG0_RSSI_VALID_CNT_9		3 + +#define  CC1200_AGC_CFG0_AGC_ASK_DECAY		0 +#define   CC1200_AGC_CFG0_AGC_ASK_DECAY_1200		0 +#define   CC1200_AGC_CFG0_AGC_ASK_DECAY_2400		1 +#define   CC1200_AGC_CFG0_AGC_ASK_DECAY_4700		2 +#define   CC1200_AGC_CFG0_AGC_ASK_DECAY_9500		3 + +#define CC1200_FIFO_CFG		0x1d +#define  CC1200_FIFO_CFG_CRC_AUTOFLUSH		7 +#define  CC1200_FIFO_CFG_FIFO_THR		0 + +#define CC1200_DEV_ADDR		0x1e +#define CC1200_SETTLING_CFG	0x1f +#define  CC1200_SETTLING_CFG_FS_AUTOCAL		3 +#define  CC1200_SETTLING_CFG_FS_AUTOCAL_NEVER		0 +#define  CC1200_SETTLING_CFG_FS_AUTOCAL_IDLE_TO_ON	1 +#define  CC1200_SETTLING_CFG_FS_AUTOCAL_ON_TO_IDLE	2 +#define  CC1200_SETTLING_CFG_FS_AUTOCAL_EVERY_4TH_TIME	3 +#define  CC1200_SETTLING_CFG_FS_AUTOCAL_MASK		3 +#define  CC1200_SETTLING_CFG_LOCK_TIME		1 +#define  CC1200_SETTLING_CFG_LOCK_TIME_50_20		0 +#define  CC1200_SETTLING_CFG_LOCK_TIME_75_30		1 +#define  CC1200_SETTLING_CFG_LOCK_TIME_100_40		2 +#define  CC1200_SETTLING_CFG_LOCK_TIME_150_60		3 +#define  CC1200_SETTLING_CFG_LOCK_TIME_MASK		3 +#define  CC1200_SETTLING_CFG_FSREG_TIME		0 +#define  CC1200_SETTLING_CFG_FSREG_TIME_30		0 +#define  CC1200_SETTLING_CFG_FSREG_TIME_60		1 +#define  CC1200_SETTLING_CFG_FSREG_TIME_MASK		1 + +#define CC1200_FS_CFG		0x20 +#define  CC1200_FS_CFG_LOCK_EN			4 +#define  CC1200_FS_CFG_FSD_BANDSELECT		0 +#define  CC1200_FS_CFG_FSD_BANDSELECT_820_960		2 +#define  CC1200_FS_CFG_FSD_BANDSELECT_410_480		4 +#define  CC1200_FS_CFG_FSD_BANDSELECT_273_320		6 +#define  CC1200_FS_CFG_FSD_BANDSELECT_205_240		8 +#define  CC1200_FS_CFG_FSD_BANDSELECT_164_192		10 +#define  CC1200_FS_CFG_FSD_BANDSELECT_136_160		11 +#define  CC1200_FS_CFG_FSD_BANDSELECT_MASK		0xf + +#define CC1200_WOR_CFG1		0x21 +#define CC1200_WOR_CFG0		0x22 +#define CC1200_WOR_EVENT0_MSB	0x23 +#define CC1200_WOR_EVENT0_LSB	0x24 +#define CC1200_RXDCM_TIME	0x25 +#define CC1200_PKT_CFG2		0x26 +#define  CC1200_PKT_CFG2_BYTE_SWAP_EN	6 +#define  CC1200_PKT_CFG2_FG_MODE_EN	5 +#define  CC1200_PKT_CFG2_CCA_MODE	2 +#define  CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR		0 +#define  CC1200_PKT_CFG2_CCA_MODE_RSSI_THRESHOLD	1 +#define  CC1200_PKT_CFG2_CCA_MODE_NOT_RECEIVING		2 +#define  CC1200_PKT_CFG2_CCA_MODE_RSSI_OR_NOT		3 +#define  CC1200_PKT_CFG2_CCA_MODE_RSSI_AND_ETSI_LBT	4 +#define  CC1200_PKT_CFG2_CCA_MODE_MASK			7 +#define  CC1200_PKT_CFG2_PKT_FORMAT	0 +#define  CC1200_PKT_CFG2_PKT_FORMAT_NORMAL		0 +#define  CC1200_PKT_CFG2_PKT_FORMAT_SYNCHRONOUS_SERIAL	1 +#define  CC1200_PKT_CFG2_PKT_FORMAT_RANDOM		2 +#define  CC1200_PKT_CFG2_PKT_FORMAT_TRANSPARENT_SERIAL	3 +#define  CC1200_PKT_CFG2_PKT_FORMAT_MASK		3 + +#define CC1200_PKT_CFG1		0x27 +#define  CC1200_PKT_CFG1_FEC_EN		7 +#define  CC1200_PKT_CFG1_WHITE_DATA	6 +#define  CC1200_PKT_CFG1_PN9_SWAP_EN	5 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG	3 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE		0 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG_CHECK		1 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG_00_BROADCAST	2 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG_00_FF_BROADCAST	3 +#define  CC1200_PKT_CFG1_ADDR_CHECK_CFG_MASK		3 +#define  CC1200_PKT_CFG1_CRC_CFG	1 +#define  CC1200_PKT_CFG1_CRC_CFG_DISABLED		0 +#define  CC1200_PKT_CFG1_CRC_CFG_CRC16_INIT_ONES	1 +#define  CC1200_PKT_CFG1_CRC_CFG_CRC16_INIT_ZEROS	2 +#define  CC1200_PKT_CFG1_CRC_CFG_MASK			3 +#define  CC1200_PKT_CFG1_APPEND_STATUS	0 + +#define CC1200_PKT_CFG0		0x28 +#define  CC1200_PKT_CFG0_RESERVED7	7 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG	5 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG_FIXED		0 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG_VARIABLE		1 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG_INFINITE		2 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG_VARIABLE_5LSB	3 +#define  CC1200_PKT_CFG0_LENGTH_CONFIG_MASK		3 +#define  CC1200_PKT_CFG0_PKG_BIT_LEN	2 +#define  CC1200_PKT_CFG0_PKG_BIT_LEN_MASK	7 +#define  CC1200_PKT_CFG0_UART_MODE_EN	1 +#define  CC1200_PKT_CFG0_UART_SWAP_EN	0 + +#define CC1200_RFEND_CFG1	0x29 +#define  CC1200_RFEND_CFG1_RXOFF_MODE	4 +#define  CC1200_RFEND_CFG1_RXOFF_MODE_IDLE	0 +#define  CC1200_RFEND_CFG1_RXOFF_MODE_FSTXON	1 +#define  CC1200_RFEND_CFG1_RXOFF_MODE_TX	2 +#define  CC1200_RFEND_CFG1_RXOFF_MODE_RX	3 +#define  CC1200_RFEND_CFG1_RX_TIME	1 +#define  CC1200_RFEND_CFG1_RX_TIME_INFINITE	7 +#define  CC1200_RFEND_CFG1_RX_TIME_QUAL	0 +#define CC1200_RFEND_CFG0	0x2a +#define  CC1200_RFEND_CFG0_CAL_END_WAKE_UP_EN	6 +#define  CC1200_RFEND_CFG0_TXOFF_MODE		4 +#define  CC1200_RFEND_CFG0_TXOFF_MODE_IDLE	0 +#define  CC1200_RFEND_CFG0_TXOFF_MODE_FSTXON	1 +#define  CC1200_RFEND_CFG0_TXOFF_MODE_TX	2 +#define  CC1200_RFEND_CFG0_TXOFF_MODE_RX	3 +#define  CC1200_RFEND_CFG0_TERM_ON_BAD_PACKET_EN 3 +#define  CC1200_RFEND_CFG0_ANT_DIV_RX_TERM_CFG	0 +#define CC1200_PA_CFG1		0x2b +#define CC1200_PA_CFG0		0x2c +#define CC1200_ASK_CFG		0x2d +#define CC1200_PKT_LEN		0x2e + +#define CC1200_EXTENDED		0x2f + +/* Command strobes */ +#define CC1200_SRES		0x30 +#define CC1200_SFSTXON		0x31 +#define CC1200_SXOFF		0x32 +#define CC1200_SCAL		0x33 +#define CC1200_SRX		0x34 +#define CC1200_STX		0x35 +#define CC1200_SIDLE		0x36 +#define CC1200_SAFC		0x37 +#define CC1200_SWOR		0x38 +#define CC1200_SPWD		0x39 +#define CC1200_SFRX		0x3a +#define CC1200_SFTX		0x3b +#define CC1200_SWORRST		0x3c +#define CC1200_SNOP		0x3d + +#define CC1200_DIRECT_FIFO	0x3e +#define CC1200_FIFO		0x3f + +#define CC1200_FIFO_SIZE	128 + +/* Extended register space */ + +#define CC1200_EXTENDED_BIT	0x8000 + +#define CC1200_IS_EXTENDED(r)	((r) & CC1200_EXTENDED_BIT) + +#define CC1200_IF_MIX_CFG	(CC1200_EXTENDED_BIT | 0x00) +#define CC1200_FREQOFF_CFG	(CC1200_EXTENDED_BIT | 0x01) +#define CC1200_TOC_CFG		(CC1200_EXTENDED_BIT | 0x02) +#define CC1200_MARC_SPARE	(CC1200_EXTENDED_BIT | 0x03) +#define CC1200_ECG_CFG		(CC1200_EXTENDED_BIT | 0x04) +#define CC1200_MDMCFG2		(CC1200_EXTENDED_BIT | 0x05) + +#define  CC1200_MDMCFG2_ASK_SHAPE	6 +#define  CC1200_MDMCFG2_ASK_SHAPE_8		0 +#define  CC1200_MDMCFG2_ASK_SHAPE_16		1 +#define  CC1200_MDMCFG2_ASK_SHAPE_32		2 +#define  CC1200_MDMCFG2_ASK_SHAPE_128		3 +#define  CC1200_MDMCFG2_SYMBOL_MAP_CFG	4 +#define  CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_0	0 +#define  CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_1	1 +#define  CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_2	2 +#define  CC1200_MDMCFG2_SYMBOL_MAP_CFG_MODE_3	3 +#define  CC1200_MDMCFG2_UPSAMPLER_P	1 +#define  CC1200_MDMCFG2_UPSAMPLER_P_1		0 +#define  CC1200_MDMCFG2_UPSAMPLER_P_2		1 +#define  CC1200_MDMCFG2_UPSAMPLER_P_4		2 +#define  CC1200_MDMCFG2_UPSAMPLER_P_8		3 +#define  CC1200_MDMCFG2_UPSAMPLER_P_16		4 +#define  CC1200_MDMCFG2_UPSAMPLER_P_32		5 +#define  CC1200_MDMCFG2_UPSAMPLER_P_64		6 +#define  CC1200_MDMCFG2_CFM_DATA_EN	0 + +#define CC1200_EXT_CTRL		(CC1200_EXTENDED_BIT | 0x06) +#define CC1200_RCCAL_FINE	(CC1200_EXTENDED_BIT | 0x07) +#define CC1200_RCCAL_COARSE	(CC1200_EXTENDED_BIT | 0x08) +#define CC1200_RCCAL_OFFSET	(CC1200_EXTENDED_BIT | 0x09) +#define CC1200_FREQOFF1		(CC1200_EXTENDED_BIT | 0x0A) +#define CC1200_FREQOFF0		(CC1200_EXTENDED_BIT | 0x0B) +#define CC1200_FREQ2		(CC1200_EXTENDED_BIT | 0x0C) +#define CC1200_FREQ1		(CC1200_EXTENDED_BIT | 0x0D) +#define CC1200_FREQ0		(CC1200_EXTENDED_BIT | 0x0E) +#define CC1200_IF_ADC2		(CC1200_EXTENDED_BIT | 0x0F) +#define CC1200_IF_ADC1		(CC1200_EXTENDED_BIT | 0x10) +#define CC1200_IF_ADC0		(CC1200_EXTENDED_BIT | 0x11) +#define CC1200_FS_DIG1		(CC1200_EXTENDED_BIT | 0x12) +#define CC1200_FS_DIG0		(CC1200_EXTENDED_BIT | 0x13) +#define CC1200_FS_CAL3		(CC1200_EXTENDED_BIT | 0x14) +#define CC1200_FS_CAL2		(CC1200_EXTENDED_BIT | 0x15) +#define CC1200_FS_CAL1		(CC1200_EXTENDED_BIT | 0x16) +#define CC1200_FS_CAL0		(CC1200_EXTENDED_BIT | 0x17) +#define CC1200_FS_CHP		(CC1200_EXTENDED_BIT | 0x18) +#define CC1200_FS_DIVTWO	(CC1200_EXTENDED_BIT | 0x19) +#define CC1200_FS_DSM1		(CC1200_EXTENDED_BIT | 0x1A) +#define CC1200_FS_DSM0		(CC1200_EXTENDED_BIT | 0x1B) +#define CC1200_FS_DVC1		(CC1200_EXTENDED_BIT | 0x1C) +#define CC1200_FS_DVC0		(CC1200_EXTENDED_BIT | 0x1D) +#define CC1200_FS_LBI		(CC1200_EXTENDED_BIT | 0x1E) +#define CC1200_FS_PFD		(CC1200_EXTENDED_BIT | 0x1F) +#define CC1200_FS_PRE		(CC1200_EXTENDED_BIT | 0x20) +#define CC1200_FS_REG_DIV_CML	(CC1200_EXTENDED_BIT | 0x21) +#define CC1200_FS_SPARE		(CC1200_EXTENDED_BIT | 0x22) +#define CC1200_FS_VCO4		(CC1200_EXTENDED_BIT | 0x23) +#define CC1200_FS_VCO3		(CC1200_EXTENDED_BIT | 0x24) +#define CC1200_FS_VCO2		(CC1200_EXTENDED_BIT | 0x25) +#define CC1200_FS_VCO1		(CC1200_EXTENDED_BIT | 0x26) +#define CC1200_FS_VCO0		(CC1200_EXTENDED_BIT | 0x27) +#define CC1200_GBIAS6		(CC1200_EXTENDED_BIT | 0x28) +#define CC1200_GBIAS5		(CC1200_EXTENDED_BIT | 0x29) +#define CC1200_GBIAS4		(CC1200_EXTENDED_BIT | 0x2A) +#define CC1200_GBIAS3		(CC1200_EXTENDED_BIT | 0x2B) +#define CC1200_GBIAS2		(CC1200_EXTENDED_BIT | 0x2C) +#define CC1200_GBIAS1		(CC1200_EXTENDED_BIT | 0x2D) +#define CC1200_GBIAS0		(CC1200_EXTENDED_BIT | 0x2E) +#define CC1200_IFAMP		(CC1200_EXTENDED_BIT | 0x2F) +#define CC1200_LNA		(CC1200_EXTENDED_BIT | 0x30) +#define CC1200_RXMIX		(CC1200_EXTENDED_BIT | 0x31) +#define CC1200_XOSC5		(CC1200_EXTENDED_BIT | 0x32) +#define CC1200_XOSC4		(CC1200_EXTENDED_BIT | 0x33) +#define CC1200_XOSC3		(CC1200_EXTENDED_BIT | 0x34) +#define CC1200_XOSC2		(CC1200_EXTENDED_BIT | 0x35) +#define CC1200_XOSC1		(CC1200_EXTENDED_BIT | 0x36) +#define CC1200_XOSC0		(CC1200_EXTENDED_BIT | 0x37) +#define CC1200_ANALOG_SPARE	(CC1200_EXTENDED_BIT | 0x38) +#define CC1200_PA_CFG3		(CC1200_EXTENDED_BIT | 0x39) +#define CC1200_WOR_TIME1	(CC1200_EXTENDED_BIT | 0x64) +#define CC1200_WOR_TIME0	(CC1200_EXTENDED_BIT | 0x65) +#define CC1200_WOR_CAPTURE1	(CC1200_EXTENDED_BIT | 0x66) +#define CC1200_WOR_CAPTURE0	(CC1200_EXTENDED_BIT | 0x67) +#define CC1200_BIST		(CC1200_EXTENDED_BIT | 0x68) +#define CC1200_DCFILTOFFSET_I1	(CC1200_EXTENDED_BIT | 0x69) +#define CC1200_DCFILTOFFSET_I0	(CC1200_EXTENDED_BIT | 0x6A) +#define CC1200_DCFILTOFFSET_Q1	(CC1200_EXTENDED_BIT | 0x6B) +#define CC1200_DCFILTOFFSET_Q0	(CC1200_EXTENDED_BIT | 0x6C) +#define CC1200_IQIE_I1		(CC1200_EXTENDED_BIT | 0x6D) +#define CC1200_IQIE_I0		(CC1200_EXTENDED_BIT | 0x6E) +#define CC1200_IQIE_Q1		(CC1200_EXTENDED_BIT | 0x6f) +#define CC1200_IQIE_Q0		(CC1200_EXTENDED_BIT | 0x70) +#define CC1200_RSSI1		(CC1200_EXTENDED_BIT | 0x71) +#define CC1200_RSSI0		(CC1200_EXTENDED_BIT | 0x72) +#define CC1200_MARCSTATE	(CC1200_EXTENDED_BIT | 0x73) +#define CC1200_LQI_VAL		(CC1200_EXTENDED_BIT | 0x74) +#define CC1200_PQT_SYNC_ERR	(CC1200_EXTENDED_BIT | 0x75) +#define CC1200_DEM_STATUS	(CC1200_EXTENDED_BIT | 0x76) +#define CC1200_FREQOFF_EST1	(CC1200_EXTENDED_BIT | 0x77) +#define CC1200_FREQOFF_EST0	(CC1200_EXTENDED_BIT | 0x78) +#define CC1200_AGC_GAIN3	(CC1200_EXTENDED_BIT | 0x79) +#define CC1200_AGC_GAIN2	(CC1200_EXTENDED_BIT | 0x7a) +#define CC1200_AGC_GAIN1	(CC1200_EXTENDED_BIT | 0x7b) +#define CC1200_AGC_GAIN0	(CC1200_EXTENDED_BIT | 0x7c) +#define CC1200_SOFT_RX_DATA_OUT	(CC1200_EXTENDED_BIT | 0x7d) +#define CC1200_SOFT_TX_DATA_IN	(CC1200_EXTENDED_BIT | 0x7e) +#define CC1200_ASK_SOFT_RX_DATA	(CC1200_EXTENDED_BIT | 0x7f) +#define CC1200_RNDGEN		(CC1200_EXTENDED_BIT | 0x80) +#define CC1200_MAGN2		(CC1200_EXTENDED_BIT | 0x81) +#define CC1200_MAGN1		(CC1200_EXTENDED_BIT | 0x82) +#define CC1200_MAGN0		(CC1200_EXTENDED_BIT | 0x83) +#define CC1200_ANG1		(CC1200_EXTENDED_BIT | 0x84) +#define CC1200_ANG0		(CC1200_EXTENDED_BIT | 0x85) +#define CC1200_CHFILT_I2	(CC1200_EXTENDED_BIT | 0x86) +#define CC1200_CHFILT_I1	(CC1200_EXTENDED_BIT | 0x87) +#define CC1200_CHFILT_I0	(CC1200_EXTENDED_BIT | 0x88) +#define CC1200_CHFILT_Q2	(CC1200_EXTENDED_BIT | 0x89) +#define CC1200_CHFILT_Q1	(CC1200_EXTENDED_BIT | 0x8a) +#define CC1200_CHFILT_Q0	(CC1200_EXTENDED_BIT | 0x8b) +#define CC1200_GPIO_STATUS	(CC1200_EXTENDED_BIT | 0x8c) +#define CC1200_FSCAL_CTRL	(CC1200_EXTENDED_BIT | 0x8d) +#define CC1200_PHASE_ADJUST	(CC1200_EXTENDED_BIT | 0x8e) +#define CC1200_PARTNUMBER	(CC1200_EXTENDED_BIT | 0x8f) +#define CC1200_PARTVERSION	(CC1200_EXTENDED_BIT | 0x90) +#define CC1200_SERIAL_STATUS	(CC1200_EXTENDED_BIT | 0x91) +#define CC1200_MODEM_STATUS1	(CC1200_EXTENDED_BIT | 0x92) +#define  CC1200_MODEM_STATUS1_SYNC_FOUND	7 +#define  CC1200_MODEM_STATUS1_RXFIFO_FULL	6 +#define  CC1200_MODEM_STATUS1_RXFIFO_THR	5 +#define  CC1200_MODEM_STATUS1_RXFIFO_EMPTY	4 +#define  CC1200_MODEM_STATUS1_RXFIFO_OVERFLOW	3 +#define  CC1200_MODEM_STATUS1_RXFIFO_UNDERFLOW	2 +#define  CC1200_MODEM_STATUS1_PQT_REACHED	1 +#define  CC1200_MODEM_STATUS1_PQT_VALID		0 + +#define CC1200_MODEM_STATUS0	(CC1200_EXTENDED_BIT | 0x93) +#define  CC1200_MODEM_STATUS0_FEC_RX_OVERFLOW	6 +#define  CC1200_MODEM_STATUS0_SYNC_SENT		4 +#define  CC1200_MODEM_STATUS0_TXFIFO_FULL	3 +#define  CC1200_MODEM_STATUS0_TXFIFO_THR	2 +#define  CC1200_MODEM_STATUS0_TXFIFO_OVERFLOW	1 +#define  CC1200_MODEM_STATUS0_TXFIFO_UNDERFLOW	0 + +#define CC1200_MARC_STATUS1	(CC1200_EXTENDED_BIT | 0x94) +#define  CC1200_MARC_STATUS1_NO_FAILURE		0 +#define  CC1200_MARC_STATUS1_RX_TIMEOUT		1 +#define  CC1200_MARC_STATUS1_RX_TERMINATION	2 +#define  CC1200_MARC_STATUS1_EWOR_SYNC_LOST	3 +#define  CC1200_MARC_STATUS1_MAXIMUM_LENGTH	4 +#define  CC1200_MARC_STATUS1_ADDRESS		5 +#define  CC1200_MARC_STATUS1_CRC		6 +#define  CC1200_MARC_STATUS1_TX_FIFO_OVERFLOW	7 +#define  CC1200_MARC_STATUS1_TX_FIFO_UNDERFLOW	8 +#define  CC1200_MARC_STATUS1_RX_FIFO_OVERFLOW	9 +#define  CC1200_MARC_STATUS1_RX_FIFO_UNDERFLOW	10 +#define  CC1200_MARC_STATUS1_TX_ON_CCA_FAILED	11 +#define  CC1200_MARC_STATUS1_TX_FINISHED	0x40 +#define  CC1200_MARC_STATUS1_RX_FINISHED	0x80 +#define CC1200_MARC_STATUS0	(CC1200_EXTENDED_BIT | 0x95) +#define CC1200_PA_IFAMP_TEST	(CC1200_EXTENDED_BIT | 0x96) +#define CC1200_FSRF_TEST	(CC1200_EXTENDED_BIT | 0x97) +#define CC1200_PRE_TEST		(CC1200_EXTENDED_BIT | 0x98) +#define CC1200_PRE_OVR		(CC1200_EXTENDED_BIT | 0x99) +#define CC1200_ADC_TEST		(CC1200_EXTENDED_BIT | 0x9a) +#define CC1200_DVC_TEST		(CC1200_EXTENDED_BIT | 0x9b) +#define CC1200_ATEST		(CC1200_EXTENDED_BIT | 0x9c) +#define CC1200_ATEST_LVDS	(CC1200_EXTENDED_BIT | 0x9d) +#define CC1200_ATEST_MODE	(CC1200_EXTENDED_BIT | 0x9e) +#define CC1200_XOSC_TEST1	(CC1200_EXTENDED_BIT | 0x9f) +#define CC1200_XOSC_TEST0	(CC1200_EXTENDED_BIT | 0xa0) +#define CC1200_RXFIRST		(CC1200_EXTENDED_BIT | 0xd2) +#define CC1200_TXFIRST		(CC1200_EXTENDED_BIT | 0xd3) +#define CC1200_RXLAST		(CC1200_EXTENDED_BIT | 0xd4) +#define CC1200_TXLAST		(CC1200_EXTENDED_BIT | 0xd5) +#define CC1200_NUM_TXBYTES	(CC1200_EXTENDED_BIT | 0xd6) +#define CC1200_NUM_RXBYTES	(CC1200_EXTENDED_BIT | 0xd7) +#define CC1200_FIFO_NUM_TXBYTES	(CC1200_EXTENDED_BIT | 0xd8) +#define CC1200_FIFO_NUM_RXBYTES	(CC1200_EXTENDED_BIT | 0xd9) +#define CC1200_RXFIFO_PRE_BUF	(CC1200_EXTENDED_BIT | 0xda) +#define CC1200_AES_WORKSPACE_0	(CC1200_EXTENDED_BIT | 0xe0) + +/* Status byte */ +#define CC1200_STATUS_CHIP_RDY	7 +#define CC1200_STATUS_STATE	4 +#define  CC1200_STATUS_STATE_IDLE		0 +#define  CC1200_STATUS_STATE_RX			1 +#define  CC1200_STATUS_STATE_TX			2 +#define  CC1200_STATUS_STATE_FSTXON		3 +#define  CC1200_STATUS_STATE_CALIBRATE		4 +#define  CC1200_STATUS_STATE_SETTLING		5 +#define  CC1200_STATUS_STATE_RX_FIFO_ERROR	6 +#define  CC1200_STATUS_STATE_TX_FIFO_ERROR	7 +#define  CC1200_STATUS_STATE_MASK		7 + +#endif /* _AO_CC1200_H_ */ diff --git a/src/drivers/ao_cc1200_CC1200.h b/src/drivers/ao_cc1200_CC1200.h new file mode 100644 index 00000000..35673123 --- /dev/null +++ b/src/drivers/ao_cc1200_CC1200.h @@ -0,0 +1,122 @@ +/*************************************************************** + *  SmartRF Studio(tm) Export + * + *  Radio register settings specifed with address, value + * + *  RF device: CC1200 + * + ***************************************************************/ + +/* + * Values affecting receive sensitivity: + * + * + *	PQT		- sets how good the preamble needs to look before + *			  we start looking for a sync word + *	SYNC_THR	- sets how good the sync needs to be before we + *			  start decoding a packet + */ + +/* Values depending on data rate + * + *	DCFILT_BW_SETTLE + *	DCFILT_BW + */ + +#ifndef AO_CC1200_AGC_GAIN_ADJUST +#define AO_CC1200_AGC_GAIN_ADJUST	-94 +#endif + +        CC1200_IOCFG2,                       0x06,       /* GPIO2 IO Pin Configuration */ +	CC1200_SYNC3,		             0xD3,	 /* Sync Word Configuration [23:16] */ +	CC1200_SYNC2,		             0x91,	 /* Sync Word Configuration [23:16] */ +        CC1200_SYNC1,                        0xD3,       /* Sync Word Configuration [15:8] */ +        CC1200_SYNC0,                        0x91,       /* Sync Word Configuration [7:0] */ +        CC1200_SYNC_CFG1,                                /* Sync Word Detection Configuration Reg. 1 */ +		((CC1200_SYNC_CFG1_SYNC_MODE_16_BITS << CC1200_SYNC_CFG1_SYNC_MODE) | +		 (11 << CC1200_SYNC_CFG1_SYNC_THR)), +        CC1200_SYNC_CFG0,                                /* Sync Word Detection Configuration Reg. 0 */ +		((1 << CC1200_SYNC_CFG0_AUTO_CLEAR) | +		 (0 << CC1200_SYNC_CFG0_RX_CONFIG_LIMITATION) | +		 (1 << CC1200_SYNC_CFG0_PQT_GATING_EN) | +		 (0 << CC1200_SYNC_CFG0_EXT_SYNC_DETECT) | +		 (CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK_DISABLED << CC1200_SYNC_CFG0_SYNC_STRICT_SYNC_CHECK)), +        CC1200_DEVIATION_M,                  0x50,       /* Frequency Deviation Configuration */ +        CC1200_DCFILT_CFG,                   0x5d,       /* Digital DC Removal Configuration */ +        CC1200_PREAMBLE_CFG0,       			 /* Preamble Detection Configuration Reg. 0 */ +		((1 << CC1200_PREAMBLE_CFG0_PQT_EN) | +		 (CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT_11 << CC1200_PREAMBLE_CFG0_PQT_VALID_TIMEOUT) | +		 (15 << CC1200_PREAMBLE_CFG0_PQT)), +        CC1200_IQIC,                         0xcb,       /* Digital Image Channel Compensation Configuration */ +        CC1200_CHAN_BW,                      0x11,       /* Channel Filter Configuration */ +        CC1200_MDMCFG1,                      0x40,       /* General Modem Parameter Configuration Reg. 1 */ +        CC1200_MDMCFG0,                      0x05,       /* General Modem Parameter Configuration Reg. 0 */ +        CC1200_SYMBOL_RATE2,                 0x93,       /* Symbol Rate Configuration Exponent and Mantissa [1.. */ +        CC1200_AGC_REF,                      0x27,       /* AGC Reference Level Configuration */ +        CC1200_AGC_CS_THR,                   0xec,       /* Carrier Sense Threshold Configuration */ +	CC1200_AGC_GAIN_ADJUST,				 /* RSSI adjustment */ +		AO_CC1200_AGC_GAIN_ADJUST, +        CC1200_AGC_CFG1,                     0x51,       /* Automatic Gain Control Configuration Reg. 1 */ +        CC1200_AGC_CFG0,                     0x87,       /* Automatic Gain Control Configuration Reg. 0 */ +        CC1200_FIFO_CFG,                     0x40,       /* FIFO Configuration */ +	CC1200_SETTLING_CFG,	                         /* Frequency Synthesizer Calibration and Settling Configuration */ +		((CC1200_SETTLING_CFG_FS_AUTOCAL_EVERY_4TH_TIME << CC1200_SETTLING_CFG_FS_AUTOCAL) | +		 (CC1200_SETTLING_CFG_LOCK_TIME_75_30 << CC1200_SETTLING_CFG_LOCK_TIME) | +		 (CC1200_SETTLING_CFG_FSREG_TIME_60 << CC1200_SETTLING_CFG_FSREG_TIME)), +        CC1200_FS_CFG,                                   /* Frequency Synthesizer Configuration */ +		((1 << CC1200_FS_CFG_LOCK_EN) | +		 (CC1200_FS_CFG_FSD_BANDSELECT_410_480 << CC1200_FS_CFG_FSD_BANDSELECT)), +        CC1200_PKT_CFG2,                            	 /* Packet Configuration Reg. 2 */ +		((0 << CC1200_PKT_CFG2_FG_MODE_EN) | +		 (CC1200_PKT_CFG2_CCA_MODE_ALWAYS_CLEAR << CC1200_PKT_CFG2_CCA_MODE) | +		 (CC1200_PKT_CFG2_PKT_FORMAT_NORMAL << CC1200_PKT_CFG2_PKT_FORMAT)), +        CC1200_PKT_CFG1,                                 /* Packet Configuration Reg. 1 */ +		((1 << CC1200_PKT_CFG1_FEC_EN) | +		 (1 << CC1200_PKT_CFG1_WHITE_DATA) | +		 (0 << CC1200_PKT_CFG1_PN9_SWAP_EN) | +		 (CC1200_PKT_CFG1_ADDR_CHECK_CFG_NONE << CC1200_PKT_CFG1_ADDR_CHECK_CFG) | +		 (CC1200_PKT_CFG1_CRC_CFG_CRC16_INIT_ONES << CC1200_PKT_CFG1_CRC_CFG) | +		 (1 << CC1200_PKT_CFG1_APPEND_STATUS)), +        CC1200_PKT_CFG0,                                 /* Packet Configuration Reg. 0 */ +		((CC1200_PKT_CFG0_LENGTH_CONFIG_FIXED << CC1200_PKT_CFG0_LENGTH_CONFIG) | +		 (0 << CC1200_PKT_CFG0_PKG_BIT_LEN) | +		 (0 << CC1200_PKT_CFG0_UART_MODE_EN) | +		 (0 << CC1200_PKT_CFG0_UART_SWAP_EN)), +	CC1200_RFEND_CFG1,				 /* RFEND Configuration Reg. 1 */ +		((CC1200_RFEND_CFG1_RXOFF_MODE_IDLE << CC1200_RFEND_CFG1_RXOFF_MODE) | +		 (CC1200_RFEND_CFG1_RX_TIME_INFINITE << CC1200_RFEND_CFG1_RX_TIME) | +		 (0 << CC1200_RFEND_CFG1_RX_TIME_QUAL)), +	CC1200_RFEND_CFG0,				 /* RFEND Configuration Reg. 0 */ +		((0 << CC1200_RFEND_CFG0_CAL_END_WAKE_UP_EN) | +		 (CC1200_RFEND_CFG0_TXOFF_MODE_IDLE << CC1200_RFEND_CFG0_TXOFF_MODE) | +		 (1 << CC1200_RFEND_CFG0_TERM_ON_BAD_PACKET_EN) | +		 (0 << CC1200_RFEND_CFG0_ANT_DIV_RX_TERM_CFG)), +        CC1200_PA_CFG1,                      0x3f,       /* Power Amplifier Configuration Reg. 1 */ +        CC1200_PA_CFG0,                      0x53,       /* Power Amplifier Configuration Reg. 0 */ +        CC1200_PKT_LEN,                      0xff,       /* Packet Length Configuration */ +        CC1200_IF_MIX_CFG,                   0x1c,       /* IF Mix Configuration */ +        CC1200_FREQOFF_CFG,                  0x22,       /* Frequency Offset Correction Configuration */ +        CC1200_MDMCFG2,                                  /* General Modem Parameter Configuration Reg. 2 */ +		((CC1200_MDMCFG2_ASK_SHAPE_8 << CC1200_MDMCFG2_ASK_SHAPE) | +		 (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_FREQ2,                        0x6c,       /* Frequency Configuration [23:16] */ +        CC1200_FREQ1,                        0xa3,       /* Frequency Configuration [15:8] */ +        CC1200_FREQ0,                        0x33,       /* Frequency Configuration [7:0] */ +        CC1200_IF_ADC1,                      0xee,       /* Analog to Digital Converter Configuration Reg. 1 */ +        CC1200_IF_ADC0,                      0x10,       /* Analog to Digital Converter Configuration Reg. 0 */ +        CC1200_FS_DIG1,                      0x07,       /* Frequency Synthesizer Digital Reg. 1 */ +        CC1200_FS_DIG0,                      0xaf,       /* Frequency Synthesizer Digital Reg. 0 */ +        CC1200_FS_CAL1,                      0x40,       /* Frequency Synthesizer Calibration Reg. 1 */ +        CC1200_FS_CAL0,                      0x0e,       /* Frequency Synthesizer Calibration Reg. 0 */ +        CC1200_FS_DIVTWO,                    0x03,       /* Frequency Synthesizer Divide by 2 */ +        CC1200_FS_DSM0,                      0x33,       /* FS Digital Synthesizer Module Configuration Reg. 0 */ +        CC1200_FS_DVC0,                      0x17,       /* Frequency Synthesizer Divider Chain Configuration .. */ +        CC1200_FS_PFD,                       0x00,       /* Frequency Synthesizer Phase Frequency Detector Con.. */ +        CC1200_FS_PRE,                       0x6e,       /* Frequency Synthesizer Prescaler Configuration */ +        CC1200_FS_REG_DIV_CML,               0x1c,       /* Frequency Synthesizer Divider Regulator Configurat.. */ +        CC1200_FS_SPARE,                     0xac,       /* Frequency Synthesizer Spare */ +        CC1200_FS_VCO0,                      0xb5,       /* FS Voltage Controlled Oscillator Configuration Reg.. */ +        CC1200_XOSC5,                        0x0e,       /* Crystal Oscillator Configuration Reg. 5 */ +        CC1200_XOSC1,                        0x03,       /* Crystal Oscillator Configuration Reg. 1 */ diff --git a/src/drivers/ao_packet_master.c b/src/drivers/ao_packet_master.c index 23545049..42a4f5bf 100644 --- a/src/drivers/ao_packet_master.c +++ b/src/drivers/ao_packet_master.c @@ -17,7 +17,7 @@  #include "ao.h" -static char +static int  ao_packet_getchar(void)  {  	int c; diff --git a/src/easymini-v1.0/ao_pins.h b/src/easymini-v1.0/ao_pins.h index 0edde5a2..1d794497 100644 --- a/src/easymini-v1.0/ao_pins.h +++ b/src/easymini-v1.0/ao_pins.h @@ -18,7 +18,7 @@  #define HAS_BEEP		1  #define HAS_BATTERY_REPORT	1 -#define AO_STACK_SIZE	384 +#define AO_STACK_SIZE	376  #define IS_FLASH_LOADER	0 diff --git a/src/kernel/ao.h b/src/kernel/ao.h index ad5bbf8e..59a469ae 100644 --- a/src/kernel/ao.h +++ b/src/kernel/ao.h @@ -43,10 +43,6 @@  #define HAS_TASK	1  #endif -#ifndef AO_PORT_TYPE -#define AO_PORT_TYPE uint8_t -#endif -  typedef AO_PORT_TYPE ao_port_t;  #if HAS_TASK @@ -76,6 +72,7 @@ typedef AO_PORT_TYPE ao_port_t;  #define AO_PANIC_BUFIO		15	/* Mis-using bufio API */  #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_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 */ @@ -518,15 +515,9 @@ struct ao_telemetry_raw_recv {  /* Set delay between telemetry reports (0 to disable) */ -#ifdef AO_SEND_ALL_BARO -#define AO_TELEMETRY_INTERVAL_PAD	AO_MS_TO_TICKS(100) -#define AO_TELEMETRY_INTERVAL_FLIGHT	AO_MS_TO_TICKS(100) -#define AO_TELEMETRY_INTERVAL_RECOVER	AO_MS_TO_TICKS(100) -#else  #define AO_TELEMETRY_INTERVAL_PAD	AO_MS_TO_TICKS(1000)  #define AO_TELEMETRY_INTERVAL_FLIGHT	AO_MS_TO_TICKS(100)  #define AO_TELEMETRY_INTERVAL_RECOVER	AO_MS_TO_TICKS(1000) -#endif  void  ao_telemetry_reset_interval(void); @@ -662,6 +653,7 @@ union ao_monitor {  extern __xdata union ao_monitor ao_monitor_ring[AO_MONITOR_RING];  #define ao_monitor_ring_next(n)	(((n) + 1) & (AO_MONITOR_RING - 1)) +#define ao_monitor_ring_prev(n)	(((n) - 1) & (AO_MONITOR_RING - 1))  extern __data uint8_t ao_monitoring;  extern __data uint8_t ao_monitor_head; diff --git a/src/kernel/ao_config.c b/src/kernel/ao_config.c index 6b8a1813..8dab7c42 100644 --- a/src/kernel/ao_config.c +++ b/src/kernel/ao_config.c @@ -557,10 +557,10 @@ ao_config_radio_rate_set(void) __reentrant  	}  	_ao_config_edit_start();  	ao_config.radio_rate = ao_cmd_lex_i; +	_ao_config_edit_finish();  #if HAS_TELEMETRY  	ao_telemetry_reset_interval();  #endif -	_ao_config_edit_finish();  #if HAS_RADIO_RECV  	ao_radio_recv_abort();  #endif @@ -684,6 +684,9 @@ ao_config_radio_enable_set(void) __reentrant  	_ao_config_edit_start();  	ao_config.radio_enable = ao_cmd_lex_i;  	_ao_config_edit_finish(); +#if HAS_TELEMETRY && HAS_RADIO_RATE +	ao_telemetry_reset_interval(); +#endif  }  #endif /* HAS_RADIO */ @@ -735,6 +738,7 @@ ao_config_aprs_set(void)  	_ao_config_edit_start();  	ao_config.aprs_interval = ao_cmd_lex_i;  	_ao_config_edit_finish(); +	ao_telemetry_reset_interval();  }  #endif /* HAS_APRS */ @@ -825,6 +829,9 @@ ao_config_tracker_set(void)  	ao_config.tracker_motion = m;  	ao_config.tracker_interval = i;  	_ao_config_edit_finish(); +#if HAS_TELEMETRY +	ao_telemetry_reset_interval(); +#endif  }  #endif /* HAS_TRACKER */ diff --git a/src/kernel/ao_gps_print.c b/src/kernel/ao_gps_print.c index d26021da..6d9ee346 100644 --- a/src/kernel/ao_gps_print.c +++ b/src/kernel/ao_gps_print.c @@ -20,8 +20,8 @@  #endif  #include "ao_telem.h" -#ifndef AO_TELEMETRY_LOCATION_ALTITUDE -#define AO_TELEMETRY_LOCATION_ALTITUDE(l)	((l)->altitude) +#ifndef AO_GPS_ORIG_ALTITUDE +#define AO_GPS_ORIG_ALTITUDE(l)	((l)->altitude)  #endif  void @@ -46,7 +46,7 @@ ao_gps_print(__xdata struct ao_gps_orig *gps_data) __reentrant  	       AO_TELEM_GPS_ALTITUDE " %d ",  	       (long) gps_data->latitude,  	       (long) gps_data->longitude, -	       AO_TELEMETRY_LOCATION_ALTITUDE(gps_data)); +	       AO_GPS_ORIG_ALTITUDE(gps_data));  	if (gps_data->flags & AO_GPS_DATE_VALID)  		printf(AO_TELEM_GPS_YEAR " %d " diff --git a/src/kernel/ao_log.h b/src/kernel/ao_log.h index c13a2580..f86fb359 100644 --- a/src/kernel/ao_log.h +++ b/src/kernel/ao_log.h @@ -43,11 +43,12 @@ extern __pdata enum ao_flight_state ao_log_state;  #define AO_LOG_FORMAT_TINY		2	/* two byte state/baro records */  #define AO_LOG_FORMAT_TELEMETRY		3	/* 32 byte ao_telemetry records */  #define AO_LOG_FORMAT_TELESCIENCE	4	/* 32 byte typed telescience records */ -#define AO_LOG_FORMAT_TELEMEGA		5	/* 32 byte typed telemega records */ +#define AO_LOG_FORMAT_TELEMEGA_OLD	5	/* 32 byte typed telemega records */  #define AO_LOG_FORMAT_EASYMINI		6	/* 16-byte MS5607 baro only, 3.0V supply */  #define AO_LOG_FORMAT_TELEMETRUM	7	/* 16-byte typed telemetrum records */  #define AO_LOG_FORMAT_TELEMINI		8	/* 16-byte MS5607 baro only, 3.3V supply */  #define AO_LOG_FORMAT_TELEGPS		9	/* 32 byte telegps records */ +#define AO_LOG_FORMAT_TELEMEGA		10	/* 32 byte typed telemega records with 32 bit gyro cal */  #define AO_LOG_FORMAT_NONE		127	/* No log at all */  extern __code uint8_t ao_log_format; @@ -215,10 +216,22 @@ struct ao_log_mega {  			int16_t		ground_accel_along;	/* 12 */  			int16_t		ground_accel_across;	/* 14 */  			int16_t		ground_accel_through;	/* 16 */ +			int16_t		pad_18;			/* 18 */ +			int32_t		ground_roll;		/* 20 */ +			int32_t		ground_pitch;		/* 24 */ +			int32_t		ground_yaw;		/* 28 */ +		} flight;					/* 32 */ +		struct { +			uint16_t	flight;			/* 4 */ +			int16_t		ground_accel;		/* 6 */ +			uint32_t	ground_pres;		/* 8 */ +			int16_t		ground_accel_along;	/* 12 */ +			int16_t		ground_accel_across;	/* 14 */ +			int16_t		ground_accel_through;	/* 16 */  			int16_t		ground_roll;		/* 18 */  			int16_t		ground_pitch;		/* 20 */  			int16_t		ground_yaw;		/* 22 */ -		} flight;					/* 24 */ +		} flight_old;					/* 24 */  		/* AO_LOG_STATE */  		struct {  			uint16_t	state; diff --git a/src/kernel/ao_monitor.c b/src/kernel/ao_monitor.c index 2d75c41c..cba0d80a 100644 --- a/src/kernel/ao_monitor.c +++ b/src/kernel/ao_monitor.c @@ -94,9 +94,18 @@ __xdata struct ao_task ao_monitor_blink_task;  void  ao_monitor_blink(void)  { +#ifdef AO_MONITOR_BAD +	uint8_t		*recv; +#endif  	for (;;) {  		ao_sleep(DATA_TO_XDATA(&ao_monitor_head)); -		ao_led_for(AO_MONITOR_LED, AO_MS_TO_TICKS(100)); +#ifdef AO_MONITOR_BAD +		recv = (uint8_t *) &ao_monitor_ring[ao_monitor_ring_prev(ao_monitor_head)]; +		if (ao_monitoring && !(recv[ao_monitoring + 1] & AO_RADIO_STATUS_CRC_OK)) +			ao_led_for(AO_MONITOR_BAD, AO_MS_TO_TICKS(100)); +		else +#endif +			ao_led_for(AO_MONITOR_LED, AO_MS_TO_TICKS(100));  	}  }  #endif diff --git a/src/kernel/ao_serial.h b/src/kernel/ao_serial.h index baf213c0..dbc9f8e4 100644 --- a/src/kernel/ao_serial.h +++ b/src/kernel/ao_serial.h @@ -34,6 +34,9 @@ ao_serial0_getchar(void);  int  _ao_serial0_pollchar(void); +uint8_t +_ao_serial0_sleep(void); +  void  ao_serial0_putchar(char c); @@ -54,6 +57,9 @@ ao_serial1_getchar(void);  int  _ao_serial1_pollchar(void); +uint8_t +_ao_serial1_sleep(void); +  void  ao_serial1_putchar(char c); @@ -74,6 +80,9 @@ ao_serial2_getchar(void);  int  _ao_serial2_pollchar(void); +uint8_t +_ao_serial2_sleep(void); +  void  ao_serial2_putchar(char c); @@ -94,6 +103,9 @@ ao_serial3_getchar(void);  int  _ao_serial3_pollchar(void); +uint8_t +_ao_serial3_sleep(void); +  void  ao_serial3_putchar(char c); diff --git a/src/kernel/ao_stdio.c b/src/kernel/ao_stdio.c index 99118137..1d65fcf5 100644 --- a/src/kernel/ao_stdio.c +++ b/src/kernel/ao_stdio.c @@ -142,10 +142,8 @@ ao_add_stdio(int (*_pollchar)(void),  	     void (*putchar)(char),  	     void (*flush)(void)) __reentrant  { -#if AO_NUM_STDIOS > 1  	if (ao_num_stdios == AO_NUM_STDIOS)  		ao_panic(AO_PANIC_STDIO); -#endif  	ao_stdios[ao_num_stdios]._pollchar = _pollchar;  	ao_stdios[ao_num_stdios].putchar = putchar;  	ao_stdios[ao_num_stdios].flush = flush; diff --git a/src/kernel/ao_telemetry.c b/src/kernel/ao_telemetry.c index 27306a34..e2197f7a 100644 --- a/src/kernel/ao_telemetry.c +++ b/src/kernel/ao_telemetry.c @@ -19,19 +19,32 @@  #include "ao_log.h"  #include "ao_product.h" -#ifndef HAS_RDF -#define HAS_RDF 1 -#endif -  static __pdata uint16_t ao_telemetry_interval;  #if HAS_RADIO_RATE  static __xdata uint16_t ao_telemetry_desired_interval;  #endif +/* TeleMetrum v1.0 just doesn't have enough space to + * manage the more complicated telemetry scheduling, so + * it loses the ability to disable telem/rdf separately + */ + +#if defined(TELEMETRUM_V_1_0) +#define SIMPLIFY +#endif + +#ifdef SIMPLIFY +#define ao_telemetry_time time +#define RDF_SPACE	__pdata +#else +#define RDF_SPACE	__xdata +static __pdata uint16_t ao_telemetry_time; +#endif +  #if HAS_RDF -static __pdata uint8_t ao_rdf = 0; -static __pdata uint16_t ao_rdf_time; +static RDF_SPACE uint8_t ao_rdf = 0; +static RDF_SPACE uint16_t ao_rdf_time;  #endif  #if HAS_APRS @@ -120,7 +133,9 @@ ao_send_mega_sensor(void)  	telemetry.generic.tick = packet->tick;  	telemetry.generic.type = AO_TELEMETRY_MEGA_SENSOR; +#if HAS_MPU6000  	telemetry.mega_sensor.orient = ao_sample_orient; +#endif  	telemetry.mega_sensor.accel = ao_data_accel(packet);  	telemetry.mega_sensor.pres = ao_data_pres(packet);  	telemetry.mega_sensor.temp = ao_data_temp(packet); @@ -269,30 +284,6 @@ ao_send_mini(void)  #endif /* AO_SEND_MINI */ -#ifdef AO_SEND_ALL_BARO -static uint8_t		ao_baro_sample; - -static void -ao_send_baro(void) -{ -	uint8_t		sample = ao_sample_data; -	uint8_t		samples = (sample - ao_baro_sample) & (AO_DATA_RING - 1); - -	if (samples > 12) { -		ao_baro_sample = (ao_baro_sample + (samples - 12)) & (AO_DATA_RING - 1); -		samples = 12; -	} -	telemetry.generic.tick = ao_data_ring[sample].tick; -	telemetry.generic.type = AO_TELEMETRY_BARO; -	telemetry.baro.samples = samples; -	for (sample = 0; sample < samples; sample++) { -		telemetry.baro.baro[sample] = ao_data_ring[ao_baro_sample].adc.pres; -		ao_baro_sample = ao_data_ring_next(ao_baro_sample); -	} -	ao_radio_send(&telemetry, sizeof (telemetry)); -} -#endif -  static __pdata int8_t ao_telemetry_config_max;  static __pdata int8_t ao_telemetry_config_cur; @@ -332,6 +323,7 @@ ao_send_configuration(void)  #if HAS_GPS +static __pdata int8_t ao_telemetry_gps_max;  static __pdata int8_t ao_telemetry_loc_cur;  static __pdata int8_t ao_telemetry_sat_cur; @@ -348,7 +340,7 @@ ao_send_location(void)  		telemetry.location.tick = ao_gps_tick;  		ao_mutex_put(&ao_gps_mutex);  		ao_radio_send(&telemetry, sizeof (telemetry)); -		ao_telemetry_loc_cur = ao_telemetry_config_max; +		ao_telemetry_loc_cur = ao_telemetry_gps_max;  	}  } @@ -365,7 +357,7 @@ ao_send_satellite(void)  		       AO_MAX_GPS_TRACKING * sizeof (struct ao_telemetry_satellite_info));  		ao_mutex_put(&ao_gps_mutex);  		ao_radio_send(&telemetry, sizeof (telemetry)); -		ao_telemetry_sat_cur = ao_telemetry_config_max; +		ao_telemetry_sat_cur = ao_telemetry_gps_max;  	}  }  #endif @@ -411,6 +403,7 @@ ao_telemetry(void)  		while (ao_telemetry_interval == 0)  			ao_sleep(&telemetry);  		time = ao_time(); +		ao_telemetry_time = time;  #if HAS_RDF  		ao_rdf_time = time;  #endif @@ -418,79 +411,85 @@ ao_telemetry(void)  		ao_aprs_time = time;  #endif  		while (ao_telemetry_interval) { -#if HAS_APRS +			time = ao_time() + AO_SEC_TO_TICKS(100); +#ifndef SIMPLIFY  			if (!(ao_config.radio_enable & AO_RADIO_DISABLE_TELEMETRY))  #endif  			{ -#ifdef AO_SEND_ALL_BARO -				ao_send_baro(); +#ifndef SIMPLIFY +				if ( (int16_t) (ao_time() - ao_telemetry_time) >= 0)  #endif - -#if HAS_FLIGHT +				{ +					ao_telemetry_time = ao_time() + ao_telemetry_interval;  # ifdef AO_SEND_MEGA -				ao_send_mega_sensor(); -				ao_send_mega_data(); +					ao_send_mega_sensor(); +					ao_send_mega_data();  # endif  # ifdef AO_SEND_METRUM -				ao_send_metrum_sensor(); -				ao_send_metrum_data(); +					ao_send_metrum_sensor(); +					ao_send_metrum_data();  # endif  # ifdef AO_SEND_MINI -				ao_send_mini(); +					ao_send_mini();  # endif  # ifdef AO_TELEMETRY_SENSOR -				ao_send_sensor(); +					ao_send_sensor();  # endif -#endif /* HAS_FLIGHT */ -  #if HAS_COMPANION -				if (ao_companion_running) -					ao_send_companion(); +					if (ao_companion_running) +						ao_send_companion();  #endif -				ao_send_configuration();  #if HAS_GPS -				ao_send_location(); -				ao_send_satellite(); +					ao_send_location(); +					ao_send_satellite(); +#endif +					ao_send_configuration(); +				} +#ifndef SIMPLIFY +				time = ao_telemetry_time;  #endif  			} -#ifndef AO_SEND_ALL_BARO  #if HAS_RDF -			if (ao_rdf && -#if HAS_APRS -			    !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) && -#endif /* HAS_APRS */ -			    (int16_t) (ao_time() - ao_rdf_time) >= 0) +			if (ao_rdf +#ifndef SIMPLIFY +			    && !(ao_config.radio_enable & AO_RADIO_DISABLE_RDF) +#endif +				)  			{ +				if ((int16_t) (ao_time() - ao_rdf_time) >= 0) {  #if HAS_IGNITE_REPORT -				uint8_t	c; -#endif /* HAS_IGNITE_REPORT */ -				ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS; +					uint8_t	c; +#endif +					ao_rdf_time = ao_time() + AO_RDF_INTERVAL_TICKS;  #if HAS_IGNITE_REPORT -				if (ao_flight_state == ao_flight_pad && (c = ao_report_igniter())) -					ao_radio_continuity(c); -				else -#endif /* HAS_IGNITE_REPORT*/ -					ao_radio_rdf(); +					if (ao_flight_state == ao_flight_pad && (c = ao_report_igniter())) +						ao_radio_continuity(c); +					else +#endif +						ao_radio_rdf(); +				} +#ifndef SIMPLIFY +				if ((int16_t) (time - ao_rdf_time) > 0) +					time = ao_rdf_time; +#endif  			}  #endif /* HAS_RDF */  #if HAS_APRS -			if (ao_config.aprs_interval != 0 && -			    (int16_t) (ao_time() - ao_aprs_time) >= 0) -			{ -				ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval); -				ao_aprs_send(); +			if (ao_config.aprs_interval != 0) { +				if ((int16_t) (ao_time() - ao_aprs_time) >= 0) { +					ao_aprs_time = ao_time() + AO_SEC_TO_TICKS(ao_config.aprs_interval); +					ao_aprs_send(); +				} +				if ((int16_t) (time - ao_aprs_time) > 0) +					time = ao_aprs_time;  			}  #endif /* HAS_APRS */ -#endif /* !AO_SEND_ALL_BARO */ -			time += ao_telemetry_interval;  			delay = time - ao_time();  			if (delay > 0) {  				ao_alarm(delay);  				ao_sleep(&telemetry);  				ao_clear_alarm();  			} -			else -				time = ao_time();  		}  	}  } @@ -547,21 +546,31 @@ ao_telemetry_set_interval(uint16_t interval)  	ao_telemetry_companion_cur = cur;  #endif -	ao_telemetry_config_max = AO_SEC_TO_TICKS(5) / interval; -#if HAS_COMPANION -	if (ao_telemetry_config_max > cur) -		cur++; -	ao_telemetry_config_cur = cur; -#endif -  #if HAS_GPS -	if (ao_telemetry_config_max > cur) +	ao_telemetry_gps_max = AO_SEC_TO_TICKS(1) / interval; +	if (ao_telemetry_gps_max > cur)  		cur++;  	ao_telemetry_loc_cur = cur; -	if (ao_telemetry_config_max > cur) +	if (ao_telemetry_gps_max > cur)  		cur++;  	ao_telemetry_sat_cur = cur;  #endif + +	ao_telemetry_config_max = AO_SEC_TO_TICKS(5) / interval; +	if (ao_telemetry_config_max > cur) +		cur++; +	ao_telemetry_config_cur = cur; + +#ifndef SIMPLIFY +	ao_telemetry_time =  +#if HAS_RDF +		ao_rdf_time = +#endif +#if HAS_APRS +		ao_aprs_time = +#endif +		ao_time(); +#endif  	ao_wakeup(&telemetry);  } diff --git a/src/kernel/ao_telemetry.h b/src/kernel/ao_telemetry.h index 83d432cf..711e0d36 100644 --- a/src/kernel/ao_telemetry.h +++ b/src/kernel/ao_telemetry.h @@ -116,12 +116,16 @@ struct ao_telemetry_location {  	/* 32 */  }; -#if HAS_GPS -  #ifndef HAS_WIDE_GPS  #define HAS_WIDE_GPS	1  #endif +#ifdef HAS_TELEMETRY +#ifndef HAS_RDF +#define HAS_RDF		1 +#endif +#endif +  #if HAS_WIDE_GPS  typedef int32_t		gps_alt_t;  #define AO_TELEMETRY_LOCATION_ALTITUDE(l) 	(((gps_alt_t) (l)->altitude_high << 16) | ((l)->altitude_low)) @@ -135,8 +139,6 @@ typedef int16_t		gps_alt_t;  						  (l)->altitude_low = (a)))  #endif /* HAS_WIDE_GPS */ -#endif /* HAS_GPS */ -  #define AO_TELEMETRY_SATELLITE		0x06  struct ao_telemetry_satellite_info { diff --git a/src/kernel/ao_tracker.c b/src/kernel/ao_tracker.c index 9b007af8..962f145d 100644 --- a/src/kernel/ao_tracker.c +++ b/src/kernel/ao_tracker.c @@ -132,7 +132,7 @@ ao_tracker(void)  					if (height < 0)  						height = -height; -					if (ao_tracker_force_telem) +					if (ao_tracker_force_telem > 1)  						printf("head %d ring %d ground_distance %d height %d\n", gps_head, ring, ground_distance, height);  					if (ground_distance > ao_config.tracker_motion ||  					    height > (ao_config.tracker_motion << 1)) @@ -141,7 +141,7 @@ ao_tracker(void)  						break;  					}  				} -				if (ao_tracker_force_telem) { +				if (ao_tracker_force_telem > 1) {  					printf ("moving %d started %d\n", moving, log_started);  					flush();  				} @@ -191,11 +191,9 @@ static struct ao_task ao_tracker_task;  static void  ao_tracker_set_telem(void)  { -	uint8_t	telem;  	ao_cmd_hex(); -	telem = ao_cmd_lex_i;  	if (ao_cmd_status == ao_cmd_success) -		ao_tracker_force_telem = telem; +		ao_tracker_force_telem = ao_cmd_lex_i;  	ao_cmd_status = ao_cmd_success;  	printf ("flight: %d\n", ao_flight_number);  	printf ("force_telem: %d\n", ao_tracker_force_telem); @@ -211,7 +209,7 @@ ao_tracker_set_telem(void)  }  static const struct ao_cmds ao_tracker_cmds[] = { -	{ ao_tracker_set_telem,	"t <d>\0Set telem on USB" }, +	{ ao_tracker_set_telem,	"t <d>\0Set telem on USB (0 off, 1 on, 2 dbg)" },  	{ 0, NULL },  }; diff --git a/src/lpc/ao_arch.h b/src/lpc/ao_arch.h index 5fbb8dfa..42faf06f 100644 --- a/src/lpc/ao_arch.h +++ b/src/lpc/ao_arch.h @@ -130,12 +130,15 @@ ao_serial_init(void);  /* SPI definitions */  #define AO_SPI_SPEED_12MHz		4 +#define AO_SPI_SPEED_8MHz		6  #define AO_SPI_SPEED_6MHz		8  #define AO_SPI_SPEED_4MHz		12  #define AO_SPI_SPEED_2MHz		24  #define AO_SPI_SPEED_1MHz		48  #define AO_SPI_SPEED_500kHz		96  #define AO_SPI_SPEED_250kHz		192 +#define AO_SPI_SPEED_125kHz		384 +#define AO_SPI_SPEED_62500Hz		768  #define AO_SPI_SPEED_FAST	AO_SPI_SPEED_12MHz diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index 21a7a8e5..fbe641d8 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -30,8 +30,19 @@  #define ao_gpio_get(port, bit, pin) 	(lpc_gpio.byte[lpc_all_bit(port,bit)]) +#define PORT0_JTAG_REGS	((1 << 11) | (1 << 12) | (1 << 14)) + +static inline void lpc_set_gpio(int port, int bit) { +	if (port == 0 && (1 << bit) & (PORT0_JTAG_REGS)) { +		vuint32_t *_ioconf = &lpc_ioconf.pio0_0 + ((port)*24+(bit)); + +		*_ioconf = (*_ioconf & ~LPC_IOCONF_FUNC_MASK) | LPC_IOCONF_FUNC_PIO0_11; +	} +} +  #define ao_enable_output(port,bit,pin,v) do {			\  		ao_enable_port(port);				\ +		lpc_set_gpio(port,bit);				\  		ao_gpio_set(port, bit, pin, v);			\  		lpc_gpio.dir[port] |= (1 << bit);		\  	} while (0) @@ -52,6 +63,7 @@  #define ao_enable_input(port,bit,mode) do {				\  		ao_enable_port(port);					\ +		lpc_set_gpio(port,bit);					\  		lpc_gpio.dir[port] &= ~(1 << bit);			\  		ao_gpio_set_mode(port,bit,mode);			\  	} while (0) @@ -201,7 +213,7 @@ void  ao_spi_put(uint8_t spi_index);  void -ao_spi_send(void *block, uint16_t len, uint8_t spi_index); +ao_spi_send(const void *block, uint16_t len, uint8_t spi_index);  void  ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); @@ -210,9 +222,7 @@ void  ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);  void -ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index); - -extern uint16_t	ao_spi_speed[LPC_NUM_SPI]; +ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index);  void  ao_spi_init(void); diff --git a/src/lpc/ao_led_lpc.c b/src/lpc/ao_led_lpc.c index d983437c..a0b293b9 100644 --- a/src/lpc/ao_led_lpc.c +++ b/src/lpc/ao_led_lpc.c @@ -59,6 +59,15 @@ void  ao_led_init(AO_PORT_TYPE enable)  {  	ao_led_enable = enable; -	lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_GPIO); +	ao_enable_port(LED_PORT); +	if (LED_PORT == 0) { +		if (enable & (1 << 11)) +			lpc_ioconf.pio0_11 = LPC_IOCONF_FUNC_PIO0_11 | (1 << LPC_IOCONF_ADMODE); +		if (enable & (1 << 12)) +			lpc_ioconf.pio0_12 = LPC_IOCONF_FUNC_PIO0_12 | (1 << LPC_IOCONF_ADMODE); +		if (enable & (1 << 14)) +			lpc_ioconf.pio0_14 = LPC_IOCONF_FUNC_PIO0_14 | (1 << LPC_IOCONF_ADMODE); +	}  	lpc_gpio.dir[LED_PORT] |= enable; +	ao_led_off(enable);  } diff --git a/src/lpc/ao_spi_lpc.c b/src/lpc/ao_spi_lpc.c index e72b8286..f091c89c 100644 --- a/src/lpc/ao_spi_lpc.c +++ b/src/lpc/ao_spi_lpc.c @@ -21,34 +21,27 @@ static uint8_t		ao_spi_mutex[LPC_NUM_SPI];  static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 }; -#define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF) -#define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE) -  #define spi_loop(len, put, get) do {					\  		while (len--) {						\ -			/* Wait for space in the fifo */		\ -			while (tx_busy(lpc_ssp))			\ -				;					\ -									\  			/* send a byte */				\  			lpc_ssp->dr = put;				\ -									\ -			/* Wait for byte to appear in the fifo */	\ -			while (rx_busy(lpc_ssp))			\ +			/* wait for the received byte to appear */	\ +			while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) == 0) \  				;					\ -									\ -			/* recv a byte */				\ +			/* receive a byte */				\  			get lpc_ssp->dr;				\  		}							\ +		/* Wait for the SSP to go idle (it already should be) */ \ +		while (lpc_ssp->sr & (1 << LPC_SSP_SR_BSY));		\  	} while (0)  void -ao_spi_send(void *block, uint16_t len, uint8_t id) +ao_spi_send(const void *block, uint16_t len, uint8_t id)  { -	uint8_t	*b = block;  	struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; +	const uint8_t	*o = block; -	spi_loop(len, *b++, (void)); +	spi_loop(len, *o++, (void));  }  void @@ -62,18 +55,18 @@ ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)  void  ao_spi_recv(void *block, uint16_t len, uint8_t id)  { -	uint8_t	*b = block;  	struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; +	uint8_t *i = block; -	spi_loop(len, 0xff, *b++ =); +	spi_loop(len, 0xff, *i++ =);  }  void -ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id) +ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id)  { -	uint8_t	*o = out; -	uint8_t	*i = in;  	struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id]; +	const uint8_t *o = out; +	uint8_t *i = in;  	spi_loop(len, *o++, *i++ =);  } @@ -84,7 +77,7 @@ ao_spi_get(uint8_t id, uint32_t speed)  	struct lpc_ssp	*lpc_ssp = ao_lpc_ssp[id];  	ao_mutex_get(&ao_spi_mutex[id]); -	 +  	/* Set the clock prescale */  	lpc_ssp->cpsr = speed;  } @@ -101,6 +94,11 @@ ao_spi_channel_init(uint8_t id)  	struct lpc_ssp	*lpc_ssp = ao_lpc_ssp[id];  	uint8_t	d; +	/* Clear interrupt registers */ +	lpc_ssp->imsc = 0; +	lpc_ssp->ris = 0; +	lpc_ssp->mis = 0; +  	lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |  			(LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |  			(0 << LPC_SSP_CR0_CPOL) | @@ -151,7 +149,7 @@ ao_spi_init(void)  	lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);  	lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);  	ao_spi_channel_init(0); -#endif			    +#endif  #if HAS_SPI_1 @@ -190,7 +188,7 @@ ao_spi_init(void)  #ifndef HAS_MOSI1  #error "No pin specified for MOSI1"  #endif -		 +  	/* Enable the device */  	lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1); diff --git a/src/lpc/ao_usb_lpc.c b/src/lpc/ao_usb_lpc.c index 12f5d8e6..0dfaece4 100644 --- a/src/lpc/ao_usb_lpc.c +++ b/src/lpc/ao_usb_lpc.c @@ -80,14 +80,12 @@ static uint8_t	*ao_usb_ep0_setup_buffer;  static uint8_t	*ao_usb_ep0_rx_buffer;  /* Pointer to bulk data tx/rx buffers in USB memory */ -static uint8_t	*ao_usb_in_tx_buffer; -static uint8_t	*ao_usb_out_rx_buffer; - -/* Our data buffers */ -static uint8_t	ao_usb_tx_buffer[AO_USB_IN_SIZE]; +static uint8_t	*ao_usb_in_tx_buffer[2]; +static uint8_t	ao_usb_in_tx_cur;  static uint8_t	ao_usb_tx_count; -static uint8_t	ao_usb_rx_buffer[AO_USB_OUT_SIZE]; +static uint8_t	*ao_usb_out_rx_buffer[2]; +static uint8_t	ao_usb_out_rx_cur;  static uint8_t	ao_usb_rx_count, ao_usb_rx_pos;  extern struct lpc_usb_endpoint lpc_usb_endpoint; @@ -234,15 +232,15 @@ ao_usb_ep0_in(void)  }  static inline vuint32_t * -ao_usb_epn_out(uint8_t n) +ao_usb_epn_out(uint8_t n, uint8_t i)  { -	return &lpc_usb_endpoint.epn[n-1].out[0]; +	return &lpc_usb_endpoint.epn[n-1].out[i];  }  static inline vuint32_t * -ao_usb_epn_in(uint8_t n) +ao_usb_epn_in(uint8_t n, uint8_t i)  { -	return &lpc_usb_endpoint.epn[n-1].in[0]; +	return &lpc_usb_endpoint.epn[n-1].in[i];  }  #if UNUSED @@ -256,26 +254,26 @@ ao_usb_set_epn_in(uint8_t n, uint8_t *addr, uint16_t nbytes)  static void  ao_usb_set_epn_out(uint8_t n, uint8_t *addr, uint16_t nbytes)  { -	ao_usb_set_ep(ao_usb_epn_out(n), addr, nbytes); +	ao_usb_set_ep(ao_usb_epn_out(n, 0), addr, nbytes);  }  static inline uint16_t  ao_usb_epn_out_count(uint8_t n)  { -	return ao_usb_ep_count(ao_usb_epn_out(n)); +	return ao_usb_ep_count(ao_usb_epn_out(n, 0));  }  static inline uint16_t  ao_usb_epn_in_count(uint8_t n)  { -	return ao_usb_ep_count(ao_usb_epn_in(n)); +	return ao_usb_ep_count(ao_usb_epn_in(n, 0));  }  static uint8_t *  ao_usb_enable_ep(vuint32_t *ep, uint16_t nbytes, uint16_t set_nbytes)  {  	uint8_t	*addr = ao_usb_alloc_sram(nbytes); -	 +  	ao_usb_set_ep(ep, addr, set_nbytes);  	return addr;  } @@ -294,28 +292,34 @@ ao_usb_disable_ep(vuint32_t *ep)  }  static void -ao_usb_enable_epn(uint8_t n, uint16_t out_bytes, uint8_t **out_addr, uint16_t in_bytes, uint8_t **in_addr) +ao_usb_enable_epn(uint8_t n, +		  uint16_t out_bytes, uint8_t *out_addrs[2], +		  uint16_t in_bytes, uint8_t *in_addrs[2])  {  	uint8_t	*addr; -	addr = ao_usb_enable_ep(ao_usb_epn_out(n), out_bytes, out_bytes); -	if (out_addr) -		*out_addr = addr; -	ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); +	addr = ao_usb_enable_ep(ao_usb_epn_out(n, 0), out_bytes * 2, out_bytes); +	if (out_addrs) { +		out_addrs[0] = addr; +		out_addrs[1] = addr + out_bytes; +	} +	ao_usb_disable_ep(ao_usb_epn_out(n, 1)); -	addr = ao_usb_enable_ep(ao_usb_epn_in(n), in_bytes, 0); -	if (in_addr) -		*in_addr = addr; -	ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); +	addr = ao_usb_enable_ep(ao_usb_epn_in(n, 0), in_bytes * 2, 0); +	if (in_addrs) { +		in_addrs[0] = addr; +		in_addrs[1] = addr + in_bytes; +	} +	ao_usb_disable_ep(ao_usb_epn_in(n, 1));  }  static void  ao_usb_disable_epn(uint8_t n)  { -	ao_usb_disable_ep(ao_usb_epn_out(n)); -	ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].out[1]); -	ao_usb_disable_ep(ao_usb_epn_in(n)); -	ao_usb_disable_ep(&lpc_usb_endpoint.epn[n-1].in[1]); +	ao_usb_disable_ep(ao_usb_epn_out(n, 0)); +	ao_usb_disable_ep(ao_usb_epn_out(n, 1)); +	ao_usb_disable_ep(ao_usb_epn_in(n, 0)); +	ao_usb_disable_ep(ao_usb_epn_in(n, 1));  }  static void @@ -362,12 +366,18 @@ ao_usb_set_configuration(void)  	/* Set up the INT end point */  	ao_usb_enable_epn(AO_USB_INT_EP, 0, NULL, 0, NULL); -	 +  	/* Set up the OUT end point */ -	ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, &ao_usb_out_rx_buffer, 0, NULL); +	ao_usb_enable_epn(AO_USB_OUT_EP, AO_USB_OUT_SIZE, ao_usb_out_rx_buffer, 0, NULL); + +	/* Set the current RX pointer to the *other* buffer so that when buffer 0 gets +	 * data, we'll switch to it and pull bytes from there +	 */ +	ao_usb_out_rx_cur = 1;  	/* Set up the IN end point */ -	ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, &ao_usb_in_tx_buffer); +	ao_usb_enable_epn(AO_USB_IN_EP, 0, NULL, AO_USB_IN_SIZE, ao_usb_in_tx_buffer); +	ao_usb_in_tx_cur = 0;  	ao_usb_running = 1;  } @@ -716,8 +726,8 @@ _ao_usb_in_send(void)  	ao_usb_in_pending = 1;  	if (ao_usb_tx_count != AO_USB_IN_SIZE)  		ao_usb_in_flushed = 1; -	memcpy(ao_usb_in_tx_buffer, ao_usb_tx_buffer, ao_usb_tx_count); -	ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP), ao_usb_in_tx_buffer, ao_usb_tx_count); +	ao_usb_set_ep(ao_usb_epn_in(AO_USB_IN_EP, 0), ao_usb_in_tx_buffer[ao_usb_in_tx_cur], ao_usb_tx_count); +	ao_usb_in_tx_cur = 1 - ao_usb_in_tx_cur;  	ao_usb_tx_count = 0;  	_tx_dbg0("in_send end");  } @@ -771,7 +781,7 @@ ao_usb_putchar(char c)  	_ao_usb_in_wait();  	ao_usb_in_flushed = 0; -	ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; +	ao_usb_in_tx_buffer[ao_usb_in_tx_cur][ao_usb_tx_count++] = (uint8_t) c;  	/* Send the packet when full */  	if (ao_usb_tx_count == AO_USB_IN_SIZE) { @@ -792,13 +802,12 @@ _ao_usb_out_recv(void)  	_rx_dbg1("out_recv count", ao_usb_rx_count);  	debug ("recv %d\n", ao_usb_rx_count); -	debug_data("Fill OUT len %d:", ao_usb_rx_count); -	memcpy(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count); -	debug_data("\n"); +	debug_data("Fill OUT len %d\n", ao_usb_rx_count);  	ao_usb_rx_pos = 0; +	ao_usb_out_rx_cur = 1 - ao_usb_out_rx_cur;  	/* ACK the packet */ -	ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer, AO_USB_OUT_SIZE); +	ao_usb_set_epn_out(AO_USB_OUT_EP, ao_usb_out_rx_buffer[1-ao_usb_out_rx_cur], AO_USB_OUT_SIZE);  }  int @@ -823,7 +832,7 @@ _ao_usb_pollchar(void)  	}  	/* Pull a character out of the fifo */ -	c = ao_usb_rx_buffer[ao_usb_rx_pos++]; +	c = ao_usb_out_rx_buffer[ao_usb_out_rx_cur][ao_usb_rx_pos++];  	return c;  } @@ -897,7 +906,7 @@ ao_usb_enable(void)  	/* Enable USB PHY */  	lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPAD_PD); -	 +  	/* Turn on USB PLL */  	lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_USBPLL_PD); @@ -1044,7 +1053,7 @@ static void _dbg(int line, char *msg, uint32_t value)  	dbg[dbg_i].primask = primask;  #if TX_DBG  	dbg[dbg_i].in_count = in_count; -	dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP); +	dbg[dbg_i].in_ep = *ao_usb_epn_in(AO_USB_IN_EP, 0);  	dbg[dbg_i].in_pending = ao_usb_in_pending;  	dbg[dbg_i].tx_count = ao_usb_tx_count;  	dbg[dbg_i].in_flushed = ao_usb_in_flushed; @@ -1053,7 +1062,7 @@ static void _dbg(int line, char *msg, uint32_t value)  	dbg[dbg_i].rx_count = ao_usb_rx_count;  	dbg[dbg_i].rx_pos = ao_usb_rx_pos;  	dbg[dbg_i].out_avail = ao_usb_out_avail; -	dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP); +	dbg[dbg_i].out_ep = *ao_usb_epn_out(AO_USB_OUT_EP, 0);  #endif  	if (++dbg_i == NUM_USB_DBG)  		dbg_i = 0; diff --git a/src/microsplash/.gitignore b/src/microsplash/.gitignore new file mode 100644 index 00000000..5f6fe3b2 --- /dev/null +++ b/src/microsplash/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +microsplash-* diff --git a/src/microwater/Makefile b/src/microsplash/Makefile index a49cda4b..10cb825b 100644 --- a/src/microwater/Makefile +++ b/src/microsplash/Makefile @@ -48,14 +48,14 @@ INC=\  	altitude-pa.h  IDPRODUCT=0 -PRODUCT=MicroWater-v0.1 +PRODUCT=MicroSplash-v0.1  PRODUCT_DEF=-DMICROPEAK  CFLAGS = $(PRODUCT_DEF) -I. -I../attiny -I../kernel -I.. -I../drivers -I../product  CFLAGS += -g -mmcu=$(MCU) -Wall -Wstrict-prototypes -O2 -mcall-prologues -DATTINY  NICKLE=nickle -PROG=microwater-v0.1 +PROG=microsplash-v1.0  SRC=$(ALTOS_SRC)  OBJ=$(SRC:.c=.o) diff --git a/src/microwater/ao_pins.h b/src/microsplash/ao_pins.h index 37885ec2..37885ec2 100644 --- a/src/microwater/ao_pins.h +++ b/src/microsplash/ao_pins.h diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 7ad3b4b8..42f1a2e5 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -74,7 +74,7 @@ void  ao_spi_put(uint8_t spi_index);  void -ao_spi_send(void *block, uint16_t len, uint8_t spi_index); +ao_spi_send(const void *block, uint16_t len, uint8_t spi_index);  void  ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); diff --git a/src/stm/ao_led.c b/src/stm/ao_led.c index 0acab106..9b61cf62 100644 --- a/src/stm/ao_led.c +++ b/src/stm/ao_led.c @@ -86,7 +86,7 @@ ao_led_for(uint16_t colors, uint16_t ticks) __reentrant  		stm_moder_set(port, bit, STM_MODER_OUTPUT);		\  		stm_otyper_set(port, bit, STM_OTYPER_PUSH_PULL);	\  	} while (0) -	 +  void  ao_led_init(uint16_t enable)  { diff --git a/src/stm/ao_serial_stm.c b/src/stm/ao_serial_stm.c index 2133c584..2568cf43 100644 --- a/src/stm/ao_serial_stm.c +++ b/src/stm/ao_serial_stm.c @@ -63,7 +63,7 @@ int  _ao_usart_pollchar(struct ao_stm_usart *usart)  {  	int	c; -	 +  	if (ao_fifo_empty(usart->rx_fifo))  		c = AO_READ_AGAIN;  	else { @@ -85,6 +85,12 @@ ao_usart_getchar(struct ao_stm_usart *usart)  	return (char) c;  } +static inline uint8_t +_ao_usart_sleep(struct ao_stm_usart *usart) +{ +	return ao_sleep(&usart->rx_fifo); +} +  void  ao_usart_putchar(struct ao_stm_usart *usart, char c)  { @@ -179,6 +185,13 @@ ao_usart_init(struct ao_stm_usart *usart)  	ao_usart_set_speed(usart, AO_SERIAL_SPEED_9600);  } +void +ao_usart_set_flow(struct ao_stm_usart *usart) +{ +	usart->reg->cr3 |= ((1 << STM_USART_CR3_CTSE) | +			    (1 << STM_USART_CR3_RTSE)); +} +  #if HAS_SERIAL_1  struct ao_stm_usart ao_stm_usart1; @@ -203,6 +216,18 @@ _ao_serial1_pollchar(void)  	return _ao_usart_pollchar(&ao_stm_usart1);  } +uint8_t +_ao_serial1_sleep(void) +{ +	return _ao_usart_sleep(&ao_stm_usart1); +} + +void +ao_serial1_drain(void) +{ +	ao_usart_drain(&ao_stm_usart1); +} +  void  ao_serial1_set_speed(uint8_t speed)  { @@ -234,6 +259,18 @@ _ao_serial2_pollchar(void)  	return _ao_usart_pollchar(&ao_stm_usart2);  } +uint8_t +_ao_serial2_sleep(void) +{ +	return _ao_usart_sleep(&ao_stm_usart2); +} + +void +ao_serial2_drain(void) +{ +	ao_usart_drain(&ao_stm_usart2); +} +  void  ao_serial2_set_speed(uint8_t speed)  { @@ -265,6 +302,12 @@ _ao_serial3_pollchar(void)  	return _ao_usart_pollchar(&ao_stm_usart3);  } +uint8_t +_ao_serial3_sleep(void) +{ +	return _ao_usart_sleep(&ao_stm_usart3); +} +  void  ao_serial3_set_speed(uint8_t speed)  { @@ -305,7 +348,7 @@ ao_serial_init(void)  	stm_nvic_set_enable(STM_ISR_USART1_POS);  	stm_nvic_set_priority(STM_ISR_USART1_POS, 4); -#if USE_SERIAL_1_STDIN +#if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN  	ao_add_stdio(_ao_serial1_pollchar,  		     ao_serial1_putchar,  		     NULL); @@ -324,25 +367,35 @@ ao_serial_init(void)  	stm_afr_set(&stm_gpioa, 2, STM_AFR_AF7);  	stm_afr_set(&stm_gpioa, 3, STM_AFR_AF7); +#if USE_SERIAL_2_FLOW +	stm_afr_set(&stm_gpioa, 0, STM_AFR_AF7); +	stm_afr_set(&stm_gpioa, 1, STM_AFR_AF7); +#endif  #else  #if SERIAL_2_PD5_PD6  	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);  	stm_afr_set(&stm_gpiod, 5, STM_AFR_AF7);  	stm_afr_set(&stm_gpiod, 6, STM_AFR_AF7); +#if USE_SERIAL_2_FLOW +#error "Don't know how to set flowcontrol for serial 2 on PD" +#endif  #else  #error "No SERIAL_2 port configuration specified" -#endif	 +#endif  #endif  	/* Enable USART */  	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USART2EN);  	ao_stm_usart2.reg = &stm_usart2;  	ao_usart_init(&ao_stm_usart2); +#if USE_SERIAL_2_FLOW +	ao_usart_set_flow(&ao_stm_usart2); +#endif  	stm_nvic_set_enable(STM_ISR_USART2_POS);  	stm_nvic_set_priority(STM_ISR_USART2_POS, 4); -#if USE_SERIAL_2_STDIN +#if USE_SERIAL_2_STDIN && !DELAY_SERIAL_2_STDIN  	ao_add_stdio(_ao_serial2_pollchar,  		     ao_serial2_putchar,  		     NULL); @@ -386,12 +439,10 @@ ao_serial_init(void)  	stm_nvic_set_enable(STM_ISR_USART3_POS);  	stm_nvic_set_priority(STM_ISR_USART3_POS, 4); -#if USE_SERIAL_3_STDIN +#if USE_SERIAL_3_STDIN && !DELAY_SERIAL_3_STDIN  	ao_add_stdio(_ao_serial3_pollchar,  		     ao_serial3_putchar,  		     NULL);  #endif  #endif  } - - diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c index 885af544..7eaa3924 100644 --- a/src/stm/ao_spi_stm.c +++ b/src/stm/ao_spi_stm.c @@ -42,7 +42,7 @@ static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {  static uint8_t	spi_dev_null;  void -ao_spi_send(void *block, uint16_t len, uint8_t spi_index) +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; @@ -51,7 +51,7 @@ ao_spi_send(void *block, uint16_t len, uint8_t spi_index)  	/* Set up the transmit DMA to deliver data */  	ao_dma_set_transfer(mosi_dma_index,  			    &stm_spi->dr, -			    block, +			    (void *) block,  			    len,  			    (0 << STM_DMA_CCR_MEM2MEM) |  			    (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) | diff --git a/src/stmf0/Makefile-flash.defs b/src/stmf0/Makefile-flash.defs new file mode 100644 index 00000000..706b93ee --- /dev/null +++ b/src/stmf0/Makefile-flash.defs @@ -0,0 +1,61 @@ +include $(TOPDIR)/stmf0/Makefile-stmf0.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_flash_pins.h \ +	ao_flash_stm_pins.h \ +	ao_flash_task.h \ +	ao_pins.h \ +	ao_product.h \ +	Makefile + +# +# Common AltOS sources +# +SRC = \ +	ao_interrupt.c \ +	ao_romconfig.c \ +	ao_boot_chain.c \ +	ao_boot_pin.c \ +	ao_product.c \ +	ao_notask.c \ +	ao_timer.c \ +	ao_usb_stm.c \ +	ao_flash_stm.c \ +	ao_flash_task.c \ +	ao_flash_loader_stm.c + +OBJ=$(SRC:.c=.o) + +PRODUCT=AltosFlash +PRODUCT_DEF=-DALTOS_FLASH +IDPRODUCT=0x000a + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos-loader.ld + +PROGNAME=altos-flash +PROG=$(HARDWARE)-$(PROGNAME)-$(VERSION).elf + +$(PROG): Makefile $(OBJ) altos-loader.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c $(TOPDIR)/Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +all: $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(HARDWARE)-$(PROGNAME)-*.elf +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/stmf0/Makefile-stmf0.defs b/src/stmf0/Makefile-stmf0.defs new file mode 100644 index 00000000..4862f46e --- /dev/null +++ b/src/stmf0/Makefile-stmf0.defs @@ -0,0 +1,47 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/Makedefs + +vpath % $(TOPDIR)/stmf0:$(TOPDIR)/product:$(TOPDIR)/drivers:$(TOPDIR)/kernel:$(TOPDIR)/util:$(TOPDIR)/kalman:$(TOPDIR/aes):$(TOPDIR):$(TOPDIR)/math +vpath make-altitude $(TOPDIR)/util +vpath make-kalman $(TOPDIR)/util +vpath kalman.5c $(TOPDIR)/kalman +vpath kalman_filter.5c $(TOPDIR)/kalman +vpath load_csv.5c $(TOPDIR)/kalman +vpath matrix.5c $(TOPDIR)/kalman +vpath ao-make-product.5c $(TOPDIR)/util + +.SUFFIXES: .elf .ihx + +.elf.ihx: +	$(ELFTOHEX) --output=$@ $*.elf + +ifndef VERSION +include $(TOPDIR)/Version +endif + +ELFTOHEX=$(TOPDIR)/../ao-tools/ao-elftohex/ao-elftohex +CC=$(ARM_CC) + +WARN_FLAGS=-Wall -Wextra -Werror + +AO_CFLAGS=-I. -I$(TOPDIR)/stmf0 -I$(TOPDIR)/kernel -I$(TOPDIR)/drivers -I$(TOPDIR)/product -I$(TOPDIR) -I$(TOPDIR)/math $(PDCLIB_INCLUDES)  +STMF0_CFLAGS=-std=gnu99 -mlittle-endian -mcpu=cortex-m0 -mthumb\ +	-ffreestanding -nostdlib $(AO_CFLAGS) $(WARN_FLAGS) + +NICKLE=nickle + +LIBS=$(PDCLIB_LIBS_M0) -lgcc + +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) + +.c.o: +	$(call quiet,CC) -c $(CFLAGS) -o $@ $< diff --git a/src/stmf0/Makefile.defs b/src/stmf0/Makefile.defs new file mode 100644 index 00000000..a1d93eb5 --- /dev/null +++ b/src/stmf0/Makefile.defs @@ -0,0 +1,9 @@ +ifndef TOPDIR +TOPDIR=.. +endif + +include $(TOPDIR)/stmf0/Makefile-stmf0.defs + +LDFLAGS=$(CFLAGS) -L$(TOPDIR)/stmf0 -Wl,-Taltos.ld + +.DEFAULT_GOAL=all diff --git a/src/stmf0/altos-loader.ld b/src/stmf0/altos-loader.ld new file mode 100644 index 00000000..86cf1838 --- /dev/null +++ b/src/stmf0/altos-loader.ld @@ -0,0 +1,95 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +MEMORY { +	rom : ORIGIN = 0x08000000, LENGTH = 4K +	ram : ORIGIN = 0x20000000, LENGTH = 6K +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.interrupt : { +		__text_start__ = .; +		*(.interrupt)	/* Interrupt vectors */ +	} > rom + +	.text ORIGIN(rom) + 0x100 : { +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) + +		*(.text*)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ +	} > rom +	__text_end__ = .; + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot ORIGIN(ram) + SIZEOF(.interrupt) (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		__boot_end__ = .; +	} >ram + +	/* Functions placed in RAM (required for flashing) +	 * +	 * Align to 8 bytes as that's what the ARM likes text +	 * segment alignments to be, and if we don't, then +	 * we end up with a mismatch between the location in +	 * ROM and the desired location in RAM. I don't +	 * entirely understand this, but at least this appears +	 * to work... +	 */ + +	.textram BLOCK(8): { +		__data_start__ = .; +		__text_ram_start__ = .; +		*(.ramtext) +		__text_ram_end = .; +	} >ram AT>rom + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		*(.data)	/* initialized data */ +		__data_end__ = .; +	} >ram AT>rom + + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		__bss_end__ = .; +	} >ram + +	PROVIDE(__stack__ = ORIGIN(ram) + LENGTH(ram)); +	PROVIDE(end = .); +} + +ENTRY(start); + + diff --git a/src/stmf0/altos.ld b/src/stmf0/altos.ld new file mode 100644 index 00000000..9dbc83d0 --- /dev/null +++ b/src/stmf0/altos.ld @@ -0,0 +1,98 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +MEMORY { +	rom (rx) :   ORIGIN = 0x08001000, LENGTH = 28K +	ram (!w) :   ORIGIN = 0x20000000, LENGTH = 6k - 128 +	stack (!w) : ORIGIN = 0x20000000 + 6k - 128, LENGTH = 128 +} + +INCLUDE registers.ld + +EXTERN (stm_interrupt_vector) + +SECTIONS { +	/* +	 * Rom contents +	 */ + +	.interrupt ORIGIN(ram) : AT (ORIGIN(rom)) { +		__interrupt_start__ = .; +		__interrupt_rom__ = ORIGIN(rom); +		*(.interrupt)	/* Interrupt vectors */ +		__interrupt_end__ = .; +	} > ram + +	.text ORIGIN(rom) + 0x100 : { +		__text_start__ = .; + +		/* Ick. What I want is to specify the +		 * addresses of some global constants so +		 * that I can find them across versions +		 * of the application. I can't figure out +		 * how to make gnu ld do that, so instead +		 * we just load the two files that include +		 * these defines in the right order here and +		 * expect things to 'just work'. Don't change +		 * the contents of those files, ok? +		 */ +		ao_romconfig.o(.romconfig*) +		ao_product.o(.romconfig*) + +		*(.text*)	/* Executable code */ +		*(.ARM.exidx* .gnu.linkonce.armexidx.*) +		*(.rodata*)	/* Constants */ + +	} > rom +	__text_end__ = .; + +	/* Boot data which must live at the start of ram so that +	 * the application and bootloader share the same addresses. +	 * This must be all uninitialized data +	 */ +	.boot (NOLOAD) : { +		__boot_start__ = .; +		*(.boot) +		. = ALIGN(4); +		__boot_end__ = .; +	} >ram + +	/* Data -- relocated to RAM, but written to ROM +	 */ +	.data : { +		__data_start__ = .; +		*(.data)	/* initialized data */ +		. = ALIGN(4); +		__data_end__ = .; +	} >ram AT>rom + +	.bss : { +		__bss_start__ = .; +		*(.bss) +		*(COMMON) +		. = ALIGN(4); +		__bss_end__ = .; +	} >ram + +	PROVIDE(end = .); + +	PROVIDE(__stack__ = ORIGIN(stack) + LENGTH(stack)); +} + +ENTRY(start); + + diff --git a/src/stmf0/ao_adc_fast.c b/src/stmf0/ao_adc_fast.c new file mode 100644 index 00000000..be9b5986 --- /dev/null +++ b/src/stmf0/ao_adc_fast.c @@ -0,0 +1,190 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_adc_fast.h> + +uint16_t ao_adc_ring[AO_ADC_RING_SIZE]; + +uint16_t ao_adc_ring_head, ao_adc_ring_tail; +uint8_t ao_adc_running; + +/* + * Callback from DMA ISR + * + * Mark time in ring, shut down DMA engine + */ +static void ao_adc_dma_done(int index) +{ +	(void) index; +	ao_adc_ring_head += AO_ADC_RING_CHUNK; +	if (ao_adc_ring_head == AO_ADC_RING_SIZE) +		ao_adc_ring_head = 0; +	ao_adc_running = 0; +	ao_wakeup(&ao_adc_ring_head); +	ao_dma_done_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); +} + +void +_ao_adc_start(void) +{ +	uint16_t	*buf; + +	if (ao_adc_running) +		return; +	if (_ao_adc_space() < AO_ADC_RING_CHUNK) +		return; +	ao_adc_running = 1; +	buf = ao_adc_ring + ao_adc_ring_head; +	stm_adc.isr = 0; +	ao_dma_set_transfer(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), +			    &stm_adc.dr, +			    buf, +			    AO_ADC_RING_CHUNK, +			    (0 << STM_DMA_CCR_MEM2MEM) | +			    (STM_DMA_CCR_PL_HIGH << STM_DMA_CCR_PL) | +			    (STM_DMA_CCR_MSIZE_16 << STM_DMA_CCR_MSIZE) | +			    (STM_DMA_CCR_PSIZE_16 << STM_DMA_CCR_PSIZE) | +			    (1 << STM_DMA_CCR_MINC) | +			    (0 << STM_DMA_CCR_PINC) | +			    (0 << STM_DMA_CCR_CIRC) | +			    (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); +	ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_dma_done); +	ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); + +	stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); +} + +void +ao_adc_init(void) +{ +	uint32_t	chselr; +	int		i; + +	/* Reset ADC */ +	stm_rcc.apb2rstr |= (1 << STM_RCC_APB2RSTR_ADCRST); +	stm_rcc.apb2rstr &= ~(1 << STM_RCC_APB2RSTR_ADCRST); + +	/* Turn on ADC pins */ +	stm_rcc.ahbenr |= AO_ADC_RCC_AHBENR; + +#ifdef AO_ADC_PIN0_PORT +	stm_moder_set(AO_ADC_PIN0_PORT, AO_ADC_PIN0_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN1_PORT +	stm_moder_set(AO_ADC_PIN1_PORT, AO_ADC_PIN1_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN2_PORT +	stm_moder_set(AO_ADC_PIN2_PORT, AO_ADC_PIN2_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN3_PORT +	stm_moder_set(AO_ADC_PIN3_PORT, AO_ADC_PIN3_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN4_PORT +	stm_moder_set(AO_ADC_PIN4_PORT, AO_ADC_PIN4_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN5_PORT +	stm_moder_set(AO_ADC_PIN5_PORT, AO_ADC_PIN5_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN6_PORT +	stm_moder_set(AO_ADC_PIN6_PORT, AO_ADC_PIN6_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN7_PORT +	stm_moder_set(AO_ADC_PIN7_PORT, AO_ADC_PIN7_PIN, STM_MODER_ANALOG); +#endif +#ifdef AO_ADC_PIN24_PORT +	#error "Too many ADC ports" +#endif + +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN); + +	chselr = 0; +#if AO_NUM_ADC > 0 +	chselr |= (1 << AO_ADC_PIN0_CH); +#endif +#if AO_NUM_ADC > 1 +	chselr |= (1 << AO_ADC_PIN1_CH); +#endif +#if AO_NUM_ADC > 2 +	chselr |= (1 << AO_ADC_PIN2_CH); +#endif +#if AO_NUM_ADC > 3 +	chselr |= (1 << AO_ADC_PIN3_CH); +#endif +#if AO_NUM_ADC > 4 +	chselr |= (1 << AO_ADC_PIN4_CH); +#endif +#if AO_NUM_ADC > 5 +	chselr |= (1 << AO_ADC_PIN5_CH); +#endif +#if AO_NUM_ADC > 6 +	chselr |= (1 << AO_ADC_PIN6_CH); +#endif +#if AO_NUM_ADC > 7 +	chselr |= (1 << AO_ADC_PIN7_CH); +#endif +#if AO_NUM_ADC > 8 +#error Need more ADC defines +#endif +	stm_adc.chselr = chselr; + +	/* Set the clock */ +	stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE; + +	/* Shortest sample time */ +	stm_adc.smpr = STM_ADC_SMPR_SMP_1_5 << STM_ADC_SMPR_SMP; + +	/* Calibrate */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADCAL); +	for (i = 0; i < 0xf000; i++) { +		if ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) == 0) +			break; +	} + +	/* Enable */ +	stm_adc.cr |= (1 << STM_ADC_CR_ADEN); +	while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) +		; + +	stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | +			 (0 << STM_ADC_CFGR1_AWDEN) | +			 (0 << STM_ADC_CFGR1_AWDSGL) | +			 (0 << STM_ADC_CFGR1_DISCEN) | +			 (0 << STM_ADC_CFGR1_AUTOOFF) | +			 (1 << STM_ADC_CFGR1_WAIT) | +			 (1 << STM_ADC_CFGR1_CONT) | +			 (0 << STM_ADC_CFGR1_OVRMOD) | +			 (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | +			 (0 << STM_ADC_CFGR1_ALIGN) | +			 (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | +			 (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | +			 (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | +			 (1 << STM_ADC_CFGR1_DMAEN)); +	stm_adc.ccr = 0; + +	/* Clear any stale status bits */ +	stm_adc.isr = 0; + +	/* Turn on syscfg */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + +	/* Set ADC to use DMA channel 1 (option 1) */ +	stm_syscfg.cfgr1 &= ~(1 << STM_SYSCFG_CFGR1_ADC_DMA_RMP); + +	ao_dma_alloc(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1)); +	ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_dma_done); +} diff --git a/src/stmf0/ao_adc_fast.h b/src/stmf0/ao_adc_fast.h new file mode 100644 index 00000000..eec45505 --- /dev/null +++ b/src/stmf0/ao_adc_fast.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_ADC_FAST_H_ +#define _AO_ADC_FAST_H_ + +void +ao_adc_read(uint16_t *dest, int len); + +void +ao_adc_init(void); + +/* Total ring size in samples */ +#define AO_ADC_RING_SIZE	256 +/* Number of samples fetched per ao_adc_start call */ +#define AO_ADC_RING_CHUNK	(AO_ADC_RING_SIZE >> 1) + +extern uint16_t	ao_adc_ring[AO_ADC_RING_SIZE]; + +#define ao_adc_ring_step(pos,inc)	(((pos) + (inc)) & (AO_ADC_RING_SIZE - 1)) + +extern uint16_t	ao_adc_ring_head, ao_adc_ring_tail; +extern uint8_t	ao_adc_running; + +void +_ao_adc_start(void); + +static inline uint16_t +_ao_adc_remain(void) +{ +	if (ao_adc_ring_tail > ao_adc_ring_head) +		return AO_ADC_RING_SIZE - ao_adc_ring_tail; +	return ao_adc_ring_head - ao_adc_ring_tail; +} + +static inline uint16_t +_ao_adc_space(void) +{ +	if (ao_adc_ring_head == ao_adc_ring_tail) +		return AO_ADC_RING_SIZE; +	if (ao_adc_ring_head > ao_adc_ring_tail) +		return AO_ADC_RING_SIZE - ao_adc_ring_head; +	return ao_adc_ring_tail - ao_adc_ring_head; +} + +static inline uint16_t * +ao_adc_get(uint16_t n) +{ +	if (ao_adc_ring_tail + n > AO_ADC_RING_SIZE) +		ao_panic(AO_PANIC_ADC); +	ao_arch_block_interrupts(); +	while (_ao_adc_remain() < n) { +		if (!ao_adc_running) +			_ao_adc_start(); +		ao_sleep(&ao_adc_ring_head); +	} +	ao_arch_release_interrupts(); +	return &ao_adc_ring[ao_adc_ring_tail]; +} + +static inline void +ao_adc_ack(uint16_t n) +{ +	if (ao_adc_ring_tail + n > AO_ADC_RING_SIZE) +		ao_panic(AO_PANIC_ADC); +	ao_arch_block_interrupts(); +	ao_adc_ring_tail += n; +	if (ao_adc_ring_tail == AO_ADC_RING_SIZE) +		ao_adc_ring_tail = 0; +	if (!ao_adc_running && _ao_adc_space() >= AO_ADC_RING_CHUNK) +		_ao_adc_start(); +	ao_arch_release_interrupts(); +} + +#endif /* _AO_ADC_FAST_H_ */ diff --git a/src/stmf0/ao_arch.h b/src/stmf0/ao_arch.h new file mode 100644 index 00000000..6ee71ef9 --- /dev/null +++ b/src/stmf0/ao_arch.h @@ -0,0 +1,157 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_ARCH_H_ +#define _AO_ARCH_H_ + +#include <stdio.h> +#include <stm32f0.h> + +/* + * STM32F0 definitions and code fragments for AltOS + */ + +#define AO_STACK_SIZE	512 + +#define AO_LED_TYPE	uint16_t + +#ifndef AO_TICK_TYPE +#define AO_TICK_TYPE	uint16_t +#define AO_TICK_SIGNED	int16_t +#endif + +#define AO_PORT_TYPE	uint16_t + +/* Various definitions to make GCC look more like SDCC */ + +#define ao_arch_naked_declare	__attribute__((naked)) +#define ao_arch_naked_define +#define __pdata +#define __data +#define __xdata +#define __code const +#define __reentrant +#define __interrupt(n) +#define __at(n) + +#define ao_arch_reboot() \ +	(stm_scb.aircr = ((STM_SCB_AIRCR_VECTKEY_KEY << STM_SCB_AIRCR_VECTKEY) | \ +			  (1 << STM_SCB_AIRCR_SYSRESETREQ))) + +#define ao_arch_nop()		asm("nop") + +#define ao_arch_interrupt(n)	/* nothing */ + +#undef putchar +#undef getchar +#define putchar(c)	ao_putchar(c) +#define getchar		ao_getchar + +extern void putchar(char c); +extern char getchar(void); +extern void ao_avr_stdio_init(void); + + +/* + * ao_romconfig.c + */ + +#define AO_ROMCONFIG_VERSION	2 + +#define AO_ROMCONFIG_SYMBOL(a) __attribute__((section(".romconfig"))) const + +extern const uint16_t ao_romconfig_version; +extern const uint16_t ao_romconfig_check; +extern const uint16_t ao_serial_number; +extern const uint32_t ao_radio_cal; + +#define ao_arch_task_members\ +	uint32_t *sp;			/* saved stack pointer */ + +#define ao_arch_block_interrupts()	asm("cpsid i") +#define ao_arch_release_interrupts()	asm("cpsie i") + +/* + * ao_timer.c + * + * For the stm32f042, we want to use the USB-based HSI48 clock + */ + +#if AO_HSI48 + +#define AO_SYSCLK	48000000 +#define AO_HCLK		(AO_SYSCLK / AO_AHB_PRESCALER) + +#endif + +#if AO_HSE || AO_HSI + +#if AO_HSE +#define AO_PLLSRC	AO_HSE +#else +#define AO_PLLSRC	STM_HSI_FREQ +#endif + +#define AO_PLLVCO	(AO_PLLSRC * AO_PLLMUL) +#define AO_SYSCLK	(AO_PLLVCO / AO_PLLDIV) + +#endif + +#define AO_HCLK		(AO_SYSCLK / AO_AHB_PRESCALER) +#define AO_PCLK1	(AO_HCLK / AO_APB1_PRESCALER) +#define AO_PCLK2	(AO_HCLK / AO_APB2_PRESCALER) +#define AO_SYSTICK	(AO_HCLK) + +#if AO_APB1_PRESCALER == 1 +#define AO_TIM23467_CLK		AO_PCLK1 +#else +#define AO_TIM23467_CLK		(2 * AO_PCLK1) +#endif + +#if AO_APB2_PRESCALER == 1 +#define AO_TIM91011_CLK		AO_PCLK2 +#else +#define AO_TIM91011_CLK		(2 * AO_PCLK2) +#endif + +#define AO_STM_NVIC_HIGH_PRIORITY	4 +#define AO_STM_NVIC_CLOCK_PRIORITY	6 +#define AO_STM_NVIC_MED_PRIORITY	8 +#define AO_STM_NVIC_LOW_PRIORITY	10 + +void ao_lcd_stm_init(void); + +void ao_lcd_font_init(void); + +void ao_lcd_font_string(char *s); + +extern const uint32_t	ao_radio_cal; + +void +ao_adc_init(); + +/* ADC maximum reported value */ +#define AO_ADC_MAX			4095 + +#define AO_BOOT_APPLICATION_BASE	((uint32_t *) 0x08001000) +#define AO_BOOT_APPLICATION_BOUND	((uint32_t *) (0x08000000 + stm_flash_size())) +#define AO_BOOT_LOADER_BASE		((uint32_t *) 0x08000000) +#define HAS_BOOT_LOADER			1 + +#endif /* _AO_ARCH_H_ */ + + diff --git a/src/stmf0/ao_arch_funcs.h b/src/stmf0/ao_arch_funcs.h new file mode 100644 index 00000000..3db96be2 --- /dev/null +++ b/src/stmf0/ao_arch_funcs.h @@ -0,0 +1,400 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_ARCH_FUNCS_H_ +#define _AO_ARCH_FUNCS_H_ + +/* ao_spi_stm.c + */ + +/* PCLK is set to 16MHz (HCLK 32MHz, APB prescaler 2) */ + +#define AO_SPI_SPEED_8MHz	STM_SPI_CR1_BR_PCLK_2 +#define AO_SPI_SPEED_4MHz	STM_SPI_CR1_BR_PCLK_4 +#define AO_SPI_SPEED_2MHz	STM_SPI_CR1_BR_PCLK_8 +#define AO_SPI_SPEED_1MHz	STM_SPI_CR1_BR_PCLK_16 +#define AO_SPI_SPEED_500kHz	STM_SPI_CR1_BR_PCLK_32 +#define AO_SPI_SPEED_250kHz	STM_SPI_CR1_BR_PCLK_64 +#define AO_SPI_SPEED_125kHz	STM_SPI_CR1_BR_PCLK_128 +#define AO_SPI_SPEED_62500Hz	STM_SPI_CR1_BR_PCLK_256 + +#define AO_SPI_SPEED_FAST	AO_SPI_SPEED_8MHz + +/* Companion bus wants something no faster than 200kHz */ + +#define AO_SPI_SPEED_200kHz	AO_SPI_SPEED_125kHz + +#define AO_SPI_CONFIG_1		0x00 +#define AO_SPI_1_CONFIG_PA5_PA6_PA7	AO_SPI_CONFIG_1 +#define AO_SPI_2_CONFIG_PB13_PB14_PB15	AO_SPI_CONFIG_1 + +#define AO_SPI_CONFIG_2		0x04 +#define AO_SPI_1_CONFIG_PB3_PB4_PB5	AO_SPI_CONFIG_2 +#define AO_SPI_2_CONFIG_PD1_PD3_PD4	AO_SPI_CONFIG_2 + +#define AO_SPI_CONFIG_3		0x08 +#define AO_SPI_1_CONFIG_PE13_PE14_PE15	AO_SPI_CONFIG_3 + +#define AO_SPI_CONFIG_NONE	0x0c + +#define AO_SPI_INDEX_MASK	0x01 +#define AO_SPI_CONFIG_MASK	0x0c + +#define AO_SPI_1_PA5_PA6_PA7	(STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PA5_PA6_PA7) +#define AO_SPI_1_PB3_PB4_PB5	(STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PB3_PB4_PB5) +#define AO_SPI_1_PE13_PE14_PE15	(STM_SPI_INDEX(1) | AO_SPI_1_CONFIG_PE13_PE14_PE15) + +#define AO_SPI_2_PB13_PB14_PB15	(STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PB13_PB14_PB15) +#define AO_SPI_2_PD1_PD3_PD4	(STM_SPI_INDEX(2) | AO_SPI_2_CONFIG_PD1_PD3_PD4) + +#define AO_SPI_INDEX(id)	((id) & AO_SPI_INDEX_MASK) +#define AO_SPI_CONFIG(id)	((id) & AO_SPI_CONFIG_MASK) + +uint8_t +ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id); + +void +ao_spi_get(uint8_t spi_index, uint32_t speed); + +void +ao_spi_put(uint8_t spi_index); + +void +ao_spi_send(const void *block, uint16_t len, uint8_t spi_index); + +void +ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index); + +void +ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index); + +void +ao_spi_recv(void *block, uint16_t len, uint8_t spi_index); + +void +ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index); + +extern uint16_t	ao_spi_speed[STM_NUM_SPI]; + +void +ao_spi_init(void); + +#define ao_spi_set_cs(reg,mask) ((reg)->bsrr = ((uint32_t) (mask)) << 16) +#define ao_spi_clr_cs(reg,mask) ((reg)->bsrr = (mask)) + +#define ao_spi_get_mask(reg,mask,bus, speed) do {		\ +		ao_spi_get(bus, speed);				\ +		ao_spi_set_cs(reg,mask);			\ +	} while (0) + +static inline uint8_t +ao_spi_try_get_mask(struct stm_gpio *reg, uint16_t mask, uint8_t bus, uint32_t speed, uint8_t task_id) +{ +	if (!ao_spi_try_get(bus, speed, task_id)) +		return 0; +	ao_spi_set_cs(reg, mask); +	return 1; +} + +#define ao_spi_put_mask(reg,mask,bus) do {	\ +		ao_spi_clr_cs(reg,mask);	\ +		ao_spi_put(bus);		\ +	} while (0) + +#define ao_spi_get_bit(reg,bit,pin,bus,speed) ao_spi_get_mask(reg,(1<<bit),bus,speed) +#define ao_spi_put_bit(reg,bit,pin,bus) ao_spi_put_mask(reg,(1<<bit),bus) + +#define ao_enable_port(port) do {					\ +		if ((port) == &stm_gpioa)				\ +			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN); \ +		else if ((port) == &stm_gpiob)				\ +			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN); \ +		else if ((port) == &stm_gpioc)				\ +			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPCEN); \ +		else if ((port) == &stm_gpiof)				\ +			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPFEN); \ +	} while (0) + +#define ao_disable_port(port) do {					\ +		if ((port) == &stm_gpioa)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPAEN); \ +		else if ((port) == &stm_gpiob)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPBEN); \ +		else if ((port) == &stm_gpioc)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPCEN); \ +		else if ((port) == &stm_gpiof)				\ +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_IOPFEN); \ +	} while (0) + +#define ao_gpio_set(port, bit, pin, v) stm_gpio_set(port, bit, v) + +#define ao_gpio_get(port, bit, pin) stm_gpio_get(port, bit) + +#define ao_enable_output(port,bit,pin,v) do {			\ +		ao_enable_port(port);				\ +		ao_gpio_set(port, bit, pin, v);			\ +		stm_moder_set(port, bit, STM_MODER_OUTPUT);\ +	} while (0) + +#define ao_gpio_set_mode(port,bit,mode) do {				\ +		if (mode == AO_EXTI_MODE_PULL_UP)			\ +			stm_pupdr_set(port, bit, STM_PUPDR_PULL_UP);	\ +		else if (mode == AO_EXTI_MODE_PULL_DOWN)		\ +			stm_pupdr_set(port, bit, STM_PUPDR_PULL_DOWN);	\ +		else							\ +			stm_pupdr_set(port, bit, STM_PUPDR_NONE);	\ +	} while (0) + +#define ao_enable_input(port,bit,mode) do {				\ +		ao_enable_port(port);					\ +		stm_moder_set(port, bit, STM_MODER_INPUT);		\ +		ao_gpio_set_mode(port, bit, mode);			\ +	} while (0) + +#define ao_enable_cs(port,bit) do {				\ +		stm_gpio_set((port), bit, 1);			\ +		stm_moder_set((port), bit, STM_MODER_OUTPUT);	\ +	} while (0) + +#define ao_spi_init_cs(port, mask) do {				\ +		ao_enable_port(port);				\ +		if ((mask) & 0x0001) ao_enable_cs(port, 0);	\ +		if ((mask) & 0x0002) ao_enable_cs(port, 1);	\ +		if ((mask) & 0x0004) ao_enable_cs(port, 2);	\ +		if ((mask) & 0x0008) ao_enable_cs(port, 3);	\ +		if ((mask) & 0x0010) ao_enable_cs(port, 4);	\ +		if ((mask) & 0x0020) ao_enable_cs(port, 5);	\ +		if ((mask) & 0x0040) ao_enable_cs(port, 6);	\ +		if ((mask) & 0x0080) ao_enable_cs(port, 7);	\ +		if ((mask) & 0x0100) ao_enable_cs(port, 8);	\ +		if ((mask) & 0x0200) ao_enable_cs(port, 9);	\ +		if ((mask) & 0x0400) ao_enable_cs(port, 10);\ +		if ((mask) & 0x0800) ao_enable_cs(port, 11);\ +		if ((mask) & 0x1000) ao_enable_cs(port, 12);\ +		if ((mask) & 0x2000) ao_enable_cs(port, 13);\ +		if ((mask) & 0x4000) ao_enable_cs(port, 14);\ +		if ((mask) & 0x8000) ao_enable_cs(port, 15);\ +	} while (0) + +/* ao_dma_stm.c + */ + +extern uint8_t ao_dma_done[STM_NUM_DMA]; + +void +ao_dma_set_transfer(uint8_t 		index, +		    volatile void	*peripheral, +		    void		*memory, +		    uint16_t		count, +		    uint32_t		ccr); + +void +ao_dma_set_isr(uint8_t index, void (*isr)(int index)); + +void +ao_dma_start(uint8_t index); + +void +ao_dma_done_transfer(uint8_t index); + +void +ao_dma_abort(uint8_t index); + +void +ao_dma_alloc(uint8_t index); + +void +ao_dma_init(void); + +/* ao_i2c_stm.c */ + +void +ao_i2c_get(uint8_t i2c_index); + +uint8_t +ao_i2c_start(uint8_t i2c_index, uint16_t address); + +void +ao_i2c_put(uint8_t i2c_index); + +uint8_t +ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); + +uint8_t +ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); + +void +ao_i2c_init(void); + +/* ao_serial_stm.c */ +struct ao_stm_usart { +	struct ao_fifo		rx_fifo; +	struct ao_fifo		tx_fifo; +	struct stm_usart	*reg; +	uint8_t			tx_started; +}; + +#if HAS_SERIAL_1 +extern struct ao_stm_usart	ao_stm_usart1; +#endif + +#if HAS_SERIAL_2 +extern struct ao_stm_usart	ao_stm_usart2; +#endif + +#if HAS_SERIAL_3 +extern struct ao_stm_usart	ao_stm_usart3; +#endif + +#define ARM_PUSH32(stack, val)	(*(--(stack)) = (val)) + +typedef uint32_t	ao_arch_irq_t; + +static inline uint32_t +ao_arch_irqsave(void) { +	uint32_t	primask; +	asm("mrs %0,primask" : "=&r" (primask)); +	ao_arch_block_interrupts(); +	return primask; +} + +static inline void +ao_arch_irqrestore(uint32_t primask) { +	asm("msr primask,%0" : : "r" (primask)); +} + +static inline void +ao_arch_memory_barrier() { +	asm volatile("" ::: "memory"); +} + +#if HAS_TASK +static inline void +ao_arch_init_stack(struct ao_task *task, void *start) +{ +	uint32_t	*sp = (uint32_t *) (task->stack + AO_STACK_SIZE); +	uint32_t	a = (uint32_t) start; +	int		i; + +	/* Return address (goes into LR) */ +	ARM_PUSH32(sp, a); + +	/* Clear register values r0-r7 */ +	i = 8; +	while (i--) +		ARM_PUSH32(sp, 0); + +	/* APSR */ +	ARM_PUSH32(sp, 0); + +	/* PRIMASK with interrupts enabled */ +	ARM_PUSH32(sp, 0); + +	task->sp = sp; +} + +static inline void ao_arch_save_regs(void) { +	/* Save general registers */ +	asm("push {r0-r7,lr}\n"); + +	/* Save APSR */ +	asm("mrs r0,apsr"); +	asm("push {r0}"); + +	/* Save PRIMASK */ +	asm("mrs r0,primask"); +	asm("push {r0}"); +} + +static inline void ao_arch_save_stack(void) { +	uint32_t	*sp; +	asm("mov %0,sp" : "=&r" (sp) ); +	ao_cur_task->sp = (sp); +	if ((uint8_t *) sp < &ao_cur_task->stack[0]) +		ao_panic (AO_PANIC_STACK); +} + +static inline void ao_arch_restore_stack(void) { +	uint32_t	sp; +	sp = (uint32_t) ao_cur_task->sp; + +	/* Switch stacks */ +	asm("mov sp, %0" : : "r" (sp) ); + +	/* Restore PRIMASK */ +	asm("pop {r0}"); +	asm("msr primask,r0"); + +	/* Restore APSR */ +	asm("pop {r0}"); +	asm("msr apsr_nczvq,r0"); + +	/* Restore general registers */ +	asm("pop {r0-r7,pc}\n"); +} + +#ifndef HAS_SAMPLE_PROFILE +#define HAS_SAMPLE_PROFILE 0 +#endif + +#if !HAS_SAMPLE_PROFILE +#define HAS_ARCH_START_SCHEDULER	1 + +static inline void ao_arch_start_scheduler(void) { +	uint32_t	sp; +	uint32_t	control; + +	asm("mrs %0,msp" : "=&r" (sp)); +	asm("msr psp,%0" : : "r" (sp)); +	asm("mrs %0,control" : "=&r" (control)); +	control |= (1 << 1); +	asm("msr control,%0" : : "r" (control)); +	asm("isb"); +} +#endif + +#define ao_arch_isr_stack() + +#endif + +#define ao_arch_wait_interrupt() do {				\ +		asm("\twfi\n");					\ +		ao_arch_release_interrupts();			\ +		asm(".global ao_idle_loc\nao_idle_loc:");	\ +		ao_arch_block_interrupts();			\ +	} while (0) + +#define ao_arch_critical(b) do {			\ +		uint32_t __mask = ao_arch_irqsave();	\ +		do { b } while (0);			\ +		ao_arch_irqrestore(__mask);		\ +	} while (0) + +/* ao_usb_stm.c */ + +#if AO_USB_DIRECTIO +uint16_t * +ao_usb_alloc(void); + +void +ao_usb_free(uint16_t *buffer); + +void +ao_usb_write(uint16_t *buffer, uint16_t len); +#endif /* AO_USB_DIRECTIO */ + +#endif /* _AO_ARCH_FUNCS_H_ */ diff --git a/src/stmf0/ao_boot_chain.c b/src/stmf0/ao_boot_chain.c new file mode 100644 index 00000000..83a543a0 --- /dev/null +++ b/src/stmf0/ao_boot_chain.c @@ -0,0 +1,67 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_boot.h> + +void +ao_boot_chain(uint32_t *base) +{ +	uint32_t	sp; +	uint32_t	pc; + +	sp = base[0]; +	pc = base[1]; +	if (0x08000100 <= pc && pc <= 0x08200000 && (pc & 1) == 1) { +		asm ("mov sp, %0" : : "r" (sp)); +		asm ("mov lr, %0" : : "r" (pc)); +		asm ("bx lr"); +	} +} + +#define AO_BOOT_SIGNAL	0x5a5aa5a5 +#define AO_BOOT_CHECK	0xc3c33c3c + +struct ao_boot { +	uint32_t	*base; +	uint32_t	signal; +	uint32_t	check; +}; + +static struct ao_boot __attribute__ ((section(".boot"))) ao_boot; + +int +ao_boot_check_chain(void) +{ +	if (ao_boot.signal == AO_BOOT_SIGNAL && ao_boot.check == AO_BOOT_CHECK) { +		ao_boot.signal = 0; +		ao_boot.check = 0; +		if (ao_boot.base == AO_BOOT_FORCE_LOADER) +			return 0; +		ao_boot_chain(ao_boot.base); +	} +	return 1; +} + +void +ao_boot_reboot(uint32_t *base) +{ +	ao_boot.base = base; +	ao_boot.signal = AO_BOOT_SIGNAL; +	ao_boot.check = AO_BOOT_CHECK; +	ao_arch_reboot(); +} diff --git a/src/stmf0/ao_boot_pin.c b/src/stmf0/ao_boot_pin.c new file mode 100644 index 00000000..e825b618 --- /dev/null +++ b/src/stmf0/ao_boot_pin.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_boot.h> +#include <ao_exti.h> + +void +ao_boot_check_pin(void) +{ +	uint16_t v; + +	/* Enable power interface clock */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); + +	/* Enable the input pin */ +	ao_enable_input(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, +			AO_BOOT_APPLICATION_MODE); + +	for (v = 0; v < 100; v++) +		ao_arch_nop(); + +	/* Read the value */ +	v = stm_gpio_get(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN); + +	/* Reset the chip to turn off the port and the power interface clock */ +	ao_gpio_set_mode(&AO_BOOT_APPLICATION_GPIO, AO_BOOT_APPLICATION_PIN, 0); +	ao_disable_port(&AO_BOOT_APPLICATION_GPIO); +	stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_PWREN); +	if (v == AO_BOOT_APPLICATION_VALUE) +		ao_boot_chain(AO_BOOT_APPLICATION_BASE); +} diff --git a/src/stmf0/ao_crc.h b/src/stmf0/ao_crc.h new file mode 100644 index 00000000..cd011d3a --- /dev/null +++ b/src/stmf0/ao_crc.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_CRC_H_ +#define _AO_CRC_H_ + +#define AO_CRC_16_CCITT		0x1021 +#define AO_CRC_16_CDMA2000	0xc867 +#define AO_CRC_16_DECT		0x0589 +#define AO_CRC_16_T10_DIF	0x8bb7 +#define AO_CRC_16_DNP		0x3d65 +#define AO_CRC_16_ANSI		0x8005 +#define AO_CRC_16_DEFAULT	AO_CRC_16_ANSI + +#define AO_CRC_32_ANSI		0x04c11db7 +#define AO_CRC_32_C		0x1edc6f41 + +#define AO_CRC_32_DEFAULT	AO_CRC_32_ANSI + +static inline uint16_t +ao_crc_in_32_out_16(uint32_t v) { +	stm_crc.dr.u32 = v; +	return stm_crc.dr.u16; +} + +static inline uint16_t +ao_crc_in_16_out_16(uint16_t v) { +	stm_crc.dr.u16 = v; +	return stm_crc.dr.u16; +} + +static inline uint16_t +ao_crc_in_8_out_16(uint8_t v) { +	stm_crc.dr.u8 = v; +	return stm_crc.dr.u16; +} + +void +ao_crc_reset(void); + +void +ao_crc_init(void); + +#endif /* _AO_CRC_H_ */ diff --git a/src/stmf0/ao_dma_stm.c b/src/stmf0/ao_dma_stm.c new file mode 100644 index 00000000..78fabe18 --- /dev/null +++ b/src/stmf0/ao_dma_stm.c @@ -0,0 +1,141 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +struct ao_dma_config { +	void		(*isr)(int index); +}; + +uint8_t ao_dma_done[STM_NUM_DMA]; + +static struct ao_dma_config ao_dma_config[STM_NUM_DMA]; +static uint8_t ao_dma_allocated[STM_NUM_DMA]; +static uint8_t ao_dma_mutex[STM_NUM_DMA]; +static uint8_t ao_dma_active; + +#define id(ch)		STM_DMA_INDEX(ch) +#define id_mask(id)	(STM_DMA_ISR_MASK << (id)) +#define ch_mask(ch)	id_mask(id(ch)) + +static void +ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) { +	/* Get channel interrupt bits */ +	uint32_t	isr = stm_dma.isr & mask; +	uint8_t		index; + +	/* Ack them */ +	stm_dma.ifcr = isr; +	for (index = low_index; index <= high_index; index++) { +		if (isr & id_mask(index)) { +			if (ao_dma_config[index].isr) +				(*ao_dma_config[index].isr)(index); +			else { +				ao_dma_done[index] = 1; +				ao_wakeup(&ao_dma_done[index]); +			} +		} +	} +} + +void stm_dma_ch1_isr(void) { ao_dma_isr(id(1), id(1), ch_mask(1)); } +void stm_dma_ch2_3_isr(void) { ao_dma_isr(id(2), id(3), ch_mask(2) | ch_mask(3)); } +void stm_dma1_ch4_5_6_isr(void) { ao_dma_isr(id(4), id(6), ch_mask(4) | ch_mask(5) | ch_mask(6)); } + +void +ao_dma_set_transfer(uint8_t 		index, +		    volatile void	*peripheral, +		    void		*memory, +		    uint16_t		count, +		    uint32_t		ccr) +{ +	if (ao_dma_allocated[index]) { +		if (ao_dma_mutex[index]) +			ao_panic(AO_PANIC_DMA); +		ao_dma_mutex[index] = 1; +	} else +		ao_mutex_get(&ao_dma_mutex[index]); +	ao_arch_critical( +		if (ao_dma_active++ == 0) +			stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMAEN); +		); +	stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE); +	stm_dma.channel[index].cndtr = count; +	stm_dma.channel[index].cpar = peripheral; +	stm_dma.channel[index].cmar = memory; +	ao_dma_config[index].isr = NULL; +} + +void +ao_dma_set_isr(uint8_t index, void (*isr)(int)) +{ +	ao_dma_config[index].isr = isr; +} + +void +ao_dma_start(uint8_t index) +{ +	ao_dma_done[index] = 0; +	stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN); +} + +void +ao_dma_done_transfer(uint8_t index) +{ +	stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN); +	ao_arch_critical( +		if (--ao_dma_active == 0) +			stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_DMAEN); +		); +	if (ao_dma_allocated[index]) +		ao_dma_mutex[index] = 0; +	else +		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) +{ +	if (ao_dma_allocated[index]) +		ao_panic(AO_PANIC_DMA); +	ao_dma_allocated[index] = 1; +} + +#define STM_NUM_DMA_ISR	3 + +void +ao_dma_init(void) +{ +	int	isr_id; +	int	index; + +	for (isr_id = 0; isr_id < STM_NUM_DMA_ISR; isr_id++) { +		stm_nvic_set_enable(STM_ISR_DMA_CH1_POS + isr_id); +		stm_nvic_set_priority(STM_ISR_DMA_CH1_POS + isr_id, 4); +	} +	for (index = 0; index < STM_NUM_DMA; index++) { +		ao_dma_allocated[index] = 0; +		ao_dma_mutex[index] = 0; +	} +} diff --git a/src/stmf0/ao_flash.h b/src/stmf0/ao_flash.h new file mode 100644 index 00000000..09ca5ac1 --- /dev/null +++ b/src/stmf0/ao_flash.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_FLASH_STM_H_ +#define _AO_FLASH_STM_H_ + +void +ao_flash_erase_page(uint32_t *page); + +void +ao_flash_page(uint32_t *page, uint32_t *src); + +#endif /* _AO_FLASH_STM_H_ */ diff --git a/src/stmf0/ao_flash_loader_stm.c b/src/stmf0/ao_flash_loader_stm.c new file mode 100644 index 00000000..6bf89234 --- /dev/null +++ b/src/stmf0/ao_flash_loader_stm.c @@ -0,0 +1,39 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_exti.h> +#include <ao_boot.h> +#include <ao_flash_task.h> + +int +main(void) +{ +	ao_clock_init(); + +	ao_usb_init(); + +#if HAS_TICK +	ao_timer_init(); +#endif + +#ifdef AO_FLASH_LOADER_INIT +	AO_FLASH_LOADER_INIT; +#endif	 +	ao_flash_task(); +	return 0; +} diff --git a/src/stmf0/ao_flash_stm.c b/src/stmf0/ao_flash_stm.c new file mode 100644 index 00000000..5fe0e619 --- /dev/null +++ b/src/stmf0/ao_flash_stm.c @@ -0,0 +1,131 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_flash.h> + +static uint8_t +ao_flash_is_locked(void) +{ +	return (stm_flash.cr & (1 << STM_FLASH_CR_LOCK)) != 0; +} + +static void +ao_flash_unlock(void) +{ +	if (!ao_flash_is_locked()) +		return; + +	/* Unlock FLASH_CR register */ +	stm_flash.keyr = STM_FLASH_KEYR_KEY1; +	stm_flash.keyr = STM_FLASH_KEYR_KEY2; +	if (ao_flash_is_locked()) +		ao_panic(AO_PANIC_FLASH); +} + +static void +ao_flash_lock(void) +{ +	stm_flash.cr |= (1 << STM_FLASH_CR_LOCK); +} + +static void +ao_flash_wait_bsy(void) +{ +	while (stm_flash.sr & (1 << STM_FLASH_SR_BSY)) +		; +} + +static void __attribute__ ((section(".ramtext"),noinline)) +_ao_flash_erase_page(uint32_t *page) +{ +	stm_flash.cr |= (1 << STM_FLASH_CR_PER); + +	stm_flash.ar = (uintptr_t) page; + +	stm_flash.cr |= (1 << STM_FLASH_CR_STRT); + +	ao_flash_wait_bsy(); + +	stm_flash.cr &= ~(1 << STM_FLASH_CR_PER); +} + +static uint32_t +stm_flash_page_size(void) +{ +	uint16_t	dev_id = stm_dev_id(); + +	switch (dev_id) { +	case 0x440:	/* stm32f05x */ +	case 0x444:	/* stm32f03x */ +	case 0x445:	/* stm32f04x */ +		return 1024; +	case 0x442:	/* stm32f09x */ +	case 0x448:	/* stm32f07x */ +		return 2048; +	} +	ao_panic(AO_PANIC_FLASH); +	return 0; +} + +void +ao_flash_erase_page(uint32_t *page) +{ +	/* Erase the whole page at the start. This assumes we'll be flashing things +	 * in memory order +	 */ + +	if ((uintptr_t) page & (stm_flash_page_size() - 1)) +		return; + +	ao_arch_block_interrupts(); +	ao_flash_unlock(); + +	_ao_flash_erase_page(page); + +	ao_flash_lock(); +	ao_arch_release_interrupts(); +} + +static void __attribute__ ((section(".ramtext"), noinline)) +_ao_flash_page(uint16_t *dst, uint16_t *src) +{ +	uint8_t		i; + +	stm_flash.cr |= (1 << STM_FLASH_CR_PG); + +	for (i = 0; i < 128; i++) { +		*dst++ = *src++; +		ao_flash_wait_bsy(); +	} + +	stm_flash.cr &= ~(1 << STM_FLASH_CR_PG); +} + +void +ao_flash_page(uint32_t *page, uint32_t *src) +{ +	ao_flash_erase_page(page); + +	ao_arch_block_interrupts(); +	ao_flash_unlock(); + +	_ao_flash_page((uint16_t *) page, (uint16_t *) src); + +	ao_flash_lock(); +	ao_arch_release_interrupts(); +} diff --git a/src/stmf0/ao_flash_stm_pins.h b/src/stmf0/ao_flash_stm_pins.h new file mode 100644 index 00000000..ab60b4f3 --- /dev/null +++ b/src/stmf0/ao_flash_stm_pins.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_FLASH_STM_PINS_H_ +#define _AO_FLASH_STM_PINS_H_ + +#include <ao_flash_pins.h> + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB		1 + +#define AO_NEED_HSI	1 + +#endif /* _AO_FLASH_STM_PINS_H_ */ diff --git a/src/stmf0/ao_interrupt.c b/src/stmf0/ao_interrupt.c new file mode 100644 index 00000000..c6d8ef34 --- /dev/null +++ b/src/stmf0/ao_interrupt.c @@ -0,0 +1,185 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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 "stm32f0.h" +#include <string.h> +#include <ao_boot.h> + +#ifndef IS_FLASH_LOADER +#error Should define IS_FLASH_LOADER +#define IS_FLASH_LOADER	0 +#endif + +#if !IS_FLASH_LOADER +#define RELOCATE_INTERRUPT	1 +#endif + +extern void main(void); +extern char __stack__; +extern char __text_start__, __text_end__; +extern char __data_start__, __data_end__; +extern char __bss_start__, __bss_end__; +#if RELOCATE_INTERRUPT +extern char __interrupt_rom__, __interrupt_start__, __interrupt_end__; +#endif + +/* Interrupt functions */ + +void stm_halt_isr(void) +{ +	ao_panic(AO_PANIC_CRASH); +} + +void stm_ignore_isr(void) +{ +} + +const void *stm_interrupt_vector[]; + +uint32_t +stm_flash_size(void) { +	uint16_t	dev_id = stm_dev_id(); +	uint16_t	kbytes = 0; + +	switch (dev_id) { +	case 0x445: +		kbytes = stm_flash_size_04x.f_size; +		break; +	} +	return (uint32_t) kbytes * 1024; +} + +void start(void) +{ +#ifdef AO_BOOT_CHAIN +	if (ao_boot_check_chain()) { +#ifdef AO_BOOT_PIN +		ao_boot_check_pin(); +#endif +	} +#endif +#if RELOCATE_INTERRUPT +	/* Turn on syscfg */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + +	memcpy(&__interrupt_start__, &__interrupt_rom__, &__interrupt_end__ - &__interrupt_start__); +	stm_syscfg.cfgr1 = (stm_syscfg.cfgr1 & ~(STM_SYSCFG_CFGR1_MEM_MODE_MASK << STM_SYSCFG_CFGR1_MEM_MODE)) | +		(STM_SYSCFG_CFGR1_MEM_MODE_SRAM << STM_SYSCFG_CFGR1_MEM_MODE); +#endif +	memcpy(&__data_start__, &__text_end__, &__data_end__ - &__data_start__); +	memset(&__bss_start__, '\0', &__bss_end__ - &__bss_start__); +	main(); +} + +#define STRINGIFY(x) #x + +#define isr(name) \ +	void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ +	_Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_ignore_isr)) + +#define isr_halt(name) \ +	void __attribute__ ((weak)) stm_ ## name ## _isr(void); \ +	_Pragma(STRINGIFY(weak stm_ ## name ## _isr = stm_halt_isr)) + +isr(nmi) +isr_halt(hardfault) +isr_halt(memmanage) +isr_halt(busfault) +isr_halt(usagefault) +isr(svc) +isr(debugmon) +isr(pendsv) +isr(systick) +isr(wwdg) +isr(pvd) +isr(rtc) +isr(flash) +isr(rcc_crs) +isr(exti0_1) +isr(exti2_3) +isr(exti4_15) +isr(tsc) +isr(dma_ch1) +isr(dma_ch2_3) +isr(dma_ch4_5_6) +isr(adc_comp) +isr(tim1_brk_up_trg_com) +isr(tim1_cc) +isr(tim2) +isr(tim3) +isr(tim6_dac) +isr(tim7) +isr(tim14) +isr(tim15) +isr(tim16) +isr(tim17) +isr(i2c1) +isr(i2c2) +isr(spi1) +isr(spi2) +isr(usart1) +isr(usart2) +isr(usart3_4_5_6_7_8) +isr(cec_can) +isr(usb) + +#define i(addr,name)	[(addr)/4] = stm_ ## name ## _isr + +__attribute__ ((section(".interrupt"))) +const void *stm_interrupt_vector[] = { +	[0] = &__stack__, +	[1] = start, +	i(0x08, nmi), +	i(0x0c, hardfault), +	i(0x2c, svc), +	i(0x30, debugmon), +	i(0x38, pendsv), +	i(0x3c, systick), +	i(0x40, wwdg),		/* IRQ0 */ +	i(0x44, pvd), +	i(0x48, rtc), +	i(0x4c, flash), +	i(0x50, rcc_crs), +	i(0x54, exti0_1), +	i(0x58, exti2_3), +	i(0x5c, exti4_15), +	i(0x60, tsc), +	i(0x64, dma_ch1), +	i(0x68, dma_ch2_3), +	i(0x6c, dma_ch4_5_6), +	i(0x70, adc_comp), +	i(0x74, tim1_brk_up_trg_com), +	i(0x78, tim1_cc), +	i(0x7c, tim2), +	i(0x80, tim3), +	i(0x84, tim6_dac), +	i(0x88, tim7), +	i(0x8c, tim14), +	i(0x90, tim15), +	i(0x94, tim16), +	i(0x98, tim17), +	i(0x9c, i2c1), +	i(0xa0, i2c2), +	i(0xa4, spi1), +	i(0xa8, spi2), +	i(0xac, usart1), +	i(0xb0, usart2), +	i(0xb4, usart3_4_5_6_7_8), +	i(0xb8, cec_can), +	i(0xbc, usb), +}; diff --git a/src/stmf0/ao_led.c b/src/stmf0/ao_led.c new file mode 100644 index 00000000..9b61cf62 --- /dev/null +++ b/src/stmf0/ao_led.c @@ -0,0 +1,125 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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" + +__pdata uint16_t ao_led_enable; + +void +ao_led_on(uint16_t colors) +{ +#ifdef LED_PORT +	LED_PORT->bsrr = (colors & ao_led_enable); +#else +#ifdef LED_PORT_0 +	LED_PORT_0->bsrr = ((colors & ao_led_enable) & LED_PORT_0_MASK) << LED_PORT_0_SHIFT; +#endif +#ifdef LED_PORT_1 +	LED_PORT_1->bsrr = ((colors & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT; +#endif +#endif +} + +void +ao_led_off(uint16_t colors) +{ +#ifdef LED_PORT +	LED_PORT->bsrr = (uint32_t) (colors & ao_led_enable) << 16; +#else +#ifdef LED_PORT_0 +	LED_PORT_0->bsrr = ((uint32_t) (colors & ao_led_enable) & LED_PORT_0_MASK) << (LED_PORT_0_SHIFT + 16); +#endif +#ifdef LED_PORT_1 +	LED_PORT_1->bsrr = ((uint32_t) (colors & ao_led_enable) & LED_PORT_1_MASK) << (LED_PORT_1_SHIFT + 16); +#endif +#endif +} + +void +ao_led_set(uint16_t colors) +{ +	uint16_t	on = colors & ao_led_enable; +	uint16_t	off = ~colors & ao_led_enable; + +	ao_led_off(off); +	ao_led_on(on); +} + +void +ao_led_toggle(uint16_t colors) +{ +#ifdef LED_PORT +	LED_PORT->odr ^= (colors & ao_led_enable); +#else +#ifdef LED_PORT_0 +	LED_PORT_0->odr ^= ((colors & ao_led_enable) & LED_PORT_0_MASK) << LED_PORT_0_SHIFT; +#endif +#ifdef LED_PORT_1 +	LED_PORT_1->odr ^= ((colors & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT; +#endif +#endif +} + +void +ao_led_for(uint16_t colors, uint16_t ticks) __reentrant +{ +	ao_led_on(colors); +	ao_delay(ticks); +	ao_led_off(colors); +} + +#define init_led_pin(port, bit) do { \ +		stm_moder_set(port, bit, STM_MODER_OUTPUT);		\ +		stm_otyper_set(port, bit, STM_OTYPER_PUSH_PULL);	\ +	} while (0) + +void +ao_led_init(uint16_t enable) +{ +	int	bit; + +	ao_led_enable = enable; +#ifdef LED_PORT +	stm_rcc.ahbenr |= (1 << LED_PORT_ENABLE); +	LED_PORT->odr &= ~enable; +#else +#ifdef LED_PORT_0 +	stm_rcc.ahbenr |= (1 << LED_PORT_0_ENABLE); +	LED_PORT_0->odr &= ~((enable & ao_led_enable) & LED_PORT_0_MASK) << LED_PORT_0_SHIFT; +#endif +#ifdef LED_PORT_1 +	stm_rcc.ahbenr |= (1 << LED_PORT_1_ENABLE); +	LED_PORT_1->odr &= ~((enable & ao_led_enable) & LED_PORT_1_MASK) << LED_PORT_1_SHIFT; +#endif +#endif +	for (bit = 0; bit < 16; bit++) { +		if (enable & (1 << bit)) { +#ifdef LED_PORT +			init_led_pin(LED_PORT, bit); +#else +#ifdef LED_PORT_0 +			if (LED_PORT_0_MASK & (1 << bit)) +				init_led_pin(LED_PORT_0, bit + LED_PORT_0_SHIFT); +#endif +#ifdef LED_PORT_1 +			if (LED_PORT_1_MASK & (1 << bit)) +				init_led_pin(LED_PORT_1, bit + LED_PORT_1_SHIFT); +#endif +#endif +		} +	} +} diff --git a/src/stmf0/ao_romconfig.c b/src/stmf0/ao_romconfig.c new file mode 100644 index 00000000..5da15072 --- /dev/null +++ b/src/stmf0/ao_romconfig.c @@ -0,0 +1,27 @@ +/* + * 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" + +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_version = AO_ROMCONFIG_VERSION; +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_romconfig_check = ~AO_ROMCONFIG_VERSION; +AO_ROMCONFIG_SYMBOL (0) uint16_t ao_serial_number = 0; +#ifndef AO_RADIO_CAL_DEFAULT +#define AO_RADIO_CAL_DEFAULT 0x01020304 +#endif +AO_ROMCONFIG_SYMBOL (0) uint32_t ao_radio_cal = AO_RADIO_CAL_DEFAULT; + diff --git a/src/stmf0/ao_timer.c b/src/stmf0/ao_timer.c new file mode 100644 index 00000000..3aae7e55 --- /dev/null +++ b/src/stmf0/ao_timer.c @@ -0,0 +1,266 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_task.h> +#if HAS_FAKE_FLIGHT +#include <ao_fake_flight.h> +#endif + +#ifndef HAS_TICK +#define HAS_TICK 1 +#endif + +#if HAS_TICK +volatile AO_TICK_TYPE ao_tick_count; + +AO_TICK_TYPE +ao_time(void) +{ +	return ao_tick_count; +} + +#if AO_DATA_ALL +volatile __data uint8_t	ao_data_interval = 1; +volatile __data uint8_t	ao_data_count; +#endif + +void stm_systick_isr(void) +{ +	if (stm_systick.csr & (1 << STM_SYSTICK_CSR_COUNTFLAG)) { +		++ao_tick_count; +#if HAS_TASK_QUEUE +		if (ao_task_alarm_tick && (int16_t) (ao_tick_count - ao_task_alarm_tick) >= 0) +			ao_task_check_alarm((uint16_t) ao_tick_count); +#endif +#if AO_DATA_ALL +		if (++ao_data_count == ao_data_interval) { +			ao_data_count = 0; +#if HAS_FAKE_FLIGHT +			if (ao_fake_flight_active) +				ao_fake_flight_poll(); +			else +#endif +				ao_adc_poll(); +#if (AO_DATA_ALL & ~(AO_DATA_ADC)) +			ao_wakeup((void *) &ao_data_count); +#endif +		} +#endif +#ifdef AO_TIMER_HOOK +		AO_TIMER_HOOK; +#endif +	} +} + +#if HAS_ADC +void +ao_timer_set_adc_interval(uint8_t interval) +{ +	ao_arch_critical( +		ao_data_interval = interval; +		ao_data_count = 0; +		); +} +#endif + +#define SYSTICK_RELOAD (AO_SYSTICK / 100 - 1) + +void +ao_timer_init(void) +{ +	stm_systick.rvr = SYSTICK_RELOAD; +	stm_systick.cvr = 0; +	stm_systick.csr = ((1 << STM_SYSTICK_CSR_ENABLE) | +			   (1 << STM_SYSTICK_CSR_TICKINT) | +			   (STM_SYSTICK_CSR_CLKSOURCE_HCLK_8 << STM_SYSTICK_CSR_CLKSOURCE)); +} + +#endif + +static void +ao_clock_enable_crs(void) +{ +	/* Enable crs interface clock */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_CRSEN); + +	/* Disable error counter */ +	stm_crs.cr = ((stm_crs.cr & (1 << 4)) | +		      (32 << STM_CRS_CR_TRIM) | +		      (0 << STM_CRS_CR_SWSYNC) | +		      (0 << STM_CRS_CR_AUTOTRIMEN) | +		      (0 << STM_CRS_CR_CEN) | +		      (0 << STM_CRS_CR_ESYNCIE) | +		      (0 << STM_CRS_CR_ERRIE) | +		      (0 << STM_CRS_CR_SYNCWARNIE) | +		      (0 << STM_CRS_CR_SYNCOKIE)); + +	/* Configure for USB source */ +	stm_crs.cfgr = ((stm_crs.cfgr & ((1 << 30) | (1 << 27))) | +			(0 << STM_CRS_CFGR_SYNCPOL) | +			(STM_CRS_CFGR_SYNCSRC_USB << STM_CRS_CFGR_SYNCSRC) | +			(STM_CRS_CFGR_SYNCDIV_1 << STM_CRS_CFGR_SYNCDIV) | +			(0x22 << STM_CRS_CFGR_FELIM) | +			(((48000000 / 1000) - 1) << STM_CRS_CFGR_RELOAD)); + +	/* Enable error counter, set auto trim */ +	stm_crs.cr = ((stm_crs.cr & (1 << 4)) | +		      (32 << STM_CRS_CR_TRIM) | +		      (0 << STM_CRS_CR_SWSYNC) | +		      (1 << STM_CRS_CR_AUTOTRIMEN) | +		      (1 << STM_CRS_CR_CEN) | +		      (0 << STM_CRS_CR_ESYNCIE) | +		      (0 << STM_CRS_CR_ERRIE) | +		      (0 << STM_CRS_CR_SYNCWARNIE) | +		      (0 << STM_CRS_CR_SYNCOKIE)); + +} + +void +ao_clock_init(void) +{ +	uint32_t	cfgr; + +	/* Switch to HSI while messing about */ +	stm_rcc.cr |= (1 << STM_RCC_CR_HSION); +	while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSIRDY))) +		ao_arch_nop(); + +	stm_rcc.cfgr = (stm_rcc.cfgr & ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW)) | +		(STM_RCC_CFGR_SW_HSI << STM_RCC_CFGR_SW); + +	/* wait for system to switch to HSI */ +	while ((stm_rcc.cfgr & (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS)) != +	       (STM_RCC_CFGR_SWS_HSI << STM_RCC_CFGR_SWS)) +		ao_arch_nop(); + +	/* reset the clock config, leaving us running on the HSI */ +	stm_rcc.cfgr &= (uint32_t)0x0000000f; + +	/* reset PLLON, CSSON, HSEBYP, HSEON */ +	stm_rcc.cr &= 0x0000ffff; + +	/* Disable all interrupts */ +	stm_rcc.cir = 0; + +#if AO_HSE +#define STM_RCC_CFGR_SWS_TARGET_CLOCK		STM_RCC_CFGR_SWS_HSE +#define STM_RCC_CFGR_SW_TARGET_CLOCK		STM_RCC_CFGR_SW_HSE +#define STM_PLLSRC				AO_HSE +#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK	1 + +#if AO_HSE_BYPASS +	stm_rcc.cr |= (1 << STM_RCC_CR_HSEBYP); +#else +	stm_rcc.cr &= ~(1 << STM_RCC_CR_HSEBYP); +#endif +	/* Enable HSE clock */ +	stm_rcc.cr |= (1 << STM_RCC_CR_HSEON); +	while (!(stm_rcc.cr & (1 << STM_RCC_CR_HSERDY))) +		asm("nop"); +#endif + + +#if AO_HSI48 +#define STM_RCC_CFGR_SWS_TARGET_CLOCK		STM_RCC_CFGR_SWS_HSI48 +#define STM_RCC_CFGR_SW_TARGET_CLOCK		STM_RCC_CFGR_SW_HSI48 + +	/* Turn HSI48 clock on */ +	stm_rcc.cr2 |= (1 << STM_RCC_CR2_HSI48ON); + +	/* Wait for clock to stabilize */ +	while ((stm_rcc.cr2 & (1 << STM_RCC_CR2_HSI48RDY)) == 0) +		ao_arch_nop(); + +	ao_clock_enable_crs(); +#endif + +#ifndef STM_RCC_CFGR_SWS_TARGET_CLOCK +#define STM_HSI 				16000000 +#define STM_RCC_CFGR_SWS_TARGET_CLOCK		STM_RCC_CFGR_SWS_HSI +#define STM_RCC_CFGR_SW_TARGET_CLOCK		STM_RCC_CFGR_SW_HSI +#define STM_PLLSRC				STM_HSI +#define STM_RCC_CFGR_PLLSRC_TARGET_CLOCK	0 +#endif + +#ifdef STM_PLLSRC +#error No code for PLL initialization yet +#endif + +	/* Set flash latency to tolerate 48MHz SYSCLK  -> 1 wait state */ + +	/* Enable prefetch */ +	stm_flash.acr |= (1 << STM_FLASH_ACR_PRFTBE); + +	/* Enable 1 wait state so the CPU can run at 48MHz */ +	stm_flash.acr |= (STM_FLASH_ACR_LATENCY_1 << STM_FLASH_ACR_LATENCY); + +	/* Enable power interface clock */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN); + +	/* HCLK to 48MHz -> AHB prescaler = /1 */ +	cfgr = stm_rcc.cfgr; +	cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE); +	cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE); +	stm_rcc.cfgr = cfgr; +	while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) != +	       (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE)) +		ao_arch_nop(); + +	/* APB Prescaler = AO_APB_PRESCALER */ +	cfgr = stm_rcc.cfgr; +	cfgr &= ~(STM_RCC_CFGR_PPRE_MASK << STM_RCC_CFGR_PPRE); +	cfgr |= (AO_RCC_CFGR_PPRE_DIV << STM_RCC_CFGR_PPRE); +	stm_rcc.cfgr = cfgr; + +	/* Switch to the desired system clock */ + +	cfgr = stm_rcc.cfgr; +	cfgr &= ~(STM_RCC_CFGR_SW_MASK << STM_RCC_CFGR_SW); +	cfgr |= (STM_RCC_CFGR_SW_TARGET_CLOCK << STM_RCC_CFGR_SW); +	stm_rcc.cfgr = cfgr; +	for (;;) { +		uint32_t	c, part, mask, val; + +		c = stm_rcc.cfgr; +		mask = (STM_RCC_CFGR_SWS_MASK << STM_RCC_CFGR_SWS); +		val = (STM_RCC_CFGR_SWS_TARGET_CLOCK << STM_RCC_CFGR_SWS); +		part = c & mask; +		if (part == val) +			break; +	} + +	/* Clear reset flags */ +	stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF); + +#if !AO_HSI && !AO_NEED_HSI +	/* Turn off the HSI clock */ +	stm_rcc.cr &= ~(1 << STM_RCC_CR_HSION); +#endif +#if DEBUG_THE_CLOCK +	/* Output SYSCLK on PA8 for measurments */ + +	stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN); + +	stm_afr_set(&stm_gpioa, 8, STM_AFR_AF0); +	stm_moder_set(&stm_gpioa, 8, STM_MODER_ALTERNATE); +	stm_ospeedr_set(&stm_gpioa, 8, STM_OSPEEDR_40MHz); + +	stm_rcc.cfgr |= (STM_RCC_CFGR_MCOPRE_DIV_1 << STM_RCC_CFGR_MCOPRE); +	stm_rcc.cfgr |= (STM_RCC_CFGR_MCOSEL_HSE << STM_RCC_CFGR_MCOSEL); +#endif +} diff --git a/src/stmf0/ao_usb_stm.c b/src/stmf0/ao_usb_stm.c new file mode 100644 index 00000000..3ea7da5e --- /dev/null +++ b/src/stmf0/ao_usb_stm.c @@ -0,0 +1,1150 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_usb.h" +#include "ao_product.h" + +#define USB_DEBUG 	0 +#define USB_DEBUG_DATA	0 +#define USB_ECHO	0 + +#ifndef AO_PA11_PA12_RMP +#error "must define AO_PA11_PA12_RMP" +#endif + +#ifndef USE_USB_STDIO +#define USE_USB_STDIO	1 +#endif + +#if USE_USB_STDIO +#define AO_USB_OUT_SLEEP_ADDR	(&ao_stdin_ready) +#else +#define AO_USB_OUT_SLEEP_ADDR	(&ao_usb_out_avail) +#endif + +#if USB_DEBUG +#define debug(format, args...)	printf(format, ## args); +#else +#define debug(format, args...) +#endif + +#if USB_DEBUG_DATA +#define debug_data(format, args...)	printf(format, ## args); +#else +#define debug_data(format, args...) +#endif + +struct ao_usb_setup { +	uint8_t		dir_type_recip; +	uint8_t		request; +	uint16_t	value; +	uint16_t	index; +	uint16_t	length; +} ao_usb_setup; + +static uint8_t 	ao_usb_ep0_state; + +/* Pending EP0 IN data */ +static const uint8_t	*ao_usb_ep0_in_data;	/* Remaining data */ +static uint8_t 		ao_usb_ep0_in_len;	/* Remaining amount */ + +/* Temp buffer for smaller EP0 in data */ +static uint8_t	ao_usb_ep0_in_buf[2]; + +/* Pending EP0 OUT data */ +static uint8_t *ao_usb_ep0_out_data; +static uint8_t 	ao_usb_ep0_out_len; + +/* + * Objects allocated in special USB memory + */ + +/* Buffer description tables */ +static union stm_usb_bdt	*ao_usb_bdt; +/* USB address of end of allocated storage */ +static uint16_t	ao_usb_sram_addr; + +/* Pointer to ep0 tx/rx buffers in USB memory */ +static uint16_t	*ao_usb_ep0_tx_buffer; +static uint16_t	*ao_usb_ep0_rx_buffer; + +/* Pointer to bulk data tx/rx buffers in USB memory */ +static uint16_t ao_usb_in_tx_offset; +static uint16_t	*ao_usb_in_tx_buffer; +static uint16_t	*ao_usb_out_rx_buffer; + +/* System ram shadow of USB buffer; writing individual bytes is + * too much of a pain (sigh) */ +static uint8_t	ao_usb_tx_buffer[AO_USB_IN_SIZE]; +static uint8_t	ao_usb_tx_count; + +static uint8_t	ao_usb_rx_buffer[AO_USB_OUT_SIZE]; +static uint8_t	ao_usb_rx_count, ao_usb_rx_pos; + +/* + * End point register indices + */ + +#define AO_USB_CONTROL_EPR	0 +#define AO_USB_INT_EPR		1 +#define AO_USB_OUT_EPR		2 +#define AO_USB_IN_EPR		3 + +/* Marks when we don't need to send an IN packet. + * This happens only when the last IN packet is not full, + * otherwise the host will expect to keep seeing packets. + * Send a zero-length packet as required + */ +static uint8_t	ao_usb_in_flushed; + +/* Marks when we have delivered an IN packet to the hardware + * and it has not been received yet. ao_sleep on this address + * to wait for it to be delivered. + */ +static uint8_t	ao_usb_in_pending; + +/* Marks when an OUT packet has been received by the hardware + * but not pulled to the shadow buffer. + */ +static uint8_t	ao_usb_out_avail; +uint8_t		ao_usb_running; +static uint8_t	ao_usb_configuration; + +#define AO_USB_EP0_GOT_RESET	1 +#define AO_USB_EP0_GOT_SETUP	2 +#define AO_USB_EP0_GOT_RX_DATA	4 +#define AO_USB_EP0_GOT_TX_ACK	8 + +static uint8_t	ao_usb_ep0_receive; +static uint8_t	ao_usb_address; +static uint8_t	ao_usb_address_pending; + +static inline uint32_t set_toggle(uint32_t 	current_value, +				   uint32_t	mask, +				   uint32_t	desired_value) +{ +	return (current_value ^ desired_value) & mask; +} + +static inline uint16_t *ao_usb_packet_buffer_addr(uint16_t sram_addr) +{ +	return (uint16_t *) (stm_usb_sram + sram_addr); +} + +#if AO_USB_DIRECTIO +static inline uint16_t ao_usb_packet_buffer_offset(uint16_t *addr) +{ +	return (uint16_t) ((uint8_t *) addr - stm_usb_sram); +} +#endif + +static inline uint32_t ao_usb_epr_stat_rx(uint32_t epr) { +	return (epr >> STM_USB_EPR_STAT_RX) & STM_USB_EPR_STAT_RX_MASK; +} + +static inline uint32_t ao_usb_epr_stat_tx(uint32_t epr) { +	return (epr >> STM_USB_EPR_STAT_TX) & STM_USB_EPR_STAT_TX_MASK; +} + +static inline uint32_t ao_usb_epr_ctr_rx(uint32_t epr) { +	return (epr >> STM_USB_EPR_CTR_RX) & 1; +} + +static inline uint32_t ao_usb_epr_ctr_tx(uint32_t epr) { +	return (epr >> STM_USB_EPR_CTR_TX) & 1; +} + +static inline uint32_t ao_usb_epr_setup(uint32_t epr) { +	return (epr >> STM_USB_EPR_SETUP) & 1; +} + +static inline uint32_t ao_usb_epr_dtog_rx(uint32_t epr) { +	return (epr >> STM_USB_EPR_DTOG_RX) & 1; +} + +static inline uint32_t ao_usb_epr_dtog_tx(uint32_t epr) { +	return (epr >> STM_USB_EPR_DTOG_TX) & 1; +} + +/* + * Set current device address and mark the + * interface as active + */ +void +ao_usb_set_address(uint8_t address) +{ +	debug("ao_usb_set_address %02x\n", address); +	stm_usb.daddr = (1 << STM_USB_DADDR_EF) | address; +	ao_usb_address_pending = 0; +} + +/* + * Write these values to preserve register contents under HW changes + */ + +#define STM_USB_EPR_INVARIANT	((1 << STM_USB_EPR_CTR_RX) |		\ +				 (STM_USB_EPR_DTOG_RX_WRITE_INVARIANT << STM_USB_EPR_DTOG_RX) | \ +				 (STM_USB_EPR_STAT_RX_WRITE_INVARIANT << STM_USB_EPR_STAT_RX) | \ +				 (1 << STM_USB_EPR_CTR_TX) |		\ +				 (STM_USB_EPR_DTOG_TX_WRITE_INVARIANT << STM_USB_EPR_DTOG_TX) |	\ +				 (STM_USB_EPR_STAT_TX_WRITE_INVARIANT << STM_USB_EPR_STAT_TX)) + +#define STM_USB_EPR_INVARIANT_MASK	((1 << STM_USB_EPR_CTR_RX) |	\ +					 (STM_USB_EPR_DTOG_RX_MASK << STM_USB_EPR_DTOG_RX) | \ +					 (STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX) | \ +					 (1 << STM_USB_EPR_CTR_TX) |	\ +					 (STM_USB_EPR_DTOG_TX_MASK << STM_USB_EPR_DTOG_TX) | \ +					 (STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX)) + +/* + * These bits are purely under sw control, so preserve them in the + * register by re-writing what was read + */ +#define STM_USB_EPR_PRESERVE_MASK	((STM_USB_EPR_EP_TYPE_MASK << STM_USB_EPR_EP_TYPE) | \ +					 (1 << STM_USB_EPR_EP_KIND) |	\ +					 (STM_USB_EPR_EA_MASK << STM_USB_EPR_EA)) + +#define TX_DBG 0 +#define RX_DBG 0 + +#if TX_DBG +#define _tx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _tx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _tx_dbg0(msg) +#define _tx_dbg1(msg,value) +#endif + +#if RX_DBG +#define _rx_dbg0(msg) _dbg(__LINE__,msg,0) +#define _rx_dbg1(msg,value) _dbg(__LINE__,msg,value) +#else +#define _rx_dbg0(msg) +#define _rx_dbg1(msg,value) +#endif + +#if TX_DBG || RX_DBG +static void _dbg(int line, char *msg, uint32_t value); +#endif + +/* + * Set the state of the specified endpoint register to a new + * value. This is tricky because the bits toggle where the new + * value is one, and we need to write invariant values in other + * spots of the register. This hardware is strange... + */ +static void +_ao_usb_set_stat_tx(int ep, uint32_t stat_tx) +{ +	uint16_t	epr_write, epr_old; + +	_tx_dbg1("set_stat_tx top", stat_tx); +	epr_old = epr_write = stm_usb.epr[ep].r; +	epr_write &= STM_USB_EPR_PRESERVE_MASK; +	epr_write |= STM_USB_EPR_INVARIANT; +	epr_write |= set_toggle(epr_old, +			      STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX, +			      stat_tx << STM_USB_EPR_STAT_TX); +	stm_usb.epr[ep].r = epr_write; +	_tx_dbg1("set_stat_tx bottom", epr_write); +} + +static void +ao_usb_set_stat_tx(int ep, uint32_t stat_tx) +{ +	ao_arch_block_interrupts(); +	_ao_usb_set_stat_tx(ep, stat_tx); +	ao_arch_release_interrupts(); +} + +static void +_ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { +	uint16_t	epr_write, epr_old; + +	epr_write = epr_old = stm_usb.epr[ep].r; +	epr_write &= STM_USB_EPR_PRESERVE_MASK; +	epr_write |= STM_USB_EPR_INVARIANT; +	epr_write |= set_toggle(epr_old, +			      STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX, +			      stat_rx << STM_USB_EPR_STAT_RX); +	stm_usb.epr[ep].r = epr_write; +} + +static void +ao_usb_set_stat_rx(int ep, uint32_t stat_rx) { +	ao_arch_block_interrupts(); +	_ao_usb_set_stat_rx(ep, stat_rx); +	ao_arch_release_interrupts(); +} + +/* + * Set just endpoint 0, for use during startup + */ + +static void +ao_usb_init_ep(uint8_t ep, uint32_t addr, uint32_t type, uint32_t stat_rx, uint32_t stat_tx) +{ +	uint16_t		epr; + +	ao_arch_block_interrupts(); +	epr = stm_usb.epr[ep].r; +	epr = ((0 << STM_USB_EPR_CTR_RX) | +	       (epr & (1 << STM_USB_EPR_DTOG_RX)) | +	       set_toggle(epr, +			  (STM_USB_EPR_STAT_RX_MASK << STM_USB_EPR_STAT_RX), +			  (stat_rx << STM_USB_EPR_STAT_RX)) | +	       (type << STM_USB_EPR_EP_TYPE) | +	       (0 << STM_USB_EPR_EP_KIND) | +	       (0 << STM_USB_EPR_CTR_TX) | +	       (epr & (1 << STM_USB_EPR_DTOG_TX)) | +	       set_toggle(epr, +			  (STM_USB_EPR_STAT_TX_MASK << STM_USB_EPR_STAT_TX), +			  (stat_tx << STM_USB_EPR_STAT_TX)) | +	       (addr << STM_USB_EPR_EA)); +	stm_usb.epr[ep].r = epr; +	ao_arch_release_interrupts(); +	debug ("writing epr[%d] 0x%04x wrote 0x%04x\n", +	       ep, epr, stm_usb.epr[ep].r); +} + +static void +ao_usb_init_btable(void) +{ +	ao_usb_sram_addr = 0; + +	ao_usb_bdt = (void *) stm_usb_sram; + +	ao_usb_sram_addr += 8 * STM_USB_BDT_SIZE; + +	/* Set up EP 0 - a Control end point with 32 bytes of in and out buffers */ + +	ao_usb_bdt[0].single.addr_tx = ao_usb_sram_addr; +	ao_usb_bdt[0].single.count_tx = 0; +	ao_usb_ep0_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); +	ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + +	ao_usb_bdt[0].single.addr_rx = ao_usb_sram_addr; +	ao_usb_bdt[0].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | +				  (((AO_USB_CONTROL_SIZE / 32) - 1) << STM_USB_BDT_COUNT_RX_NUM_BLOCK)); +	ao_usb_ep0_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); +	ao_usb_sram_addr += AO_USB_CONTROL_SIZE; + +} + +static void +ao_usb_set_ep0(void) +{ +	int			e; + +	ao_usb_init_btable(); + +	/* buffer table is at the start of USB memory */ +	stm_usb.btable = 0; + +	ao_usb_init_ep(AO_USB_CONTROL_EPR, AO_USB_CONTROL_EP, +		       STM_USB_EPR_EP_TYPE_CONTROL, +		       STM_USB_EPR_STAT_RX_VALID, +		       STM_USB_EPR_STAT_TX_NAK); + +	/* Clear all of the other endpoints */ +	for (e = 1; e < 8; e++) { +		ao_usb_init_ep(e, 0, +			       STM_USB_EPR_EP_TYPE_CONTROL, +			       STM_USB_EPR_STAT_RX_DISABLED, +			       STM_USB_EPR_STAT_TX_DISABLED); +	} + +	ao_usb_set_address(0); +} + +static void +ao_usb_set_configuration(void) +{ +	debug ("ao_usb_set_configuration\n"); + +	/* Set up the INT end point */ +	ao_usb_bdt[AO_USB_INT_EPR].single.addr_tx = ao_usb_sram_addr; +	ao_usb_bdt[AO_USB_INT_EPR].single.count_tx = 0; +	ao_usb_sram_addr += AO_USB_INT_SIZE; + +	ao_usb_init_ep(AO_USB_INT_EPR, +		       AO_USB_INT_EP, +		       STM_USB_EPR_EP_TYPE_INTERRUPT, +		       STM_USB_EPR_STAT_RX_DISABLED, +		       STM_USB_EPR_STAT_TX_NAK); + +	/* Set up the OUT end point */ +	ao_usb_bdt[AO_USB_OUT_EPR].single.addr_rx = ao_usb_sram_addr; +	ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx = ((1 << STM_USB_BDT_COUNT_RX_BL_SIZE) | +						      (((AO_USB_OUT_SIZE / 32) - 1) << STM_USB_BDT_COUNT_RX_NUM_BLOCK)); +	ao_usb_out_rx_buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); +	ao_usb_sram_addr += AO_USB_OUT_SIZE; + +	ao_usb_init_ep(AO_USB_OUT_EPR, +		       AO_USB_OUT_EP, +		       STM_USB_EPR_EP_TYPE_BULK, +		       STM_USB_EPR_STAT_RX_VALID, +		       STM_USB_EPR_STAT_TX_DISABLED); + +	/* Set up the IN end point */ +	ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_sram_addr; +	ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = 0; +	ao_usb_in_tx_offset = ao_usb_sram_addr; +	ao_usb_in_tx_buffer = ao_usb_packet_buffer_addr(ao_usb_in_tx_offset); +	ao_usb_sram_addr += AO_USB_IN_SIZE; + +	ao_usb_init_ep(AO_USB_IN_EPR, +		       AO_USB_IN_EP, +		       STM_USB_EPR_EP_TYPE_BULK, +		       STM_USB_EPR_STAT_RX_DISABLED, +		       STM_USB_EPR_STAT_TX_NAK); + +	ao_usb_running = 1; +} + +static uint16_t	control_count; +static uint16_t int_count; +static uint16_t	in_count; +static uint16_t	out_count; +static uint16_t	reset_count; + +/* The USB memory must be accessed in 16-bit units + */ + +static void +ao_usb_copy_tx(const uint8_t *src, uint16_t *base, uint16_t bytes) +{ +	while (bytes >= 2) { +		*base++ = src[0] | (src[1] << 8); +		src += 2; +		bytes -= 2; +	} +	if (bytes) +		*base = *src; +} + +static void +ao_usb_copy_rx(uint8_t *dst, uint16_t *base, uint16_t bytes) +{ +	while (bytes >= 2) { +		uint16_t s = *base++; +		dst[0] = s; +		dst[1] = s >> 8; +		dst += 2; +		bytes -= 2; +	} +	if (bytes) +		*dst = *base; +} + +/* Send an IN data packet */ +static void +ao_usb_ep0_flush(void) +{ +	uint8_t this_len; + +	/* Check to see if the endpoint is still busy */ +	if (ao_usb_epr_stat_tx(stm_usb.epr[0].r) == STM_USB_EPR_STAT_TX_VALID) { +		debug("EP0 not accepting IN data\n"); +		return; +	} + +	this_len = ao_usb_ep0_in_len; +	if (this_len > AO_USB_CONTROL_SIZE) +		this_len = AO_USB_CONTROL_SIZE; + +	if (this_len < AO_USB_CONTROL_SIZE) +		ao_usb_ep0_state = AO_USB_EP0_IDLE; + +	ao_usb_ep0_in_len -= this_len; + +	debug_data ("Flush EP0 len %d:", this_len); +	ao_usb_copy_tx(ao_usb_ep0_in_data, ao_usb_ep0_tx_buffer, this_len); +	debug_data ("\n"); +	ao_usb_ep0_in_data += this_len; + +	/* Mark the endpoint as TX valid to send the packet */ +	ao_usb_bdt[AO_USB_CONTROL_EPR].single.count_tx = this_len; +	ao_usb_set_stat_tx(AO_USB_CONTROL_EPR, STM_USB_EPR_STAT_TX_VALID); +	debug ("queue tx. epr 0 now %08x\n", stm_usb.epr[AO_USB_CONTROL_EPR]); +} + +/* Read data from the ep0 OUT fifo */ +static void +ao_usb_ep0_fill(void) +{ +	uint16_t	len = ao_usb_bdt[0].single.count_rx & STM_USB_BDT_COUNT_RX_COUNT_RX_MASK; + +	if (len > ao_usb_ep0_out_len) +		len = ao_usb_ep0_out_len; +	ao_usb_ep0_out_len -= len; + +	/* Pull all of the data out of the packet */ +	debug_data ("Fill EP0 len %d:", len); +	ao_usb_copy_rx(ao_usb_ep0_out_data, ao_usb_ep0_rx_buffer, len); +	debug_data ("\n"); +	ao_usb_ep0_out_data += len; + +	/* ACK the packet */ +	ao_usb_set_stat_rx(0, STM_USB_EPR_STAT_RX_VALID); +} + +static void +ao_usb_ep0_in_reset(void) +{ +	ao_usb_ep0_in_data = ao_usb_ep0_in_buf; +	ao_usb_ep0_in_len = 0; +} + +static void +ao_usb_ep0_in_queue_byte(uint8_t a) +{ +	if (ao_usb_ep0_in_len < sizeof (ao_usb_ep0_in_buf)) +		ao_usb_ep0_in_buf[ao_usb_ep0_in_len++] = a; +} + +static void +ao_usb_ep0_in_set(const uint8_t *data, uint8_t len) +{ +	ao_usb_ep0_in_data = data; +	ao_usb_ep0_in_len = len; +} + +static void +ao_usb_ep0_out_set(uint8_t *data, uint8_t len) +{ +	ao_usb_ep0_out_data = data; +	ao_usb_ep0_out_len = len; +} + +static void +ao_usb_ep0_in_start(uint16_t max) +{ +	/* Don't send more than asked for */ +	if (ao_usb_ep0_in_len > max) +		ao_usb_ep0_in_len = max; +	ao_usb_ep0_flush(); +} + +static struct ao_usb_line_coding ao_usb_line_coding = {115200, 0, 0, 8}; + +/* Walk through the list of descriptors and find a match + */ +static void +ao_usb_get_descriptor(uint16_t value) +{ +	const uint8_t		*descriptor; +	uint8_t		type = value >> 8; +	uint8_t		index = value; + +	descriptor = ao_usb_descriptors; +	while (descriptor[0] != 0) { +		if (descriptor[1] == type && index-- == 0) { +			uint8_t	len; +			if (type == AO_USB_DESC_CONFIGURATION) +				len = descriptor[2]; +			else +				len = descriptor[0]; +			ao_usb_ep0_in_set(descriptor, len); +			break; +		} +		descriptor += descriptor[0]; +	} +} + +static void +ao_usb_ep0_setup(void) +{ +	/* Pull the setup packet out of the fifo */ +	ao_usb_ep0_out_set((uint8_t *) &ao_usb_setup, 8); +	ao_usb_ep0_fill(); +	if (ao_usb_ep0_out_len != 0) { +		debug ("invalid setup packet length\n"); +		return; +	} + +	if ((ao_usb_setup.dir_type_recip & AO_USB_DIR_IN) || ao_usb_setup.length == 0) +		ao_usb_ep0_state = AO_USB_EP0_DATA_IN; +	else +		ao_usb_ep0_state = AO_USB_EP0_DATA_OUT; + +	ao_usb_ep0_in_reset(); + +	switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_TYPE_MASK) { +	case AO_USB_TYPE_STANDARD: +		debug ("Standard setup packet\n"); +		switch(ao_usb_setup.dir_type_recip & AO_USB_SETUP_RECIP_MASK) { +		case AO_USB_RECIP_DEVICE: +			debug ("Device setup packet\n"); +			switch(ao_usb_setup.request) { +			case AO_USB_REQ_GET_STATUS: +				debug ("get status\n"); +				ao_usb_ep0_in_queue_byte(0); +				ao_usb_ep0_in_queue_byte(0); +				break; +			case AO_USB_REQ_SET_ADDRESS: +				debug ("set address %d\n", ao_usb_setup.value); +				ao_usb_address = ao_usb_setup.value; +				ao_usb_address_pending = 1; +				break; +			case AO_USB_REQ_GET_DESCRIPTOR: +				debug ("get descriptor %d\n", ao_usb_setup.value); +				ao_usb_get_descriptor(ao_usb_setup.value); +				break; +			case AO_USB_REQ_GET_CONFIGURATION: +				debug ("get configuration %d\n", ao_usb_configuration); +				ao_usb_ep0_in_queue_byte(ao_usb_configuration); +				break; +			case AO_USB_REQ_SET_CONFIGURATION: +				ao_usb_configuration = ao_usb_setup.value; +				debug ("set configuration %d\n", ao_usb_configuration); +				ao_usb_set_configuration(); +				break; +			} +			break; +		case AO_USB_RECIP_INTERFACE: +			debug ("Interface setup packet\n"); +			switch(ao_usb_setup.request) { +			case AO_USB_REQ_GET_STATUS: +				ao_usb_ep0_in_queue_byte(0); +				ao_usb_ep0_in_queue_byte(0); +				break; +			case AO_USB_REQ_GET_INTERFACE: +				ao_usb_ep0_in_queue_byte(0); +				break; +			case AO_USB_REQ_SET_INTERFACE: +				break; +			} +			break; +		case AO_USB_RECIP_ENDPOINT: +			debug ("Endpoint setup packet\n"); +			switch(ao_usb_setup.request) { +			case AO_USB_REQ_GET_STATUS: +				ao_usb_ep0_in_queue_byte(0); +				ao_usb_ep0_in_queue_byte(0); +				break; +			} +			break; +		} +		break; +	case AO_USB_TYPE_CLASS: +		debug ("Class setup packet\n"); +		switch (ao_usb_setup.request) { +		case AO_USB_SET_LINE_CODING: +			debug ("set line coding\n"); +			ao_usb_ep0_out_set((uint8_t *) &ao_usb_line_coding, 7); +			break; +		case AO_USB_GET_LINE_CODING: +			debug ("get line coding\n"); +			ao_usb_ep0_in_set((const uint8_t *) &ao_usb_line_coding, 7); +			break; +		case AO_USB_SET_CONTROL_LINE_STATE: +			break; +		} +		break; +	} + +	/* If we're not waiting to receive data from the host, +	 * queue an IN response +	 */ +	if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) +		ao_usb_ep0_in_start(ao_usb_setup.length); +} + +static void +ao_usb_ep0_handle(uint8_t receive) +{ +	ao_usb_ep0_receive = 0; +	if (receive & AO_USB_EP0_GOT_RESET) { +		debug ("\treset\n"); +		ao_usb_set_ep0(); +		return; +	} +	if (receive & AO_USB_EP0_GOT_SETUP) { +		debug ("\tsetup\n"); +		ao_usb_ep0_setup(); +	} +	if (receive & AO_USB_EP0_GOT_RX_DATA) { +		debug ("\tgot rx data\n"); +		if (ao_usb_ep0_state == AO_USB_EP0_DATA_OUT) { +			ao_usb_ep0_fill(); +			if (ao_usb_ep0_out_len == 0) { +				ao_usb_ep0_state = AO_USB_EP0_DATA_IN; +				ao_usb_ep0_in_start(0); +			} +		} +	} +	if (receive & AO_USB_EP0_GOT_TX_ACK) { +		debug ("\tgot tx ack\n"); + +#if HAS_FLIGHT && AO_USB_FORCE_IDLE +		ao_flight_force_idle = 1; +#endif +		/* Wait until the IN packet is received from addr 0 +		 * before assigning our local address +		 */ +		if (ao_usb_address_pending) +			ao_usb_set_address(ao_usb_address); +		if (ao_usb_ep0_state == AO_USB_EP0_DATA_IN) +			ao_usb_ep0_flush(); +	} +} + +void +stm_usb_isr(void) +{ +	uint32_t	istr = stm_usb.istr; + +	stm_usb.istr = ~istr; +	if (istr & (1 << STM_USB_ISTR_CTR)) { +		uint8_t		ep = istr & STM_USB_ISTR_EP_ID_MASK; +		uint16_t	epr, epr_write; + +		/* Preserve the SW write bits, don't mess with most HW writable bits, +		 * clear the CTR_RX and CTR_TX bits +		 */ +		epr = stm_usb.epr[ep].r; +		epr_write = epr; +		epr_write &= STM_USB_EPR_PRESERVE_MASK; +		epr_write |= STM_USB_EPR_INVARIANT; +		epr_write &= ~(1 << STM_USB_EPR_CTR_RX); +		epr_write &= ~(1 << STM_USB_EPR_CTR_TX); +		stm_usb.epr[ep].r = epr_write; + +		switch (ep) { +		case 0: +			++control_count; +			if (ao_usb_epr_ctr_rx(epr)) { +				if (ao_usb_epr_setup(epr)) +					ao_usb_ep0_receive |= AO_USB_EP0_GOT_SETUP; +				else +					ao_usb_ep0_receive |= AO_USB_EP0_GOT_RX_DATA; +			} +			if (ao_usb_epr_ctr_tx(epr)) +				ao_usb_ep0_receive |= AO_USB_EP0_GOT_TX_ACK; +			ao_usb_ep0_handle(ao_usb_ep0_receive); +			break; +		case AO_USB_OUT_EPR: +			++out_count; +			if (ao_usb_epr_ctr_rx(epr)) { +				_rx_dbg1("RX ISR", epr); +				ao_usb_out_avail = 1; +				_rx_dbg0("out avail set"); +				ao_wakeup(AO_USB_OUT_SLEEP_ADDR); +				_rx_dbg0("stdin awoken"); +			} +			break; +		case AO_USB_IN_EPR: +			++in_count; +			_tx_dbg1("TX ISR", epr); +			if (ao_usb_epr_ctr_tx(epr)) { +				ao_usb_in_pending = 0; +				ao_wakeup(&ao_usb_in_pending); +			} +			break; +		case AO_USB_INT_EPR: +			++int_count; +			if (ao_usb_epr_ctr_tx(epr)) +				_ao_usb_set_stat_tx(AO_USB_INT_EPR, STM_USB_EPR_STAT_TX_NAK); +			break; +		} +		return; +	} + +	if (istr & (1 << STM_USB_ISTR_RESET)) { +		++reset_count; +		ao_usb_ep0_receive |= AO_USB_EP0_GOT_RESET; +		ao_usb_ep0_handle(ao_usb_ep0_receive); +	} + +} + +/* Queue the current IN buffer for transmission */ +static void +_ao_usb_in_send(void) +{ +	_tx_dbg0("in_send start"); +	debug ("send %d\n", ao_usb_tx_count); +	while (ao_usb_in_pending) +		ao_sleep(&ao_usb_in_pending); +	ao_usb_in_pending = 1; +	if (ao_usb_tx_count != AO_USB_IN_SIZE) +		ao_usb_in_flushed = 1; +	ao_usb_copy_tx(ao_usb_tx_buffer, ao_usb_in_tx_buffer, ao_usb_tx_count); +	ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_in_tx_offset; +	ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = ao_usb_tx_count; +	ao_usb_tx_count = 0; +	_ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); +	_tx_dbg0("in_send end"); +} + +/* Wait for a free IN buffer. Interrupts are blocked */ +static void +_ao_usb_in_wait(void) +{ +	for (;;) { +		/* Check if the current buffer is writable */ +		if (ao_usb_tx_count < AO_USB_IN_SIZE) +			break; + +		_tx_dbg0("in_wait top"); +		/* Wait for an IN buffer to be ready */ +		while (ao_usb_in_pending) +			ao_sleep(&ao_usb_in_pending); +		_tx_dbg0("in_wait bottom"); +	} +} + +void +ao_usb_flush(void) +{ +	if (!ao_usb_running) +		return; + +	/* Anytime we've sent a character since +	 * the last time we flushed, we'll need +	 * to send a packet -- the only other time +	 * we would send a packet is when that +	 * packet was full, in which case we now +	 * want to send an empty packet +	 */ +	ao_arch_block_interrupts(); +	while (!ao_usb_in_flushed) { +		_tx_dbg0("flush top"); +		_ao_usb_in_send(); +		_tx_dbg0("flush end"); +	} +	ao_arch_release_interrupts(); +} + +void +ao_usb_putchar(char c) +{ +	if (!ao_usb_running) +		return; + +	ao_arch_block_interrupts(); +	_ao_usb_in_wait(); + +	ao_usb_in_flushed = 0; +	ao_usb_tx_buffer[ao_usb_tx_count++] = (uint8_t) c; + +	/* Send the packet when full */ +	if (ao_usb_tx_count == AO_USB_IN_SIZE) { +		_tx_dbg0("putchar full"); +		_ao_usb_in_send(); +		_tx_dbg0("putchar flushed"); +	} +	ao_arch_release_interrupts(); +} + +static void +_ao_usb_out_recv(void) +{ +	_rx_dbg0("out_recv top"); +	ao_usb_out_avail = 0; + +	ao_usb_rx_count = ao_usb_bdt[AO_USB_OUT_EPR].single.count_rx & STM_USB_BDT_COUNT_RX_COUNT_RX_MASK; + +	_rx_dbg1("out_recv count", ao_usb_rx_count); +	debug ("recv %d\n", ao_usb_rx_count); +	debug_data("Fill OUT len %d:", ao_usb_rx_count); +	ao_usb_copy_rx(ao_usb_rx_buffer, ao_usb_out_rx_buffer, ao_usb_rx_count); +	debug_data("\n"); +	ao_usb_rx_pos = 0; + +	/* ACK the packet */ +	_ao_usb_set_stat_rx(AO_USB_OUT_EPR, STM_USB_EPR_STAT_RX_VALID); +} + +int +_ao_usb_pollchar(void) +{ +	uint8_t c; + +	if (!ao_usb_running) +		return AO_READ_AGAIN; + +	for (;;) { +		if (ao_usb_rx_pos != ao_usb_rx_count) +			break; + +		_rx_dbg0("poll check"); +		/* Check to see if a packet has arrived */ +		if (!ao_usb_out_avail) { +			_rx_dbg0("poll none"); +			return AO_READ_AGAIN; +		} +		_ao_usb_out_recv(); +	} + +	/* Pull a character out of the fifo */ +	c = ao_usb_rx_buffer[ao_usb_rx_pos++]; +	return c; +} + +char +ao_usb_getchar(void) +{ +	int	c; + +	ao_arch_block_interrupts(); +	while ((c = _ao_usb_pollchar()) == AO_READ_AGAIN) +		ao_sleep(AO_USB_OUT_SLEEP_ADDR); +	ao_arch_release_interrupts(); +	return c; +} + +#if AO_USB_DIRECTIO +uint16_t * +ao_usb_alloc(void) +{ +	uint16_t	*buffer; + +	if (!ao_usb_running) +		return NULL; +	buffer = ao_usb_packet_buffer_addr(ao_usb_sram_addr); +	ao_usb_sram_addr += AO_USB_IN_SIZE; +	return buffer; +} + +void +ao_usb_free(uint16_t *addr) +{ +	uint16_t	offset = ao_usb_packet_buffer_offset(addr); +	if (offset < ao_usb_sram_addr) +		ao_usb_sram_addr = offset; +} + +void +ao_usb_write(uint16_t *buffer, uint16_t len) +{ +	ao_arch_block_interrupts(); + +	/* Flush any pending regular */ +	if (ao_usb_tx_count) +		_ao_usb_in_send(); + +	while (ao_usb_in_pending) +		ao_sleep(&ao_usb_in_pending); +	ao_usb_in_pending = 1; +	ao_usb_in_flushed = (len != AO_USB_IN_SIZE); +	ao_usb_bdt[AO_USB_IN_EPR].single.addr_tx = ao_usb_packet_buffer_offset(buffer); +	ao_usb_bdt[AO_USB_IN_EPR].single.count_tx = len; +	_ao_usb_set_stat_tx(AO_USB_IN_EPR, STM_USB_EPR_STAT_TX_VALID); +	ao_arch_release_interrupts(); +} +#endif + +void +ao_usb_disable(void) +{ +	ao_arch_block_interrupts(); +	stm_usb.cntr = (1 << STM_USB_CNTR_FRES); +	stm_usb.istr = 0; + +	/* Disable USB pull-up */ +	stm_usb.bcdr &= ~(1 << STM_USB_BCDR_DPPU); + +	/* Switch off the device */ +	stm_usb.cntr = (1 << STM_USB_CNTR_PDWN) | (1 << STM_USB_CNTR_FRES); + +	/* Disable the interface */ +	stm_rcc.apb1enr &= ~(1 << STM_RCC_APB1ENR_USBEN); +	ao_arch_release_interrupts(); +} + +void +ao_usb_enable(void) +{ +	int	t; + +	/* Select HSI48 as USB clock source */ +	stm_rcc.cfgr3 &= ~(1 << STM_RCC_CFGR3_USBSW); + +	/* Enable USB device */ +	stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_USBEN); + +	/* Clear reset condition */ +	stm_rcc.apb1rstr &= ~(1 << STM_RCC_APB1RSTR_USBRST); + +	/* Disable USB pull-up */ +	stm_usb.bcdr &= ~(1 << STM_USB_BCDR_DPPU); + +	/* Do not touch the GPIOA configuration; USB takes priority +	 * over GPIO on pins A11 and A12, but if you select alternate +	 * input 10 (the documented correct selection), then USB is +	 * pulled low and doesn't work at all +	 */ + +	ao_arch_block_interrupts(); + +	/* Route interrupts */ +	stm_nvic_set_enable(STM_ISR_USB_POS); +	stm_nvic_set_priority(STM_ISR_USB_POS, 3); + +	ao_usb_configuration = 0; + +	/* Set up buffer descriptors */ +	ao_usb_init_btable(); + +	/* Reset the USB controller */ +	stm_usb.cntr = (1 << STM_USB_CNTR_FRES); + +	/* Clear the reset bit */ +	stm_usb.cntr = 0; + +	/* Clear any spurious interrupts */ +	stm_usb.istr = 0; + +	ao_usb_set_ep0(); + +	debug ("ao_usb_enable\n"); + +	/* Enable interrupts */ +	stm_usb.cntr = ((1 << STM_USB_CNTR_CTRM) | +			(0 << STM_USB_CNTR_PMAOVRM) | +			(0 << STM_USB_CNTR_ERRM) | +			(0 << STM_USB_CNTR_WKUPM) | +			(0 << STM_USB_CNTR_SUSPM) | +			(1 << STM_USB_CNTR_RESETM) | +			(0 << STM_USB_CNTR_SOFM) | +			(0 << STM_USB_CNTR_ESOFM) | +			(0 << STM_USB_CNTR_RESUME) | +			(0 << STM_USB_CNTR_FSUSP) | +			(0 << STM_USB_CNTR_LP_MODE) | +			(0 << STM_USB_CNTR_PDWN) | +			(0 << STM_USB_CNTR_FRES)); + +	ao_arch_release_interrupts(); + +	for (t = 0; t < 1000; t++) +		ao_arch_nop(); + +	/* Enable USB pull-up */ +	stm_usb.bcdr |= (1 << STM_USB_BCDR_DPPU); +} + +#if USB_ECHO +struct ao_task ao_usb_echo_task; + +static void +ao_usb_echo(void) +{ +	char	c; + +	for (;;) { +		c = ao_usb_getchar(); +		ao_usb_putchar(c); +		ao_usb_flush(); +	} +} +#endif + +#if USB_DEBUG +static void +ao_usb_irq(void) +{ +	printf ("control: %d out: %d in: %d int: %d reset: %d\n", +		control_count, out_count, in_count, int_count, reset_count); +} + +__code struct ao_cmds ao_usb_cmds[] = { +	{ ao_usb_irq, "I\0Show USB interrupt counts" }, +	{ 0, NULL } +}; +#endif + +void +ao_usb_init(void) +{ +	/* Turn on syscfg */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + +	/* Set PA11/PA12 remapping bit */ +	stm_syscfg.cfgr1 |= (AO_PA11_PA12_RMP << STM_SYSCFG_CFGR1_PA11_PA12_RMP); + +	ao_usb_enable(); + +	debug ("ao_usb_init\n"); +	ao_usb_ep0_state = AO_USB_EP0_IDLE; +#if USB_ECHO +	ao_add_task(&ao_usb_echo_task, ao_usb_echo, "usb echo"); +#endif +#if USB_DEBUG +	ao_cmd_register(&ao_usb_cmds[0]); +#endif +#if !USB_ECHO +#if USE_USB_STDIO +	ao_add_stdio(_ao_usb_pollchar, ao_usb_putchar, ao_usb_flush); +#endif +#endif +} + +#if TX_DBG || RX_DBG + +struct ao_usb_dbg { +	int		line; +	char		*msg; +	uint32_t	value; +	uint32_t	primask; +#if TX_DBG +	uint16_t	in_count; +	uint32_t	in_epr; +	uint32_t	in_pending; +	uint32_t	tx_count; +	uint32_t	in_flushed; +#endif +#if RX_DBG +	uint8_t		rx_count; +	uint8_t		rx_pos; +	uint8_t		out_avail; +	uint32_t	out_epr; +#endif +}; + +#define NUM_USB_DBG	128 + +static struct ao_usb_dbg dbg[128]; +static int dbg_i; + +static void _dbg(int line, char *msg, uint32_t value) +{ +	uint32_t	primask; +	dbg[dbg_i].line = line; +	dbg[dbg_i].msg = msg; +	dbg[dbg_i].value = value; +	asm("mrs %0,primask" : "=&r" (primask)); +	dbg[dbg_i].primask = primask; +#if TX_DBG +	dbg[dbg_i].in_count = in_count; +	dbg[dbg_i].in_epr = stm_usb.epr[AO_USB_IN_EPR]; +	dbg[dbg_i].in_pending = ao_usb_in_pending; +	dbg[dbg_i].tx_count = ao_usb_tx_count; +	dbg[dbg_i].in_flushed = ao_usb_in_flushed; +#endif +#if RX_DBG +	dbg[dbg_i].rx_count = ao_usb_rx_count; +	dbg[dbg_i].rx_pos = ao_usb_rx_pos; +	dbg[dbg_i].out_avail = ao_usb_out_avail; +	dbg[dbg_i].out_epr = stm_usb.epr[AO_USB_OUT_EPR]; +#endif +	if (++dbg_i == NUM_USB_DBG) +		dbg_i = 0; +} +#endif diff --git a/src/stmf0/registers.ld b/src/stmf0/registers.ld new file mode 100644 index 00000000..598fc1af --- /dev/null +++ b/src/stmf0/registers.ld @@ -0,0 +1,57 @@ +stm_gpiof  = 0x48001400; +stm_gpioc  = 0x48000800; +stm_gpiob  = 0x48000400; +stm_gpioa  = 0x48000000; + +stm_tsc    = 0x40024000; +stm_crc    = 0x40023000; +stm_flash  = 0x40022000; +stm_rcc    = 0x40021000; +stm_dma    = 0x40020000; +stm_dbgmcu = 0x40015800; +stm_tim17  = 0x40014800; +stm_tim16  = 0x40014400; +stm_usart1 = 0x40013800; +stm_spi1   = 0x40013000; +stm_tim1   = 0x40012c00; +stm_adc    = 0x40012400; + +stm_exti   = 0x40010400; +stm_syscfg = 0x40010000; + +stm_cec    = 0x40007800; + +stm_pwr    = 0x40007000; +stm_crs    = 0x40006c00; + +stm_bxcan  = 0x40006400; +stm_usb_sram = 0x40006000; +stm_usb    = 0x40005c00; + +stm_i2c1   = 0x40005400; + +stm_usart2 = 0x40004400; + +stm_spi2   = 0x40003800;	/* docs are broken here */ + +stm_iwdg   = 0x40003000; +stm_wwdg   = 0x40002c00; +stm_rtc    = 0x40002800; + +stm_tim14  = 0x40002000; + +stm_tim3   = 0x40000400; +stm_tim2   = 0x40000000; + +stm_systick = 0xe000e010; + +stm_nvic   = 0xe000e100; + +stm_scb    = 0xe000ed00; + +stm_mpu    = 0xe000ed90; + +/* calibration data in system memory */ +stm_cal = 0x1ffff7b8; +stm_flash_size_04x = 0x1ffff7cc; +stm_device_id = 0x1ff80050; diff --git a/src/stmf0/stm32f0.h b/src/stmf0/stm32f0.h new file mode 100644 index 00000000..ce8ca456 --- /dev/null +++ b/src/stmf0/stm32f0.h @@ -0,0 +1,1667 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _STM32F0_H_ +#define _STM32F0_H_ + +#include <stdint.h> + +typedef volatile uint32_t	vuint32_t; +typedef volatile void *		vvoid_t; +typedef volatile uint16_t	vuint16_t; +typedef volatile uint8_t	vuint8_t; + +struct stm_gpio { +	vuint32_t	moder; +	vuint32_t	otyper; +	vuint32_t	ospeedr; +	vuint32_t	pupdr; + +	vuint32_t	idr; +	vuint32_t	odr; +	vuint32_t	bsrr; +	vuint32_t	lckr; + +	vuint32_t	afrl; +	vuint32_t	afrh; +	vuint32_t	brr; +}; + +#define STM_MODER_SHIFT(pin)		((pin) << 1) +#define STM_MODER_MASK			3 +#define STM_MODER_INPUT			0 +#define STM_MODER_OUTPUT		1 +#define STM_MODER_ALTERNATE		2 +#define STM_MODER_ANALOG		3 + +static inline void +stm_moder_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +	gpio->moder = ((gpio->moder & +			~(STM_MODER_MASK << STM_MODER_SHIFT(pin))) | +		       value << STM_MODER_SHIFT(pin)); +} + +static inline uint32_t +stm_moder_get(struct stm_gpio *gpio, int pin) { +	return (gpio->moder >> STM_MODER_SHIFT(pin)) & STM_MODER_MASK; +} + +#define STM_OTYPER_SHIFT(pin)		(pin) +#define STM_OTYPER_MASK			1 +#define STM_OTYPER_PUSH_PULL		0 +#define STM_OTYPER_OPEN_DRAIN		1 + +static inline void +stm_otyper_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +	gpio->otyper = ((gpio->otyper & +			 ~(STM_OTYPER_MASK << STM_OTYPER_SHIFT(pin))) | +			value << STM_OTYPER_SHIFT(pin)); +} + +static inline uint32_t +stm_otyper_get(struct stm_gpio *gpio, int pin) { +	return (gpio->otyper >> STM_OTYPER_SHIFT(pin)) & STM_OTYPER_MASK; +} + +#define STM_OSPEEDR_SHIFT(pin)		((pin) << 1) +#define STM_OSPEEDR_MASK		3 +#define STM_OSPEEDR_LOW			0	/* 2MHz */ +#define STM_OSPEEDR_MEDIUM		1	/* 10MHz */ +#define STM_OSPEEDR_HIGH		3	/* 10-50MHz */ + +static inline void +stm_ospeedr_set(struct stm_gpio *gpio, int pin, vuint32_t value) { +	gpio->ospeedr = ((gpio->ospeedr & +			~(STM_OSPEEDR_MASK << STM_OSPEEDR_SHIFT(pin))) | +		       value << STM_OSPEEDR_SHIFT(pin)); +} + +static inline uint32_t +stm_ospeedr_get(struct stm_gpio *gpio, int pin) { +	return (gpio->ospeedr >> STM_OSPEEDR_SHIFT(pin)) & STM_OSPEEDR_MASK; +} + +#define STM_PUPDR_SHIFT(pin)		((pin) << 1) +#define STM_PUPDR_MASK			3 +#define STM_PUPDR_NONE			0 +#define STM_PUPDR_PULL_UP		1 +#define STM_PUPDR_PULL_DOWN		2 +#define STM_PUPDR_RESERVED		3 + +static inline void +stm_pupdr_set(struct stm_gpio *gpio, int pin, uint32_t value) { +	gpio->pupdr = ((gpio->pupdr & +			~(STM_PUPDR_MASK << STM_PUPDR_SHIFT(pin))) | +		       value << STM_PUPDR_SHIFT(pin)); +} + +static inline uint32_t +stm_pupdr_get(struct stm_gpio *gpio, int pin) { +	return (gpio->pupdr >> STM_PUPDR_SHIFT(pin)) & STM_PUPDR_MASK; +} + +#define STM_AFR_SHIFT(pin)		((pin) << 2) +#define STM_AFR_MASK			0xf +#define STM_AFR_NONE			0 +#define STM_AFR_AF0			0x0 +#define STM_AFR_AF1			0x1 +#define STM_AFR_AF2			0x2 +#define STM_AFR_AF3			0x3 +#define STM_AFR_AF4			0x4 +#define STM_AFR_AF5			0x5 +#define STM_AFR_AF6			0x6 +#define STM_AFR_AF7			0x7 + +static inline void +stm_afr_set(struct stm_gpio *gpio, int pin, uint32_t value) { +	/* +	 * Set alternate pin mode too +	 */ +	stm_moder_set(gpio, pin, STM_MODER_ALTERNATE); +	if (pin < 8) +		gpio->afrl = ((gpio->afrl & +			       ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) | +			      value << STM_AFR_SHIFT(pin)); +	else { +		pin -= 8; +		gpio->afrh = ((gpio->afrh & +			       ~(STM_AFR_MASK << STM_AFR_SHIFT(pin))) | +			      value << STM_AFR_SHIFT(pin)); +	} +} + +static inline uint32_t +stm_afr_get(struct stm_gpio *gpio, int pin) { +	if (pin < 8) +		return (gpio->afrl >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK; +	else { +		pin -= 8; +		return (gpio->afrh >> STM_AFR_SHIFT(pin)) & STM_AFR_MASK; +	} +} + +static inline void +stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) { +	/* Use the bit set/reset register to do this atomically */ +	gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin); +} + +static inline uint8_t +stm_gpio_get(struct stm_gpio *gpio, int pin) { +	return (gpio->idr >> pin) & 1; +} + +static inline uint16_t +stm_gpio_get_all(struct stm_gpio *gpio) { +	return gpio->idr; +} + +/* + * We can't define these in registers.ld or our fancy + * ao_enable_gpio macro will expand into a huge pile of code + * as the compiler won't do correct constant folding and + * dead-code elimination + */ + +extern struct stm_gpio stm_gpioa; +extern struct stm_gpio stm_gpiob; +extern struct stm_gpio stm_gpioc; +extern struct stm_gpio stm_gpiof; + +#define stm_gpiof  (*((struct stm_gpio *) 0x48001400)) +#define stm_gpioc  (*((struct stm_gpio *) 0x48000800)) +#define stm_gpiob  (*((struct stm_gpio *) 0x48000400)) +#define stm_gpioa  (*((struct stm_gpio *) 0x48000000)) + +/* Flash interface */ + +struct stm_flash { +	vuint32_t	acr; +	vuint32_t	keyr; +	vuint32_t	optkeyr; +	vuint32_t	sr; + +	vuint32_t	cr; +	vuint32_t	ar; +	vuint32_t	unused_0x18; +	vuint32_t	obr; + +	vuint32_t	wrpr; +}; + +extern struct stm_flash	stm_flash; + +#define STM_FLASH_ACR_PRFTBS	(5) +#define STM_FLASH_ACR_PRFTBE	(4) +#define STM_FLASH_ACR_LATENCY	(0) +#define  STM_FLASH_ACR_LATENCY_0		0 +#define  STM_FLASH_ACR_LATENCY_1		1 + +#define STM_FLASH_PECR_OBL_LAUNCH	18 +#define STM_FLASH_PECR_ERRIE		17 +#define STM_FLASH_PECR_EOPIE		16 +#define STM_FLASH_PECR_FPRG		10 +#define STM_FLASH_PECR_ERASE		9 +#define STM_FLASH_PECR_FTDW		8 +#define STM_FLASH_PECR_DATA		4 +#define STM_FLASH_PECR_PROG		3 +#define STM_FLASH_PECR_OPTLOCK		2 +#define STM_FLASH_PECR_PRGLOCK		1 +#define STM_FLASH_PECR_PELOCK		0 + +#define STM_FLASH_SR_EOP		5 +#define STM_FLASH_SR_WRPRTERR		4 +#define STM_FLASH_SR_PGERR		2 +#define STM_FLASH_SR_BSY		0 + +#define STM_FLASH_CR_OBL_LAUNCH		13 +#define STM_FLASH_CR_EOPIE		12 +#define STM_FLASH_CR_ERRIE		10 +#define STM_FLASH_CR_OPTWRE		9 +#define STM_FLASH_CR_LOCK		7 +#define STM_FLASH_CR_STRT		6 +#define STM_FLASH_CR_OPTER		5 +#define STM_FLASH_CR_OPTPG		4 +#define STM_FLASH_CR_MER		2 +#define STM_FLASH_CR_PER		1 +#define STM_FLASH_CR_PG			0 + +#define STM_FLASH_OBR_DATA1		24 +#define STM_FLASH_OBR_DATA0		16 +#define STM_FLASH_OBR_BOOT_SEL		15 +#define STM_FLASH_OBR_RAM_PARITY_CHECK	14 +#define STM_FLASH_OBR_VDDA_MONITOR	13 +#define STM_FLASH_OBR_NBOOT1		12 +#define STM_FLASH_OBR_NBOOT0		11 +#define STM_FLASH_OBR_NRST_STDBY	10 +#define STM_FLASH_OBR_NRST_STOP		9 +#define STM_FLASH_OBR_WDG_SW		8 +#define STM_FLASH_OBR_RDPRT		1 +#define  STM_FLASH_OBR_RDPRT_LEVEL0		0 +#define  STM_FLASH_OBR_RDPRT_LEVEL1		1 +#define  STM_FLASH_OBR_RDPRT_LEVEL2		3 +#define STM_FLASH_OBR_OPTERR		0 + +#define STM_FLASH_KEYR_KEY1	0x45670123 +#define STM_FLASH_KEYR_KEY2 	0xcdef89ab + +struct stm_rcc { +	vuint32_t	cr; +	vuint32_t	cfgr; +	vuint32_t	cir; +	vuint32_t	apb2rstr; + +	vuint32_t	apb1rstr; +	vuint32_t	ahbenr; +	vuint32_t	apb2enr; +	vuint32_t	apb1enr; + +	vuint32_t	bdcr; +	vuint32_t	csr; +	vuint32_t	ahbrstr; +	vuint32_t	cfgr2; + +	vuint32_t	cfgr3; +	vuint32_t	cr2; +}; + +extern struct stm_rcc stm_rcc; + +/* Nominal high speed internal oscillator frequency is 16MHz */ +#define STM_HSI_FREQ		16000000 + +#define STM_RCC_CR_PLLRDY	(25) +#define STM_RCC_CR_PLLON	(24) +#define STM_RCC_CR_CSSON	(19) +#define STM_RCC_CR_HSEBYP	(18) +#define STM_RCC_CR_HSERDY	(17) +#define STM_RCC_CR_HSEON	(16) +#define STM_RCC_CR_HSICAL	(8) +#define STM_RCC_CR_HSITRIM	(3) +#define STM_RCC_CR_HSIRDY	(1) +#define STM_RCC_CR_HSION	(0) + +#define STM_RCC_CFGR_PLL_NODIV	(31) +#define  STM_RCC_CFGR_PLL_NODIV_DIV_1	1 +#define  STM_RCC_CFGR_PLL_NODIV_DIV_2	0 + +#define STM_RCC_CFGR_MCOPRE	(28) +#define  STM_RCC_CFGR_MCOPRE_DIV_1	0 +#define  STM_RCC_CFGR_MCOPRE_DIV_2	1 +#define  STM_RCC_CFGR_MCOPRE_DIV_4	2 +#define  STM_RCC_CFGR_MCOPRE_DIV_8	3 +#define  STM_RCC_CFGR_MCOPRE_DIV_16	4 +#define  STM_RCC_CFGR_MCOPRE_DIV_32	5 +#define  STM_RCC_CFGR_MCOPRE_DIV_64	6 +#define  STM_RCC_CFGR_MCOPRE_DIV_128	7 +#define  STM_RCC_CFGR_MCOPRE_DIV_MASK	7 + +#define STM_RCC_CFGR_MCO	(24) +# define STM_RCC_CFGR_MCO_DISABLE	0 + +#define STM_RCC_CFGR_PLLMUL	(18) +#define  STM_RCC_CFGR_PLLMUL_2		0 +#define  STM_RCC_CFGR_PLLMUL_3		1 +#define  STM_RCC_CFGR_PLLMUL_4		2 +#define  STM_RCC_CFGR_PLLMUL_5		3 +#define  STM_RCC_CFGR_PLLMUL_6		4 +#define  STM_RCC_CFGR_PLLMUL_7		5 +#define  STM_RCC_CFGR_PLLMUL_8		6 +#define  STM_RCC_CFGR_PLLMUL_9		7 +#define  STM_RCC_CFGR_PLLMUL_10		8 +#define  STM_RCC_CFGR_PLLMUL_11		9 +#define  STM_RCC_CFGR_PLLMUL_12		10 +#define  STM_RCC_CFGR_PLLMUL_13		11 +#define  STM_RCC_CFGR_PLLMUL_14	       	12 +#define  STM_RCC_CFGR_PLLMUL_15	       	13 +#define  STM_RCC_CFGR_PLLMUL_16	       	14 +#define  STM_RCC_CFGR_PLLMUL_MASK	0xf + +#define STM_RCC_CFGR_PLLXTPRE	(17) + +#define STM_RCC_CFGR_PLLSRC	(15) +# define STM_RCC_CFGR_PLLSRC_HSI_DIV_2	0 +# define STM_RCC_CFGR_PLLSRC_HSI	1 +# define STM_RCC_CFGR_PLLSRC_HSE	2 +# define STM_RCC_CFGR_PLLSRC_HSI48	3 + +#define STM_RCC_CFGR_ADCPRE	(14) + +#define STM_RCC_CFGR_PPRE	(8) +#define  STM_RCC_CFGR_PPRE_DIV_1	0 +#define  STM_RCC_CFGR_PPRE_DIV_2	4 +#define  STM_RCC_CFGR_PPRE_DIV_4	5 +#define  STM_RCC_CFGR_PPRE_DIV_8	6 +#define  STM_RCC_CFGR_PPRE_DIV_16	7 +#define  STM_RCC_CFGR_PPRE_MASK		7 + +#define STM_RCC_CFGR_HPRE	(4) +#define  STM_RCC_CFGR_HPRE_DIV_1	0 +#define  STM_RCC_CFGR_HPRE_DIV_2	8 +#define  STM_RCC_CFGR_HPRE_DIV_4	9 +#define  STM_RCC_CFGR_HPRE_DIV_8	0xa +#define  STM_RCC_CFGR_HPRE_DIV_16	0xb +#define  STM_RCC_CFGR_HPRE_DIV_64	0xc +#define  STM_RCC_CFGR_HPRE_DIV_128	0xd +#define  STM_RCC_CFGR_HPRE_DIV_256	0xe +#define  STM_RCC_CFGR_HPRE_DIV_512	0xf +#define  STM_RCC_CFGR_HPRE_MASK		0xf + +#define STM_RCC_CFGR_SWS	(2) +#define  STM_RCC_CFGR_SWS_HSI		0 +#define  STM_RCC_CFGR_SWS_HSE		1 +#define  STM_RCC_CFGR_SWS_PLL		2 +#define  STM_RCC_CFGR_SWS_HSI48		3 +#define  STM_RCC_CFGR_SWS_MASK		3 + +#define STM_RCC_CFGR_SW		(0) +#define  STM_RCC_CFGR_SW_HSI		0 +#define  STM_RCC_CFGR_SW_HSE		1 +#define  STM_RCC_CFGR_SW_PLL		2 +#define  STM_RCC_CFGR_SW_HSI48		3 +#define  STM_RCC_CFGR_SW_MASK		3 + +#define STM_RCC_APB2RSTR_DBGMCURST	22 +#define STM_RCC_APB2RSTR_TIM17RST	18 +#define STM_RCC_APB2RSTR_TIM16RST	17 +#define STM_RCC_APB2RSTR_TIM15RST	16 +#define STM_RCC_APB2RSTR_USART1RST	14 +#define STM_RCC_APB2RSTR_SPI1RST	12 +#define STM_RCC_APB2RSTR_TIM1RST	11 +#define STM_RCC_APB2RSTR_ADCRST		9 +#define STM_RCC_APB2RSTR_USART8RST	7 +#define STM_RCC_APB2RSTR_USART7RST	6 +#define STM_RCC_APB2RSTR_USART6RST	5 +#define STM_RCC_APB2RSTR_SYSCFGRST	1 + +#define STM_RCC_APB1RSTR_CECRST		30 +#define STM_RCC_APB1RSTR_DACRST		29 +#define STM_RCC_APB1RSTR_PWRRST		28 +#define STM_RCC_APB1RSTR_CRSRST		27 +#define STM_RCC_APB1RSTR_CANRST		25 +#define STM_RCC_APB1RSTR_USBRST		23 +#define STM_RCC_APB1RSTR_I2C2RST	22 +#define STM_RCC_APB1RSTR_I1C1RST	21 +#define STM_RCC_APB1RSTR_USART5RST	20 +#define STM_RCC_APB1RSTR_USART4RST	19 +#define STM_RCC_APB1RSTR_USART3RST	18 +#define STM_RCC_APB1RSTR_USART2RST	17 +#define STM_RCC_APB1RSTR_SPI2RST	14 +#define STM_RCC_APB1RSTR_WWDGRST	11 +#define STM_RCC_APB1RSTR_TIM14RST	8 +#define STM_RCC_APB1RSTR_TIM7RST	5 +#define STM_RCC_APB1RSTR_TIM6RST	4 +#define STM_RCC_APB1RSTR_TIM3RST	1 +#define STM_RCC_APB1RSTR_TIM2RST	0 + +#define STM_RCC_AHBENR_TSCEN	24 +#define STM_RCC_AHBENR_IOPFEN	22 +#define STM_RCC_AHBENR_IOPEEN	21 +#define STM_RCC_AHBENR_IOPDEN	20 +#define STM_RCC_AHBENR_IOPCEN	19 +#define STM_RCC_AHBENR_IOPBEN	18 +#define STM_RCC_AHBENR_IOPAEN	17 +#define STM_RCC_AHBENR_CRCEN	6 +#define STM_RCC_AHBENR_FLITFEN	4 +#define STM_RCC_AHBENR_SRAMEN	2 +#define STM_RCC_AHBENR_DMA2EN	1 +#define STM_RCC_AHBENR_DMAEN	0 + +#define STM_RCC_APB2ENR_DBGMCUEN	22 +#define STM_RCC_APB2ENR_TIM17EN		18 +#define STM_RCC_APB2ENR_TIM16EN		17 +#define STM_RCC_APB2ENR_TIM15EN		16 +#define STM_RCC_APB2ENR_USART1EN	14 +#define STM_RCC_APB2ENR_SPI1EN		12 +#define STM_RCC_APB2ENR_TIM1EN		11 +#define STM_RCC_APB2ENR_ADCEN		9 +#define STM_RCC_APB2ENR_USART8EN	7 +#define STM_RCC_APB2ENR_USART7EN	6 +#define STM_RCC_APB2ENR_USART6EN	5 +#define STM_RCC_APB2ENR_SYSCFGCOMPEN	0 + +#define STM_RCC_APB1ENR_CECEN		30 +#define STM_RCC_APB1ENR_DACEN		29 +#define STM_RCC_APB1ENR_PWREN		28 +#define STM_RCC_APB1ENR_CRSEN		27 +#define STM_RCC_APB1ENR_CANEN		25 +#define STM_RCC_APB1ENR_USBEN		23 +#define STM_RCC_APB1ENR_I2C2EN		22 +#define STM_RCC_APB1ENR_IC21EN		21 +#define STM_RCC_APB1ENR_USART5EN	20 +#define STM_RCC_APB1ENR_USART4EN	19 +#define STM_RCC_APB1ENR_USART3EN	18 +#define STM_RCC_APB1ENR_USART2EN	17 +#define STM_RCC_APB1ENR_SPI2EN		14 +#define STM_RCC_APB1ENR_WWDGEN		11 +#define STM_RCC_APB1ENR_TIM14EN		8 +#define STM_RCC_APB1ENR_TIM7EN		5 +#define STM_RCC_APB1ENR_TIM6EN		4 +#define STM_RCC_APB1ENR_TIM3EN		1 +#define STM_RCC_APB1ENR_TIM2EN		0 + +#define STM_RCC_CSR_LPWRRSTF		(31) +#define STM_RCC_CSR_WWDGRSTF		(30) +#define STM_RCC_CSR_IWDGRSTF		(29) +#define STM_RCC_CSR_SFTRSTF		(28) +#define STM_RCC_CSR_PORRSTF		(27) +#define STM_RCC_CSR_PINRSTF		(26) +#define STM_RCC_CSR_OBLRSTF		(25) +#define STM_RCC_CSR_RMVF		(24) +#define STM_RCC_CSR_V18PWRRSTF		(23) +#define STM_RCC_CSR_LSIRDY		(1) +#define STM_RCC_CSR_LSION		(0) + +#define STM_RCC_CR2_HSI48CAL		24 +#define STM_RCC_CR2_HSI48RDY		17 +#define STM_RCC_CR2_HSI48ON		16 +#define STM_RCC_CR2_HSI14CAL		8 +#define STM_RCC_CR2_HSI14TRIM		3 +#define STM_RCC_CR2_HSI14DIS		2 +#define STM_RCC_CR2_HSI14RDY		1 +#define STM_RCC_CR2_HSI14ON		0 + +#define STM_RCC_CFGR3_USART3SW		18 +#define STM_RCC_CFGR3_USART2SW		16 +#define STM_RCC_CFGR3_ADCSW		8 +#define STM_RCC_CFGR3_USBSW		7 +#define STM_RCC_CFGR3_CECSW		6 +#define STM_RCC_CFGR3_I2C1SW		4 +#define STM_RCC_CFGR3_USART1SW		0 + +struct stm_crs { +	vuint32_t	cr; +	vuint32_t	cfgr; +	vuint32_t	isr; +	vuint32_t	icr; +}; + +extern struct stm_crs stm_crs; + +#define STM_CRS_CR_TRIM		8 +#define STM_CRS_CR_SWSYNC	7 +#define STM_CRS_CR_AUTOTRIMEN	6 +#define STM_CRS_CR_CEN		5 +#define STM_CRS_CR_ESYNCIE	3 +#define STM_CRS_CR_ERRIE	2 +#define STM_CRS_CR_SYNCWARNIE	1 +#define STM_CRS_CR_SYNCOKIE	0 + +#define STM_CRS_CFGR_SYNCPOL	31 +#define STM_CRS_CFGR_SYNCSRC	28 +#define  STM_CRS_CFGR_SYNCSRC_GPIO	0 +#define  STM_CRS_CFGR_SYNCSRC_LSE	1 +#define  STM_CRS_CFGR_SYNCSRC_USB	2 +#define STM_CRS_CFGR_SYNCDIV	24 +#define  STM_CRS_CFGR_SYNCDIV_1		0 +#define  STM_CRS_CFGR_SYNCDIV_2		1 +#define  STM_CRS_CFGR_SYNCDIV_4		2 +#define  STM_CRS_CFGR_SYNCDIV_8		3 +#define  STM_CRS_CFGR_SYNCDIV_16	4 +#define  STM_CRS_CFGR_SYNCDIV_32	5 +#define  STM_CRS_CFGR_SYNCDIV_64	6 +#define  STM_CRS_CFGR_SYNCDIV_128	7 +#define STM_CRS_CFGR_FELIM	16 +#define STM_CRS_CFGR_RELOAD	0 + +#define STM_CRS_ISR_FECAP	16 +#define STM_CRS_ISR_FEDIR	15 +#define STM_CRS_ISR_TRIMOVF	10 +#define STM_CRS_ISR_SYNCMISS	9 +#define STM_CRS_ISR_SYNCERR	8 +#define STM_CRS_ISR_ESYNCF	3 +#define STM_CRS_ISR_ERRF	2 +#define STM_CRS_ISR_SYNCWARNF	1 +#define STM_CRS_ISR_SYNCOKF	0 + +#define STM_CRS_ICR_ESYNCC	3 +#define STM_CRS_ICR_ERRC	2 +#define STM_CRS_ICR_SYNCWARNC	1 +#define STM_CRS_ICR_SYNCOKC	0 + +struct stm_pwr { +	vuint32_t	cr; +	vuint32_t	csr; +}; + +extern struct stm_pwr stm_pwr; + +#define STM_PWR_CR_DBP		(8) + +#define STM_PWR_CR_PLS		(5) +#define  STM_PWR_CR_PLS_2_0	0 +#define  STM_PWR_CR_PLS_2_1	1 +#define  STM_PWR_CR_PLS_2_2	2 +#define  STM_PWR_CR_PLS_2_3	3 +#define  STM_PWR_CR_PLS_2_4	4 +#define  STM_PWR_CR_PLS_2_5	5 +#define  STM_PWR_CR_PLS_2_6	6 +#define  STM_PWR_CR_PLS_EXT	7 +#define  STM_PWR_CR_PLS_MASK	7 + +#define STM_PWR_CR_PVDE		(4) +#define STM_PWR_CR_CSBF		(3) +#define STM_PWR_CR_CWUF		(2) +#define STM_PWR_CR_PDDS		(1) +#define STM_PWR_CR_LPSDSR	(0) + +#define STM_PWR_CSR_EWUP3	(10) +#define STM_PWR_CSR_EWUP2	(9) +#define STM_PWR_CSR_EWUP1	(8) +#define STM_PWR_CSR_REGLPF	(5) +#define STM_PWR_CSR_VOSF	(4) +#define STM_PWR_CSR_VREFINTRDYF	(3) +#define STM_PWR_CSR_PVDO	(2) +#define STM_PWR_CSR_SBF		(1) +#define STM_PWR_CSR_WUF		(0) + +struct stm_crc { +	union { +		vuint32_t	u32; +		vuint16_t	u16; +		vuint8_t	u8; +	} 		dr; +	vuint32_t	idr; +	vuint32_t	cr; +	uint32_t	_0c; + +	vuint32_t	init; +	vuint32_t	pol; +}; + +extern struct stm_crc	stm_crc; + +#define stm_crc	(*((struct stm_crc *) 0x40023000)) + +#define STM_CRC_CR_REV_OUT	7 +#define STM_CRC_CR_REV_IN	5 +#define  STM_CRC_CR_REV_IN_NONE		0 +#define  STM_CRC_CR_REV_IN_BY_BYTE	1 +#define  STM_CRC_CR_REV_IN_BY_HALF_WORD	2 +#define  STM_CRC_CR_REV_IN_BY_WORD	3 +#define STM_CRC_CR_POLYSIZE	3 +#define  STM_CRC_CR_POLYSIZE_32		0 +#define  STM_CRC_CR_POLYSIZE_16		1 +#define  STM_CRC_CR_POLYSIZE_8		2 +#define  STM_CRC_CR_POLYSIZE_7		3 +#define STM_CRC_CR_RESET	0 + +/* The SYSTICK starts at 0xe000e010 */ + +struct stm_systick { +	vuint32_t	csr; +	vuint32_t	rvr; +	vuint32_t	cvr; +	vuint32_t	calib; +}; + +extern struct stm_systick stm_systick; + +#define STM_SYSTICK_CSR_ENABLE		0 +#define STM_SYSTICK_CSR_TICKINT		1 +#define STM_SYSTICK_CSR_CLKSOURCE	2 +#define  STM_SYSTICK_CSR_CLKSOURCE_EXTERNAL		0 +#define  STM_SYSTICK_CSR_CLKSOURCE_HCLK_8		1 +#define STM_SYSTICK_CSR_COUNTFLAG	16 + +/* The NVIC starts at 0xe000e100, so add that to the offsets to find the absolute address */ + +struct stm_nvic { +	vuint32_t	iser;		/* 0x000 0xe000e100 Set Enable Register */ + +	uint8_t		_unused020[0x080 - 0x004]; + +	vuint32_t	icer;		/* 0x080 0xe000e180 Clear Enable Register */ + +	uint8_t		_unused0a0[0x100 - 0x084]; + +	vuint32_t	ispr;		/* 0x100 0xe000e200 Set Pending Register */ + +	uint8_t		_unused120[0x180 - 0x104]; + +	vuint32_t	icpr;		/* 0x180 0xe000e280 Clear Pending Register */ + +	uint8_t		_unused1a0[0x300 - 0x184]; + +	vuint32_t	ipr[8];		/* 0x300 0xe000e400 Priority Register */ +}; + +extern struct stm_nvic stm_nvic; + +#define IRQ_MASK(irq)	(1 << (irq)) +#define IRQ_BOOL(v,irq)	(((v) >> (irq)) & 1) + +static inline void +stm_nvic_set_enable(int irq) { +	stm_nvic.iser = IRQ_MASK(irq); +} + +static inline void +stm_nvic_clear_enable(int irq) { +	stm_nvic.icer = IRQ_MASK(irq); +} + +static inline int +stm_nvic_enabled(int irq) { +	return IRQ_BOOL(stm_nvic.iser, irq); +} + +static inline void +stm_nvic_set_pending(int irq) { +	stm_nvic.ispr = IRQ_MASK(irq); +} + +static inline void +stm_nvic_clear_pending(int irq) { +	stm_nvic.icpr = IRQ_MASK(irq); +} + +static inline int +stm_nvic_pending(int irq) { +	return IRQ_BOOL(stm_nvic.ispr, irq); +} + +#define IRQ_PRIO_REG(irq)	((irq) >> 2) +#define IRQ_PRIO_BIT(irq)	(((irq) & 3) << 3) +#define IRQ_PRIO_MASK(irq)	(0xff << IRQ_PRIO_BIT(irq)) + +static inline void +stm_nvic_set_priority(int irq, uint8_t prio) { +	int		n = IRQ_PRIO_REG(irq); +	uint32_t	v; + +	v = stm_nvic.ipr[n]; +	v &= ~IRQ_PRIO_MASK(irq); +	v |= (prio) << IRQ_PRIO_BIT(irq); +	stm_nvic.ipr[n] = v; +} + +static inline uint8_t +stm_nvic_get_priority(int irq) { +	return (stm_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0); +} + +struct stm_scb { +	vuint32_t	cpuid; +	vuint32_t	icsr; +	vuint32_t	vtor; +	vuint32_t	aircr; + +	vuint32_t	scr; +	vuint32_t	ccr; +	vuint32_t	shpr1; +	vuint32_t	shpr2; + +	vuint32_t	shpr3; +	vuint32_t	shcrs; +	vuint32_t	cfsr; +	vuint32_t	hfsr; + +	uint32_t	unused_30; +	vuint32_t	mmfar; +	vuint32_t	bfar; +}; + +extern struct stm_scb stm_scb; + +#define STM_SCB_AIRCR_VECTKEY		16 +#define  STM_SCB_AIRCR_VECTKEY_KEY		0x05fa +#define STM_SCB_AIRCR_PRIGROUP		8 +#define STM_SCB_AIRCR_SYSRESETREQ	2 +#define STM_SCB_AIRCR_VECTCLRACTIVE	1 +#define STM_SCB_AIRCR_VECTRESET		0 + +#define isr(name) void stm_ ## name ## _isr(void); + +isr(nmi) +isr(hardfault) +isr(memmanage) +isr(busfault) +isr(usagefault) +isr(svc) +isr(debugmon) +isr(pendsv) +isr(systick) +isr(wwdg) +isr(pvd) +isr(tamper_stamp) +isr(rtc_wkup) +isr(flash) +isr(rcc) +isr(exti0) +isr(exti1) +isr(exti2) +isr(exti3) +isr(exti4) +isr(dma1_channel1) +isr(dma1_channel2) +isr(dma1_channel3) +isr(dma1_channel4) +isr(dma1_channel5) +isr(dma1_channel6) +isr(dma1_channel7) +isr(adc1) +isr(usb_hp) +isr(usb_lp) +isr(dac) +isr(comp) +isr(exti9_5) +isr(lcd) +isr(tim9) +isr(tim10) +isr(tim11) +isr(tim2) +isr(tim3) +isr(tim4) +isr(i2c1_ev) +isr(i2c1_er) +isr(i2c2_ev) +isr(i2c2_er) +isr(spi1) +isr(spi2) +isr(usart1) +isr(usart2) +isr(usart3) +isr(exti15_10) +isr(rtc_alarm) +isr(usb_fs_wkup) +isr(tim6) +isr(tim7) + +#undef isr + +#define STM_ISR_WWDG_POS		0 +#define STM_ISR_PVD_VDDIO2_POS		1 +#define STM_ISR_RTC_POS			2 +#define STM_ISR_FLASH_POS		3 +#define STM_ISR_RCC_CRS_POS		4 +#define STM_ISR_EXTI0_1_POS		5 +#define STM_ISR_EXTI2_3_POS		6 +#define STM_ISR_EXTI4_15_POS		7 +#define STM_ISR_TSC_POS			8 +#define STM_ISR_DMA_CH1_POS		9 +#define STM_ISR_DMA_CH2_3_DMA2_CH1_2_POS	10 +#define STM_ISR_DMA_CH44_5_6_7_DMA2_CH3_4_5_POS	11 +#define STM_ISR_ADC_COMP_POS		12 +#define STM_ISR_TIM1_BRK_UP_TRG_COM_POS	13 +#define STM_ISR_TIM1_CC_POS		14 +#define STM_ISR_TIM2_POS		15 +#define STM_ISR_TIM3_POS		16 +#define STM_ISR_TIM6_DAC_POS		17 +#define STM_ISR_TIM7_POS		18 +#define STM_ISR_TIM14_POS		19 +#define STM_ISR_TIM15_POS		20 +#define STM_ISR_TIM16_POS		21 +#define STM_ISR_TIM17_POS		22 +#define STM_ISR_I2C1_POS		23 +#define STM_ISR_I2C2_POS		24 +#define STM_ISR_SPI1_POS		25 +#define STM_ISR_SPI2_POS		26 +#define STM_ISR_USART1_POS		27 +#define STM_ISR_USART2_POS		28 +#define STM_ISR_UASART3_4_5_6_7_8_POS	29 +#define STM_ISR_CEC_CAN_POS		30 +#define STM_ISR_USB_POS			31 + +struct stm_syscfg { +	vuint32_t	cfgr1; +	vuint32_t	exticr[4]; +	vuint32_t	cfgr2; +}; + +extern struct stm_syscfg stm_syscfg; + +#define STM_SYSCFG_CFGR1_TIM3_DMA_RMP	30 +#define STM_SYSCFG_CFGR1_TIM2_DMA_RMP	29 +#define STM_SYSCFG_CFGR1_TIM1_DMA_RMP	28 +#define STM_SYSCFG_CFGR1_I2C1_DMA_RMP	27 +#define STM_SYSCFG_CFGR1_USART3_DMA_RMP	26 +#define STM_SYSCFG_CFGR1_USART2_DMA_RMP	25 +#define STM_SYSCFG_CFGR1_SPI2_DMA_RMP	24 +#define STM_SYSCFG_CFGR1_I2C_PA10_FMP	23 +#define STM_SYSCFG_CFGR1_I2C_PA9_FMP	22 +#define STM_SYSCFG_CFGR1_I2C2_FMP	21 +#define STM_SYSCFG_CFGR1_I2C1_FMP	20 +#define STM_SYSCFG_CFGR1_I2C_PB9_FMP	19 +#define STM_SYSCFG_CFGR1_I2C_PB8_FMP	18 +#define STM_SYSCFG_CFGR1_I2C_PB7_FMP	17 +#define STM_SYSCFG_CFGR1_I2C_PB6_FMP	16 +#define STM_SYSCFG_CFGR1_TIM17_DMA_RMP2	14 +#define STM_SYSCFG_CFGR1_TIM16_DMA_RMP2	13 +#define STM_SYSCFG_CFGR1_TIM17_DMA_RMP	12 +#define STM_SYSCFG_CFGR1_TIM16_DMA_RMP	11 +#define STM_SYSCFG_CFGR1_USART1_RX_DMA_RMP	10 +#define STM_SYSCFG_CFGR1_USART1_TX_DMA_RMP	9 +#define STM_SYSCFG_CFGR1_ADC_DMA_RMP		8 +#define STM_SYSCFG_CFGR1_IRDA_ENV_SEL	6 +#define  STM_SYSCFG_CFGR1_IRDA_ENV_SEL_TIMER16	0 +#define  STM_SYSCFG_CFGR1_IRDA_ENV_SEL_USART1	1 +#define  STM_SYSCFG_CFGR1_IRDA_ENV_SEL_USART4	2 +#define STM_SYSCFG_CFGR1_PA11_PA12_RMP	4 +#define STM_SYSCFG_CFGR1_MEM_MODE	0 +#define  STM_SYSCFG_CFGR1_MEM_MODE_MAIN_FLASH	0 +#define  STM_SYSCFG_CFGR1_MEM_MODE_SYSTEM_FLASH	1 +#define  STM_SYSCFG_CFGR1_MEM_MODE_SRAM		3 +#define  STM_SYSCFG_CFGR1_MEM_MODE_MASK		3 + +#if 0 +static inline void +stm_exticr_set(struct stm_gpio *gpio, int pin) { +	uint8_t	reg = pin >> 2; +	uint8_t	shift = (pin & 3) << 2; +	uint8_t	val = 0; + +	/* Enable SYSCFG */ +	stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); + +	if (gpio == &stm_gpioa) +		val = STM_SYSCFG_EXTICR_PA; +	else if (gpio == &stm_gpiob) +		val = STM_SYSCFG_EXTICR_PB; +	else if (gpio == &stm_gpioc) +		val = STM_SYSCFG_EXTICR_PC; +	else if (gpio == &stm_gpiof) +		val = STM_SYSCFG_EXTICR_PF; + +	stm_syscfg.exticr[reg] = (stm_syscfg.exticr[reg] & ~(0xf << shift)) | val << shift; +} +#endif + + +struct stm_dma_channel { +	vuint32_t	ccr; +	vuint32_t	cndtr; +	vvoid_t		cpar; +	vvoid_t		cmar; +	vuint32_t	reserved; +}; + +#define STM_NUM_DMA	6 + +struct stm_dma { +	vuint32_t		isr; +	vuint32_t		ifcr; +	struct stm_dma_channel	channel[STM_NUM_DMA]; +}; + +extern struct stm_dma stm_dma; + +/* DMA channels go from 1 to 6, instead of 0 to 5 (sigh) + */ + +#define STM_DMA_INDEX(channel)		((channel) - 1) + +#define STM_DMA_ISR(index)		((index) << 2) +#define STM_DMA_ISR_MASK			0xf +#define STM_DMA_ISR_TEIF			3 +#define STM_DMA_ISR_HTIF			2 +#define STM_DMA_ISR_TCIF			1 +#define STM_DMA_ISR_GIF				0 + +#define STM_DMA_IFCR(index)		((index) << 2) +#define STM_DMA_IFCR_MASK			0xf +#define STM_DMA_IFCR_CTEIF      		3 +#define STM_DMA_IFCR_CHTIF			2 +#define STM_DMA_IFCR_CTCIF			1 +#define STM_DMA_IFCR_CGIF			0 + +#define STM_DMA_CCR_MEM2MEM		(14) + +#define STM_DMA_CCR_PL			(12) +#define  STM_DMA_CCR_PL_LOW			(0) +#define  STM_DMA_CCR_PL_MEDIUM			(1) +#define  STM_DMA_CCR_PL_HIGH			(2) +#define  STM_DMA_CCR_PL_VERY_HIGH		(3) +#define  STM_DMA_CCR_PL_MASK			(3) + +#define STM_DMA_CCR_MSIZE		(10) +#define  STM_DMA_CCR_MSIZE_8			(0) +#define  STM_DMA_CCR_MSIZE_16			(1) +#define  STM_DMA_CCR_MSIZE_32			(2) +#define  STM_DMA_CCR_MSIZE_MASK			(3) + +#define STM_DMA_CCR_PSIZE		(8) +#define  STM_DMA_CCR_PSIZE_8			(0) +#define  STM_DMA_CCR_PSIZE_16			(1) +#define  STM_DMA_CCR_PSIZE_32			(2) +#define  STM_DMA_CCR_PSIZE_MASK			(3) + +#define STM_DMA_CCR_MINC		(7) +#define STM_DMA_CCR_PINC		(6) +#define STM_DMA_CCR_CIRC		(5) +#define STM_DMA_CCR_DIR			(4) +#define  STM_DMA_CCR_DIR_PER_TO_MEM		0 +#define  STM_DMA_CCR_DIR_MEM_TO_PER		1 +#define STM_DMA_CCR_TEIE		(3) +#define STM_DMA_CCR_HTIE		(2) +#define STM_DMA_CCR_TCIE		(1) +#define STM_DMA_CCR_EN			(0) + +/* DMA channel assignments. When a peripheral has multiple channels + * (indicated with _<number>), then it can be configured to either + * channel using syscfg.cfgr1 + */ + +#define STM_DMA_CHANNEL_ADC_1		1 +#define STM_DMA_CHANNEL_ADC_2		2 + +#define STM_DMA_CHANNEL_SPI1_RX		2 +#define STM_DMA_CHANNEL_SPI1_TX		3 + +#define STM_DMA_CHANNEL_SPI2_RX		4 +#define STM_DMA_CHANNEL_SPI2_TX		5 + +#define STM_DMA_CHANNEL_USART1_TX_1	2 +#define STM_DMA_CHANNEL_USART1_RX_1	3 +#define STM_DMA_CHANNEL_USART1_TX_2	4 +#define STM_DMA_CHANNEL_USART1_RX_2	5 + +#define STM_DMA_CHANNEL_USART2_RX	4 +#define STM_DMA_CHANNEL_USART2_TX	5 + +#define STM_DMA_CHANNEL_I2C1_TX		2 +#define STM_DMA_CHANNEL_I2C1_RX		3 + +#define STM_DMA_CHANNEL_I2C2_TX		4 +#define STM_DMA_CHANNEL_I2C2_RX		5 + +#define STM_DMA_CHANNEL_TIM1_CH1	2 +#define STM_DMA_CHANNEL_TIM1_CH2	3 +#define STM_DMA_CHANNEL_TIM1_CH4	4 +#define STM_DMA_CHANNEL_TIM1_TRIG	4 +#define STM_DMA_CHANNEL_TIM1_COM	4 +#define STM_DMA_CHANNEL_TIM1_CH3	5 +#define STM_DMA_CHANNEL_TIM1_UP		5 + +#define STM_DMA_CHANNEL_TIM2_CH3	1 +#define STM_DMA_CHANNEL_TIM2_UP		2 +#define STM_DMA_CHANNEL_TIM2_CH2	3 +#define STM_DMA_CHANNEL_TIM2_CH4	4 +#define STM_DMA_CHANNEL_TIM2_CH1	5 + +#define STM_DMA_CHANNEL_TIM3_CH3	2 +#define STM_DMA_CHANNEL_TIM3_CH4	3 +#define STM_DMA_CHANNEL_TIM3_UP		3 +#define STM_DMA_CHANNEL_TIM3_CH1	4 +#define STM_DMA_CHANNEL_TIM3_TRIG	4 + +#define STM_DMA_CHANNEL_TIM6_UP_DAC	2 + +#define STM_DMA_CHANNEL_TIM15_CH1	5 +#define STM_DMA_CHANNEL_TIM15_UP	5 +#define STM_DMA_CHANNEL_TIM15_TRIG	5 +#define STM_DMA_CHANNEL_TIM15_COM	5 + +#define STM_DMA_CHANNEL_TIM16_CH1_1	3 +#define STM_DMA_CHANNEL_TIM16_UP_1	3 +#define STM_DMA_CHANNEL_TIM16_CH1_2	4 +#define STM_DMA_CHANNEL_TIM16_UP_2	4 + +#define STM_DMA_CHANNEL_TIM17_CH1_1	1 +#define STM_DMA_CHANNEL_TIM17_UP_1	1 +#define STM_DMA_CHANNEL_TIM17_CH1_2	2 +#define STM_DMA_CHANNEL_TIM17_UP_2	2 + +/* + * Only spi channel 1 and 2 can use DMA + */ +#define STM_NUM_SPI	2 + +struct stm_spi { +	vuint32_t	cr1; +	vuint32_t	cr2; +	vuint32_t	sr; +	vuint32_t	dr; +	vuint32_t	crcpr; +	vuint32_t	rxcrcr; +	vuint32_t	txcrcr; +}; + +extern struct stm_spi stm_spi1, stm_spi2, stm_spi3; + +/* SPI channels go from 1 to 3, instead of 0 to 2 (sigh) + */ + +#define STM_SPI_INDEX(channel)		((channel) - 1) + +#define STM_SPI_CR1_BIDIMODE		15 +#define STM_SPI_CR1_BIDIOE		14 +#define STM_SPI_CR1_CRCEN		13 +#define STM_SPI_CR1_CRCNEXT		12 +#define STM_SPI_CR1_DFF			11 +#define STM_SPI_CR1_RXONLY		10 +#define STM_SPI_CR1_SSM			9 +#define STM_SPI_CR1_SSI			8 +#define STM_SPI_CR1_LSBFIRST		7 +#define STM_SPI_CR1_SPE			6 +#define STM_SPI_CR1_BR			3 +#define  STM_SPI_CR1_BR_PCLK_2			0 +#define  STM_SPI_CR1_BR_PCLK_4			1 +#define  STM_SPI_CR1_BR_PCLK_8			2 +#define  STM_SPI_CR1_BR_PCLK_16			3 +#define  STM_SPI_CR1_BR_PCLK_32			4 +#define  STM_SPI_CR1_BR_PCLK_64			5 +#define  STM_SPI_CR1_BR_PCLK_128		6 +#define  STM_SPI_CR1_BR_PCLK_256		7 +#define  STM_SPI_CR1_BR_MASK			7 + +#define STM_SPI_CR1_MSTR		2 +#define STM_SPI_CR1_CPOL		1 +#define STM_SPI_CR1_CPHA		0 + +#define STM_SPI_CR2_TXEIE	7 +#define STM_SPI_CR2_RXNEIE	6 +#define STM_SPI_CR2_ERRIE	5 +#define STM_SPI_CR2_SSOE	2 +#define STM_SPI_CR2_TXDMAEN	1 +#define STM_SPI_CR2_RXDMAEN	0 + +#define STM_SPI_SR_BSY		7 +#define STM_SPI_SR_OVR		6 +#define STM_SPI_SR_MODF		5 +#define STM_SPI_SR_CRCERR	4 +#define STM_SPI_SR_TXE		1 +#define STM_SPI_SR_RXNE		0 + +struct stm_adc { +	vuint32_t	isr; +	vuint32_t	ier; +	vuint32_t	cr; +	vuint32_t	cfgr1; + +	vuint32_t	cfgr2; +	vuint32_t	smpr; +	vuint32_t	r_18; +	vuint32_t	r_1c; + +	vuint32_t	tr; +	vuint32_t	r_24; +	vuint32_t	chselr; +	vuint32_t	r_2c; + +	vuint32_t	r_30[4]; + +	vuint32_t	dr; + +	uint8_t		r_44[0x308 - 0x44]; +	vuint32_t	ccr; +}; + +extern struct stm_adc stm_adc; + +#define STM_ADC_ISR_AWD		7 +#define STM_ADC_ISR_OVR		4 +#define STM_ADC_ISR_EOSEQ	3 +#define STM_ADC_ISR_EOC		2 +#define STM_ADC_ISR_EOSMP	1 +#define STM_ADC_ISR_ADRDY	0 + +#define STM_ADC_IER_AWDIE	7 +#define STM_ADC_IER_OVRIE	4 +#define STM_ADC_IER_EOSEQIE	3 +#define STM_ADC_IER_EOCIE	2 +#define STM_ADC_IER_EOSMPIE	1 +#define STM_ADC_IER_ADRDYIE	0 + +#define STM_ADC_CR_ADCAL	31 +#define STM_ADC_CR_ADSTP	4 +#define STM_ADC_CR_ADSTART	2 +#define STM_ADC_CR_ADDIS	1 +#define STM_ADC_CR_ADEN		0 + +#define STM_ADC_CFGR1_AWDCH	26 +#define STM_ADC_CFGR1_AWDEN	23 +#define STM_ADC_CFGR1_AWDSGL	22 +#define STM_ADC_CFGR1_DISCEN	16 +#define STM_ADC_CFGR1_AUTOOFF	15 +#define STM_ADC_CFGR1_WAIT	14 +#define STM_ADC_CFGR1_CONT	13 +#define STM_ADC_CFGR1_OVRMOD	12 +#define STM_ADC_CFGR1_EXTEN	10 +#define  STM_ADC_CFGR1_EXTEN_DISABLE	0 +#define  STM_ADC_CFGR1_EXTEN_RISING	1 +#define  STM_ADC_CFGR1_EXTEN_FALLING	2 +#define  STM_ADC_CFGR1_EXTEN_BOTH	3 +#define  STM_ADC_CFGR1_EXTEN_MASK	3 + +#define STM_ADC_CFGR1_EXTSEL	6 +#define STM_ADC_CFGR1_ALIGN	5 +#define STM_ADC_CFGR1_RES	3 +#define  STM_ADC_CFGR1_RES_12		0 +#define  STM_ADC_CFGR1_RES_10		1 +#define  STM_ADC_CFGR1_RES_8		2 +#define  STM_ADC_CFGR1_RES_6		3 +#define  STM_ADC_CFGR1_RES_MASK		3 +#define STM_ADC_CFGR1_SCANDIR	2 +#define  STM_ADC_CFGR1_SCANDIR_UP	0 +#define  STM_ADC_CFGR1_SCANDIR_DOWN	1 +#define STM_ADC_CFGR1_DMACFG	1 +#define  STM_ADC_CFGR1_DMACFG_ONESHOT	0 +#define  STM_ADC_CFGR1_DMACFG_CIRCULAR	1 +#define STM_ADC_CFGR1_DMAEN	0 + +#define STM_ADC_CFGR2_CKMODE	30 +#define  STM_ADC_CFGR2_CKMODE_ADCCLK	0 +#define  STM_ADC_CFGR2_CKMODE_PCLK_2	1 +#define  STM_ADC_CFGR2_CKMODE_PCLK_4	2 + +#define STM_ADC_SMPR_SMP	0 +#define  STM_ADC_SMPR_SMP_1_5		0 +#define  STM_ADC_SMPR_SMP_7_5		1 +#define  STM_ADC_SMPR_SMP_13_5		2 +#define  STM_ADC_SMPR_SMP_28_5		3 +#define  STM_ADC_SMPR_SMP_41_5		4 +#define  STM_ADC_SMPR_SMP_55_5		5 +#define  STM_ADC_SMPR_SMP_71_5		6 +#define  STM_ADC_SMPR_SMP_239_5		7 + +#define STM_ADC_TR_HT		16 +#define STM_ADC_TR_LT		0 + +#define STM_ADC_CCR_VBATEN	24 +#define STM_ADC_CCR_TSEN	23 +#define STM_ADC_CCR_VREFEN	22 + +struct stm_cal { +	uint16_t	ts_cal_cold;	/* 30°C */ +	uint16_t	vrefint_cal; +	uint16_t	unused_c0; +	uint16_t	ts_cal_hot;	/* 110°C */ +}; + +extern struct stm_cal	stm_cal; + +#define stm_temp_cal_cold	30 +#define stm_temp_cal_hot	110 + +struct stm_dbgmcu { +	uint32_t	idcode; +}; + +extern struct stm_dbgmcu	stm_dbgmcu; + +static inline uint16_t +stm_dev_id(void) { +	return stm_dbgmcu.idcode & 0xfff; +} + +struct stm_flash_size { +	uint16_t	f_size; +}; + +extern struct stm_flash_size	stm_flash_size_04x; + +/* Returns flash size in bytes */ +extern uint32_t +stm_flash_size(void); + +struct stm_device_id { +	uint32_t	u_id0; +	uint32_t	u_id1; +	uint32_t	u_id2; +}; + +extern struct stm_device_id	stm_device_id; + +#define STM_NUM_I2C	2 + +#define STM_I2C_INDEX(channel)	((channel) - 1) + +struct stm_i2c { +	vuint32_t	cr1; +	vuint32_t	cr2; +	vuint32_t	oar1; +	vuint32_t	oar2; +	vuint32_t	dr; +	vuint32_t	sr1; +	vuint32_t	sr2; +	vuint32_t	ccr; +	vuint32_t	trise; +}; + +extern struct stm_i2c stm_i2c1, stm_i2c2; + +#define STM_I2C_CR1_SWRST	15 +#define STM_I2C_CR1_ALERT	13 +#define STM_I2C_CR1_PEC		12 +#define STM_I2C_CR1_POS		11 +#define STM_I2C_CR1_ACK		10 +#define STM_I2C_CR1_STOP	9 +#define STM_I2C_CR1_START	8 +#define STM_I2C_CR1_NOSTRETCH	7 +#define STM_I2C_CR1_ENGC	6 +#define STM_I2C_CR1_ENPEC	5 +#define STM_I2C_CR1_ENARP	4 +#define STM_I2C_CR1_SMBTYPE	3 +#define STM_I2C_CR1_SMBUS	1 +#define STM_I2C_CR1_PE		0 + +#define STM_I2C_CR2_LAST	12 +#define STM_I2C_CR2_DMAEN	11 +#define STM_I2C_CR2_ITBUFEN	10 +#define STM_I2C_CR2_ITEVTEN	9 +#define STM_I2C_CR2_ITERREN	8 +#define STM_I2C_CR2_FREQ	0 +#define  STM_I2C_CR2_FREQ_2_MHZ		2 +#define  STM_I2C_CR2_FREQ_4_MHZ		4 +#define  STM_I2C_CR2_FREQ_8_MHZ		8 +#define  STM_I2C_CR2_FREQ_16_MHZ	16 +#define  STM_I2C_CR2_FREQ_32_MHZ	32 +#define  STM_I2C_CR2_FREQ_MASK		0x3f + +#define STM_I2C_SR1_SMBALERT	15 +#define STM_I2C_SR1_TIMEOUT	14 +#define STM_I2C_SR1_PECERR	12 +#define STM_I2C_SR1_OVR		11 +#define STM_I2C_SR1_AF		10 +#define STM_I2C_SR1_ARLO	9 +#define STM_I2C_SR1_BERR	8 +#define STM_I2C_SR1_TXE		7 +#define STM_I2C_SR1_RXNE	6 +#define STM_I2C_SR1_STOPF	4 +#define STM_I2C_SR1_ADD10	3 +#define STM_I2C_SR1_BTF		2 +#define STM_I2C_SR1_ADDR	1 +#define STM_I2C_SR1_SB		0 + +#define STM_I2C_SR2_PEC		8 +#define  STM_I2C_SR2_PEC_MASK	0xff00 +#define STM_I2C_SR2_DUALF	7 +#define STM_I2C_SR2_SMBHOST	6 +#define STM_I2C_SR2_SMBDEFAULT	5 +#define STM_I2C_SR2_GENCALL	4 +#define STM_I2C_SR2_TRA		2 +#define STM_I2C_SR2_BUSY       	1 +#define STM_I2C_SR2_MSL		0 + +#define STM_I2C_CCR_FS		15 +#define STM_I2C_CCR_DUTY	14 +#define STM_I2C_CCR_CCR		0 +#define  STM_I2C_CCR_MASK	0x7ff + +struct stm_tim234 { +	vuint32_t	cr1; +	vuint32_t	cr2; +	vuint32_t	smcr; +	vuint32_t	dier; + +	vuint32_t	sr; +	vuint32_t	egr; +	vuint32_t	ccmr1; +	vuint32_t	ccmr2; + +	vuint32_t	ccer; +	vuint32_t	cnt; +	vuint32_t	psc; +	vuint32_t	arr; + +	uint32_t	reserved_30; +	vuint32_t	ccr1; +	vuint32_t	ccr2; +	vuint32_t	ccr3; + +	vuint32_t	ccr4; +	uint32_t	reserved_44; +	vuint32_t	dcr; +	vuint32_t	dmar; + +	uint32_t	reserved_50; +}; + +extern struct stm_tim234 stm_tim2, stm_tim3, stm_tim4; + +#define STM_TIM234_CR1_CKD	8 +#define  STM_TIM234_CR1_CKD_1		0 +#define  STM_TIM234_CR1_CKD_2		1 +#define  STM_TIM234_CR1_CKD_4		2 +#define  STM_TIM234_CR1_CKD_MASK	3 +#define STM_TIM234_CR1_ARPE	7 +#define STM_TIM234_CR1_CMS	5 +#define  STM_TIM234_CR1_CMS_EDGE	0 +#define  STM_TIM234_CR1_CMS_CENTER_1	1 +#define  STM_TIM234_CR1_CMS_CENTER_2	2 +#define  STM_TIM234_CR1_CMS_CENTER_3	3 +#define  STM_TIM234_CR1_CMS_MASK	3 +#define STM_TIM234_CR1_DIR	4 +#define  STM_TIM234_CR1_DIR_UP		0 +#define  STM_TIM234_CR1_DIR_DOWN	1 +#define STM_TIM234_CR1_OPM	3 +#define STM_TIM234_CR1_URS	2 +#define STM_TIM234_CR1_UDIS	1 +#define STM_TIM234_CR1_CEN	0 + +#define STM_TIM234_CR2_TI1S	7 +#define STM_TIM234_CR2_MMS	4 +#define  STM_TIM234_CR2_MMS_RESET		0 +#define  STM_TIM234_CR2_MMS_ENABLE		1 +#define  STM_TIM234_CR2_MMS_UPDATE		2 +#define  STM_TIM234_CR2_MMS_COMPARE_PULSE	3 +#define  STM_TIM234_CR2_MMS_COMPARE_OC1REF	4 +#define  STM_TIM234_CR2_MMS_COMPARE_OC2REF	5 +#define  STM_TIM234_CR2_MMS_COMPARE_OC3REF	6 +#define  STM_TIM234_CR2_MMS_COMPARE_OC4REF	7 +#define  STM_TIM234_CR2_MMS_MASK		7 +#define STM_TIM234_CR2_CCDS	3 + +#define STM_TIM234_SMCR_ETP	15 +#define STM_TIM234_SMCR_ECE	14 +#define STM_TIM234_SMCR_ETPS	12 +#define  STM_TIM234_SMCR_ETPS_OFF		0 +#define  STM_TIM234_SMCR_ETPS_DIV_2	       	1 +#define  STM_TIM234_SMCR_ETPS_DIV_4		2 +#define  STM_TIM234_SMCR_ETPS_DIV_8		3 +#define  STM_TIM234_SMCR_ETPS_MASK		3 +#define STM_TIM234_SMCR_ETF	8 +#define  STM_TIM234_SMCR_ETF_NONE		0 +#define  STM_TIM234_SMCR_ETF_INT_N_2		1 +#define  STM_TIM234_SMCR_ETF_INT_N_4		2 +#define  STM_TIM234_SMCR_ETF_INT_N_8		3 +#define  STM_TIM234_SMCR_ETF_DTS_2_N_6		4 +#define  STM_TIM234_SMCR_ETF_DTS_2_N_8		5 +#define  STM_TIM234_SMCR_ETF_DTS_4_N_6		6 +#define  STM_TIM234_SMCR_ETF_DTS_4_N_8		7 +#define  STM_TIM234_SMCR_ETF_DTS_8_N_6		8 +#define  STM_TIM234_SMCR_ETF_DTS_8_N_8		9 +#define  STM_TIM234_SMCR_ETF_DTS_16_N_5		10 +#define  STM_TIM234_SMCR_ETF_DTS_16_N_6		11 +#define  STM_TIM234_SMCR_ETF_DTS_16_N_8		12 +#define  STM_TIM234_SMCR_ETF_DTS_32_N_5		13 +#define  STM_TIM234_SMCR_ETF_DTS_32_N_6		14 +#define  STM_TIM234_SMCR_ETF_DTS_32_N_8		15 +#define  STM_TIM234_SMCR_ETF_MASK		15 +#define STM_TIM234_SMCR_MSM	7 +#define STM_TIM234_SMCR_TS	4 +#define  STM_TIM234_SMCR_TS_ITR0		0 +#define  STM_TIM234_SMCR_TS_ITR1		1 +#define  STM_TIM234_SMCR_TS_ITR2		2 +#define  STM_TIM234_SMCR_TS_ITR3		3 +#define  STM_TIM234_SMCR_TS_TI1F_ED		4 +#define  STM_TIM234_SMCR_TS_TI1FP1		5 +#define  STM_TIM234_SMCR_TS_TI2FP2		6 +#define  STM_TIM234_SMCR_TS_ETRF		7 +#define  STM_TIM234_SMCR_TS_MASK		7 +#define STM_TIM234_SMCR_OCCS	3 +#define STM_TIM234_SMCR_SMS	0 +#define  STM_TIM234_SMCR_SMS_DISABLE		0 +#define  STM_TIM234_SMCR_SMS_ENCODER_MODE_1	1 +#define  STM_TIM234_SMCR_SMS_ENCODER_MODE_2	2 +#define  STM_TIM234_SMCR_SMS_ENCODER_MODE_3	3 +#define  STM_TIM234_SMCR_SMS_RESET_MODE		4 +#define  STM_TIM234_SMCR_SMS_GATED_MODE		5 +#define  STM_TIM234_SMCR_SMS_TRIGGER_MODE	6 +#define  STM_TIM234_SMCR_SMS_EXTERNAL_CLOCK	7 +#define  STM_TIM234_SMCR_SMS_MASK		7 + +#define STM_TIM234_SR_CC4OF	12 +#define STM_TIM234_SR_CC3OF	11 +#define STM_TIM234_SR_CC2OF	10 +#define STM_TIM234_SR_CC1OF	9 +#define STM_TIM234_SR_TIF	6 +#define STM_TIM234_SR_CC4IF	4 +#define STM_TIM234_SR_CC3IF	3 +#define STM_TIM234_SR_CC2IF	2 +#define STM_TIM234_SR_CC1IF	1 +#define STM_TIM234_SR_UIF	0 + +#define STM_TIM234_EGR_TG	6 +#define STM_TIM234_EGR_CC4G	4 +#define STM_TIM234_EGR_CC3G	3 +#define STM_TIM234_EGR_CC2G	2 +#define STM_TIM234_EGR_CC1G	1 +#define STM_TIM234_EGR_UG	0 + +#define STM_TIM234_CCMR1_OC2CE	15 +#define STM_TIM234_CCMR1_OC2M	12 +#define  STM_TIM234_CCMR1_OC2M_FROZEN			0 +#define  STM_TIM234_CCMR1_OC2M_SET_HIGH_ON_MATCH	1 +#define  STM_TIM234_CCMR1_OC2M_SET_LOW_ON_MATCH		2 +#define  STM_TIM234_CCMR1_OC2M_TOGGLE			3 +#define  STM_TIM234_CCMR1_OC2M_FORCE_LOW		4 +#define  STM_TIM234_CCMR1_OC2M_FORCE_HIGH		5 +#define  STM_TIM234_CCMR1_OC2M_PWM_MODE_1		6 +#define  STM_TIM234_CCMR1_OC2M_PWM_MODE_2		7 +#define  STM_TIM234_CCMR1_OC2M_MASK			7 +#define STM_TIM234_CCMR1_OC2PE	11 +#define STM_TIM234_CCMR1_OC2FE	10 +#define STM_TIM234_CCMR1_CC2S	8 +#define  STM_TIM234_CCMR1_CC2S_OUTPUT			0 +#define  STM_TIM234_CCMR1_CC2S_INPUT_TI2		1 +#define  STM_TIM234_CCMR1_CC2S_INPUT_TI1		2 +#define  STM_TIM234_CCMR1_CC2S_INPUT_TRC		3 +#define  STM_TIM234_CCMR1_CC2S_MASK			3 + +#define STM_TIM234_CCMR1_OC1CE	7 +#define STM_TIM234_CCMR1_OC1M	4 +#define  STM_TIM234_CCMR1_OC1M_FROZEN			0 +#define  STM_TIM234_CCMR1_OC1M_SET_HIGH_ON_MATCH	1 +#define  STM_TIM234_CCMR1_OC1M_SET_LOW_ON_MATCH		2 +#define  STM_TIM234_CCMR1_OC1M_TOGGLE			3 +#define  STM_TIM234_CCMR1_OC1M_FORCE_LOW		4 +#define  STM_TIM234_CCMR1_OC1M_FORCE_HIGH		5 +#define  STM_TIM234_CCMR1_OC1M_PWM_MODE_1		6 +#define  STM_TIM234_CCMR1_OC1M_PWM_MODE_2		7 +#define  STM_TIM234_CCMR1_OC1M_MASK			7 +#define STM_TIM234_CCMR1_OC1PE	11 +#define STM_TIM234_CCMR1_OC1FE	2 +#define STM_TIM234_CCMR1_CC1S	0 +#define  STM_TIM234_CCMR1_CC1S_OUTPUT			0 +#define  STM_TIM234_CCMR1_CC1S_INPUT_TI1		1 +#define  STM_TIM234_CCMR1_CC1S_INPUT_TI2		2 +#define  STM_TIM234_CCMR1_CC1S_INPUT_TRC		3 +#define  STM_TIM234_CCMR1_CC1S_MASK			3 + +#define STM_TIM234_CCMR2_OC4CE	15 +#define STM_TIM234_CCMR2_OC4M	12 +#define  STM_TIM234_CCMR2_OC4M_FROZEN			0 +#define  STM_TIM234_CCMR2_OC4M_SET_HIGH_ON_MATCH	1 +#define  STM_TIM234_CCMR2_OC4M_SET_LOW_ON_MATCH		2 +#define  STM_TIM234_CCMR2_OC4M_TOGGLE			3 +#define  STM_TIM234_CCMR2_OC4M_FORCE_LOW		4 +#define  STM_TIM234_CCMR2_OC4M_FORCE_HIGH		5 +#define  STM_TIM234_CCMR2_OC4M_PWM_MODE_1		6 +#define  STM_TIM234_CCMR2_OC4M_PWM_MODE_2		7 +#define  STM_TIM234_CCMR2_OC4M_MASK			7 +#define STM_TIM234_CCMR2_OC4PE	11 +#define STM_TIM234_CCMR2_OC4FE	10 +#define STM_TIM234_CCMR2_CC4S	8 +#define  STM_TIM234_CCMR2_CC4S_OUTPUT			0 +#define  STM_TIM234_CCMR2_CC4S_INPUT_TI4		1 +#define  STM_TIM234_CCMR2_CC4S_INPUT_TI3		2 +#define  STM_TIM234_CCMR2_CC4S_INPUT_TRC		3 +#define  STM_TIM234_CCMR2_CC4S_MASK			3 + +#define STM_TIM234_CCMR2_OC3CE	7 +#define STM_TIM234_CCMR2_OC3M	4 +#define  STM_TIM234_CCMR2_OC3M_FROZEN			0 +#define  STM_TIM234_CCMR2_OC3M_SET_HIGH_ON_MATCH	1 +#define  STM_TIM234_CCMR2_OC3M_SET_LOW_ON_MATCH		2 +#define  STM_TIM234_CCMR2_OC3M_TOGGLE			3 +#define  STM_TIM234_CCMR2_OC3M_FORCE_LOW		4 +#define  STM_TIM234_CCMR2_OC3M_FORCE_HIGH		5 +#define  STM_TIM234_CCMR2_OC3M_PWM_MODE_1		6 +#define  STM_TIM234_CCMR2_OC3M_PWM_MODE_2		7 +#define  STM_TIM234_CCMR2_OC3M_MASK			7 +#define STM_TIM234_CCMR2_OC3PE	11 +#define STM_TIM234_CCMR2_OC3FE	2 +#define STM_TIM234_CCMR2_CC3S	0 +#define  STM_TIM234_CCMR2_CC3S_OUTPUT			0 +#define  STM_TIM234_CCMR2_CC3S_INPUT_TI3		1 +#define  STM_TIM234_CCMR2_CC3S_INPUT_TI4		2 +#define  STM_TIM234_CCMR2_CC3S_INPUT_TRC		3 +#define  STM_TIM234_CCMR2_CC3S_MASK			3 + +#define STM_TIM234_CCER_CC4NP	15 +#define STM_TIM234_CCER_CC4P	13 +#define STM_TIM234_CCER_CC4E	12 +#define STM_TIM234_CCER_CC3NP	11 +#define STM_TIM234_CCER_CC3P	9 +#define STM_TIM234_CCER_CC3E	8 +#define STM_TIM234_CCER_CC2NP	7 +#define STM_TIM234_CCER_CC2P	5 +#define STM_TIM234_CCER_CC2E	4 +#define STM_TIM234_CCER_CC1NP	3 +#define STM_TIM234_CCER_CC1P	1 +#define STM_TIM234_CCER_CC1E	0 + +struct stm_usb { +	struct { +		vuint16_t	r; +		uint16_t	_; +	} epr[8]; +	uint8_t		reserved_20[0x40 - 0x20]; +	vuint16_t	cntr; +	uint16_t	reserved_42; +	vuint16_t	istr; +	uint16_t	reserved_46; +	vuint16_t	fnr; +	uint16_t	reserved_4a; +	vuint16_t	daddr; +	uint16_t	reserved_4e; +	vuint16_t	btable; +	uint16_t	reserved_52; +	vuint16_t	lpmcsr; +	uint16_t	reserved_56; +	vuint16_t	bcdr; +	uint16_t	reserved_5a; +}; + +extern struct stm_usb stm_usb; + +#define STM_USB_EPR_CTR_RX	15 +#define  STM_USB_EPR_CTR_RX_WRITE_INVARIANT		1 +#define STM_USB_EPR_DTOG_RX	14 +#define STM_USB_EPR_DTOG_RX_WRITE_INVARIANT		0 +#define STM_USB_EPR_STAT_RX	12 +#define  STM_USB_EPR_STAT_RX_DISABLED			0 +#define  STM_USB_EPR_STAT_RX_STALL			1 +#define  STM_USB_EPR_STAT_RX_NAK			2 +#define  STM_USB_EPR_STAT_RX_VALID			3 +#define  STM_USB_EPR_STAT_RX_MASK			3 +#define  STM_USB_EPR_STAT_RX_WRITE_INVARIANT		0 +#define STM_USB_EPR_SETUP	11 +#define STM_USB_EPR_EP_TYPE	9 +#define  STM_USB_EPR_EP_TYPE_BULK			0 +#define  STM_USB_EPR_EP_TYPE_CONTROL			1 +#define  STM_USB_EPR_EP_TYPE_ISO			2 +#define  STM_USB_EPR_EP_TYPE_INTERRUPT			3 +#define  STM_USB_EPR_EP_TYPE_MASK			3 +#define STM_USB_EPR_EP_KIND	8 +#define  STM_USB_EPR_EP_KIND_DBL_BUF			1	/* Bulk */ +#define  STM_USB_EPR_EP_KIND_STATUS_OUT			1	/* Control */ +#define STM_USB_EPR_CTR_TX	7 +#define  STM_USB_CTR_TX_WRITE_INVARIANT			1 +#define STM_USB_EPR_DTOG_TX	6 +#define  STM_USB_EPR_DTOG_TX_WRITE_INVARIANT		0 +#define STM_USB_EPR_STAT_TX	4 +#define  STM_USB_EPR_STAT_TX_DISABLED			0 +#define  STM_USB_EPR_STAT_TX_STALL			1 +#define  STM_USB_EPR_STAT_TX_NAK			2 +#define  STM_USB_EPR_STAT_TX_VALID			3 +#define  STM_USB_EPR_STAT_TX_WRITE_INVARIANT		0 +#define  STM_USB_EPR_STAT_TX_MASK			3 +#define STM_USB_EPR_EA		0 +#define  STM_USB_EPR_EA_MASK				0xf + +#define STM_USB_CNTR_CTRM	15 +#define STM_USB_CNTR_PMAOVRM	14 +#define STM_USB_CNTR_ERRM	13 +#define STM_USB_CNTR_WKUPM	12 +#define STM_USB_CNTR_SUSPM	11 +#define STM_USB_CNTR_RESETM	10 +#define STM_USB_CNTR_SOFM	9 +#define STM_USB_CNTR_ESOFM	8 +#define STM_USB_CNTR_RESUME	4 +#define STM_USB_CNTR_FSUSP	3 +#define STM_USB_CNTR_LP_MODE	2 +#define STM_USB_CNTR_PDWN	1 +#define STM_USB_CNTR_FRES	0 + +#define STM_USB_ISTR_CTR	15 +#define STM_USB_ISTR_PMAOVR	14 +#define STM_USB_ISTR_ERR	13 +#define STM_USB_ISTR_WKUP	12 +#define STM_USB_ISTR_SUSP	11 +#define STM_USB_ISTR_RESET	10 +#define STM_USB_ISTR_SOF	9 +#define STM_USB_ISTR_ESOF	8 +#define STM_USB_L1REQ		7 +#define STM_USB_ISTR_DIR	4 +#define STM_USB_ISTR_EP_ID	0 +#define  STM_USB_ISTR_EP_ID_MASK		0xf + +#define STM_USB_FNR_RXDP	15 +#define STM_USB_FNR_RXDM	14 +#define STM_USB_FNR_LCK		13 +#define STM_USB_FNR_LSOF	11 +#define  STM_USB_FNR_LSOF_MASK			0x3 +#define STM_USB_FNR_FN		0 +#define  STM_USB_FNR_FN_MASK			0x7ff + +#define STM_USB_DADDR_EF	7 +#define STM_USB_DADDR_ADD	0 +#define  STM_USB_DADDR_ADD_MASK			0x7f + +#define STM_USB_BCDR_DPPU	15 +#define STM_USB_BCDR_PS2DET	7 +#define STM_USB_BCDR_SDET	6 +#define STM_USB_BCDR_PDET	5 +#define STM_USB_BCDR_DCDET	4 +#define STM_USB_BCDR_SDEN	3 +#define STM_USB_BCDR_PDEN	2 +#define STM_USB_BCDR_DCDEN	1 +#define STM_USB_BCDR_BCDEN	0 + +union stm_usb_bdt { +	struct { +		vuint16_t	addr_tx; +		vuint16_t	count_tx; +		vuint16_t	addr_rx; +		vuint16_t	count_rx; +	} single; +	struct { +		vuint16_t	addr; +		vuint16_t	count; +	} double_tx[2]; +	struct { +		vuint16_t	addr; +		vuint16_t	count; +	} double_rx[2]; +}; + +#define STM_USB_BDT_COUNT_RX_BL_SIZE	15 +#define STM_USB_BDT_COUNT_RX_NUM_BLOCK	10 +#define  STM_USB_BDT_COUNT_RX_NUM_BLOCK_MASK	0x1f +#define STM_USB_BDT_COUNT_RX_COUNT_RX	0 +#define  STM_USB_BDT_COUNT_RX_COUNT_RX_MASK	0x1ff + +#define STM_USB_BDT_SIZE	8 + +extern uint8_t stm_usb_sram[]; + +struct stm_exti { +	vuint32_t	imr; +	vuint32_t	emr; +	vuint32_t	rtsr; +	vuint32_t	ftsr; + +	vuint32_t	swier; +	vuint32_t	pr; +}; + +extern struct stm_exti stm_exti; + +#endif /* _STM32F0_H_ */ diff --git a/src/telebt-v3.0/Makefile b/src/telebt-v3.0/Makefile new file mode 100644 index 00000000..a7ef4d64 --- /dev/null +++ b/src/telebt-v3.0/Makefile @@ -0,0 +1,94 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_cc1200_CC1200.h \ +	ao_profile.h \ +	ao_task.h \ +	stm32l.h \ +	Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +#	ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_data.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_serial_stm.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_cc1200.c \ +	ao_adc_stm.c \ +	ao_btm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_eeprom_stm.c \ +	ao_convert_volt.c \ +	ao_packet_master.c \ +	ao_packet.c \ +	ao_monitor.c \ +	$(PROFILE) \ +	$(SAMPLE_PROFILE) \ +	$(STACK_GUARD) + +PRODUCT=TeleBT-v3.0 +PRODUCT_DEF=-DTELEBT_V_3_0 +IDPRODUCT=0x000e + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=telebt-v3.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_telebt.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/telebt-v3.0/ao_pins.h b/src/telebt-v3.0/ao_pins.h new file mode 100644 index 00000000..838f0dfc --- /dev/null +++ b/src/telebt-v3.0/ao_pins.h @@ -0,0 +1,208 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1		0 +#define USE_SERIAL_1_STDIN	0 +#define SERIAL_1_PB6_PB7	0 +#define SERIAL_1_PA9_PA10	1 + +#define HAS_SERIAL_2		1 +#define USE_SERIAL_2_STDIN	1 +#define DELAY_SERIAL_2_STDIN	1 +#define USE_SERIAL_2_FLOW	1 +#define SERIAL_2_PA2_PA3	1 +#define SERIAL_2_PD5_PD6	0 + +#define HAS_SERIAL_3		0 +#define USE_SERIAL_3_STDIN	0 +#define SERIAL_3_PB10_PB11	1 +#define SERIAL_3_PC10_PC11	0 +#define SERIAL_3_PD8_PD9	0 + +#define AO_CONFIG_MAX_SIZE			1024 + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	0 +#define USE_EEPROM_CONFIG	1 +#define USE_STORAGE_CONFIG	0 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_BATTERY_REPORT	0 +#define HAS_RADIO		1 +#define HAS_TELEMETRY		0 +#define HAS_APRS		0 +#define HAS_ACCEL		0 + +#define HAS_SPI_1		1 +#define SPI_1_PA5_PA6_PA7	1	/* CC1200 */ +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0 +#define SPI_1_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_SPI_2		0 +#define SPI_2_PB13_PB14_PB15	0 +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define HAS_I2C_1		0 +#define I2C_1_PB8_PB9		0 + +#define HAS_I2C_2		0 +#define I2C_2_PB10_PB11		0 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	1 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_0_ENABLE	STM_RCC_AHBENR_GPIOAEN +#define LED_PORT_1_ENABLE	STM_RCC_AHBENR_GPIOCEN +#define LED_PORT_0		(&stm_gpioa) +#define LED_PORT_1		(&stm_gpioc) +#define LED_PORT_0_SHIFT	0 +#define LED_PORT_1_SHIFT	0 +#define LED_PIN_RED		(4 + LED_PORT_0_SHIFT) +#define LED_PIN_BLUE		(15 + LED_PORT_1_SHIFT) +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_BLUE		(1 << LED_PIN_BLUE) +#define LED_PORT_0_MASK		(AO_LED_RED) +#define LED_PORT_1_MASK		(AO_LED_BLUE) +#define AO_BT_LED		AO_LED_BLUE + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_BLUE) + +#define HAS_GPS			0 +#define HAS_FLIGHT		0 +#define HAS_ADC			1 +#define HAS_ADC_TEMP		0 +#define HAS_LOG			0 + +/* + * ADC + */ +#define AO_DATA_RING		32 +#define AO_ADC_NUM_SENSE	2 + +struct ao_adc { +	int16_t			v_batt; +}; + +#define AO_ADC_DUMP(p) \ +	printf("tick: %5u %5d batt: %5d\n", \ +	       (p)->tick, \ +	       (p)->adc.v_batt); + +#define AO_ADC_V_BATT		8 +#define AO_ADC_V_BATT_PORT	(&stm_gpiob) +#define AO_ADC_V_BATT_PIN	0 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_GPIOEEN)) + +#define AO_NUM_ADC_PIN		1 + +#define AO_ADC_PIN0_PORT	AO_ADC_V_BATT_PORT +#define AO_ADC_PIN0_PIN		AO_ADC_V_BATT_PIN + +#define AO_NUM_ADC	       	(AO_NUM_ADC_PIN) + +#define AO_ADC_SQ1		AO_ADC_V_BATT + +/* + * Voltage divider on ADC battery sampler + */ +#define AO_BATTERY_DIV_PLUS	51	/* 5.6k */ +#define AO_BATTERY_DIV_MINUS	100	/* 10k */ + +/* + * ADC reference in decivolts + */ +#define AO_ADC_REFERENCE_DV	33 + +/* + * BTM + */ +#define HAS_BTM			1 + +#define ao_serial_btm_getchar	ao_serial2_getchar +#define ao_serial_btm_putchar	ao_serial2_putchar +#define _ao_serial_btm_pollchar	_ao_serial2_pollchar +#define _ao_serial_btm_sleep	_ao_serial2_sleep +#define ao_serial_btm_set_speed ao_serial2_set_speed +#define ao_serial_btm_drain	ao_serial2_drain +#define ao_serial_btm_rx_fifo	(ao_stm_usart2.rx_fifo) + +#define AO_BTM_INT_PORT		(&stm_gpioa) +#define AO_BTM_INT_PIN		15 +#define AO_BTM_RESET_PORT	(&stm_gpiob) +#define AO_BTM_RESET_PIN	3 + +/* + * Radio (cc1200) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 	5695485 + +#define AO_FEC_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	(&stm_gpiob) +#define AO_CC1200_SPI_CS_PIN	10 +#define AO_CC1200_SPI_BUS	AO_SPI_1_PA5_PA6_PA7 +#define AO_CC1200_SPI		stm_spi1 + +#define AO_CC1200_INT_PORT		(&stm_gpiob) +#define AO_CC1200_INT_PIN		(11) + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +#define HAS_BOOT_RADIO		0 + +/* Monitor bits */ +#define HAS_MONITOR		1 +#define LEGACY_MONITOR		0 +#define AO_MONITOR_LED		AO_LED_RED + +#endif /* _AO_PINS_H_ */ diff --git a/src/telebt-v3.0/ao_telebt.c b/src/telebt-v3.0/ao_telebt.c new file mode 100644 index 00000000..44ee4f3d --- /dev/null +++ b/src/telebt-v3.0/ao_telebt.c @@ -0,0 +1,60 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_exti.h> +#include <ao_packet.h> +#include <ao_eeprom.h> +#include <ao_profile.h> +#include <ao_btm.h> +#if HAS_SAMPLE_PROFILE +#include <ao_sample_profile.h> +#endif + +int +main(void) +{ +	ao_clock_init(); + +	ao_task_init(); +	ao_serial_init(); +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_RED); +	ao_timer_init(); + +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_adc_init(); +	ao_btm_init(); +	ao_cmd_init(); + +	ao_eeprom_init(); + +	ao_usb_init(); +	ao_radio_init(); +	ao_packet_master_init(); +	ao_monitor_init(); + +	ao_config_init(); + +	ao_led_off(AO_LED_RED); + +	ao_start_scheduler(); +	return 0; +} diff --git a/src/telebt-v3.0/flash-loader/Makefile b/src/telebt-v3.0/flash-loader/Makefile new file mode 100644 index 00000000..a1c5168f --- /dev/null +++ b/src/telebt-v3.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=telebt-v3.0 +include $(TOPDIR)/stm/Makefile-flash.defs diff --git a/src/telebt-v3.0/flash-loader/ao_pins.h b/src/telebt-v3.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..8711548d --- /dev/null +++ b/src/telebt-v3.0/flash-loader/ao_pins.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +/* External crystal at 8MHz */ +#define AO_HSE		8000000 + +#include <ao_flash_stm_pins.h> + +/* Blue LED */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioc +#define AO_BOOT_APPLICATION_PIN		15 +#define AO_BOOT_APPLICATION_VALUE	0 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_DOWN + +#endif /* _AO_PINS_H_ */ diff --git a/src/teledongle-v1.8/.gitignore b/src/teledongle-v1.8/.gitignore new file mode 100644 index 00000000..9a30cbb6 --- /dev/null +++ b/src/teledongle-v1.8/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +teledongle-*.elf diff --git a/src/teledongle-v1.8/Makefile b/src/teledongle-v1.8/Makefile new file mode 100644 index 00000000..6c05ce9f --- /dev/null +++ b/src/teledongle-v1.8/Makefile @@ -0,0 +1,88 @@ +# +# AltOS build +# +# + +include ../stm/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	ao_whiten.h \ +	stm32l.h \ +	ao_cc1200.h \ +	ao_cc1200_CC1200.h \ +	Makefile + +#PROFILE=ao_profile.c +#PROFILE_DEF=-DAO_PROFILE=1 + +#SAMPLE_PROFILE=ao_sample_profile.c \ +#	ao_sample_profile_timer.c +#SAMPLE_PROFILE_DEF=-DHAS_SAMPLE_PROFILE=1 + +#STACK_GUARD=ao_mpu_stm.c +#STACK_GUARD_DEF=-DHAS_STACK_GUARD=1 + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cc1200.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_dma_stm.c \ +	ao_spi_stm.c \ +	ao_usb_stm.c \ +	ao_exti_stm.c \ +	ao_send_packet.c \ +	ao_eeprom_stm.c \ +	ao_monitor.c \ +	ao_packet_master.c \ +	ao_packet.c + +PRODUCT=TeleDongle-v1.8 +PRODUCT_DEF=-DTELEDONGLE +IDPRODUCT=0x000c + +CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) $(STACK_GUARD_DEF) -Os -g + +PROGNAME=teledongle-v1.8 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_teledongle.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/teledongle-v1.8/ao_pins.h b/src/teledongle-v1.8/ao_pins.h new file mode 100644 index 00000000..cff3e5e8 --- /dev/null +++ b/src/teledongle-v1.8/ao_pins.h @@ -0,0 +1,147 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +/* Using TeleMetrum v1.9 board */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define HAS_TASK_QUEUE		1 + +/* 8MHz High speed external crystal */ +#define AO_HSE			8000000 + +/* PLLVCO = 96MHz (so that USB will work) */ +#define AO_PLLMUL		12 +#define AO_RCC_CFGR_PLLMUL	(STM_RCC_CFGR_PLLMUL_12) + +/* SYSCLK = 32MHz (no need to go faster than CPU) */ +#define AO_PLLDIV		3 +#define AO_RCC_CFGR_PLLDIV	(STM_RCC_CFGR_PLLDIV_3) + +/* HCLK = 32MHz (CPU clock) */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* Run APB1 at 16MHz (HCLK/2) */ +#define AO_APB1_PRESCALER	2 +#define AO_RCC_CFGR_PPRE1_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +/* Run APB2 at 16MHz (HCLK/2) */ +#define AO_APB2_PRESCALER	2 +#define AO_RCC_CFGR_PPRE2_DIV	STM_RCC_CFGR_PPRE2_DIV_2 + +#define HAS_SERIAL_1		0 +#define USE_SERIAL_1_STDIN	0 +#define SERIAL_1_PB6_PB7	0 +#define SERIAL_1_PA9_PA10	0 + +#define HAS_SERIAL_2		0 +#define USE_SERIAL_2_STDIN	0 +#define SERIAL_2_PA2_PA3	0 +#define SERIAL_2_PD5_PD6	0 + +#define HAS_SERIAL_3		0 +#define USE_SERIAL_3_STDIN	0 +#define SERIAL_3_PB10_PB11	0 +#define SERIAL_3_PC10_PC11	0 +#define SERIAL_3_PD8_PD9	0 + +#define HAS_EEPROM		1 +#define USE_INTERNAL_FLASH	1 +#define USE_STORAGE_CONFIG	0 +#define USE_EEPROM_CONFIG	1 +#define HAS_USB			1 +#define HAS_BEEP		0 +#define HAS_RADIO		1 +#define HAS_TELEMETRY		0 +#define HAS_RSSI		0 + +#define HAS_SPI_1		0 +#define SPI_1_PA5_PA6_PA7	0	/* Barometer */ +#define SPI_1_PB3_PB4_PB5	0 +#define SPI_1_PE13_PE14_PE15	0	/* Accelerometer */ + +#define HAS_SPI_2		1 +#define SPI_2_PB13_PB14_PB15	1	/* Radio */ +#define SPI_2_PD1_PD3_PD4	0 +#define SPI_2_OSPEEDR		STM_OSPEEDR_10MHz + +#define SPI_2_PORT		(&stm_gpiob) +#define SPI_2_SCK_PIN		13 +#define SPI_2_MISO_PIN		14 +#define SPI_2_MOSI_PIN		15 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	1 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT_0_ENABLE	STM_RCC_AHBENR_GPIOCEN +#define LED_PORT_0		(&stm_gpioc) +#define LED_PORT_0_MASK		(0xffff) +#define LED_PORT_0_SHIFT	0 +#define LED_PIN_RED		8 +#define LED_PIN_GREEN		9 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_GREEN) + +#define HAS_GPS			0 +#define HAS_FLIGHT		0 +#define HAS_ADC			0 +#define HAS_LOG			0 + +/* + * Telemetry monitoring + */ +#define HAS_MONITOR		1 +#define LEGACY_MONITOR		0 +#define HAS_MONITOR_PUT		1 +#define AO_MONITOR_LED		AO_LED_GREEN +#define AO_MONITOR_BAD		AO_LED_RED + +/* + * Radio (cc1200) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_FEC_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	(&stm_gpioc) +#define AO_CC1200_SPI_CS_PIN	5 +#define AO_CC1200_SPI_BUS	AO_SPI_2_PB13_PB14_PB15 +#define AO_CC1200_SPI		stm_spi2 + +#define AO_CC1200_INT_PORT	(&stm_gpioe) +#define AO_CC1200_INT_PIN	1 + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE	       	0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/teledongle-v1.8/ao_teledongle.c b/src/teledongle-v1.8/ao_teledongle.c new file mode 100644 index 00000000..5ce6b15b --- /dev/null +++ b/src/teledongle-v1.8/ao_teledongle.c @@ -0,0 +1,54 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_exti.h> +#include <ao_packet.h> +#include <ao_send_packet.h> + +int +main(void) +{ +	ao_clock_init(); + +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_RED); +	ao_timer_init(); + +	ao_spi_init(); +	ao_dma_init(); +	ao_exti_init(); + +	ao_cmd_init(); + +	ao_usb_init(); +	ao_radio_init(); +	ao_monitor_init(); +	ao_packet_master_init(); +	ao_send_packet_init(); + +	ao_config_init(); + +	ao_led_off(AO_LED_RED); +	ao_start_scheduler(); +	return 0; +} diff --git a/src/teledongle-v3.0/.gitignore b/src/teledongle-v3.0/.gitignore new file mode 100644 index 00000000..9a30cbb6 --- /dev/null +++ b/src/teledongle-v3.0/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +teledongle-*.elf diff --git a/src/teledongle-v3.0/Makefile b/src/teledongle-v3.0/Makefile new file mode 100644 index 00000000..a656cde5 --- /dev/null +++ b/src/teledongle-v3.0/Makefile @@ -0,0 +1,79 @@ +# +# AltOS build +# +# + +include ../lpc/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_boot.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	ao_whiten.h \ +	lpc.h \ +	ao_cc1200.h \ +	ao_cc1200_CC1200.h \ +	Makefile + +ALTOS_SRC = \ +	ao_boot_chain.c \ +	ao_interrupt.c \ +	ao_product.c \ +	ao_romconfig.c \ +	ao_cc1200.c \ +	ao_cmd.c \ +	ao_config.c \ +	ao_task.c \ +	ao_led_lpc.c \ +	ao_stdio.c \ +	ao_panic.c \ +	ao_timer_lpc.c \ +	ao_mutex.c \ +	ao_freq.c \ +	ao_spi_lpc.c \ +	ao_usb_lpc.c \ +	ao_exti_lpc.c \ +	ao_send_packet.c \ +	ao_monitor.c \ +	ao_packet_master.c \ +	ao_packet.c + +PRODUCT=TeleDongle-v3.0 +PRODUCT_DEF=-DTELEDONGLE +IDPRODUCT=0x000c + +CFLAGS = $(PRODUCT_DEF) $(LPC_CFLAGS) -Os -g + +PROGNAME=teledongle-v3.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_teledongle.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +$(OBJ): $(INC) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +load: $(PROG) +	lpc-load $(PROG) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/teledongle-v3.0/ao_pins.h b/src/teledongle-v3.0/ao_pins.h new file mode 100644 index 00000000..52a86fcb --- /dev/null +++ b/src/teledongle-v3.0/ao_pins.h @@ -0,0 +1,113 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +/* Using TeleDongle v3.0 board */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define AO_STACK_SIZE	320 + +#define HAS_TASK_QUEUE		1 + +#define IS_FLASH_LOADER	0 + +/* Crystal on the board */ +#define AO_LPC_CLKIN	12000000 + +/* Main clock frequency. 48MHz for USB so we don't use the USB PLL */ +#define AO_LPC_CLKOUT	48000000 + +/* System clock frequency */ +#define AO_LPC_SYSCLK	24000000 + +#define HAS_EEPROM		0 +#define USE_INTERNAL_FLASH	0 +#define USE_STORAGE_CONFIG	0 +#define USE_EEPROM_CONFIG	0 + +#define HAS_USB			1 +#define HAS_USB_CONNECT		0 +#define HAS_USB_VBUS		0 +#define HAS_USB_PULLUP		1 +#define AO_USB_PULLUP_PORT	0 +#define AO_USB_PULLUP_PIN	20 + +#define HAS_BEEP		0 +#define HAS_RADIO		1 +#define HAS_TELEMETRY		0 +#define HAS_RSSI		0 + +#define HAS_SPI_0		1 +#define SPI_SCK0_P0_6		1 + +#define PACKET_HAS_SLAVE	0 +#define PACKET_HAS_MASTER	1 + +#define LOW_LEVEL_DEBUG		0 + +#define LED_PORT		0 +#define LED_PIN_RED		14 +#define LED_PIN_GREEN		7 +#define AO_LED_RED		(1 << LED_PIN_RED) +#define AO_LED_GREEN		(1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE		(AO_LED_RED | AO_LED_GREEN) + +#define HAS_GPS			0 +#define HAS_FLIGHT		0 +#define HAS_ADC			0 +#define HAS_LOG			0 + +/* + * Telemetry monitoring + */ +#define HAS_MONITOR		1 +#define LEGACY_MONITOR		0 +#define HAS_MONITOR_PUT		1 +#define AO_MONITOR_LED		AO_LED_GREEN +#define AO_MONITOR_BAD		AO_LED_RED + +/* + * Radio (cc1200) + */ + +/* gets pretty close to 434.550 */ + +#define AO_RADIO_CAL_DEFAULT 	5695733 + +#define AO_FEC_DEBUG		0 +#define AO_CC1200_SPI_CS_PORT	0 +#define AO_CC1200_SPI_CS_PIN	3 +#define AO_CC1200_SPI_BUS	0 +#define AO_CC1200_SPI		0 + +#define AO_CC1200_INT_PORT	0 +#define AO_CC1200_INT_PIN	2 + +#define AO_CC1200_INT_GPIO	2 +#define AO_CC1200_INT_GPIO_IOCFG	CC1200_IOCFG2 + +/* + * Profiling Viterbi decoding + */ + +#ifndef AO_PROFILE +#define AO_PROFILE	       	0 +#endif + +#endif /* _AO_PINS_H_ */ diff --git a/src/teledongle-v3.0/ao_teledongle.c b/src/teledongle-v3.0/ao_teledongle.c new file mode 100644 index 00000000..02b93efe --- /dev/null +++ b/src/teledongle-v3.0/ao_teledongle.c @@ -0,0 +1,53 @@ +/* + * Copyright © 2012 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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_exti.h> +#include <ao_packet.h> +#include <ao_send_packet.h> + +int +main(void) +{ +	ao_clock_init(); + +#if HAS_STACK_GUARD +	ao_mpu_init(); +#endif + +	ao_task_init(); +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_RED); +	ao_timer_init(); + +	ao_spi_init(); +	ao_exti_init(); + +	ao_cmd_init(); + +	ao_usb_init(); +	ao_radio_init(); +	ao_monitor_init(); +	ao_packet_master_init(); +	ao_send_packet_init(); + +	ao_config_init(); + +	ao_led_off(AO_LED_RED); +	ao_start_scheduler(); +	return 0; +} diff --git a/src/teledongle-v3.0/flash-loader/Makefile b/src/teledongle-v3.0/flash-loader/Makefile new file mode 100644 index 00000000..b8325114 --- /dev/null +++ b/src/teledongle-v3.0/flash-loader/Makefile @@ -0,0 +1,7 @@ +# +# AltOS flash loader build +# + +TOPDIR=../.. +HARDWARE=teledongle-v3.0 +include $(TOPDIR)/lpc/Makefile-flash.defs diff --git a/src/teledongle-v3.0/flash-loader/ao_pins.h b/src/teledongle-v3.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..aee5be27 --- /dev/null +++ b/src/teledongle-v3.0/flash-loader/ao_pins.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_lpc_pins.h> + +/* Debug port TXD (pin 6) */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	0 +#define AO_BOOT_APPLICATION_PIN		19 +#define AO_BOOT_APPLICATION_VALUE	1 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_UP + +#define HAS_USB_PULLUP	1 +#define AO_USB_PULLUP_PORT	0 +#define AO_USB_PULLUP_PIN	20 + +#endif /* _AO_PINS_H_ */ diff --git a/src/test/.gitignore b/src/test/.gitignore index b8b2513e..9237780b 100644 --- a/src/test/.gitignore +++ b/src/test/.gitignore @@ -15,5 +15,6 @@ ao_fat_test  ao_fec_test  ao_flight_test_mm  ao_flight_test_noisy_accel +ao_flight_test_metrum  ao_micropeak_test  ao_aes_test diff --git a/src/test/ao_flight_test.c b/src/test/ao_flight_test.c index 8b737ca1..fbbc4bd9 100644 --- a/src/test/ao_flight_test.c +++ b/src/test/ao_flight_test.c @@ -600,7 +600,7 @@ ao_insert(void)  #if 1  			printf("%7.2f height %8.2f accel %8.3f " -#if TELEMEGA && 0 +#if TELEMEGA && 1  			       "angle %5d "  			       "accel_x %8.3f accel_y %8.3f accel_z %8.3f gyro_x %8.3f gyro_y %8.3f gyro_z %8.3f mag_x %8d mag_y %8d, mag_z %8d mag_angle %4d "  #endif @@ -608,7 +608,7 @@ ao_insert(void)  			       time,  			       height,  			       accel, -#if TELEMEGA && 0 +#if TELEMEGA && 1  			       ao_sample_orient,  			       ao_mpu6000_accel(ao_data_static.mpu6000.accel_x), @@ -764,6 +764,8 @@ ao_sleep(void *wchan)  					ao_data_static.hmc5883.z = int16(bytes, 24);  #if HAS_MMA655X  					ao_data_static.mma655x = int16(bytes, 26); +					if (ao_config.pad_orientation != AO_PAD_ORIENTATION_ANTENNA_UP) +						ao_data_static.mma655x = ao_data_accel_invert(ao_data_static.mma655x);  #endif  					ao_records_read++;  					ao_insert(); @@ -900,6 +902,9 @@ ao_sleep(void *wchan)  			} else if (nword >= 3 && strcmp(words[0], "Apogee") == 0 &&  				   strcmp(words[1], "lockout:") == 0) {  				ao_config.apogee_lockout = atoi(words[2]); +			} else if (nword >= 3 && strcmp(words[0], "Pad") == 0 && +				   strcmp(words[1], "orientation:") == 0) { +				ao_config.pad_orientation = atoi(words[2]);  			} else if (nword >= 36 && strcmp(words[0], "CALL") == 0) {  				tick = atoi(words[10]);  				if (!ao_flight_started) { diff --git a/src/test/ao_gps_test_ublox.c b/src/test/ao_gps_test_ublox.c index 5ea205d6..83efbb4f 100644 --- a/src/test/ao_gps_test_ublox.c +++ b/src/test/ao_gps_test_ublox.c @@ -59,6 +59,7 @@ struct ao_telemetry_location {  typedef int32_t		gps_alt_t;  #define AO_TELEMETRY_LOCATION_ALTITUDE(l) 	(((gps_alt_t) (l)->altitude_high << 16) | ((l)->altitude_low)) +#define AO_GPS_ORIG_ALTITUDE(l)			AO_TELEMETRY_LOCATION_ALTITUDE(l)  #define AO_TELEMETRY_LOCATION_SET_ALTITUDE(l,a) (((l)->altitude_high = (a) >> 16), \  						 ((l)->altitude_low = (a))) diff --git a/src/microwater/.gitignore b/src/usbtrng-v2.0/.gitignore index 0573d989..93b38d11 100644 --- a/src/microwater/.gitignore +++ b/src/usbtrng-v2.0/.gitignore @@ -1,2 +1,2 @@  ao_product.h -microwater-* +usbtrng-* diff --git a/src/usbtrng-v2.0/Makefile b/src/usbtrng-v2.0/Makefile new file mode 100644 index 00000000..abbdbbcc --- /dev/null +++ b/src/usbtrng-v2.0/Makefile @@ -0,0 +1,68 @@ +# +# AltOS build +# +# + +include ../stmf0/Makefile.defs + +INC = \ +	ao.h \ +	ao_arch.h \ +	ao_arch_funcs.h \ +	ao_pins.h \ +	ao_product.h \ +	ao_task.h \ +	stm32f0.h + +# +# Common AltOS sources +# +ALTOS_SRC = \ +	ao_interrupt.c \ +	ao_timer.c \ +	ao_panic.c \ +	ao_mutex.c \ +	ao_dma_stm.c \ +	ao_adc_fast.c \ +	ao_crc_stm.c \ +	ao_stdio.c \ +	ao_led.c \ +	ao_romconfig.c \ +	ao_boot_chain.c \ +	ao_cmd.c \ +	ao_usb_stm.c \ +	ao_task.c \ +	ao_product.c + +PRODUCT=usbtrng-v2.0 +PRODUCT_DEF=-DUSBTRNG_V_2_0 +IDPRODUCT=0x0028 + +CFLAGS = $(PRODUCT_DEF) $(STMF0_CFLAGS) -g -Os + +PROGNAME=usbtrng-v2.0 +PROG=$(PROGNAME)-$(VERSION).elf +HEX=$(PROGNAME)-$(VERSION).ihx + +SRC=$(ALTOS_SRC) ao_usbtrng.c +OBJ=$(SRC:.c=.o) + +all: $(PROG) $(HEX) + +$(PROG): Makefile $(OBJ) altos.ld +	$(call quiet,CC) $(LDFLAGS) $(CFLAGS) -o $(PROG) $(OBJ) $(LIBS) + +ao_product.h: ao-make-product.5c ../Version +	$(call quiet,NICKLE,$<) $< -m altusmetrum.org -i $(IDPRODUCT) -p $(PRODUCT) -v $(VERSION) > $@ + +$(OBJ): $(INC) + +distclean:	clean + +clean: +	rm -f *.o $(PROGNAME)-*.elf $(PROGNAME)-*.ihx +	rm -f ao_product.h + +install: + +uninstall: diff --git a/src/usbtrng-v2.0/ao_pins.h b/src/usbtrng-v2.0/ao_pins.h new file mode 100644 index 00000000..23759444 --- /dev/null +++ b/src/usbtrng-v2.0/ao_pins.h @@ -0,0 +1,63 @@ +/* + * Copyright © 2015 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#define LED_PORT_ENABLE	STM_RCC_AHBENR_IOPAEN +#define LED_PORT	(&stm_gpioa) +#define LED_PIN_RED	2 +#define LED_PIN_GREEN	3 +#define AO_LED_RED	(1 << LED_PIN_RED) +#define AO_LED_GREEN	(1 << LED_PIN_GREEN) + +#define LEDS_AVAILABLE	(AO_LED_RED | AO_LED_GREEN) + +#define HAS_BEEP	0 + +/* 48MHz clock based on USB */ +#define AO_HSI48	1 + +/* HCLK = 48MHz */ +#define AO_AHB_PRESCALER	1 +#define AO_RCC_CFGR_HPRE_DIV	STM_RCC_CFGR_HPRE_DIV_1 + +/* APB = 48MHz */ +#define AO_APB_PRESCALER	1 +#define AO_RCC_CFGR_PPRE_DIV	STM_RCC_CFGR_PPRE_DIV_1 + +#define HAS_USB			1 +#define AO_USB_DIRECTIO		1 +#define AO_PA11_PA12_RMP	0 + +#define IS_FLASH_LOADER	0 + +/* ADC */ + +#define AO_ADC_PIN0_PORT	(&stm_gpioa) +#define AO_ADC_PIN0_PIN		6 +#define AO_ADC_PIN0_CH		6 + +#define AO_ADC_RCC_AHBENR	((1 << STM_RCC_AHBENR_IOPAEN)) + +#define AO_NUM_ADC		1 + +/* CRC */ +#define AO_CRC_WIDTH	32 +#define AO_CRC_INIT	0xffffffff + +#endif /* _AO_PINS_H_ */ diff --git a/src/usbtrng-v2.0/ao_usbtrng.c b/src/usbtrng-v2.0/ao_usbtrng.c new file mode 100644 index 00000000..e1f43cdd --- /dev/null +++ b/src/usbtrng-v2.0/ao_usbtrng.c @@ -0,0 +1,93 @@ +/* + * Copyright © 2014 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_adc_fast.h> +#include <ao_crc.h> + +static void +ao_trng_fetch(void) +{ +	static uint16_t	*buffer[2]; +	uint32_t	kbytes = 1; +	uint32_t	count; +	int		usb_buf_id; +	int		i; +	uint16_t	*buf; +	uint32_t	*rnd; + +	if (!buffer[0]) { +		buffer[0] = ao_usb_alloc(); +		buffer[1] = ao_usb_alloc(); +		if (!buffer[0]) +			return; +	} + +	ao_cmd_decimal(); +	if (ao_cmd_status == ao_cmd_success) +		kbytes = ao_cmd_lex_u32; +	else +		ao_cmd_status = ao_cmd_success; +	usb_buf_id = 0; +	count = kbytes * (1024/AO_USB_IN_SIZE); + +	ao_crc_reset(); + +	ao_led_on(AO_LED_GREEN); +	while (count--) { +		buf = buffer[usb_buf_id]; +//		printf ("before get: head %3d tail %3d running %d\n", ao_adc_ring_head, ao_adc_ring_tail, ao_adc_running); flush(); +		rnd = (uint32_t *) ao_adc_get(AO_USB_IN_SIZE);	/* one 16-bit value per output byte */ +//		printf ("after get: head %3d tail %3d running %d\n", ao_adc_ring_head, ao_adc_ring_tail, ao_adc_running); flush(); +		for (i = 0; i < 32; i++) +			*buf++ = ao_crc_in_32_out_16(*rnd++); +		ao_adc_ack(AO_USB_IN_SIZE); +//		printf ("after ack: head %3d tail %3d running %d\n", ao_adc_ring_head, ao_adc_ring_tail, ao_adc_running); flush(); +		ao_led_toggle(AO_LED_GREEN|AO_LED_RED); +		ao_usb_write(buffer[usb_buf_id], AO_USB_IN_SIZE); +		ao_led_toggle(AO_LED_GREEN|AO_LED_RED); +		usb_buf_id = 1-usb_buf_id; +	} +	ao_led_off(AO_LED_GREEN|AO_LED_RED); +	flush(); +} + +static const struct ao_cmds usbtrng_cmds[] = { +	{ ao_trng_fetch,	"f <kbytes>\0Fetch a block of numbers" }, +	{ 0, NULL }, +}; + +void main(void) +{ +	ao_led_init(LEDS_AVAILABLE); +	ao_led_on(AO_LED_RED); +	ao_clock_init(); +	ao_task_init(); +	ao_timer_init(); +	ao_dma_init(); +	ao_adc_init(); +	ao_crc_init(); + +	ao_cmd_init(); + +	ao_usb_init(); + +	ao_cmd_register(usbtrng_cmds); +	ao_led_off(AO_LED_RED); + +	ao_start_scheduler(); +} diff --git a/src/usbtrng-v2.0/flash-loader/.gitignore b/src/usbtrng-v2.0/flash-loader/.gitignore new file mode 100644 index 00000000..32dbbbcf --- /dev/null +++ b/src/usbtrng-v2.0/flash-loader/.gitignore @@ -0,0 +1,2 @@ +ao_product.h +usbtrng* diff --git a/src/usbtrng-v2.0/flash-loader/Makefile b/src/usbtrng-v2.0/flash-loader/Makefile new file mode 100644 index 00000000..a2bf199f --- /dev/null +++ b/src/usbtrng-v2.0/flash-loader/Makefile @@ -0,0 +1,8 @@ +# +# AltOS flash loader build +# +# + +TOPDIR=../.. +HARDWARE=usbtrng-v2.0 +include $(TOPDIR)/stmf0/Makefile-flash.defs diff --git a/src/usbtrng-v2.0/flash-loader/ao_pins.h b/src/usbtrng-v2.0/flash-loader/ao_pins.h new file mode 100644 index 00000000..9fa8b715 --- /dev/null +++ b/src/usbtrng-v2.0/flash-loader/ao_pins.h @@ -0,0 +1,31 @@ +/* + * Copyright © 2013 Keith Packard <keithp@keithp.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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. + */ + +#ifndef _AO_PINS_H_ +#define _AO_PINS_H_ + +#include <ao_flash_stm_pins.h> + +/* Red LED */ + +#define AO_BOOT_PIN			1 +#define AO_BOOT_APPLICATION_GPIO	stm_gpioa +#define AO_BOOT_APPLICATION_PIN		2 +#define AO_BOOT_APPLICATION_VALUE	0 +#define AO_BOOT_APPLICATION_MODE	AO_EXTI_MODE_PULL_DOWN + +#endif /* _AO_PINS_H_ */ diff --git a/src/usbtrng/ao_pins.h b/src/usbtrng/ao_pins.h index b1fa6eb9..0f2b1ea6 100644 --- a/src/usbtrng/ao_pins.h +++ b/src/usbtrng/ao_pins.h @@ -71,3 +71,5 @@   */  #define HAS_SCK1		0  #define HAS_MOSI1		0 + +#define AO_ADC_6		1 diff --git a/src/usbtrng/ao_usbtrng.c b/src/usbtrng/ao_usbtrng.c index 6b4d20fe..66e12337 100644 --- a/src/usbtrng/ao_usbtrng.c +++ b/src/usbtrng/ao_usbtrng.c @@ -18,7 +18,53 @@  #include <ao.h>  #define AO_TRNG_SPI_BUS		1 -#define AO_TRNG_SPI_SPEED	AO_SPI_SPEED_250kHz + +static uint32_t			spi_speed = AO_SPI_SPEED_4MHz; + +#define AO_TRNG_SPI_BUF		1024 + +#if 0 + +static uint8_t	*spi_buf; +static uint8_t	*spi_head, *spi_tail; +static uint8_t	spi_wakeup; + +static void +ao_trng_run(void) +{ +	int	this_time; +	uint8_t	*end; + +	if (!spi_buf) +		spi_buf = ao_usb_alloc(AO_TRNG_SPI_BUF); +	flush(); +	ao_spi_get(AO_TRNG_SPI_BUS, spi_speed); +	spi_tail = spi_buf; +	spi_head = spi_buf; +	ao_spi_recv_ring_start(spi_buf, AO_TRNG_SPI_BUF, &spi_head, &spi_tail, &spi_wakeup, AO_TRNG_SPI_BUS); +	while (!ao_usb_out_avail) { +		ao_arch_block_interrupts(); +		while (spi_head == spi_tail) { +			spi_wakeup = 0; +			ao_sleep(&spi_wakeup); +		} +		ao_arch_release_interrupts(); +		if (spi_tail > spi_head) +			end = spi_buf + AO_TRNG_SPI_BUF; +		else +			end = spi_head; +		this_time = end - spi_tail; +		if (this_time > 64) +			this_time = 64; +		ao_usb_write(spi_tail, this_time); +		spi_tail += this_time; +		if (spi_tail == spi_buf + AO_TRNG_SPI_BUF) +			spi_tail = spi_buf; +	} +	ao_spi_put(AO_TRNG_SPI_BUS); +	getchar(); +} +  static void  ao_trng_test(void) @@ -26,16 +72,153 @@ ao_trng_test(void)  	static uint8_t	random[32];  	uint8_t		i; -	ao_spi_get(AO_TRNG_SPI_BUS, AO_TRNG_SPI_SPEED); +	ao_spi_get(AO_TRNG_SPI_BUS, spi_speed);  	ao_spi_recv(random, sizeof (random), AO_TRNG_SPI_BUS);  	ao_spi_put(AO_TRNG_SPI_BUS);  	for (i = 0; i < sizeof (random); i++)  		printf (" %02x", random[i]);  	printf ("\n");  } +#endif + +#define ADC_RING_SIZE	512 + +static uint8_t *adc_ring; +static uint16_t	adc_head, adc_tail; +static uint16_t adc_wake; + +void  lpc_adc_isr(void) +{ +	uint16_t	avail; +	uint16_t	this, next; + +	this = adc_head; +	next = (this + 1) & (ADC_RING_SIZE - 1); +	if  (next == adc_tail) { +		lpc_adc.inten = 0; +		return; +	} +	adc_ring[this] = lpc_adc.dr[6] >> 8; +	adc_head = next; + +	/* If there are enough entries, wake up any waiters +	 */ +	avail = (next - adc_tail) & (ADC_RING_SIZE - 1); +	if (avail >= adc_wake) { +		adc_wake = 0; +		ao_wakeup(&adc_wake); +	} +} + +#define AO_ADC_CLKDIV	(AO_LPC_SYSCLK / 450000) + +static void +ao_trng_adc_init(void) +{ +	adc_ring = ao_usb_alloc(ADC_RING_SIZE); + +	lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_ADC); +	lpc_scb.pdruncfg &= ~(1 << LPC_SCB_PDRUNCFG_ADC_PD); + +	/* Enable interrupt when AO_ADC_6 is complete */ +	lpc_adc.inten = 0; + +	lpc_nvic_set_enable(LPC_ISR_ADC_POS); +	lpc_nvic_set_priority(LPC_ISR_ADC_POS, AO_LPC_NVIC_CLOCK_PRIORITY); + +#if AO_ADC_0 +	ao_enable_analog(0, 11, 0); +#endif +#if AO_ADC_1 +	ao_enable_analog(0, 12, 1); +#endif +#if AO_ADC_2 +	ao_enable_analog(0, 13, 2); +#endif +#if AO_ADC_3 +	ao_enable_analog(0, 14, 3); +#endif +#if AO_ADC_4 +	ao_enable_analog(0, 15, 4); +#endif +#if AO_ADC_5 +	ao_enable_analog(0, 16, 5); +#endif +#if AO_ADC_6 +	ao_enable_analog(0, 22, 6); +#endif +#if AO_ADC_7 +	ao_enable_analog(0, 23, 7); +#endif + +	lpc_adc.cr = ((1 << (LPC_ADC_CR_SEL + 6)) | +		      (AO_ADC_CLKDIV << LPC_ADC_CR_CLKDIV) | +		      (1 << LPC_ADC_CR_BURST) | +		      (LPC_ADC_CR_CLKS_9 << LPC_ADC_CR_CLKS)); +} + +static void +ao_trng_adc_dump(void) +{ +	int	i; + +	while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 16) { +		lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6)); +		adc_wake = 16; +		ao_sleep(&adc_wake); +	} +	printf("adc_head %d tail %d\n", adc_head, adc_tail); + +	for (i = 0; i < 16; i++) { +		printf(" %4d", adc_ring[adc_tail]); +		adc_tail = (adc_tail + 1) & (ADC_RING_SIZE - 1); +	} +	printf("\n"); +	lpc_adc.inten = 0; +} + +static void +ao_trng_run(void) +{ +	uint16_t	this_time; +	flush(); + +	while (!ao_usb_out_avail) { +		ao_arch_block_interrupts(); +		while (((adc_head - adc_tail) & (ADC_RING_SIZE - 1)) < 64) { +			lpc_adc.inten = (1 << (LPC_ADC_INTEN_ADINTEN + 6)); +			adc_wake = 64; +			ao_sleep(&adc_wake); +		} +		ao_arch_release_interrupts(); + +		this_time = ADC_RING_SIZE - adc_tail; +		if (this_time > 64) +			this_time = 64; +		ao_usb_write(&adc_ring[adc_tail], this_time); +		adc_tail = (adc_tail + this_time) & (ADC_RING_SIZE - 1); +	} +	lpc_adc.inten = 0; +} + +static void +ao_trng_speed(void) +{ +	ao_cmd_decimal(); + +	if (ao_cmd_lex_u32 == 0 || ao_cmd_status != ao_cmd_success) { +		ao_cmd_status = ao_cmd_success; +		printf ("Current spi speed %d\n", spi_speed); +	} else { +		spi_speed = ao_cmd_lex_u32; +	} +}  static const struct ao_cmds ao_trng_cmds[] = { -	{ ao_trng_test, "R\0Dump some random numbers" }, +//	{ ao_trng_test,	"R\0Dump some random numbers" }, +	{ ao_trng_run,	"s\0Send random bits until char" }, +	{ ao_trng_speed, "S <speed>\0Set SPI speed (48MHz/speed)" }, +	{ ao_trng_adc_dump, "a\0Dump ADC data" },  	{ 0, NULL }  }; @@ -46,15 +229,15 @@ main(void)  	ao_task_init();  	ao_timer_init(); -	ao_spi_init(); +//	ao_spi_init();  	ao_usb_init(); +	ao_trng_adc_init(); +  	ao_serial_init();  	ao_led_init(LEDS_AVAILABLE); -	ao_led_on(AO_LED_GREEN); -  	ao_cmd_init();  	ao_cmd_register(ao_trng_cmds);  | 
