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); |