2 * Copyright © 2017 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 #include <ao_micropeak.h>
22 #include <ao_report_micro.h>
23 #include <ao_log_micro.h>
24 #include <ao_storage.h>
26 static struct ao_ms5607_value value;
28 alt_t ground_alt, max_alt;
34 ao_ms5607_sample(&ao_ms5607_current);
35 ao_ms5607_convert(&ao_ms5607_current, &value);
40 ao_compute_height(void)
42 ground_alt = ao_pa_to_altitude(pa_ground);
43 max_alt = ao_pa_to_altitude(pa_min);
44 ao_max_height = max_alt - ground_alt;
51 for (i = 0; i < 10; i++) {
52 ao_led_toggle(AO_LED_REPORT);
53 ao_delay(AO_MS_TO_TICKS(80));
55 ao_delay(AO_MS_TO_TICKS(200));
59 ao_delay_until(uint16_t target) {
60 int16_t delay = target - ao_time();
62 ao_sleep_for(ao_delay_until, delay);
66 static struct ao_task mp_task;
69 ao_battery_disable(void)
72 if (stm_adc.cr & (1 << STM_ADC_CR_ADEN)) {
73 stm_adc.cr |= (1 << STM_ADC_CR_ADDIS);
74 while (stm_adc.cr & (1 << STM_ADC_CR_ADDIS))
78 /* Turn off everything */
79 stm_adc.cr &= ~((1 << STM_ADC_CR_ADCAL) |
80 (1 << STM_ADC_CR_ADSTP) |
81 (1 << STM_ADC_CR_ADSTART) |
82 (1 << STM_ADC_CR_ADEN));
88 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_ADCEN);
93 stm_adc.cfgr1 = ((0 << STM_ADC_CFGR1_AWDCH) | /* analog watchdog channel 0 */
94 (0 << STM_ADC_CFGR1_AWDEN) | /* Disable analog watchdog */
95 (0 << STM_ADC_CFGR1_AWDSGL) | /* analog watchdog on all channels */
96 (0 << STM_ADC_CFGR1_DISCEN) | /* Not discontinuous mode. All channels converted with one trigger */
97 (0 << STM_ADC_CFGR1_AUTOOFF) | /* Leave ADC running */
98 (1 << STM_ADC_CFGR1_WAIT) | /* Wait for data to be read before next conversion */
99 (0 << STM_ADC_CFGR1_CONT) | /* only one set of conversions per trigger */
100 (1 << STM_ADC_CFGR1_OVRMOD) | /* overwrite on overrun */
101 (STM_ADC_CFGR1_EXTEN_DISABLE << STM_ADC_CFGR1_EXTEN) | /* SW trigger */
102 (0 << STM_ADC_CFGR1_ALIGN) | /* Align to LSB */
103 (STM_ADC_CFGR1_RES_12 << STM_ADC_CFGR1_RES) | /* 12 bit resolution */
104 (STM_ADC_CFGR1_SCANDIR_UP << STM_ADC_CFGR1_SCANDIR) | /* scan 0 .. n */
105 (STM_ADC_CFGR1_DMACFG_ONESHOT << STM_ADC_CFGR1_DMACFG) | /* one set of conversions then stop */
106 (1 << STM_ADC_CFGR1_DMAEN)); /* enable DMA */
109 stm_adc.cfgr2 = STM_ADC_CFGR2_CKMODE_PCLK_2 << STM_ADC_CFGR2_CKMODE;
111 /* Shortest sample time */
112 stm_adc.smpr = STM_ADC_SMPR_SMP_71_5 << STM_ADC_SMPR_SMP;
115 stm_adc.chselr = 1 << 17;
117 stm_adc.ccr = ((0 << STM_ADC_CCR_VBATEN) |
118 (0 << STM_ADC_CCR_TSEN) |
119 (1 << STM_ADC_CCR_VREFEN));
122 stm_adc.cr |= (1 << STM_ADC_CR_ADCAL);
123 while ((stm_adc.cr & (1 << STM_ADC_CR_ADCAL)) != 0)
127 stm_adc.cr |= (1 << STM_ADC_CR_ADEN);
128 while ((stm_adc.isr & (1 << STM_ADC_ISR_ADRDY)) == 0)
131 /* Clear any stale status bits */
135 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGCOMPEN);
139 ao_battery_fini(void)
142 ao_battery_disable();
145 stm_rcc.apb2enr &= ~(1 << STM_RCC_APB2ENR_ADCEN);
149 ao_battery_voltage(void)
155 stm_adc.cr |= (1 << STM_ADC_CR_ADSTART);
157 while ((stm_adc.isr & (1 << STM_ADC_ISR_EOC)) == 0)
160 vrefint = stm_adc.dr;
164 return 330 * stm_cal.vrefint_cal / vrefint;
171 for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block)
172 ao_storage_erase(pos);
175 uint8_t ao_on_battery;
182 /* Give the person a second to get their finger out of the way */
183 ao_delay(AO_MS_TO_TICKS(1000));
185 ao_log_micro_restore();
187 ao_report_altitude();
194 ao_delay(BOOST_DELAY);
202 ao_report_altitude();
205 ao_sleep(&ao_on_battery);
211 printf("battery: %u\n", ao_battery_voltage());
219 ao_eeprom_read(N_SAMPLES_OFFSET, &n_samples, sizeof (n_samples));
221 return n_samples != 0xffff;
227 if (ao_log_present())
228 printf ("flight %d start %x end %x\n",
230 0, MAX_LOG_OFFSET >> 8);
237 int16_t cmd_flight = 1;
240 if (ao_cmd_lex_c == '-') {
244 cmd_flight *= ao_cmd_decimal();
245 if (ao_cmd_status != ao_cmd_success)
248 /* Look for the flight log matching the requested flight */
249 if (cmd_flight == 1 && ao_log_present()) {
254 printf("No such flight: %d\n", cmd_flight);
257 static struct ao_cmds mp_cmd[] = {
258 { ao_log_list, "l\0List logs" },
259 { ao_log_delete, "d <flight-number>\0Delete flight" },
260 { ao_show_bat, "b\0Show battery voltage" },
269 /* Disable all interrupts */
272 /* Enable prefetch */
273 stm_flash.acr |= (1 << STM_FLASH_ACR_PRFTBE);
275 /* HCLK to 48MHz -> AHB prescaler = /1 */
277 cfgr &= ~(STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE);
278 cfgr |= (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE);
280 while ((stm_rcc.cfgr & (STM_RCC_CFGR_HPRE_MASK << STM_RCC_CFGR_HPRE)) !=
281 (AO_RCC_CFGR_HPRE_DIV << STM_RCC_CFGR_HPRE))
284 /* APB Prescaler = AO_APB_PRESCALER */
286 cfgr &= ~(STM_RCC_CFGR_PPRE_MASK << STM_RCC_CFGR_PPRE);
287 cfgr |= (AO_RCC_CFGR_PPRE_DIV << STM_RCC_CFGR_PPRE);
290 /* Clear reset flags */
291 stm_rcc.csr |= (1 << STM_RCC_CSR_RMVF);
299 for (i = 0; i < 100000; i++)
302 if (ao_battery_voltage() < 320)
305 /* Leave the system running on the HSI if we're on battery */
314 stm_moder_set(&stm_gpioa, 2, STM_MODER_OUTPUT);
324 /* Let FLITF clock turn off in sleep mode */
325 stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_FLITFEN);
327 /* Le SRAM clock turn off in sleep mode */
328 stm_rcc.ahbenr &= ~(1 << STM_RCC_AHBENR_SRAMEN);
331 /* On battery power, run the flight code */
332 ao_add_task(&mp_task, ao_micropeak, "micropeak");
334 /* otherwise, turn on USB and run the command processor */
337 ao_cmd_register(mp_cmd);
340 ao_start_scheduler();