summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2012-10-23 22:17:49 -0700
committerKeith Packard <keithp@keithp.com>2012-10-25 00:07:14 -0700
commitb119e19604aa557a40e848c60d98a67b5f259bbd (patch)
tree2391c2fb7db1843096ec4e3d288cb26f7cb88b92 /src
parent7d34811ba035367bbf26a8510265754f3fbb5a95 (diff)
altos: profiling on STM32L
Add sample-based profiling, using a 1kHz timer Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'src')
-rw-r--r--src/core/ao_flight.c2
-rw-r--r--src/core/ao_sample_profile.c173
-rw-r--r--src/core/ao_sample_profile.h29
-rw-r--r--src/core/ao_task.c16
-rw-r--r--src/core/ao_task.h13
-rw-r--r--src/drivers/ao_cc1120.c14
-rw-r--r--src/drivers/ao_ms5607.c8
-rw-r--r--src/megametrum-v0.1/Makefile11
-rw-r--r--src/megametrum-v0.1/ao_megametrum.c6
-rw-r--r--src/stm/ao_arch.h2
-rw-r--r--src/stm/ao_sample_profile_timer.c115
-rw-r--r--src/stm/ao_sample_profile_timer.h32
-rw-r--r--src/stm/stm32l.h134
13 files changed, 541 insertions, 14 deletions
diff --git a/src/core/ao_flight.c b/src/core/ao_flight.c
index aa4f6961..64c95063 100644
--- a/src/core/ao_flight.c
+++ b/src/core/ao_flight.c
@@ -115,7 +115,7 @@ ao_flight(void)
{
/* Set pad mode - we can fly! */
ao_flight_state = ao_flight_pad;
-#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG
+#if HAS_USB && HAS_RADIO && !HAS_FLIGHT_DEBUG && !HAS_SAMPLE_PROFILE
/* Disable the USB controller in flight mode
* to save power
*/
diff --git a/src/core/ao_sample_profile.c b/src/core/ao_sample_profile.c
new file mode 100644
index 00000000..1d9ed414
--- /dev/null
+++ b/src/core/ao_sample_profile.c
@@ -0,0 +1,173 @@
+/*
+ * 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_sample_profile.h>
+#include <ao_task.h>
+
+#ifndef AO_SAMPLE_PROFILE_LOW_PC
+#define AO_SAMPLE_PROFILE_LOW_PC 0x08000000
+#endif
+
+#ifndef AO_SAMPLE_PROFILE_HIGH_PC
+#define AO_SAMPLE_PROFILE_HIGH_PC (AO_SAMPLE_PROFILE_LOW_PC + 44 * 1024)
+#endif
+
+#ifndef AO_SAMPLE_PROFILE_SHIFT
+#define AO_SAMPLE_PROFILE_SHIFT 6
+#endif
+
+#define AO_SAMPLE_PROFILE_RANGE (AO_SAMPLE_PROFILE_HIGH_PC - AO_SAMPLE_PROFILE_LOW_PC)
+#define AO_SAMPLE_PROFILE_NUM (AO_SAMPLE_PROFILE_RANGE >> AO_SAMPLE_PROFILE_SHIFT)
+
+static uint16_t prev_tick;
+static uint16_t samples[AO_SAMPLE_PROFILE_NUM];
+static uint8_t missed[AO_SAMPLE_PROFILE_NUM/8];
+static uint16_t max_miss;
+static uint32_t task, isr, os, idle;
+
+extern uint8_t ao_idle_loc;
+
+void
+ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr)
+{
+ uint16_t delta = tick - prev_tick;
+
+ if (pc < AO_SAMPLE_PROFILE_LOW_PC)
+ return;
+ if (pc >= AO_SAMPLE_PROFILE_HIGH_PC)
+ return;
+ if (ao_cur_task) {
+ uint8_t *sp;
+ int32_t sp_delta;
+
+ asm("mov %0,sp" : "=&r" (sp));
+ sp_delta = sp - (uint8_t *) ao_cur_task->stack;
+ if (-96 < sp_delta && sp_delta < 16)
+ ao_panic(AO_PANIC_STACK);
+ }
+
+ if (in_isr)
+ isr += delta;
+ else if (ao_cur_task) {
+ ao_cur_task->ticks += delta;
+ task += delta;
+ } else if (pc == (uint32_t) &ao_idle_loc)
+ idle += delta;
+ else
+ os += delta;
+
+ pc -= AO_SAMPLE_PROFILE_LOW_PC;
+ pc >>= AO_SAMPLE_PROFILE_SHIFT;
+ samples[pc] += delta;
+
+ if (delta > 1)
+ missed[pc >> 3] |= (1 << (pc & 7));
+ if (delta > max_miss)
+ max_miss = delta;
+ prev_tick = tick;
+}
+
+static void
+ao_sample_profile_start(void)
+{
+ prev_tick = ao_sample_profile_timer_start();
+}
+
+static void
+ao_sample_profile_stop(void)
+{
+ ao_sample_profile_timer_stop();
+}
+
+static void
+ao_sample_profile_dump(void)
+{
+ uint16_t a;
+ uint8_t t;
+
+ printf ("task %6d\n", task);
+ printf ("isr %6d\n", isr);
+ printf ("os %6d\n", os);
+ printf ("idle %6d\n", idle);
+ printf ("irq blocked %d\n", max_miss);
+ for (t = 0; t < ao_num_tasks; t++)
+ printf ("task %6d %6d %6d %s\n",
+ ao_tasks[t]->ticks,
+ ao_tasks[t]->yields,
+ ao_tasks[t]->max_run,
+ ao_tasks[t]->name);
+ for (a = 0; a < AO_SAMPLE_PROFILE_NUM; a++) {
+ if (samples[a])
+ printf ("%04x %c %u\n",
+ (a << AO_SAMPLE_PROFILE_SHIFT) + AO_SAMPLE_PROFILE_LOW_PC,
+ missed[a >> 3] & (1 << (a & 7)) ? '*' : ' ',
+ samples[a]);
+ }
+}
+
+static void
+ao_sample_profile_clear(void)
+{
+ int t;
+
+ task = isr = os = idle = 0;
+ max_miss = 0;
+ memset(samples, '\0', sizeof (samples));
+ memset(missed, '\0', sizeof (missed));
+ for (t = 0; t < ao_num_tasks; t++) {
+ ao_tasks[t]->ticks = 0;
+ ao_tasks[t]->yields = 0;
+ ao_tasks[t]->max_run = 0;
+ }
+}
+
+static void
+ao_sample_profile_cmd(void)
+{
+ ao_cmd_white();
+ switch (ao_cmd_lex_c) {
+ case '1':
+ ao_sample_profile_start();
+ break;
+ case '0':
+ ao_sample_profile_stop();
+ break;
+ case 'd':
+ ao_sample_profile_dump();
+ break;
+ case 'c':
+ ao_sample_profile_clear();
+ break;
+ default:
+ ao_cmd_status = ao_cmd_syntax_error;
+ break;
+ }
+}
+
+static __code struct ao_cmds ao_sample_profile_cmds[] = {
+ { ao_sample_profile_cmd, "S <1 start,0 stop, d dump,c clear>\0Sample profile" },
+ { 0, NULL }
+};
+
+void
+ao_sample_profile_init(void)
+{
+ ao_sample_profile_timer_init();
+ ao_cmd_register(&ao_sample_profile_cmds[0]);
+ ao_sample_profile_clear();
+}
diff --git a/src/core/ao_sample_profile.h b/src/core/ao_sample_profile.h
new file mode 100644
index 00000000..dbc29d3d
--- /dev/null
+++ b/src/core/ao_sample_profile.h
@@ -0,0 +1,29 @@
+/*
+ * 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_SAMPLE_PROFILE_H_
+#define _AO_SAMPLE_PROFILE_H_
+
+#include <ao_sample_profile_timer.h>
+
+void
+ao_sample_profile_point(uint32_t pc, uint16_t tick, uint8_t in_isr);
+
+void
+ao_sample_profile_init(void);
+
+#endif /* _AO_SAMPLE_PROFILE_H_ */
diff --git a/src/core/ao_task.c b/src/core/ao_task.c
index 65654731..c2b1b270 100644
--- a/src/core/ao_task.c
+++ b/src/core/ao_task.c
@@ -16,6 +16,10 @@
*/
#include <ao.h>
+#include <ao_task.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
#define AO_NO_TASK_INDEX 0xff
@@ -67,6 +71,8 @@ ao_add_task(__xdata struct ao_task * task, void (*start)(void), __code char *nam
ao_arch_init_stack(task, start);
}
+__xdata uint8_t ao_idle;
+
/* Task switching function. This must not use any stack variables */
void
ao_yield(void) ao_arch_naked_define
@@ -77,6 +83,13 @@ ao_yield(void) ao_arch_naked_define
ao_cur_task_index = ao_num_tasks-1;
else
{
+#if HAS_SAMPLE_PROFILE
+ uint16_t tick = ao_sample_profile_timer_value();
+ uint16_t run = tick - ao_cur_task->start;
+ if (run > ao_cur_task->max_run)
+ ao_cur_task->max_run = run;
+ ++ao_cur_task->yields;
+#endif
ao_arch_save_stack();
}
@@ -110,6 +123,9 @@ ao_yield(void) ao_arch_naked_define
if (ao_cur_task_index == ao_last_task_index)
ao_arch_cpu_idle();
}
+#if HAS_SAMPLE_PROFILE
+ ao_cur_task->start = ao_sample_profile_timer_value();
+#endif
}
#if AO_CHECK_STACK
cli();
diff --git a/src/core/ao_task.h b/src/core/ao_task.h
index 18edd866..4319d632 100644
--- a/src/core/ao_task.h
+++ b/src/core/ao_task.h
@@ -26,13 +26,22 @@ struct ao_task {
uint8_t task_id; /* unique id */
__code char *name; /* task name */
uint8_t stack[AO_STACK_SIZE]; /* saved stack */
+#if HAS_SAMPLE_PROFILE
+ uint32_t ticks;
+ uint32_t yields;
+ uint16_t start;
+ uint16_t max_run;
+#endif
};
-extern __xdata struct ao_task *__data ao_cur_task;
-
#define AO_NUM_TASKS 16 /* maximum number of tasks */
#define AO_NO_TASK 0 /* no task id */
+extern __xdata struct ao_task * __xdata ao_tasks[AO_NUM_TASKS];
+extern __data uint8_t ao_num_tasks;
+extern __data uint8_t ao_cur_task_index;
+extern __xdata struct ao_task *__data ao_cur_task;
+
/*
ao_task.c
*/
diff --git a/src/drivers/ao_cc1120.c b/src/drivers/ao_cc1120.c
index 2f9c296f..7428bead 100644
--- a/src/drivers/ao_cc1120.c
+++ b/src/drivers/ao_cc1120.c
@@ -21,6 +21,9 @@
#include <ao_fec.h>
#include <ao_packet.h>
+#define AO_RADIO_MAX_RECV sizeof(struct ao_packet)
+#define AO_RADIO_MAX_SEND sizeof(struct ao_packet)
+
uint8_t ao_radio_wake;
uint8_t ao_radio_mutex;
uint8_t ao_radio_abort;
@@ -559,18 +562,19 @@ ao_radio_test_cmd(void)
}
}
+static uint8_t tx_data[(AO_RADIO_MAX_SEND + 4) * 2];
+
void
ao_radio_send(const void *d, uint8_t size)
{
uint8_t marc_status;
- static uint8_t encode[256];
- uint8_t *e = encode;
+ uint8_t *e = tx_data;
uint8_t encode_len;
uint8_t this_len;
uint8_t started = 0;
uint8_t fifo_space;
- encode_len = ao_fec_encode(d, size, encode);
+ encode_len = ao_fec_encode(d, size, tx_data);
ao_radio_get(encode_len);
@@ -611,8 +615,6 @@ ao_radio_send(const void *d, uint8_t size)
ao_radio_put();
}
-#define AO_RADIO_MAX_RECV 90
-
static uint8_t rx_data[(AO_RADIO_MAX_RECV + 4) * 2 * 8];
static uint16_t rx_data_count;
static uint16_t rx_data_consumed;
@@ -1026,6 +1028,7 @@ ao_radio_init(void)
ao_radio_configured = 0;
ao_spi_init_cs (AO_CC1120_SPI_CS_PORT, (1 << AO_CC1120_SPI_CS_PIN));
+#if 0
AO_CC1120_SPI_CS_PORT->bsrr = ((uint32_t) (1 << AO_CC1120_SPI_CS_PIN));
for (i = 0; i < 10000; i++) {
if ((SPI_2_PORT->idr & (1 << SPI_2_MISO_PIN)) == 0)
@@ -1034,6 +1037,7 @@ ao_radio_init(void)
AO_CC1120_SPI_CS_PORT->bsrr = (1 << AO_CC1120_SPI_CS_PIN);
if (i == 10000)
ao_panic(AO_PANIC_SELF_TEST_CC1120);
+#endif
/* Enable the EXTI interrupt for the appropriate pin */
ao_enable_port(AO_CC1120_INT_PORT);
diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c
index 077a40e6..ce0bcf4b 100644
--- a/src/drivers/ao_ms5607.c
+++ b/src/drivers/ao_ms5607.c
@@ -130,6 +130,7 @@ static uint32_t
ao_ms5607_get_sample(uint8_t cmd) {
uint8_t reply[3];
uint8_t read;
+ uint32_t loops;
ao_ms5607_done = 0;
@@ -141,10 +142,15 @@ ao_ms5607_get_sample(uint8_t cmd) {
#if AO_MS5607_PRIVATE_PINS
ao_spi_put(AO_MS5607_SPI_INDEX);
#endif
+// loops = 0;
cli();
- while (!ao_ms5607_done)
+ while (!ao_ms5607_done) {
+// loops++;
ao_sleep((void *) &ao_ms5607_done);
+ }
sei();
+// if (loops > 1)
+// printf ("ms5607 loops %d\n", loops);
#if AO_MS5607_PRIVATE_PINS
stm_gpio_set(AO_MS5607_CS_PORT, AO_MS5607_CS_PIN, 1);
#else
diff --git a/src/megametrum-v0.1/Makefile b/src/megametrum-v0.1/Makefile
index 0e0534a5..b100fafc 100644
--- a/src/megametrum-v0.1/Makefile
+++ b/src/megametrum-v0.1/Makefile
@@ -22,7 +22,9 @@ INC = \
ao_mma655x.h \
ao_cc1120_CC1120.h \
ao_profile.h \
+ ao_task.h \
ao_whiten.h \
+ ao_sample_profile.h \
stm32l.h
#
@@ -32,6 +34,10 @@ INC = \
#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
+
# ao_hmc5883.c
ALTOS_SRC = \
@@ -80,13 +86,14 @@ ALTOS_SRC = \
ao_packet.c \
ao_companion.c \
ao_pyro.c \
- $(PROFILE)
+ $(PROFILE) \
+ $(SAMPLE_PROFILE)
PRODUCT=MegaMetrum-v0.1
PRODUCT_DEF=-DMEGAMETRUM
IDPRODUCT=0x0023
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) $(PROFILE_DEF) $(SAMPLE_PROFILE_DEF) -Os -g
PROGNAME=megametrum-v0.1
PROG=$(PROGNAME)-$(VERSION).elf
diff --git a/src/megametrum-v0.1/ao_megametrum.c b/src/megametrum-v0.1/ao_megametrum.c
index d3ae4690..114f144f 100644
--- a/src/megametrum-v0.1/ao_megametrum.c
+++ b/src/megametrum-v0.1/ao_megametrum.c
@@ -24,6 +24,9 @@
#include <ao_packet.h>
#include <ao_companion.h>
#include <ao_profile.h>
+#if HAS_SAMPLE_PROFILE
+#include <ao_sample_profile.h>
+#endif
#include <ao_pyro.h>
int
@@ -78,6 +81,9 @@ main(void)
#if AO_PROFILE
ao_profile_init();
#endif
+#if HAS_SAMPLE_PROFILE
+ ao_sample_profile_init();
+#endif
ao_start_scheduler();
return 0;
diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h
index 87eda18b..f2de719c 100644
--- a/src/stm/ao_arch.h
+++ b/src/stm/ao_arch.h
@@ -143,7 +143,7 @@ extern const uint32_t ao_radio_cal;
#define ao_arch_cpu_idle() do { \
- asm("wfi"); \
+ asm(".global ao_idle_loc\n\twfi\nao_idle_loc:"); \
} while (0)
#define ao_arch_restore_stack() do { \
diff --git a/src/stm/ao_sample_profile_timer.c b/src/stm/ao_sample_profile_timer.c
new file mode 100644
index 00000000..d5af3a57
--- /dev/null
+++ b/src/stm/ao_sample_profile_timer.c
@@ -0,0 +1,115 @@
+/*
+ * 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_sample_profile.h>
+
+struct stm_exception {
+ uint32_t r0;
+ uint32_t r1;
+ uint32_t r2;
+ uint32_t r3;
+ uint32_t r12;
+ uint32_t lr;
+ uint32_t pc;
+ uint32_t psr;
+};
+
+void
+stm_tim10_isr(void)
+{
+ struct stm_exception *ex;
+
+ asm("mov %0,sp" : "=&r" (ex));
+
+ stm_tim10.sr = 0;
+ ao_sample_profile_point(ex->pc, stm_tim11.cnt, (ex->psr & 0xff) != 0);
+}
+
+uint16_t
+ao_sample_profile_timer_start(void)
+{
+ /* Reset counts */
+ stm_tim11.cnt = 0;
+ stm_tim10.cnt = 0;
+
+ /* Turn on timer 11 */
+ stm_tim11.cr1 = ((0 << STM_TIM1011_CR1_CKD) |
+ (0 << STM_TIM1011_CR1_ARPE) |
+ (1 << STM_TIM1011_CR1_URS) |
+ (0 << STM_TIM1011_CR1_UDIS) |
+ (1 << STM_TIM1011_CR1_CEN));
+
+ /* Turn on timer 10 */
+ stm_tim10.cr1 = ((0 << STM_TIM1011_CR1_CKD) |
+ (0 << STM_TIM1011_CR1_ARPE) |
+ (1 << STM_TIM1011_CR1_URS) |
+ (0 << STM_TIM1011_CR1_UDIS) |
+ (1 << STM_TIM1011_CR1_CEN));
+ return stm_tim11.cnt;
+}
+
+void
+ao_sample_profile_timer_stop(void)
+{
+ stm_tim10.cr1 = 0;
+ stm_tim11.cr1 = 0;
+}
+
+#if AO_APB2_PRESCALER > 1
+#define TIMER_91011_SCALER 2
+#else
+#define TIMER_91011_SCALER 1
+#endif
+
+#define TIMER_10kHz ((AO_PCLK2 * TIMER_91011_SCALER) / 10000)
+#define TIMER_1kHz ((AO_PCLK2 * TIMER_91011_SCALER) / 1000)
+
+void
+ao_sample_profile_timer_init(void)
+{
+ /* Turn on power for timer 10 and 11 */
+ stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_TIM10EN) | (1 << STM_RCC_APB2ENR_TIM11EN);
+
+ /* Timer 10 is the 1kHz interrupt */
+ stm_tim10.cr1 = 0;
+ stm_tim10.psc = TIMER_10kHz;
+ stm_tim10.arr = 9;
+ stm_tim10.cnt = 0;
+
+ /* Enable timer 10 update interrupt */
+ stm_tim10.dier = (1 << STM_TIM1011_DIER_UIE);
+
+ /* Poke timer to reload values */
+ stm_tim10.egr |= (1 << STM_TIM1011_EGR_UG);
+
+ /* Timer 11 is the 1kHz counter */
+ stm_tim11.cr1 = 0;
+ stm_tim11.psc = TIMER_1kHz;
+ stm_tim11.arr = 0xffff;
+ stm_tim11.cnt = 0;
+
+ /* Disable interrupts for timer 11 */
+ stm_tim11.dier = 0;
+
+ /* Poke timer to reload values */
+ stm_tim11.egr |= (1 << STM_TIM1011_EGR_UG);
+
+ stm_tim10.sr = 0;
+ stm_nvic_set_enable(STM_ISR_TIM10_POS);
+ stm_nvic_set_priority(STM_ISR_TIM10_POS, AO_STM_NVIC_HIGH_PRIORITY);
+}
diff --git a/src/stm/ao_sample_profile_timer.h b/src/stm/ao_sample_profile_timer.h
new file mode 100644
index 00000000..1da1bfb4
--- /dev/null
+++ b/src/stm/ao_sample_profile_timer.h
@@ -0,0 +1,32 @@
+/*
+ * 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_SAMPLE_PROFILE_TIMER_H_
+#define _AO_SAMPLE_PROFILE_TIMER_H_
+
+uint16_t
+ao_sample_profile_timer_start(void);
+
+void
+ao_sample_profile_timer_stop(void);
+
+void
+ao_sample_profile_timer_init(void);
+
+#define ao_sample_profile_timer_value() ((uint16_t) stm_tim11.cnt)
+
+#endif /* _AO_SAMPLE_PROFILE_TIMER_H_ */
diff --git a/src/stm/stm32l.h b/src/stm/stm32l.h
index 25f5af07..e950d09b 100644
--- a/src/stm/stm32l.h
+++ b/src/stm/stm32l.h
@@ -254,8 +254,138 @@ struct stm_tim {
};
extern struct stm_tim stm_tim9;
-extern struct stm_tim stm_tim10;
-extern struct stm_tim stm_tim11;
+
+struct stm_tim1011 {
+ vuint32_t cr1;
+ uint32_t unused_4;
+ vuint32_t smcr;
+ vuint32_t dier;
+ vuint32_t sr;
+ vuint32_t egr;
+ vuint32_t ccmr1;
+ uint32_t unused_1c;
+ vuint32_t ccer;
+ vuint32_t cnt;
+ vuint32_t psc;
+ vuint32_t arr;
+ uint32_t unused_30;
+ vuint32_t ccr1;
+ uint32_t unused_38;
+ uint32_t unused_3c;
+ uint32_t unused_40;
+ uint32_t unused_44;
+ uint32_t unused_48;
+ uint32_t unused_4c;
+ vuint32_t or;
+};
+
+extern struct stm_tim1011 stm_tim10;
+extern struct stm_tim1011 stm_tim11;
+
+#define STM_TIM1011_CR1_CKD 8
+#define STM_TIM1011_CR1_CKD_1 0
+#define STM_TIM1011_CR1_CKD_2 1
+#define STM_TIM1011_CR1_CKD_4 2
+#define STM_TIM1011_CR1_CKD_MASK 3
+#define STM_TIM1011_CR1_ARPE 7
+#define STM_TIM1011_CR1_URS 2
+#define STM_TIM1011_CR1_UDIS 1
+#define STM_TIM1011_CR1_CEN 0
+
+#define STM_TIM1011_SMCR_ETP 15
+#define STM_TIM1011_SMCR_ECE 14
+#define STM_TIM1011_SMCR_ETPS 12
+#define STM_TIM1011_SMCR_ETPS_OFF 0
+#define STM_TIM1011_SMCR_ETPS_2 1
+#define STM_TIM1011_SMCR_ETPS_4 2
+#define STM_TIM1011_SMCR_ETPS_8 3
+#define STM_TIM1011_SMCR_ETPS_MASK 3
+#define STM_TIM1011_SMCR_ETF 8
+#define STM_TIM1011_SMCR_ETF_NONE 0
+#define STM_TIM1011_SMCR_ETF_CK_INT_2 1
+#define STM_TIM1011_SMCR_ETF_CK_INT_4 2
+#define STM_TIM1011_SMCR_ETF_CK_INT_8 3
+#define STM_TIM1011_SMCR_ETF_DTS_2_6 4
+#define STM_TIM1011_SMCR_ETF_DTS_2_8 5
+#define STM_TIM1011_SMCR_ETF_DTS_4_6 6
+#define STM_TIM1011_SMCR_ETF_DTS_4_8 7
+#define STM_TIM1011_SMCR_ETF_DTS_8_6 8
+#define STM_TIM1011_SMCR_ETF_DTS_8_8 9
+#define STM_TIM1011_SMCR_ETF_DTS_16_5 10
+#define STM_TIM1011_SMCR_ETF_DTS_16_6 11
+#define STM_TIM1011_SMCR_ETF_DTS_16_8 12
+#define STM_TIM1011_SMCR_ETF_DTS_32_5 13
+#define STM_TIM1011_SMCR_ETF_DTS_32_6 14
+#define STM_TIM1011_SMCR_ETF_DTS_32_8 15
+#define STM_TIM1011_SMCR_ETF_MASK 15
+
+#define STM_TIM1011_DIER_CC1E 1
+#define STM_TIM1011_DIER_UIE 0
+
+#define STM_TIM1011_SR_CC1OF 9
+#define STM_TIM1011_SR_CC1IF 1
+#define STM_TIM1011_SR_UIF 0
+
+#define STM_TIM1011_EGR_CC1G 1
+#define STM_TIM1011_EGR_UG 0
+
+#define STM_TIM1011_CCMR1_OC1CE 7
+#define STM_TIM1011_CCMR1_OC1M 4
+#define STM_TIM1011_CCMR1_OC1M_FROZEN 0
+#define STM_TIM1011_CCMR1_OC1M_SET_1_ACTIVE_ON_MATCH 1
+#define STM_TIM1011_CCMR1_OC1M_SET_1_INACTIVE_ON_MATCH 2
+#define STM_TIM1011_CCMR1_OC1M_TOGGLE 3
+#define STM_TIM1011_CCMR1_OC1M_FORCE_INACTIVE 4
+#define STM_TIM1011_CCMR1_OC1M_FORCE_ACTIVE 5
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_1 6
+#define STM_TIM1011_CCMR1_OC1M_PWM_MODE_2 7
+#define STM_TIM1011_CCMR1_OC1M_MASK 7
+#define STM_TIM1011_CCMR1_OC1PE 3
+#define STM_TIM1011_CCMR1_OC1FE 2
+#define STM_TIM1011_CCMR1_CC1S 0
+#define STM_TIM1011_CCMR1_CC1S_OUTPUT 0
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI1 1
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TI2 2
+#define STM_TIM1011_CCMR1_CC1S_INPUT_TRC 3
+#define STM_TIM1011_CCMR1_CC1S_MASK 3
+
+#define STM_TIM1011_CCMR1_IC1F_NONE 0
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_2 1
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_4 2
+#define STM_TIM1011_CCMR1_IC1F_CK_INT_8 3
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_6 4
+#define STM_TIM1011_CCMR1_IC1F_DTS_2_8 5
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_6 6
+#define STM_TIM1011_CCMR1_IC1F_DTS_4_8 7
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_6 8
+#define STM_TIM1011_CCMR1_IC1F_DTS_8_8 9
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_5 10
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_6 11
+#define STM_TIM1011_CCMR1_IC1F_DTS_16_8 12
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_5 13
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_6 14
+#define STM_TIM1011_CCMR1_IC1F_DTS_32_8 15
+#define STM_TIM1011_CCMR1_IC1F_MASK 15
+#define STM_TIM1011_CCMR1_IC1PSC 2
+#define STM_TIM1011_CCMR1_IC1PSC_1 0
+#define STM_TIM1011_CCMR1_IC1PSC_2 1
+#define STM_TIM1011_CCMR1_IC1PSC_4 2
+#define STM_TIM1011_CCMR1_IC1PSC_8 3
+#define STM_TIM1011_CCMR1_IC1PSC_MASK 3
+#define STM_TIM1011_CCMR1_CC1S 0
+
+#define STM_TIM1011_CCER_CC1NP 3
+#define STM_TIM1011_CCER_CC1P 1
+#define STM_TIM1011_CCER_CC1E 0
+
+#define STM_TIM1011_OR_TI1_RMP_RI 3
+#define STM_TIM1011_ETR_RMP 2
+#define STM_TIM1011_TI1_RMP 0
+#define STM_TIM1011_TI1_RMP_GPIO 0
+#define STM_TIM1011_TI1_RMP_LSI 1
+#define STM_TIM1011_TI1_RMP_LSE 2
+#define STM_TIM1011_TI1_RMP_RTC 3
+#define STM_TIM1011_TI1_RMP_MASK 3
/* Flash interface */