altos/micropeak-v2.0: Functionally complete.
[fw/altos] / src / micropeak-v2.0 / ao_micro.c
1 /*
2  * Copyright © 2020 Keith Packard <keithp@keithp.com>
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 #include <ao.h>
20 #include <ao_exti.h>
21 #include <ao_micropeak.h>
22 #include <ao_adc_stm32l0.h>
23 #include <ao_report_micro.h>
24 #include <ao_log_micro.h>
25
26 uint32_t        pa;
27 alt_t           ground_alt, max_alt;
28 alt_t           ao_max_height;
29
30 static void
31 ao_msi_init(void)
32 {
33         uint32_t icscr = stm_rcc.icscr;
34
35         /* Set MSI clock to desired range */
36         icscr &= ~(STM_RCC_ICSCR_MSIRANGE_MASK << STM_RCC_ICSCR_MSIRANGE);
37         icscr |= (AO_MSI_RANGE << STM_RCC_ICSCR_MSIRANGE);
38         stm_rcc.icscr = icscr;
39
40         /* Set vcore to 1.2V */
41         uint32_t cr = stm_pwr.cr;
42         cr &= ~(STM_PWR_CR_VOS_MASK << STM_PWR_CR_VOS);
43         cr |= (STM_PWR_CR_VOS_1_2 << STM_PWR_CR_VOS);
44         stm_pwr.cr = cr;
45 }
46
47 void
48 ao_pa_get(void)
49 {
50         static struct ao_ms5607_value   value;
51
52         ao_ms5607_sample(&ao_ms5607_current);
53         ao_ms5607_convert(&ao_ms5607_current, &value);
54         pa = value.pres;
55 }
56
57 static void
58 ao_compute_height(void)
59 {
60         ground_alt = ao_pa_to_altitude(pa_ground);
61         max_alt = ao_pa_to_altitude(pa_min);
62         ao_max_height = max_alt - ground_alt;
63 }
64
65 static void
66 ao_pips(void)
67 {
68         uint8_t i;
69         for (i = 0; i < 5; i++) {
70                 ao_led_on(AO_LED_REPORT);
71                 ao_delay(AO_MS_TO_TICKS(80));
72                 ao_led_off(AO_LED_REPORT);
73                 ao_delay(AO_MS_TO_TICKS(80));
74         }
75         ao_delay(AO_MS_TO_TICKS(200));
76 }
77
78 static void
79 power_down(void)
80 {
81         ao_timer_stop();
82         for(;;) {
83                 /*
84                  * Table 40, entering standby mode
85                  *
86                  * SLEEPDEEP = 1 in M0 SCR
87                  * PDDS = 1
88                  * WUF = 0
89                  */
90                 stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SYSCFGEN);
91                 stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_PWREN);
92                 stm_scb.scr |= ((1 << STM_SCB_SCR_SLEEPDEEP) |
93                                 (1 << STM_SCB_SCR_SLEEPONEXIT));
94                 stm_pwr.cr |= (1 << STM_PWR_CR_PDDS);
95                 stm_pwr.csr &= ~(1 << STM_PWR_CSR_WUF);
96                 ao_arch_wait_interrupt();
97         }
98 }
99
100 static bool log_stdout;
101
102 static void
103 log_micro_dump(void)
104 {
105         int i;
106         if (!log_stdout) {
107                 ao_led_off(AO_LED_REPORT);
108                 ao_lpuart1_enable();
109         }
110         ao_log_micro_dump();
111         for (i = 0; i < 4; i++)
112                 ao_async_byte(stm_device_id.lot_num_0_3[i]);
113         for (i = 0; i < 3; i++)
114                 ao_async_byte(stm_device_id.lot_num_4_6[i]);
115         ao_async_byte('-');
116         ao_log_hex(stm_device_id.waf_num);
117         ao_async_byte('-');
118         for (i = 0; i < 4; i++)
119                 ao_log_hex(stm_device_id.unique_id[i]);
120         ao_log_newline();
121         if (!log_stdout)
122                 ao_lpuart1_disable();
123 }
124
125 static void
126 log_erase(void)
127 {
128         uint32_t        pos;
129
130         for (pos = 0; pos < ao_storage_total; pos += STM_FLASH_PAGE_SIZE)
131         {
132                 if (!ao_storage_device_is_erased(pos))
133                         ao_storage_device_erase(pos);
134         }
135 }
136
137 static void
138 flight_mode(void)
139 {
140         /* Give the person a second to get their finger out of the way */
141         ao_delay(AO_MS_TO_TICKS(1000));
142
143         ao_log_micro_restore();
144         ao_compute_height();
145         ao_report_altitude();
146         ao_pips();
147         log_micro_dump();
148 #if BOOST_DELAY 
149         ao_delay(BOOST_DELAY);
150 #endif
151         log_erase();
152         ao_microflight();
153         ao_log_micro_save();
154         ao_compute_height();
155         ao_report_altitude();
156         power_down();
157 }
158
159 void ao_async_byte(char c)
160 {
161         if (log_stdout)
162                 putchar(c);
163         else
164                 ao_lpuart1_putchar(c);
165 }
166
167 static void
168 log_micro_dump_uart(void)
169 {
170         log_stdout = true;
171         log_micro_dump();
172         log_stdout = false;
173 }
174
175 static void
176 log_erase_cmd(void)
177 {
178         ao_cmd_white();
179         if (!ao_match_word("DoIt"))
180                 return;
181         log_erase();
182 }
183
184 const struct ao_cmds ao_micro_cmds[] = {
185         { log_micro_dump_uart, "l\0Dump log" },
186         { flight_mode, "F\0Flight mode" },
187         { power_down, "S\0Standby" },
188         { log_erase_cmd, "z <key>\0Erase. <key> is doit with D&I" },
189         {}
190 };
191
192 static void
193 cmd_mode(void)
194 {
195         ao_serial_init();
196         ao_cmd_init();
197         ao_cmd_register(ao_micro_cmds);
198         ao_cmd();
199 }
200
201 int
202 main(void)
203 {
204         ao_msi_init();
205         ao_led_init();
206         ao_timer_init();
207         ao_spi_init();
208         ao_ms5607_init();
209         ao_ms5607_setup();
210
211         /* Check the power supply voltage; it'll be 3.3V if
212          * the I/O board is connected
213          */
214         uint16_t vref = ao_adc_read_vref();
215
216         uint32_t vdda = 3 * stm_vrefint_cal.vrefint_cal * 1000 / vref;
217
218         /* Power supply > 3.25V means we're on USB power */
219         if (vdda > 3250) {
220                 cmd_mode();
221         } else {
222                 flight_mode();
223         }
224 }