X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fmicropeak-v2.0%2Fao_micropeak.c;fp=src%2Fmicropeak-v2.0%2Fao_micropeak.c;h=1cfa1209df781ffe788dd00511a4c9a67e7cb110;hp=0000000000000000000000000000000000000000;hb=217d77dadbef4192d2f32e290a5c5f50159f2e0d;hpb=65bb93f69b2f420281b67d62a9ee3cf30874fb7c diff --git a/src/micropeak-v2.0/ao_micropeak.c b/src/micropeak-v2.0/ao_micropeak.c new file mode 100644 index 00000000..1cfa1209 --- /dev/null +++ b/src/micropeak-v2.0/ao_micropeak.c @@ -0,0 +1,278 @@ +/* + * Copyright © 2017 Keith Packard + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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 +#include +#include +#include +#include +#include + +static struct ao_ms5607_value value; + +alt_t ground_alt, max_alt; +alt_t ao_max_height; + +void +ao_pa_get(void) +{ + ao_ms5607_sample(&ao_ms5607_current); + ao_ms5607_convert(&ao_ms5607_current, &value); + pa = value.pres; +} + +static void +ao_compute_height(void) +{ + ground_alt = ao_pa_to_altitude(pa_ground); + max_alt = ao_pa_to_altitude(pa_min); + ao_max_height = max_alt - ground_alt; +} + +static void +ao_pips(void) +{ + uint8_t i; + for (i = 0; i < 10; i++) { + ao_led_toggle(AO_LED_REPORT); + ao_delay(AO_MS_TO_TICKS(80)); + } + ao_delay(AO_MS_TO_TICKS(200)); +} + +void +ao_delay_until(uint16_t target) { + int16_t delay = target - ao_time(); + if (delay > 0) { + ao_sleep_for(ao_delay_until, delay); + } +} + +static struct ao_task mp_task; + +static void +ao_battery_disable(void) +{ + /* Disable */ + if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) { + stm_adc.cr |= (1 << STM_ADC_CR_ADDIS); + while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS)) + ; + } + + /* Turn off everything */ + stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) | + (1 << STM_ADC_CR_ADSTP) | + (1 << STM_ADC_CR_ADSTART) | + (1 << STM_ADC_CR_ADEN)); +} + +static void +ao_battery_init(void) +{ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN); + + ao_battery_disable(); + + /* Configure */ + stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */ + (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */ + (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */ + (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */ + (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */ + (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */ + (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */ + (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */ + (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */ + (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */ + (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */ + (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */ + (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */ + (1 << STM_ADC_CFGR1_DMAEN)); /* enable DMA */ + + /* 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_71_5 << STM_ADC_SMPR_SMP; + + /* Select Vref */ + stm_adc.chselr = 1 << 17; + + stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) | + (0 << STM_ADC_CCR_TSEN) | + (1 << STM_ADC_CCR_VREFEN)); + + /* Calibrate */ + stm_adc.cr |= (1 << STM_ADC_CR_ADCAL); + while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0) + ; + + /* Enable */ + stm_adc.cr |= (1 << STM_ADC_CR_ADEN); + while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0) + ; + + /* Clear any stale status bits */ + stm_adc.isr = 0; + + /* Turn on syscfg */ + stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN); +} + +static void +ao_battery_fini(void) +{ + /* Disable */ + ao_battery_disable(); + + /* Power down */ + stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_ADCEN); +} + +static uint16_t +ao_battery_voltage(void) +{ + uint16_t vrefint; + + ao_battery_init(); + + stm_adc.cr |= (1 << STM_ADC_CR_ADSTART); + + while ((stm_adc.isr & (1 << STM_ADC_ISR_EOC)) == 0) + ao_arch_nop(); + + vrefint = stm_adc.dr; + + ao_battery_fini(); + + return 330 * stm_cal.vrefint_cal / vrefint; +} + + +uint8_t ao_on_battery; + +static void +ao_micropeak(void) +{ + ao_ms5607_setup(); + ao_storage_setup(); + + /* Give the person a second to get their finger out of the way */ + ao_delay(AO_MS_TO_TICKS(1000)); + + ao_pips(); + + ao_log_micro_restore(); + ao_compute_height(); + ao_report_altitude(); + ao_log_micro_dump(); + +#if BOOST_DELAY + ao_delay(BOOST_DELAY); +#endif + + ao_microflight(); + + ao_log_micro_save(); + ao_compute_height(); + ao_report_altitude(); + + ao_sleep(&ao_on_battery); +} + +static void +ao_show_bat(void) +{ + printf("battery: %u\n", ao_battery_voltage()); +} + +static struct ao_cmds mp_cmd[] = { + { ao_show_bat, "b\0Show battery voltage" }, + { 0 } +}; + +static void +ao_hsi_init(void) +{ + uint32_t cfgr; + + /* Disable all interrupts */ + stm_rcc.cir = 0; + + /* Enable prefetch */ + stm_flash.acr |= (1 << STM_FLASH_ACR_PRFTBE); + + /* 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; + + /* Clear reset flags */ + stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF); +} + +void +main(void) +{ + if (ao_battery_voltage() < 320) + ao_on_battery = 1; + + /* Leave the system running on the HSI if we're on battery */ + if (!ao_on_battery) + ao_clock_init(); + else + ao_hsi_init(); + + ao_led_init(LEDS_AVAILABLE); + ao_task_init(); + ao_timer_init(); + ao_serial_init(); + stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT); + + ao_dma_init(); + ao_spi_init(); + ao_exti_init(); + + /* Leave USB disabled on battery */ + if (!ao_on_battery) { + ao_usb_init(); + ao_cmd_init(); + } + + ao_ms5607_init(); + + ao_storage_init(); + + ao_add_task(&mp_task, ao_micropeak, "micropeak"); + ao_cmd_register(mp_cmd); + ao_start_scheduler(); +}