diff --git a/stm/Makefile b/stm/Makefile
index 6203e9f4af176822fa201cd111cb198d2f6189e2..3752e694abb12cdefc07583e8087aed90897c603 100644
--- a/stm/Makefile
+++ b/stm/Makefile
@@ -26,6 +26,7 @@ SRC_C = \
 	usart.c \
 	usb.c \
 	sdio.c \
+	timer.c \
 	audio.c \
 	lexerstm.c \
 
diff --git a/stm/audio.c b/stm/audio.c
index 2df4e079410fc8d25f1a2446d57f6ca4a0e6c14a..41614416e2c3b31f9de24f683430db48ed09f0ac 100644
--- a/stm/audio.c
+++ b/stm/audio.c
@@ -6,13 +6,13 @@
 
 #include "nlr.h"
 #include "misc.h"
-//#include "lexer.h"
-//#include "lexerstm.h"
 #include "mpyconfig.h"
 #include "parse.h"
 #include "compile.h"
 #include "runtime.h"
 
+#include "audio.h"
+
 #define SAMPLE_BUF_SIZE (32)
 
 // sample_buf_in is always the same or ahead of sample_buf_out
diff --git a/stm/main.c b/stm/main.c
index 996684cb894e776b2199750f16baae13f36e739f..4184b389cacaf3216d7ea5c9a017afbdd7e7009f 100644
--- a/stm/main.c
+++ b/stm/main.c
@@ -20,6 +20,7 @@
 #include "usart.h"
 #include "usb.h"
 #include "ff.h"
+#include "timer.h"
 #include "audio.h"
 
 static FATFS fatfs0;
@@ -525,7 +526,7 @@ py_obj_t pyb_pwm_set(py_obj_t period, py_obj_t pulse) {
 
 #define MMA_ADDR (0x4c)
 
-py_obj_t pyb_mma_read() {
+py_obj_t pyb_mma_read(void) {
     mma_start(MMA_ADDR, 1);
     mma_send_byte(0);
     mma_restart(MMA_ADDR, 0);
@@ -731,6 +732,8 @@ int main(void) {
     storage_init();
     usart_init();
 
+    int first_soft_reset = true;
+
 soft_reset:
 
     // LCD init
@@ -749,6 +752,9 @@ soft_reset:
     // audio
     audio_init();
 
+    // timer
+    timer_init();
+
     // add some functions to the python namespace
     {
         py_obj_t m = py_module_new();
@@ -846,7 +852,7 @@ soft_reset:
     usb_init();
 
     // MMA
-    {
+    if (first_soft_reset) {
         // init and reset address to zero
         mma_init();
         mma_start(MMA_ADDR, 1);
@@ -1123,6 +1129,8 @@ soft_reset:
     pyb_sync();
 
     printf("PYB: soft reboot\n");
+
+    first_soft_reset = false;
     goto soft_reset;
 }
 
diff --git a/stm/stm32fxxx_it.c b/stm/stm32fxxx_it.c
index 41e2f7b73585f1f441443023760204aec95ed9d0..01be0da4afdd265de0b3686f83aee88253f1c4ed 100644
--- a/stm/stm32fxxx_it.c
+++ b/stm/stm32fxxx_it.c
@@ -251,4 +251,19 @@ void SDIO_IRQHandler(void)
 {
 }*/
 
+// TIM6 Update event
+#include "stm32f4xx_tim.h"
+void TIM6_DAC_IRQHandler(void) {
+    // work out if it's TIM6 that had the interrupt
+    if (TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET) {
+        extern void timer_interrupt(void);
+        timer_interrupt();
+        TIM_ClearITPendingBit(TIM6, TIM_IT_Update);
+    } else {
+        // it seems we get 2 calls to this interrupt handler, and only 1 is the TIM_IT_Update...
+        // TODO work out what the other one is, and if we can disable it
+        //printf("unhandled TIM6_DAC\n");
+    }
+}
+
 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stm/timer.c b/stm/timer.c
new file mode 100644
index 0000000000000000000000000000000000000000..31807d0ce2f228a536c80ffcffcf0973e4df84be
--- /dev/null
+++ b/stm/timer.c
@@ -0,0 +1,90 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include "stm_misc.h"
+#include "stm32f4xx_rcc.h"
+#include "stm32f4xx_tim.h"
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpyconfig.h"
+#include "parse.h"
+#include "compile.h"
+#include "runtime.h"
+
+#include "timer.h"
+
+// TIM6 is used as an internal interrup to schedule something at a specific rate
+py_obj_t timer_py_callback;
+
+py_obj_t timer_py_set_callback(py_obj_t f) {
+    timer_py_callback = f;
+    return py_const_none;
+}
+
+py_obj_t timer_py_set_period(py_obj_t period) {
+    TIM6->ARR = py_obj_get_int(period) & 0xffff;
+    //TIM6->PSC = prescaler & 0xffff;
+    return py_const_none;
+}
+
+py_obj_t timer_py_get_value(void) {
+    return py_obj_new_int(TIM6->CNT & 0xfffff);
+}
+
+void timer_init(void) {
+    timer_py_callback = py_const_none;
+
+    // TIM6 clock enable
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
+
+    // Compute the prescaler value so TIM6 runs at 10kHz
+    uint16_t PrescalerValue = (uint16_t) ((SystemCoreClock / 2) / 10000) - 1;
+
+    // Time base configuration
+    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
+    TIM_TimeBaseStructure.TIM_Period = 10000; // timer cycles at 1Hz
+    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;
+    TIM_TimeBaseStructure.TIM_ClockDivision = 0; // unused for TIM6
+    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // unused for TIM6
+    TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
+
+    // enable perhipheral preload register
+    TIM_ARRPreloadConfig(TIM6, ENABLE);
+
+    // enable interrupt when counter overflows
+    TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
+
+    // set up interrupt
+    NVIC_InitTypeDef NVIC_InitStructure;
+    NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;
+    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0f; // lowest priority
+    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0f; // lowest priority
+    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+    NVIC_Init(&NVIC_InitStructure);
+
+    // TIM6 enable counter
+    TIM_Cmd(TIM6, ENABLE);
+
+    // Python interface
+    py_obj_t m = py_module_new();
+    rt_store_attr(m, qstr_from_str_static("callback"), rt_make_function_1(timer_py_set_callback));
+    rt_store_attr(m, qstr_from_str_static("period"), rt_make_function_1(timer_py_set_period));
+    rt_store_attr(m, qstr_from_str_static("value"), rt_make_function_0(timer_py_get_value));
+    rt_store_name(qstr_from_str_static("timer"), m);
+}
+
+void timer_interrupt(void) {
+    if (timer_py_callback != py_const_none) {
+        nlr_buf_t nlr;
+        if (nlr_push(&nlr) == 0) {
+            rt_call_function_0(timer_py_callback);
+            nlr_pop();
+        } else {
+            // uncaught exception
+            printf("exception in timer interrupt\n");
+            py_obj_print((py_obj_t)nlr.ret_val);
+            printf("\n");
+        }
+    }
+}
diff --git a/stm/timer.h b/stm/timer.h
new file mode 100644
index 0000000000000000000000000000000000000000..117cff3c977c71b7969dc297dca04377dc282b8d
--- /dev/null
+++ b/stm/timer.h
@@ -0,0 +1 @@
+void timer_init(void);