From f14b92b9e13c9cb9f54a1d740dbea1eeedeccb5b Mon Sep 17 00:00:00 2001
From: Dave Hylands <dhylands@gmail.com>
Date: Wed, 12 Mar 2014 18:06:26 -0700
Subject: [PATCH] REPl working on UART6 with STMHAL

---
 stmhal/Makefile                  |  45 ++--
 stmhal/boards/stm32f4xx-prefix.c |   2 +-
 stmhal/gccollect.c               |  56 +++++
 stmhal/gccollect.h               |  17 ++
 stmhal/gchelper.s                |  62 +++++
 stmhal/import.c                  |  24 ++
 stmhal/led.c                     | 133 ++++++++++
 stmhal/led.h                     |  25 ++
 stmhal/lexerfatfs.c              |  61 +++++
 stmhal/lexerfatfs.h              |   1 +
 stmhal/main.c                    | 158 ++++--------
 stmhal/malloc0.c                 |  36 +++
 stmhal/math.c                    | 407 +++++++++++++++++++++++++++++++
 stmhal/mpconfigport.h            |  51 ++++
 stmhal/pin.c                     |  78 ++++++
 stmhal/pin.h                     | 117 +++++++++
 stmhal/printf.c                  | 371 ++++++++++++++++++++++++++++
 stmhal/pybmodule.c               | 312 +++++++++++++++++++++++
 stmhal/pybmodule.h               |   1 +
 stmhal/pyexec.c                  | 347 ++++++++++++++++++++++++++
 stmhal/pyexec.h                  |   5 +
 stmhal/qstrdefsport.h            |  57 +++++
 stmhal/stm32f4xx_it.c            |   2 +
 stmhal/string0.c                 | 137 +++++++++++
 stmhal/system_stm32f4xx.c        |  60 ++++-
 stmhal/systick.c                 |  54 ++++
 stmhal/systick.h                 |   5 +
 stmhal/usart.c                   | 269 ++++++++++++++++++++
 stmhal/usart.h                   |  25 ++
 29 files changed, 2793 insertions(+), 125 deletions(-)
 create mode 100644 stmhal/gccollect.c
 create mode 100644 stmhal/gccollect.h
 create mode 100644 stmhal/gchelper.s
 create mode 100644 stmhal/import.c
 create mode 100644 stmhal/led.c
 create mode 100644 stmhal/led.h
 create mode 100644 stmhal/lexerfatfs.c
 create mode 100644 stmhal/lexerfatfs.h
 create mode 100644 stmhal/malloc0.c
 create mode 100644 stmhal/math.c
 create mode 100644 stmhal/mpconfigport.h
 create mode 100644 stmhal/pin.c
 create mode 100644 stmhal/pin.h
 create mode 100644 stmhal/printf.c
 create mode 100644 stmhal/pybmodule.c
 create mode 100644 stmhal/pybmodule.h
 create mode 100644 stmhal/pyexec.c
 create mode 100644 stmhal/pyexec.h
 create mode 100644 stmhal/qstrdefsport.h
 create mode 100644 stmhal/string0.c
 create mode 100644 stmhal/systick.c
 create mode 100644 stmhal/systick.h
 create mode 100644 stmhal/usart.c
 create mode 100644 stmhal/usart.h

diff --git a/stmhal/Makefile b/stmhal/Makefile
index 2b5c5ffe2..f53887b74 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -19,6 +19,7 @@ CROSS_COMPILE = arm-none-eabi-
 
 INC =  -I.
 INC += -I$(PY_SRC)
+INC += -I$(CMSIS_DIR)
 INC += -I$(CMSIS_DIR)/inc
 INC += -I$(CMSIS_DIR)/devinc
 INC += -I$(HAL_DIR)/inc
@@ -54,28 +55,30 @@ LIBS =
 
 SRC_C = \
 	main.c \
+	string0.c \
 	system_stm32f4xx.c \
 	stm32f4xx_it.c \
 	stm32f4xx_hal_msp.c \
+	systick.c  \
+	led.c \
+	pin.c \
+	usart.c \
+	printf.c \
+	math.c \
+	malloc0.c \
+	gccollect.c \
+	pyexec.c \
+	pybmodule.c \
+	import.c \
+	lexerfatfs.c \
 
-#	printf.c \
-#	math.c \
-#	string0.c \
-#	malloc0.c \
-#	systick.c  \
 #	pendsv.c \
-#	gccollect.c \
-#	lexerfatfs.c \
-#	import.c \
-#	pyexec.c \
-#	led.c \
 #	gpio.c \
 #	lcd.c \
 #	servo.c \
 #	flash.c \
 #	storage.c \
 #	accel.c \
-#	usart.c \
 #	usb.c \
 #	timer.c \
 #	audio.c \
@@ -84,24 +87,23 @@ SRC_C = \
 #	adc.c \
 #	rtc.c \
 #	file.c \
-#	pin.c \
 #	pin_named_pins.c \
 #	pin_map.c \
 #	exti.c \
 #	usrsw.c \
-#	pybmodule.c \
 #	pybwlan.c \
 
 SRC_S = \
 	startup_stm32f40xx.s \
-
-#	gchelper.s \
+	gchelper.s \
 
 SRC_HAL = $(addprefix $(HAL_DIR)/src/,\
 	stm32f4xx_hal.c \
 	stm32f4xx_hal_cortex.c \
-	stm32f4xx_hal_rcc.c \
+	stm32f4xx_hal_dma.c \
 	stm32f4xx_hal_gpio.c \
+	stm32f4xx_hal_rcc.c \
+	stm32f4xx_hal_uart.c \
 	)
 
 SRC_STMPERIPH = $(addprefix $(STMPERIPH_DIR)/,\
@@ -182,7 +184,7 @@ SRC_CC3K = $(addprefix $(CC3K_DIR)/,\
 	)
 
 OBJ =
-#OBJ += $(PY_O)
+OBJ += $(PY_O)
 OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
 OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
@@ -191,7 +193,7 @@ OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
 #OBJ += $(addprefix $(BUILD)/, $(SRC_STMUSBH:.c=.o))
 #OBJ += $(addprefix $(BUILD)/, $(SRC_FATFS:.c=.o))
 #OBJ += $(addprefix $(BUILD)/, $(SRC_CC3K:.c=.o))
-#OBJ += $(BUILD)/pins_$(BOARD).o
+OBJ += $(BUILD)/pins_$(BOARD).o
 
 all: $(BUILD)/flash.dfu
 
@@ -222,7 +224,12 @@ GEN_PINS_HDR = $(BUILD)/pins.h
 # any of the objects. The normal dependency generation will deal with the
 # case when pins.h is modified. But when it doesn't exist, we don't know
 # which source files might need it.
-#$(OBJ): | $(BUILD)/pins.h
+$(OBJ): | $(BUILD)/pins.h
+
+# temp hack
+$(PY_BUILD):
+	mkdir -p $@
+$(OBJ): | $(PY_BUILD) $(PY_BUILD)/qstrdefs.generated.h
 
 # Use a pattern rule here so that make will only call make-pins.py once to make
 # both pins_$(BOARD).c and pins.h
diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c
index e68de4cf4..af3ed325c 100644
--- a/stmhal/boards/stm32f4xx-prefix.c
+++ b/stmhal/boards/stm32f4xx-prefix.c
@@ -2,7 +2,7 @@
 
 #include <stdio.h>
 #include <stdint.h>
-#include <stm32f4xx.h>
+#include <stm32f4xx_hal.h>
 
 #include "misc.h"
 #include "mpconfig.h"
diff --git a/stmhal/gccollect.c b/stmhal/gccollect.c
new file mode 100644
index 000000000..e20e92de1
--- /dev/null
+++ b/stmhal/gccollect.c
@@ -0,0 +1,56 @@
+#include <stdio.h>
+
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "gc.h"
+#include "gccollect.h"
+
+machine_uint_t gc_helper_get_regs_and_sp(machine_uint_t *regs);
+
+// obsolete
+// void gc_helper_get_regs_and_clean_stack(machine_uint_t *regs, machine_uint_t heap_end);
+
+void gc_collect(void) {
+    // get current time, in case we want to time the GC
+    uint32_t start = HAL_GetTick();
+
+    // start the GC
+    gc_collect_start();
+
+    // scan everything in RAM before the heap
+    // this includes the data and bss segments
+    // TODO possibly don't need to scan data, since all pointers should start out NULL and be in bss
+    gc_collect_root((void**)&_ram_start, ((uint32_t)&_ebss - (uint32_t)&_ram_start) / sizeof(uint32_t));
+
+    // get the registers and the sp
+    machine_uint_t regs[10];
+    machine_uint_t sp = gc_helper_get_regs_and_sp(regs);
+
+    // trace the stack, including the registers (since they live on the stack in this function)
+    gc_collect_root((void**)sp, ((uint32_t)&_ram_end - sp) / sizeof(uint32_t));
+
+    // end the GC
+    gc_collect_end();
+
+    if (0) {
+        // print GC info
+        uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
+        gc_info_t info;
+        gc_info(&info);
+        printf("GC@%lu %lums\n", start, ticks);
+        printf(" %lu total\n", info.total);
+        printf(" %lu : %lu\n", info.used, info.free);
+        printf(" 1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
+    }
+}
+
+static mp_obj_t pyb_gc(void) {
+    gc_collect();
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_gc_obj, pyb_gc);
diff --git a/stmhal/gccollect.h b/stmhal/gccollect.h
new file mode 100644
index 000000000..9aa0a4441
--- /dev/null
+++ b/stmhal/gccollect.h
@@ -0,0 +1,17 @@
+// variables defining memory layout
+// (these probably belong somewhere else...)
+extern uint32_t _etext;
+extern uint32_t _sidata;
+extern uint32_t _ram_start;
+extern uint32_t _sdata;
+extern uint32_t _edata;
+extern uint32_t _sbss;
+extern uint32_t _ebss;
+extern uint32_t _heap_start;
+extern uint32_t _heap_end;
+extern uint32_t _estack;
+extern uint32_t _ram_end;
+
+void gc_collect(void);
+
+MP_DECLARE_CONST_FUN_OBJ(pyb_gc_obj);
diff --git a/stmhal/gchelper.s b/stmhal/gchelper.s
new file mode 100644
index 000000000..6baedcdd0
--- /dev/null
+++ b/stmhal/gchelper.s
@@ -0,0 +1,62 @@
+    .syntax unified
+    .cpu cortex-m4
+    .thumb
+    .text
+    .align  2
+
+@ uint gc_helper_get_regs_and_sp(r0=uint regs[10])
+    .global gc_helper_get_regs_and_sp
+    .thumb
+    .thumb_func
+    .type   gc_helper_get_regs_and_sp, %function
+gc_helper_get_regs_and_sp:
+    @ store registers into given array
+    str     r4, [r0], #4
+    str     r5, [r0], #4
+    str     r6, [r0], #4
+    str     r7, [r0], #4
+    str     r8, [r0], #4
+    str     r9, [r0], #4
+    str     r10, [r0], #4
+    str     r11, [r0], #4
+    str     r12, [r0], #4
+    str     r13, [r0], #4
+
+    @ return the sp
+    mov     r0, sp
+    bx      lr
+
+
+@ this next function is now obsolete
+
+    .size   gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
+@ void gc_helper_get_regs_and_clean_stack(r0=uint regs[10], r1=heap_end)
+    .global gc_helper_get_regs_and_clean_stack
+    .thumb
+    .thumb_func
+    .type   gc_helper_get_regs_and_clean_stack, %function
+gc_helper_get_regs_and_clean_stack:
+    @ store registers into given array
+    str     r4, [r0], #4
+    str     r5, [r0], #4
+    str     r6, [r0], #4
+    str     r7, [r0], #4
+    str     r8, [r0], #4
+    str     r9, [r0], #4
+    str     r10, [r0], #4
+    str     r11, [r0], #4
+    str     r12, [r0], #4
+    str     r13, [r0], #4
+
+    @ clean the stack from given pointer up to current sp
+    movs    r0, #0
+    mov     r2, sp
+    b.n     .entry
+.loop:
+    str     r0, [r1], #4
+.entry:
+    cmp     r1, r2
+    bcc.n   .loop
+    bx      lr
+
+    .size   gc_helper_get_regs_and_clean_stack, .-gc_helper_get_regs_and_clean_stack
diff --git a/stmhal/import.c b/stmhal/import.c
new file mode 100644
index 000000000..f2fd3b3de
--- /dev/null
+++ b/stmhal/import.c
@@ -0,0 +1,24 @@
+#include <stdint.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "lexer.h"
+#if 0
+#include "ff.h"
+#endif
+
+mp_import_stat_t mp_import_stat(const char *path) {
+#if 0
+    FILINFO fno;
+    FRESULT res = f_stat(path, &fno);
+    if (res == FR_OK) {
+        if ((fno.fattrib & AM_DIR) != 0) {
+            return MP_IMPORT_STAT_DIR;
+        } else {
+            return MP_IMPORT_STAT_FILE;
+        }
+    }
+#endif
+    return MP_IMPORT_STAT_NO_EXIST;
+}
diff --git a/stmhal/led.c b/stmhal/led.c
new file mode 100644
index 000000000..a643ce84f
--- /dev/null
+++ b/stmhal/led.c
@@ -0,0 +1,133 @@
+#include <stdio.h>
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "led.h"
+#include "pin.h"
+#include "build/pins.h"
+
+static const pin_obj_t *gLed[] = {
+    &PYB_LED1,
+#if defined(PYB_LED2)
+    &PYB_LED2,
+#if defined(PYB_LED3)
+    &PYB_LED3,
+#if defined(PYB_LED4)
+    &PYB_LED4,
+#endif
+#endif
+#endif
+};
+#define NUM_LEDS (sizeof(gLed) / sizeof(gLed[0]))
+
+void led_init(void) {
+    /* GPIO structure */
+    GPIO_InitTypeDef GPIO_InitStructure;
+
+    /* Configure I/O speed, mode, output type and pull */
+    GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+    GPIO_InitStructure.Pull = GPIO_NOPULL;
+
+    /* Turn off LEDs and initialize */
+    for (int led = 0; led < NUM_LEDS; led++) {
+        PYB_LED_OFF(gLed[led]); 
+        GPIO_InitStructure.Pin = gLed[led]->pin_mask;
+        HAL_GPIO_Init(gLed[led]->gpio, &GPIO_InitStructure);
+    }
+}
+
+void led_state(pyb_led_t led, int state) {
+    if (led < 1 || led > NUM_LEDS) {
+        return;
+    }
+    const pin_obj_t *led_pin = gLed[led - 1];
+    if (state == 0) {
+        // turn LED off
+        PYB_LED_OFF(led_pin);
+    } else {
+        // turn LED on
+        PYB_LED_ON(led_pin);
+    }
+}
+
+void led_toggle(pyb_led_t led) {
+    if (led < 1 || led > NUM_LEDS) {
+        return;
+    }
+    const pin_obj_t *led_pin = gLed[led - 1];
+    GPIO_TypeDef *gpio = led_pin->gpio;
+
+    // We don't know if we're turning the LED on or off, but we don't really
+    // care. Just invert the state.
+    if (gpio->ODR & led_pin->pin_mask) {
+        // pin is high, make it low
+        gpio->BSRRH = led_pin->pin_mask;
+    } else {
+        // pin is low, make it high
+        gpio->BSRRL = led_pin->pin_mask;
+    }
+}
+
+#if 0
+/******************************************************************************/
+/* Micro Python bindings                                                      */
+
+typedef struct _pyb_led_obj_t {
+    mp_obj_base_t base;
+    uint led_id;
+} pyb_led_obj_t;
+
+void led_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    pyb_led_obj_t *self = self_in;
+    print(env, "<LED %lu>", self->led_id);
+}
+
+mp_obj_t led_obj_on(mp_obj_t self_in) {
+    pyb_led_obj_t *self = self_in;
+    led_state(self->led_id, 1);
+    return mp_const_none;
+}
+
+mp_obj_t led_obj_off(mp_obj_t self_in) {
+    pyb_led_obj_t *self = self_in;
+    led_state(self->led_id, 0);
+    return mp_const_none;
+}
+
+mp_obj_t led_obj_toggle(mp_obj_t self_in) {
+    pyb_led_obj_t *self = self_in;
+    led_toggle(self->led_id);
+    return mp_const_none;
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_on_obj, led_obj_on);
+static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_off_obj, led_obj_off);
+static MP_DEFINE_CONST_FUN_OBJ_1(led_obj_toggle_obj, led_obj_toggle);
+
+static const mp_method_t led_methods[] = {
+    { "on", &led_obj_on_obj },
+    { "off", &led_obj_off_obj },
+    { "toggle", &led_obj_toggle_obj },
+    { NULL, NULL },
+};
+
+static const mp_obj_type_t led_obj_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Led,
+    .print = led_obj_print,
+    .methods = led_methods,
+};
+
+static mp_obj_t pyb_Led(mp_obj_t led_id) {
+    pyb_led_obj_t *o = m_new_obj(pyb_led_obj_t);
+    o->base.type = &led_obj_type;
+    o->led_id = mp_obj_get_int(led_id);
+    return o;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_Led_obj, pyb_Led);
+#endif
diff --git a/stmhal/led.h b/stmhal/led.h
new file mode 100644
index 000000000..9e9db16ac
--- /dev/null
+++ b/stmhal/led.h
@@ -0,0 +1,25 @@
+typedef enum {
+    // PYBv3
+    PYB_LED_R1 = 1,
+    PYB_LED_R2 = 2,
+    PYB_LED_G1 = 3,
+    PYB_LED_G2 = 4,
+    // PYBv4
+    PYB_LED_RED = 1,
+    PYB_LED_GREEN = 2,
+    PYB_LED_YELLOW = 3,
+    PYB_LED_BLUE = 4,
+    //STM32F4DISC
+    PYB_LED_R = 1,
+    PYB_LED_G = 2,
+    PYB_LED_B = 3,
+    PYB_LED_O = 4,
+} pyb_led_t;
+
+void led_init(void);
+void led_state(pyb_led_t led, int state);
+void led_toggle(pyb_led_t led);
+
+#if 0
+MP_DECLARE_CONST_FUN_OBJ(pyb_Led_obj);
+#endif
diff --git a/stmhal/lexerfatfs.c b/stmhal/lexerfatfs.c
new file mode 100644
index 000000000..1910587d8
--- /dev/null
+++ b/stmhal/lexerfatfs.c
@@ -0,0 +1,61 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#if 0
+#include "ff.h"
+#endif
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "lexer.h"
+#include "lexerfatfs.h"
+
+#if 0
+typedef struct _mp_lexer_file_buf_t {
+    FIL fp;
+    char buf[20];
+    uint16_t len;
+    uint16_t pos;
+} mp_lexer_file_buf_t;
+
+static unichar file_buf_next_char(mp_lexer_file_buf_t *fb) {
+    if (fb->pos >= fb->len) {
+        if (fb->len < sizeof(fb->buf)) {
+            return MP_LEXER_CHAR_EOF;
+        } else {
+            UINT n;
+            f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
+            if (n == 0) {
+                return MP_LEXER_CHAR_EOF;
+            }
+            fb->len = n;
+            fb->pos = 0;
+        }
+    }
+    return fb->buf[fb->pos++];
+}
+
+static void file_buf_close(mp_lexer_file_buf_t *fb) {
+    f_close(&fb->fp);
+    m_del_obj(mp_lexer_file_buf_t, fb);
+}
+#endif
+
+mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
+#if 0
+    mp_lexer_file_buf_t *fb = m_new_obj(mp_lexer_file_buf_t);
+    FRESULT res = f_open(&fb->fp, filename, FA_READ);
+    if (res != FR_OK) {
+        m_del_obj(mp_lexer_file_buf_t, fb);
+        return NULL;
+    }
+    UINT n;
+    f_read(&fb->fp, fb->buf, sizeof(fb->buf), &n);
+    fb->len = n;
+    fb->pos = 0;
+    return mp_lexer_new(qstr_from_str(filename), fb, (mp_lexer_stream_next_char_t)file_buf_next_char, (mp_lexer_stream_close_t)file_buf_close);
+#else
+    return NULL;
+#endif
+}
diff --git a/stmhal/lexerfatfs.h b/stmhal/lexerfatfs.h
new file mode 100644
index 000000000..55902a300
--- /dev/null
+++ b/stmhal/lexerfatfs.h
@@ -0,0 +1 @@
+mp_lexer_t *mp_lexer_new_from_file(const char *filename);
diff --git a/stmhal/main.c b/stmhal/main.c
index ec913c30c..97a512cda 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -15,19 +15,18 @@
 #include <stm32f4xx_usart.h>
 #include <stm32f4xx_rng.h>
 #include <usbd_storage_msd.h>
-#include <stm_misc.h>
 #endif
 #include "std.h"
 
-#if 0
 #include "misc.h"
-#include "ff.h"
+#include "systick.h"
+#include "led.h"
+#include "usart.h"
 #include "mpconfig.h"
 #include "qstr.h"
 #include "nlr.h"
 #include "misc.h"
 #include "lexer.h"
-#include "lexerfatfs.h"
 #include "parse.h"
 #include "obj.h"
 #include "parsehelper.h"
@@ -36,10 +35,12 @@
 #include "runtime.h"
 #include "gc.h"
 #include "gccollect.h"
-#include "systick.h"
-#include "pendsv.h"
 #include "pyexec.h"
-#include "led.h"
+#include "pybmodule.h"
+#if 0
+#include "ff.h"
+#include "lexerfatfs.h"
+#include "pendsv.h"
 #include "servo.h"
 #include "lcd.h"
 #include "storage.h"
@@ -53,9 +54,11 @@
 #include "file.h"
 #include "pin.h"
 #include "exti.h"
-#include "pybmodule.h"
 #endif
 
+void SystemClock_Config(void);
+
+
 int errno;
 
 #if 0
@@ -65,7 +68,6 @@ static FATFS fatfs1;
 #endif
 #endif
 
-#if 0
 void flash_error(int n) {
     for (int i = 0; i < n; i++) {
         led_state(PYB_LED_R1, 1);
@@ -87,9 +89,7 @@ void __fatal_error(const char *msg) {
         flash_error(1);
     }
 }
-#endif
 
-#if 0
 STATIC mp_obj_t pyb_config_source_dir = MP_OBJ_NULL;
 STATIC mp_obj_t pyb_config_main = MP_OBJ_NULL;
 
@@ -161,93 +161,6 @@ static mp_obj_t pyb_help(void) {
     printf("%s", help_text);
     return mp_const_none;
 }
-#endif
-
-void led_init(void) {
-    /* GPIO structure */
-    GPIO_InitTypeDef GPIO_InitStructure;
-
-    /* Configure I/O speed, mode, output type and pull */
-    GPIO_InitStructure.Pin = GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
-    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
-    GPIO_InitStructure.Pull = GPIO_NOPULL;
-    GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
-    GPIO_InitStructure.Alternate = 0; // unused
-
-    /* initialize */
-    HAL_GPIO_Init(GPIOA, &GPIO_InitStructure);
-}
-
-void led_state(int led_id, int state) {
-    HAL_GPIO_WritePin(GPIOA, 1 << (13 + led_id), state);
-}
-
-/**
-  * @brief  System Clock Configuration
-  *         The system Clock is configured as follow : 
-  *            System Clock source            = PLL (HSE)
-  *            SYSCLK(Hz)                     = 168000000
-  *            HCLK(Hz)                       = 168000000
-  *            AHB Prescaler                  = 1
-  *            APB1 Prescaler                 = 4
-  *            APB2 Prescaler                 = 2
-  *            HSE Frequency(Hz)              = 8000000
-  *            PLL_M                          = 8
-  *            PLL_N                          = 336
-  *            PLL_P                          = 2
-  *            PLL_Q                          = 7
-  *            VDD(V)                         = 3.3
-  *            Main regulator output voltage  = Scale1 mode
-  *            Flash Latency(WS)              = 5
-  * @param  None
-  * @retval None
-  */
-static void SystemClock_Config(void) {
-  RCC_ClkInitTypeDef RCC_ClkInitStruct;
-  RCC_OscInitTypeDef RCC_OscInitStruct;
-  
-  /* Enable Power Control clock */
-  __PWR_CLK_ENABLE();
-  
-  /* The voltage scaling allows optimizing the power consumption when the device is 
-     clocked below the maximum system frequency, to update the voltage scaling value 
-     regarding system frequency refer to product datasheet.  */
-  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
-
-  /* Enable HSE Oscillator and activate PLL with HSE as source */
-  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
-  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
-  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
-  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
-  RCC_OscInitStruct.PLL.PLLM = 8;
-  RCC_OscInitStruct.PLL.PLLN = 336;
-  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
-  RCC_OscInitStruct.PLL.PLLQ = 7;
-  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
-  {
-    /* Initialization Error */
-    for (;;) {
-    }
-  }
-  
-  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
-     clocks dividers */
-  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
-  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
-  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
-  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
-  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;  
-  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
-  {
-    /* Initialization Error */
-    for (;;) {
-    }
-  }
-
-    // Make SysTick interrupt have the highest priority
-    // This is needed so that SysTick runs in all ISRs.
-    NVIC_SetPriority(SysTick_IRQn, 0);
-}
 
 int main(void) {
     // TODO disable JTAG
@@ -279,15 +192,13 @@ int main(void) {
     led_state(1, 0);
     led_state(2, 1);
 
+#if 0
     for (;;) {
         HAL_Delay(500);
         led_state(1, 1);
         HAL_Delay(500);
         led_state(1, 0);
     }
-
-#if 0
-    _fatal_error("done");
 #endif
 
 #if 0
@@ -328,29 +239,57 @@ int main(void) {
         GPIO_Init(GPIOB, &GPIO_InitStructure);
         GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_SET);
     }
+#endif
 #endif
 
     // basic sub-system init
     sys_tick_init();
+#if 0
     pendsv_init();
+#endif
     led_init();
 
+#if 0
 #if MICROPY_HW_ENABLE_RTC
     rtc_init();
+#endif
 #endif
 
     // turn on LED to indicate bootup
     led_state(PYB_LED_G1, 1);
 
+#if 0
     // more sub-system init
 #if MICROPY_HW_HAS_SDCARD
     sdcard_init();
 #endif
     storage_init();
+#endif
 
     // uncomment these 2 lines if you want REPL on USART_6 (or another usart) as well as on USB VCP
-    //pyb_usart_global_debug = PYB_USART_YA;
-    //usart_init(pyb_usart_global_debug, 115200);
+    pyb_usart_global_debug = PYB_USART_YA;
+    usart_init(pyb_usart_global_debug, 115200);
+
+#if 0
+    pyb_led_t led = 1;
+    while (1) {
+        led_state(led, 1);
+        usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
+        sys_tick_delay_ms(100);
+        led_state(led, 0);
+        usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
+        sys_tick_delay_ms(100);
+        led_state(led, 1);
+        usart_tx_strn_cooked(pyb_usart_global_debug, "on\n", 3);
+        sys_tick_delay_ms(100);
+        led_state(led, 0);
+        usart_tx_strn_cooked(pyb_usart_global_debug, "off\n", 4);
+        sys_tick_delay_ms(700);
+
+        led = (led % 4) + 1;
+    }
+    __fatal_error("done");
+#endif
 
     int first_soft_reset = true;
 
@@ -368,6 +307,7 @@ soft_reset:
     def_path[2] = MP_OBJ_NEW_QSTR(MP_QSTR_0_colon__slash_lib);
     sys_path = mp_obj_new_list(3, def_path);
 
+#if 0
     exti_init();
 
 #if MICROPY_HW_HAS_SWITCH
@@ -396,15 +336,19 @@ soft_reset:
 #endif
 
     pin_map_init();
+#endif
 
     // add some functions to the builtin Python namespace
     rt_store_name(MP_QSTR_help, rt_make_function_n(0, pyb_help));
+#if 0
     rt_store_name(MP_QSTR_open, rt_make_function_n(2, pyb_io_open));
+#endif
 
     // we pre-import the pyb module
     // probably shouldn't do this, so we are compatible with CPython
     rt_store_name(MP_QSTR_pyb, (mp_obj_t)&pyb_module);
 
+#if 0
     // check if user switch held (initiates reset of filesystem)
     bool reset_filesystem = false;
 #if MICROPY_HW_HAS_SWITCH
@@ -497,16 +441,20 @@ soft_reset:
         flash_error(4);
     }
 
+#endif
     if (first_soft_reset) {
+#if 0
 #if MICROPY_HW_HAS_MMA7660
         // MMA accel: init and reset address to zero
         accel_init();
+#endif
 #endif
     }
 
     // turn boot-up LED off
     led_state(PYB_LED_G1, 0);
 
+#if 0
 #if MICROPY_HW_HAS_SDCARD
     // if an SD card is present then mount it on 1:/
     if (sdcard_is_present()) {
@@ -591,16 +539,18 @@ soft_reset:
     // wifi
     pyb_wlan_init();
     pyb_wlan_start();
+#endif
 #endif
 
     pyexec_repl();
 
+#if 0
     printf("PYB: sync filesystems\n");
     storage_flush();
+#endif
 
     printf("PYB: soft reboot\n");
 
     first_soft_reset = false;
     goto soft_reset;
-#endif
 }
diff --git a/stmhal/malloc0.c b/stmhal/malloc0.c
new file mode 100644
index 000000000..85a643f72
--- /dev/null
+++ b/stmhal/malloc0.c
@@ -0,0 +1,36 @@
+#include <stdint.h>
+#include "std.h"
+#include "mpconfig.h"
+#include "gc.h"
+
+#if 0
+static uint32_t mem = 0;
+
+void *malloc(size_t n) {
+    if (mem == 0) {
+        extern uint32_t _heap_start;
+        mem = (uint32_t)&_heap_start; // need to use big ram block so we can execute code from it (is it true that we can't execute from CCM?)
+    }
+    void *ptr = (void*)mem;
+    mem = (mem + n + 3) & (~3);
+    if (mem > 0x20000000 + 0x18000) {
+        void __fatal_error(const char*);
+        __fatal_error("out of memory");
+    }
+    return ptr;
+}
+
+void free(void *ptr) {
+}
+
+void *realloc(void *ptr, size_t n) {
+    return malloc(n);
+}
+
+#endif
+
+void __assert_func(void) {
+    printf("\nASSERT FAIL!");
+    for (;;) {
+    }
+}
diff --git a/stmhal/math.c b/stmhal/math.c
new file mode 100644
index 000000000..8e2c6fc75
--- /dev/null
+++ b/stmhal/math.c
@@ -0,0 +1,407 @@
+#include <stdint.h>
+#include <math.h>
+
+// these 2 functions seem to actually work... no idea why
+// replacing with libgcc does not work (probably due to wrong calling conventions)
+double __aeabi_f2d(float x) {
+    // TODO
+    return 0.0;
+}
+
+float __aeabi_d2f(double x) {
+    // TODO
+    return 0.0;
+}
+
+/*
+double sqrt(double x) {
+    // TODO
+    return 0.0;
+}
+*/
+
+float sqrtf(float x) {
+    asm volatile (
+            "vsqrt.f32  %[r], %[x]\n"
+            : [r] "=t" (x)
+            : [x] "t"  (x));
+    return x;
+}
+
+// TODO we need import these functions from some library (eg musl or newlib)
+float powf(float x, float y) { return 0.0; }
+float logf(float x) { return 0.0; }
+float log2f(float x) { return 0.0; }
+float log10f(float x) { return 0.0; }
+float tanhf(float x) { return 0.0; }
+float acoshf(float x) { return 0.0; }
+float asinhf(float x) { return 0.0; }
+float atanhf(float x) { return 0.0; }
+float cosf(float x) { return 0.0; }
+float sinf(float x) { return 0.0; }
+float tanf(float x) { return 0.0; }
+float acosf(float x) { return 0.0; }
+float asinf(float x) { return 0.0; }
+float atanf(float x) { return 0.0; }
+float atan2f(float x, float y) { return 0.0; }
+
+/*****************************************************************************/
+// from musl-0.9.15 libm.h
+
+/* origin: FreeBSD /usr/src/lib/msun/src/math_private.h */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#define FORCE_EVAL(x) do {                        \
+	if (sizeof(x) == sizeof(float)) {         \
+		volatile float __x;               \
+		__x = (x);                        \
+                (void)__x;                        \
+	} else if (sizeof(x) == sizeof(double)) { \
+		volatile double __x;              \
+		__x = (x);                        \
+                (void)__x;                        \
+	} else {                                  \
+		volatile long double __x;         \
+		__x = (x);                        \
+                (void)__x;                        \
+	}                                         \
+} while(0)
+
+/* Get a 32 bit int from a float.  */
+#define GET_FLOAT_WORD(w,d)                       \
+do {                                              \
+  union {float f; uint32_t i;} __u;               \
+  __u.f = (d);                                    \
+  (w) = __u.i;                                    \
+} while (0)
+
+/* Set a float from a 32 bit int.  */
+#define SET_FLOAT_WORD(d,w)                       \
+do {                                              \
+      union {float f; uint32_t i;} __u;           \
+      __u.i = (w);                                \
+      (d) = __u.f;                                \
+} while (0)
+
+/*****************************************************************************/
+// scalbnf from musl-0.9.15
+
+float scalbnf(float x, int n)
+{
+	union {float f; uint32_t i;} u;
+	float_t y = x;
+
+	if (n > 127) {
+		y *= 0x1p127f;
+		n -= 127;
+		if (n > 127) {
+			y *= 0x1p127f;
+			n -= 127;
+			if (n > 127)
+				n = 127;
+		}
+	} else if (n < -126) {
+		y *= 0x1p-126f;
+		n += 126;
+		if (n < -126) {
+			y *= 0x1p-126f;
+			n += 126;
+			if (n < -126)
+				n = -126;
+		}
+	}
+	u.i = (uint32_t)(0x7f+n)<<23;
+	x = y * u.f;
+	return x;
+}
+
+/*****************************************************************************/
+// expf from musl-0.9.15
+
+/* origin: FreeBSD /usr/src/lib/msun/src/e_expf.c */
+/*
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+static const float
+half[2] = {0.5,-0.5},
+ln2hi   = 6.9314575195e-1f,  /* 0x3f317200 */
+ln2lo   = 1.4286067653e-6f,  /* 0x35bfbe8e */
+invln2  = 1.4426950216e+0f,  /* 0x3fb8aa3b */
+/*
+ * Domain [-0.34568, 0.34568], range ~[-4.278e-9, 4.447e-9]:
+ * |x*(exp(x)+1)/(exp(x)-1) - p(x)| < 2**-27.74
+ */
+P1 =  1.6666625440e-1f, /*  0xaaaa8f.0p-26 */
+P2 = -2.7667332906e-3f; /* -0xb55215.0p-32 */
+
+float expf(float x)
+{
+	float_t hi, lo, c, xx, y;
+	int k, sign;
+	uint32_t hx;
+
+	GET_FLOAT_WORD(hx, x);
+	sign = hx >> 31;   /* sign bit of x */
+	hx &= 0x7fffffff;  /* high word of |x| */
+
+	/* special cases */
+	if (hx >= 0x42aeac50) {  /* if |x| >= -87.33655f or NaN */
+		if (hx >= 0x42b17218 && !sign) {  /* x >= 88.722839f */
+			/* overflow */
+			x *= 0x1p127f;
+			return x;
+		}
+		if (sign) {
+			/* underflow */
+			FORCE_EVAL(-0x1p-149f/x);
+			if (hx >= 0x42cff1b5)  /* x <= -103.972084f */
+				return 0;
+		}
+	}
+
+	/* argument reduction */
+	if (hx > 0x3eb17218) {  /* if |x| > 0.5 ln2 */
+		if (hx > 0x3f851592)  /* if |x| > 1.5 ln2 */
+			k = invln2*x + half[sign];
+		else
+			k = 1 - sign - sign;
+		hi = x - k*ln2hi;  /* k*ln2hi is exact here */
+		lo = k*ln2lo;
+		x = hi - lo;
+	} else if (hx > 0x39000000) {  /* |x| > 2**-14 */
+		k = 0;
+		hi = x;
+		lo = 0;
+	} else {
+		/* raise inexact */
+		FORCE_EVAL(0x1p127f + x);
+		return 1 + x;
+	}
+
+	/* x is now in primary range */
+	xx = x*x;
+	c = x - xx*(P1+xx*P2);
+	y = 1 + (x*c/(2-c) - lo + hi);
+	if (k == 0)
+		return y;
+	return scalbnf(y, k);
+}
+
+/*****************************************************************************/
+// expm1f from musl-0.9.15
+
+/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */
+/*
+ * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunPro, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+static const float
+o_threshold = 8.8721679688e+01, /* 0x42b17180 */
+ln2_hi      = 6.9313812256e-01, /* 0x3f317180 */
+ln2_lo      = 9.0580006145e-06, /* 0x3717f7d1 */
+//invln2      = 1.4426950216e+00, /* 0x3fb8aa3b */
+/*
+ * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]:
+ * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04
+ * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c):
+ */
+Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */
+Q2 =  1.5807170421e-3; /*  0xcf3010.0p-33 */
+
+float expm1f(float x)
+{
+	float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk;
+	union {float f; uint32_t i;} u = {x};
+	uint32_t hx = u.i & 0x7fffffff;
+	int k, sign = u.i >> 31;
+
+	/* filter out huge and non-finite argument */
+	if (hx >= 0x4195b844) {  /* if |x|>=27*ln2 */
+		if (hx > 0x7f800000)  /* NaN */
+			return x;
+		if (sign)
+			return -1;
+		if (x > o_threshold) {
+			x *= 0x1p127f;
+			return x;
+		}
+	}
+
+	/* argument reduction */
+	if (hx > 0x3eb17218) {           /* if  |x| > 0.5 ln2 */
+		if (hx < 0x3F851592) {       /* and |x| < 1.5 ln2 */
+			if (!sign) {
+				hi = x - ln2_hi;
+				lo = ln2_lo;
+				k =  1;
+			} else {
+				hi = x + ln2_hi;
+				lo = -ln2_lo;
+				k = -1;
+			}
+		} else {
+			k  = invln2*x + (sign ? -0.5f : 0.5f);
+			t  = k;
+			hi = x - t*ln2_hi;      /* t*ln2_hi is exact here */
+			lo = t*ln2_lo;
+		}
+		x = hi-lo;
+		c = (hi-x)-lo;
+	} else if (hx < 0x33000000) {  /* when |x|<2**-25, return x */
+		if (hx < 0x00800000)
+			FORCE_EVAL(x*x);
+		return x;
+	} else
+		k = 0;
+
+	/* x is now in primary range */
+	hfx = 0.5f*x;
+	hxs = x*hfx;
+	r1 = 1.0f+hxs*(Q1+hxs*Q2);
+	t  = 3.0f - r1*hfx;
+	e  = hxs*((r1-t)/(6.0f - x*t));
+	if (k == 0)  /* c is 0 */
+		return x - (x*e-hxs);
+	e  = x*(e-c) - c;
+	e -= hxs;
+	/* exp(x) ~ 2^k (x_reduced - e + 1) */
+	if (k == -1)
+		return 0.5f*(x-e) - 0.5f;
+	if (k == 1) {
+		if (x < -0.25f)
+			return -2.0f*(e-(x+0.5f));
+		return 1.0f + 2.0f*(x-e);
+	}
+	u.i = (0x7f+k)<<23;  /* 2^k */
+	twopk = u.f;
+	if (k < 0 || k > 56) {   /* suffice to return exp(x)-1 */
+		y = x - e + 1.0f;
+		if (k == 128)
+			y = y*2.0f*0x1p127f;
+		else
+			y = y*twopk;
+		return y - 1.0f;
+	}
+	u.i = (0x7f-k)<<23;  /* 2^-k */
+	if (k < 23)
+		y = (x-e+(1-u.f))*twopk;
+	else
+		y = (x-(e+u.f)+1)*twopk;
+	return y;
+}
+
+/*****************************************************************************/
+// __expo2f from musl-0.9.15
+
+/* k is such that k*ln2 has minimal relative error and x - kln2 > log(FLT_MIN) */
+static const int k = 235;
+static const float kln2 = 0x1.45c778p+7f;
+
+/* expf(x)/2 for x >= log(FLT_MAX), slightly better than 0.5f*expf(x/2)*expf(x/2) */
+float __expo2f(float x)
+{
+	float scale;
+
+	/* note that k is odd and scale*scale overflows */
+	SET_FLOAT_WORD(scale, (uint32_t)(0x7f + k/2) << 23);
+	/* exp(x - k ln2) * 2**(k-1) */
+	return expf(x - kln2) * scale * scale;
+}
+
+/*****************************************************************************/
+// coshf from musl-0.9.15
+
+float coshf(float x)
+{
+	union {float f; uint32_t i;} u = {.f = x};
+	uint32_t w;
+	float t;
+
+	/* |x| */
+	u.i &= 0x7fffffff;
+	x = u.f;
+	w = u.i;
+
+	/* |x| < log(2) */
+	if (w < 0x3f317217) {
+		if (w < 0x3f800000 - (12<<23)) {
+			FORCE_EVAL(x + 0x1p120f);
+			return 1;
+		}
+		t = expm1f(x);
+		return 1 + t*t/(2*(1+t));
+	}
+
+	/* |x| < log(FLT_MAX) */
+	if (w < 0x42b17217) {
+		t = expf(x);
+		return 0.5f*(t + 1/t);
+	}
+
+	/* |x| > log(FLT_MAX) or nan */
+	t = __expo2f(x);
+	return t;
+}
+
+/*****************************************************************************/
+// sinhf from musl-0.9.15
+
+float sinhf(float x)
+{
+	union {float f; uint32_t i;} u = {.f = x};
+	uint32_t w;
+	float t, h, absx;
+
+	h = 0.5;
+	if (u.i >> 31)
+		h = -h;
+	/* |x| */
+	u.i &= 0x7fffffff;
+	absx = u.f;
+	w = u.i;
+
+	/* |x| < log(FLT_MAX) */
+	if (w < 0x42b17217) {
+		t = expm1f(absx);
+		if (w < 0x3f800000) {
+			if (w < 0x3f800000 - (12<<23))
+				return x;
+			return h*(2*t - t*t/(t+1));
+		}
+		return h*(t + t/(t+1));
+	}
+
+	/* |x| > logf(FLT_MAX) or nan */
+	t = 2*h*__expo2f(absx);
+	return t;
+}
diff --git a/stmhal/mpconfigport.h b/stmhal/mpconfigport.h
new file mode 100644
index 000000000..3f48c43f0
--- /dev/null
+++ b/stmhal/mpconfigport.h
@@ -0,0 +1,51 @@
+#include <stdint.h>
+
+// options to control how Micro Python is built
+
+#define MICROPY_EMIT_THUMB          (1)
+#define MICROPY_EMIT_INLINE_THUMB   (1)
+#define MICROPY_ENABLE_GC           (1)
+#define MICROPY_ENABLE_REPL_HELPERS (1)
+#define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)
+#define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_FLOAT)
+#define MICROPY_PATH_MAX            (128)
+/* Enable FatFS LFNs
+    0: Disable LFN feature.
+    1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
+    2: Enable LFN with dynamic working buffer on the STACK.
+    3: Enable LFN with dynamic working buffer on the HEAP.
+*/
+#define MICROPY_ENABLE_LFN          (0)
+#define MICROPY_LFN_CODE_PAGE       (1) /* 1=SFN/ANSI 437=LFN/U.S.(OEM) */
+
+// type definitions for the specific machine
+
+#define BYTES_PER_WORD (4)
+
+#define UINT_FMT "%lu"
+#define INT_FMT "%ld"
+
+typedef int32_t machine_int_t; // must be pointer size
+typedef uint32_t machine_uint_t; // must be pointer size
+typedef void *machine_ptr_t; // must be of pointer size
+typedef const void *machine_const_ptr_t; // must be of pointer size
+
+// There is no classical C heap in bare-metal ports, only Python
+// garbage-collected heap. For completeness, emulate C heap via
+// GC heap. Note that MicroPython core never uses malloc() and friends,
+// so these defines are mostly to help extension module writers.
+#define malloc gc_alloc
+#define free gc_free
+#define realloc gc_realloc
+
+// board specific definitions
+
+#include "mpconfigboard.h"
+
+#define STM32F40_41xxx
+#define USE_STDPERIPH_DRIVER
+#if !defined(HSE_VALUE)
+#define HSE_VALUE (8000000)
+#endif
+#define USE_DEVICE_MODE
+//#define USE_HOST_MODE
diff --git a/stmhal/pin.c b/stmhal/pin.c
new file mode 100644
index 000000000..735901c30
--- /dev/null
+++ b/stmhal/pin.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+
+#include "pin.h"
+
+#if 0
+void pin_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    pin_obj_t *self = self_in;
+    print(env, "<Pin %s>", self->name);
+}
+
+mp_obj_t pin_obj_name(mp_obj_t self_in) {
+    pin_obj_t *self = self_in;
+    return MP_OBJ_NEW_QSTR(qstr_from_str(self->name));
+}
+
+mp_obj_t pin_obj_port(mp_obj_t self_in) {
+    pin_obj_t *self = self_in;
+    return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->port);
+}
+
+mp_obj_t pin_obj_pin(mp_obj_t self_in) {
+    pin_obj_t *self = self_in;
+    return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->pin);
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_name_obj, pin_obj_name);
+static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_port_obj, pin_obj_port);
+static MP_DEFINE_CONST_FUN_OBJ_1(pin_obj_pin_obj, pin_obj_pin);
+
+static const mp_method_t pin_methods[] = {
+    { "name", &pin_obj_name_obj },
+    { "port", &pin_obj_port_obj },
+    { "pin", &pin_obj_pin_obj },
+    { NULL, NULL },
+};
+#endif
+
+const mp_obj_type_t pin_obj_type = {
+#if 0
+    { &mp_type_type },
+#else
+    { NULL },
+#endif
+    .name = MP_QSTR_Pin,
+#if 0
+    .print = pin_obj_print,
+    .methods = pin_methods,
+#endif
+};
+
+#if 0
+void pin_af_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    pin_af_obj_t *self = self_in;
+    print(env, "<Pin AF %d fn:%d unit:%d typ:%d>", self->idx, self->fn,
+          self->unit, self->type);
+}
+#endif
+
+const mp_obj_type_t pin_af_obj_type = {
+#if 0
+    { &mp_type_type },
+#else
+    { NULL },
+#endif
+    .name = MP_QSTR_PinAF,
+#if 0
+    .print = pin_af_obj_print,
+#endif
+};
+
diff --git a/stmhal/pin.h b/stmhal/pin.h
new file mode 100644
index 000000000..d5d769058
--- /dev/null
+++ b/stmhal/pin.h
@@ -0,0 +1,117 @@
+enum {
+  PORT_A,
+  PORT_B,
+  PORT_C,
+  PORT_D,
+  PORT_E,
+  PORT_F,
+  PORT_G,
+  PORT_H,
+  PORT_I,
+  PORT_J,
+};
+
+enum {
+  AF_FN_TIM,
+  AF_FN_I2C,
+  AF_FN_USART,
+  AF_FN_UART = AF_FN_USART,
+  AF_FN_SPI
+};
+
+enum {
+  AF_PIN_TYPE_TIM_CH1 = 0,
+  AF_PIN_TYPE_TIM_CH2,
+  AF_PIN_TYPE_TIM_CH3,
+  AF_PIN_TYPE_TIM_CH4,
+  AF_PIN_TYPE_TIM_CH1N,
+  AF_PIN_TYPE_TIM_CH2N,
+  AF_PIN_TYPE_TIM_CH3N,
+  AF_PIN_TYPE_TIM_CH1_ETR,
+  AF_PIN_TYPE_TIM_ETR,
+  AF_PIN_TYPE_TIM_BKIN,
+
+  AF_PIN_TYPE_I2C_SDA = 0,
+  AF_PIN_TYPE_I2C_SCL,
+
+  AF_PIN_TYPE_USART_TX = 0,
+  AF_PIN_TYPE_USART_RX,
+  AF_PIN_TYPE_USART_CTS,
+  AF_PIN_TYPE_USART_RTS,
+  AF_PIN_TYPE_USART_CK,
+  AF_PIN_TYPE_UART_TX  = AF_PIN_TYPE_USART_TX,
+  AF_PIN_TYPE_UART_RX  = AF_PIN_TYPE_USART_RX,
+  AF_PIN_TYPE_UART_CTS = AF_PIN_TYPE_USART_CTS,
+  AF_PIN_TYPE_UART_RTS = AF_PIN_TYPE_USART_RTS,
+
+  AF_PIN_TYPE_SPI_MOSI = 0,
+  AF_PIN_TYPE_SPI_MISO,
+  AF_PIN_TYPE_SPI_SCK,
+  AF_PIN_TYPE_SPI_NSS,
+};
+
+typedef struct {
+  mp_obj_base_t base;
+  uint8_t idx;
+  uint8_t fn;
+  uint8_t unit;
+  uint8_t type;
+
+  union {
+    void          *reg;
+    TIM_TypeDef   *TIM;
+    I2C_TypeDef   *I2C;
+    USART_TypeDef *USART;
+    USART_TypeDef *UART;
+    SPI_TypeDef   *SPI;
+  };
+} pin_af_obj_t;
+
+typedef struct {
+  mp_obj_base_t base;
+  const char *name;
+  uint16_t  port   : 4;
+  uint16_t  pin    : 4;
+  uint16_t  num_af : 4;
+  uint16_t pin_mask;
+  GPIO_TypeDef *gpio;
+  const pin_af_obj_t *af;
+} pin_obj_t;
+
+extern const mp_obj_type_t pin_obj_type;
+extern const mp_obj_type_t pin_af_obj_type;
+
+typedef struct {
+  const char  *name;
+  const pin_obj_t *pin;
+} pin_named_pin_t;
+
+extern const pin_named_pin_t pin_board_pins[];
+extern const pin_named_pin_t pin_cpu_pins[];
+
+typedef struct {
+    mp_obj_base_t base;
+    mp_obj_t mapper;
+    mp_obj_t map_dict;
+    bool debug;
+} pin_map_obj_t;
+
+extern pin_map_obj_t pin_map_obj;
+
+typedef struct {
+    mp_obj_base_t base;
+    const char *name;
+    const pin_named_pin_t *named_pins;
+} pin_named_pins_obj_t;
+
+extern const pin_named_pins_obj_t pin_board_pins_obj;
+extern const pin_named_pins_obj_t pin_cpu_pins_obj;
+
+const pin_obj_t *pin_find_named_pin(const pin_named_pin_t *pins, const char *name);
+const pin_af_obj_t *pin_find_af(const pin_obj_t *pin, uint8_t fn, uint8_t unit, uint8_t pin_type);
+
+void pin_map_init(void);
+
+// C function for mapping python pin identifier into an ordinal pin number.
+const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj);
+
diff --git a/stmhal/printf.c b/stmhal/printf.c
new file mode 100644
index 000000000..acd9816a5
--- /dev/null
+++ b/stmhal/printf.c
@@ -0,0 +1,371 @@
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "std.h"
+#include "misc.h"
+#include "systick.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#if 0
+#include "lcd.h"
+#endif
+#include "usart.h"
+#if 0
+#include "usb.h"
+#endif
+
+#if MICROPY_ENABLE_FLOAT
+#include "formatfloat.h"
+#endif
+
+#define PF_FLAG_LEFT_ADJUST (0x01)
+#define PF_FLAG_SHOW_SIGN   (0x02)
+#define PF_FLAG_SPACE_SIGN  (0x04)
+#define PF_FLAG_NO_TRAILZ   (0x08)
+#define PF_FLAG_ZERO_PAD    (0x10)
+
+// tricky; we compute pad string by: pad_chars + (flags & PF_FLAG_ZERO_PAD)
+#define PF_PAD_SIZE PF_FLAG_ZERO_PAD
+static const char *pad_chars = "                0000000000000000";
+
+typedef struct _pfenv_t {
+    void *data;
+    void (*print_strn)(void *, const char *str, unsigned int len);
+} pfenv_t;
+
+static void print_str_dummy(void *data, const char *str, unsigned int len) {
+}
+
+const pfenv_t pfenv_dummy = {0, print_str_dummy};
+
+static int pfenv_print_strn(const pfenv_t *pfenv, const char *str, unsigned int len, int flags, int width) {
+    int pad = width - len;
+    if (pad > 0 && (flags & PF_FLAG_LEFT_ADJUST) == 0) {
+        while (pad > 0) {
+            int p = pad;
+            if (p > PF_PAD_SIZE)
+                p = PF_PAD_SIZE;
+            pfenv->print_strn(pfenv->data, pad_chars + (flags & PF_FLAG_ZERO_PAD), p);
+            pad -= p;
+        }
+    }
+    pfenv->print_strn(pfenv->data, str, len);
+    while (pad > 0) {
+        int p = pad;
+        if (p > PF_PAD_SIZE)
+            p = PF_PAD_SIZE;
+        pfenv->print_strn(pfenv->data, pad_chars, p);
+        pad -= p;
+    }
+    return len;
+}
+
+// enough room for 32 signed number
+#define INT_BUF_SIZE (12)
+
+static int pfenv_print_int(const pfenv_t *pfenv, unsigned int x, int sgn, int base, int base_char, int flags, int width) {
+    char sign = 0;
+    if (sgn) {
+        if ((int)x < 0) {
+            sign = '-';
+            x = -x;
+        } else if (flags & PF_FLAG_SHOW_SIGN) {
+            sign = '+';
+        } else if (flags & PF_FLAG_SPACE_SIGN) {
+            sign = ' ';
+        }
+    }
+
+    char buf[INT_BUF_SIZE];
+    char *b = buf + INT_BUF_SIZE;
+
+    if (x == 0) {
+        *(--b) = '0';
+    } else {
+        do {
+            int c = x % base;
+            x /= base;
+            if (c >= 10) {
+                c += base_char - 10;
+            } else {
+                c += '0';
+            }
+            *(--b) = c;
+        } while (b > buf && x != 0);
+    }
+
+    if (b > buf && sign != 0) {
+        *(--b) = sign;
+    }
+
+    return pfenv_print_strn(pfenv, b, buf + INT_BUF_SIZE - b, flags, width);
+}
+
+void pfenv_prints(const pfenv_t *pfenv, const char *str) {
+    pfenv->print_strn(pfenv->data, str, strlen(str));
+}
+
+int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) {
+    int chrs = 0;
+    for (;;) {
+        {
+            const char *f = fmt;
+            while (*f != '\0' && *f != '%') {
+                ++f; // XXX UTF8 advance char
+            }
+            if (f > fmt) {
+                pfenv->print_strn(pfenv->data, fmt, f - fmt);
+                chrs += f - fmt;
+                fmt = f;
+            }
+        }
+
+        if (*fmt == '\0') {
+            break;
+        }
+
+        // move past % character
+        ++fmt;
+
+        // parse flags, if they exist
+        int flags = 0;
+        while (*fmt != '\0') {
+            if (*fmt == '-') flags |= PF_FLAG_LEFT_ADJUST;
+            else if (*fmt == '+') flags |= PF_FLAG_SHOW_SIGN;
+            else if (*fmt == ' ') flags |= PF_FLAG_SPACE_SIGN;
+            else if (*fmt == '!') flags |= PF_FLAG_NO_TRAILZ;
+            else if (*fmt == '0') flags |= PF_FLAG_ZERO_PAD;
+            else break;
+            ++fmt;
+        }
+
+        // parse width, if it exists
+        int width = 0;
+        for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
+            width = width * 10 + *fmt - '0';
+        }
+
+        // parse precision, if it exists
+        int prec = -1;
+        if (*fmt == '.') {
+            ++fmt;
+            if (*fmt == '*') {
+                ++fmt;
+                prec = va_arg(args, int);
+            } else {
+                prec = 0;
+                for (; '0' <= *fmt && *fmt <= '9'; ++fmt) {
+                    prec = prec * 10 + *fmt - '0';
+                }
+            }
+            if (prec < 0) {
+                prec = 0;
+            }
+        }
+
+        // parse long specifiers (current not used)
+        //bool long_arg = false;
+        if (*fmt == 'l') {
+            ++fmt;
+            //long_arg = true;
+        }
+
+        if (*fmt == '\0') {
+            break;
+        }
+
+        switch (*fmt) {
+            case 'b':
+                if (va_arg(args, int)) {
+                    chrs += pfenv_print_strn(pfenv, "true", 4, flags, width);
+                } else {
+                    chrs += pfenv_print_strn(pfenv, "false", 5, flags, width);
+                }
+                break;
+            case 'c':
+            {
+                char str = va_arg(args, int);
+                chrs += pfenv_print_strn(pfenv, &str, 1, flags, width);
+                break;
+            }
+            case 's':
+            {
+                const char *str = va_arg(args, const char*);
+                if (str) {
+                    if (prec < 0) {
+                        prec = strlen(str);
+                    }
+                    chrs += pfenv_print_strn(pfenv, str, prec, flags, width);
+                } else {
+                    chrs += pfenv_print_strn(pfenv, "(null)", 6, flags, width);
+                }
+                break;
+            }
+            case 'u':
+                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 10, 'a', flags, width);
+                break;
+            case 'd':
+                chrs += pfenv_print_int(pfenv, va_arg(args, int), 1, 10, 'a', flags, width);
+                break;
+            case 'x':
+            case 'p': // ?
+                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'a', flags, width);
+                break;
+            case 'X':
+            case 'P': // ?
+                chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, width);
+                break;
+#if MICROPY_ENABLE_FLOAT
+            case 'e':
+            case 'E':
+            case 'f':
+            case 'F':
+            case 'g':
+            case 'G':
+            {
+                char buf[32];
+                char sign = '\0';
+
+                if (flags & PF_FLAG_SHOW_SIGN) {
+                    sign = '+';
+                }
+                else
+                if (flags & PF_FLAG_SPACE_SIGN) {
+                    sign = ' ';
+                }
+                float f = va_arg(args, double);
+                int len = format_float(f, buf, sizeof(buf), *fmt, prec, sign);
+                char *s = buf;
+
+                // buf[0] < '0' returns true if the first character is space, + or -
+                // buf[1] < '9' matches a digit, and doesn't match when we get back +nan or +inf
+                if (buf[0] < '0' && buf[1] <= '9' && (flags & PF_FLAG_ZERO_PAD)) {
+                    chrs += pfenv_print_strn(pfenv, &buf[0], 1, 0, 1);
+                    s++;
+                    width--;
+                    len--;
+                }
+                if (*s < '0' || *s >= '9') {
+                    // For inf or nan, we don't want to zero pad.
+                    flags &= ~PF_FLAG_ZERO_PAD;
+                }
+                chrs += pfenv_print_strn(pfenv, s, len, flags, width); 
+                break;
+            }
+#endif
+            default:
+                pfenv->print_strn(pfenv->data, fmt, 1);
+                chrs += 1;
+                break;
+        }
+        ++fmt;
+    }
+    return chrs;
+}
+
+void stdout_print_strn(void *data, const char *str, unsigned int len) {
+    // send stdout to USART, USB CDC VCP, and LCD if nothing else
+    bool any = false;
+
+    if (pyb_usart_global_debug != PYB_USART_NONE) {
+        usart_tx_strn_cooked(pyb_usart_global_debug, str, len);
+        any = true;
+    }
+#if 0
+    if (usb_vcp_is_enabled()) {
+        usb_vcp_send_strn_cooked(str, len);
+        any = true;
+    }
+#endif
+    if (!any) {
+#if 0
+#if MICROPY_HW_HAS_LCD
+        lcd_print_strn(str, len);
+#endif
+#endif
+    }
+}
+
+static const pfenv_t pfenv_stdout = {0, stdout_print_strn};
+
+int printf(const char *fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+
+int vprintf(const char *fmt, va_list ap) {
+    return pfenv_printf(&pfenv_stdout, fmt, ap);
+}
+
+#if MICROPY_DEBUG_PRINTERS
+int DEBUG_printf(const char *fmt, ...) {
+    (void)stream;
+    va_list ap;
+    va_start(ap, fmt);
+    int ret = pfenv_printf(&pfenv_stdout, fmt, ap);
+    va_end(ap);
+    return ret;
+}
+#endif
+
+// need this because gcc optimises printf("%c", c) -> putchar(c), and printf("a") -> putchar('a')
+int putchar(int c) {
+    char chr = c;
+    stdout_print_strn(0, &chr, 1);
+    return chr;
+}
+
+// need this because gcc optimises printf("string\n") -> puts("string")
+int puts(const char *s) {
+    stdout_print_strn(0, s, strlen(s));
+    char chr = '\n';
+    stdout_print_strn(0, &chr, 1);
+    return 1;
+}
+
+typedef struct _strn_pfenv_t {
+    char *cur;
+    size_t remain;
+} strn_pfenv_t;
+
+void strn_print_strn(void *data, const char *str, unsigned int len) {
+    strn_pfenv_t *strn_pfenv = data;
+    if (len > strn_pfenv->remain) {
+        len = strn_pfenv->remain;
+    }
+    memcpy(strn_pfenv->cur, str, len);
+    strn_pfenv->cur += len;
+    strn_pfenv->remain -= len;
+}
+
+int vsnprintf(char *str, size_t size, const char *fmt, va_list ap) {
+    strn_pfenv_t strn_pfenv;
+    strn_pfenv.cur = str;
+    strn_pfenv.remain = size;
+    pfenv_t pfenv;
+    pfenv.data = &strn_pfenv;
+    pfenv.print_strn = strn_print_strn;
+    int len = pfenv_printf(&pfenv, fmt, ap);
+    // add terminating null byte
+    if (size > 0) {
+        if (strn_pfenv.remain == 0) {
+            strn_pfenv.cur[-1] = 0;
+        } else {
+            strn_pfenv.cur[0] = 0;
+        }
+    }
+    return len;
+}
+
+int snprintf(char *str, size_t size, const char *fmt, ...) {
+    va_list ap;
+    va_start(ap, fmt);
+    int ret = vsnprintf(str, size, fmt, ap);
+    va_end(ap);
+    return ret;
+}
diff --git a/stmhal/pybmodule.c b/stmhal/pybmodule.c
new file mode 100644
index 000000000..f0a7ebb6d
--- /dev/null
+++ b/stmhal/pybmodule.c
@@ -0,0 +1,312 @@
+#include <stdint.h>
+#include <stdio.h>
+
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#if 0
+#include "ff.h"
+#endif
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "map.h"
+#include "gc.h"
+#include "gccollect.h"
+#include "systick.h"
+#include "pyexec.h"
+#if 0
+#include "rtc.h"
+#include "servo.h"
+#include "storage.h"
+#include "usb.h"
+#include "usrsw.h"
+#include "sdcard.h"
+#include "accel.h"
+#include "led.h"
+#include "i2c.h"
+#include "usart.h"
+#include "adc.h"
+#include "audio.h"
+#include "pin.h"
+#include "gpio.h"
+#include "exti.h"
+#endif
+#include "pybmodule.h"
+
+// get lots of info about the board
+STATIC mp_obj_t pyb_info(void) {
+    // get and print unique id; 96 bits
+    {
+        byte *id = (byte*)0x1fff7a10;
+        printf("ID=%02x%02x%02x%02x:%02x%02x%02x%02x:%02x%02x%02x%02x\n", id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], id[9], id[10], id[11]);
+    }
+
+    // get and print clock speeds
+    // SYSCLK=168MHz, HCLK=168MHz, PCLK1=42MHz, PCLK2=84MHz
+    {
+        printf("S=%lu\nH=%lu\nP1=%lu\nP2=%lu\n", 
+               HAL_RCC_GetSysClockFreq(),
+               HAL_RCC_GetHCLKFreq(),
+               HAL_RCC_GetPCLK1Freq(),
+               HAL_RCC_GetPCLK2Freq());
+    }
+
+    // to print info about memory
+    {
+        printf("_etext=%p\n", &_etext);
+        printf("_sidata=%p\n", &_sidata);
+        printf("_sdata=%p\n", &_sdata);
+        printf("_edata=%p\n", &_edata);
+        printf("_sbss=%p\n", &_sbss);
+        printf("_ebss=%p\n", &_ebss);
+        printf("_estack=%p\n", &_estack);
+        printf("_ram_start=%p\n", &_ram_start);
+        printf("_heap_start=%p\n", &_heap_start);
+        printf("_heap_end=%p\n", &_heap_end);
+        printf("_ram_end=%p\n", &_ram_end);
+    }
+
+    // qstr info
+    {
+        uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+        qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+        printf("qstr:\n  n_pool=%u\n  n_qstr=%u\n  n_str_data_bytes=%u\n  n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
+    }
+
+    // GC info
+    {
+        gc_info_t info;
+        gc_info(&info);
+        printf("GC:\n");
+        printf("  %lu total\n", info.total);
+        printf("  %lu : %lu\n", info.used, info.free);
+        printf("  1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
+    }
+
+#if 0
+    // free space on flash
+    {
+        DWORD nclst;
+        FATFS *fatfs;
+        f_getfree("0:", &nclst, &fatfs);
+        printf("LFS free: %u bytes\n", (uint)(nclst * fatfs->csize * 512));
+    }
+#endif
+
+    return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_info_obj, pyb_info);
+
+// sync all file systems
+STATIC mp_obj_t pyb_sync(void) {
+#if 0
+    storage_flush();
+#endif
+    return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_sync_obj, pyb_sync);
+
+STATIC mp_obj_t pyb_millis(void) {
+    return mp_obj_new_int(HAL_GetTick());
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_millis_obj, pyb_millis);
+
+STATIC mp_obj_t pyb_delay(mp_obj_t count) {
+    sys_tick_delay_ms(mp_obj_get_int(count));
+    return mp_const_none;
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay);
+
+STATIC mp_obj_t pyb_udelay(mp_obj_t usec) {
+    uint32_t count = 0;
+    const uint32_t utime = (168 * mp_obj_get_int(usec) / 5);
+    for (;;) {
+        if (++count > utime) {
+            return mp_const_none;
+        }
+    }
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_udelay_obj, pyb_udelay);
+
+STATIC mp_obj_t pyb_rng_get(void) {
+#if 0
+    return mp_obj_new_int(RNG_GetRandomNumber() >> 16);
+#else
+    return mp_obj_new_int(0);
+#endif
+}
+
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(pyb_rng_get_obj, pyb_rng_get);
+
+#if 0
+STATIC void SYSCLKConfig_STOP(void) {
+    /* After wake-up from STOP reconfigure the system clock */
+    /* Enable HSE */
+    RCC_HSEConfig(RCC_HSE_ON);
+
+    /* Wait till HSE is ready */
+    while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET) {
+    }
+
+    /* Enable PLL */
+    RCC_PLLCmd(ENABLE);
+
+    /* Wait till PLL is ready */
+    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
+    }
+
+    /* Select PLL as system clock source */
+    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
+
+    /* Wait till PLL is used as system clock source */
+    while (RCC_GetSYSCLKSource() != 0x08) {
+    }
+}
+#endif
+
+STATIC mp_obj_t pyb_stop(void) {
+#if 0
+    PWR_EnterSTANDBYMode();
+    //PWR_FlashPowerDownCmd(ENABLE); don't know what the logic is with this
+
+    /* Enter Stop Mode */
+    PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
+
+    /* Configures system clock after wake-up from STOP: enable HSE, PLL and select 
+     *        PLL as system clock source (HSE and PLL are disabled in STOP mode) */
+    SYSCLKConfig_STOP();
+
+    //PWR_FlashPowerDownCmd(DISABLE);
+#endif
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_stop_obj, pyb_stop);
+
+STATIC mp_obj_t pyb_standby(void) {
+#if 0
+    PWR_EnterSTANDBYMode();
+#endif
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_standby_obj, pyb_standby);
+
+STATIC mp_obj_t pyb_hid_send_report(mp_obj_t arg) {
+#if 0
+    mp_obj_t *items = mp_obj_get_array_fixed_n(arg, 4);
+    uint8_t data[4];
+    data[0] = mp_obj_get_int(items[0]);
+    data[1] = mp_obj_get_int(items[1]);
+    data[2] = mp_obj_get_int(items[2]);
+    data[3] = mp_obj_get_int(items[3]);
+    usb_hid_send_report(data);
+#endif
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_hid_send_report_obj, pyb_hid_send_report);
+
+#if 0
+MP_DEFINE_CONST_FUN_OBJ_2(pyb_I2C_obj, pyb_I2C); // TODO put this in i2c.c
+#endif
+
+MP_DECLARE_CONST_FUN_OBJ(pyb_source_dir_obj); // defined in main.c
+MP_DECLARE_CONST_FUN_OBJ(pyb_main_obj); // defined in main.c
+
+STATIC const mp_map_elem_t pyb_module_globals_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_pyb) },
+
+    { MP_OBJ_NEW_QSTR(MP_QSTR_info), (mp_obj_t)&pyb_info_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_gc), (mp_obj_t)&pyb_gc_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj },
+
+    { MP_OBJ_NEW_QSTR(MP_QSTR_stop), (mp_obj_t)&pyb_stop_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_standby), (mp_obj_t)&pyb_standby_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_source_dir), (mp_obj_t)&pyb_source_dir_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_main), (mp_obj_t)&pyb_main_obj },
+
+    { MP_OBJ_NEW_QSTR(MP_QSTR_millis), (mp_obj_t)&pyb_millis_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_delay), (mp_obj_t)&pyb_delay_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_udelay), (mp_obj_t)&pyb_udelay_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_sync), (mp_obj_t)&pyb_sync_obj },
+
+#if MICROPY_HW_ENABLE_RNG
+    { MP_OBJ_NEW_QSTR(MP_QSTR_rand), (mp_obj_t)&pyb_rng_get_obj },
+#endif
+
+#if 0
+#if MICROPY_HW_ENABLE_RTC
+    { MP_OBJ_NEW_QSTR(MP_QSTR_time), (mp_obj_t)&pyb_rtc_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_rtc_info), (mp_obj_t)&pyb_rtc_info_obj },
+#endif
+
+#if MICROPY_HW_ENABLE_SERVO
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pwm), (mp_obj_t)&pyb_pwm_set_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_servo), (mp_obj_t)&pyb_servo_set_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Servo), (mp_obj_t)&pyb_Servo_obj },
+#endif
+
+#if MICROPY_HW_HAS_SWITCH
+    { MP_OBJ_NEW_QSTR(MP_QSTR_switch), (mp_obj_t)&pyb_switch_obj },
+#endif
+
+#if MICROPY_HW_HAS_SDCARD
+    { MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sdcard_obj },
+#endif
+
+#if MICROPY_HW_HAS_MMA7660
+    { MP_OBJ_NEW_QSTR(MP_QSTR_accel), (mp_obj_t)&pyb_accel_read_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_accel_read), (mp_obj_t)&pyb_accel_read_all_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_accel_mode), (mp_obj_t)&pyb_accel_write_mode_obj },
+#endif
+
+    { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj },
+
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_Led_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_I2C_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Usart), (mp_obj_t)&pyb_Usart_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ADC_all), (mp_obj_t)&pyb_ADC_all_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_ADC_obj },
+
+#if MICROPY_HW_ENABLE_AUDIO
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Audio), (mp_obj_t)&pyb_Audio_obj },
+#endif
+
+    // pin mapper
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_map_obj },
+
+    // GPIO bindings
+    { MP_OBJ_NEW_QSTR(MP_QSTR_gpio), (mp_obj_t)&pyb_gpio_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_gpio_in), (mp_obj_t)&pyb_gpio_input_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_gpio_out), (mp_obj_t)&pyb_gpio_output_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_NONE), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_NOPULL) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_UP) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PuPd_DOWN) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PUSH_PULL), MP_OBJ_NEW_SMALL_INT(GPIO_OType_PP) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_OType_OD) },
+
+    // EXTI bindings
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Exti), (mp_obj_t)&exti_obj_type },
+#endif
+};
+
+STATIC const mp_map_t pyb_module_globals = {
+    .all_keys_are_qstrs = 1,
+    .table_is_fixed_array = 1,
+    .used = sizeof(pyb_module_globals_table) / sizeof(mp_map_elem_t),
+    .alloc = sizeof(pyb_module_globals_table) / sizeof(mp_map_elem_t),
+    .table = (mp_map_elem_t*)pyb_module_globals_table,
+};
+
+const mp_obj_module_t pyb_module = {
+    .base = { &mp_type_module },
+    .name = MP_QSTR_pyb,
+    .globals = (mp_map_t*)&pyb_module_globals,
+};
diff --git a/stmhal/pybmodule.h b/stmhal/pybmodule.h
new file mode 100644
index 000000000..955aaefe3
--- /dev/null
+++ b/stmhal/pybmodule.h
@@ -0,0 +1 @@
+extern const mp_obj_module_t pyb_module;
diff --git a/stmhal/pyexec.c b/stmhal/pyexec.c
new file mode 100644
index 000000000..2eca892a9
--- /dev/null
+++ b/stmhal/pyexec.c
@@ -0,0 +1,347 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <stm32f4xx_hal.h>
+
+#include "nlr.h"
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "misc.h"
+#include "lexer.h"
+#include "parse.h"
+#include "obj.h"
+#include "parsehelper.h"
+#include "compile.h"
+#include "runtime.h"
+#include "repl.h"
+#include "gc.h"
+#include "gccollect.h"
+#include "systick.h"
+#include "pyexec.h"
+#if 0
+#include "storage.h"
+#include "usb.h"
+#endif
+#include "usart.h"
+
+static bool repl_display_debugging_info = 0;
+
+void stdout_tx_str(const char *str) {
+    if (pyb_usart_global_debug != PYB_USART_NONE) {
+        usart_tx_str(pyb_usart_global_debug, str);
+    }
+#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
+    lcd_print_str(str);
+#endif
+#if 0
+    usb_vcp_send_str(str);
+#endif
+}
+
+int stdin_rx_chr(void) {
+    for (;;) {
+#if 0
+#ifdef USE_HOST_MODE
+        pyb_usb_host_process();
+        int c = pyb_usb_host_get_keyboard();
+        if (c != 0) {
+            return c;
+        }
+#endif
+#endif
+#if 0
+        if (usb_vcp_rx_any() != 0) {
+            return usb_vcp_rx_get();
+        } else
+#endif
+        if (pyb_usart_global_debug != PYB_USART_NONE && usart_rx_any(pyb_usart_global_debug)) {
+            return usart_rx_char(pyb_usart_global_debug);
+        }
+        sys_tick_delay_ms(1);
+#if 0
+        if (storage_needs_flush()) {
+            storage_flush();
+        }
+#endif
+    }
+}
+
+char *str_dup(const char *str) {
+    uint32_t len = strlen(str);
+    char *s2 = m_new(char, len + 1);
+    memcpy(s2, str, len);
+    s2[len] = 0;
+    return s2;
+}
+
+#define READLINE_HIST_SIZE (8)
+
+static const char *readline_hist[READLINE_HIST_SIZE] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+
+#if 0
+#else
+#define VCP_CHAR_CTRL_A (1)
+#define VCP_CHAR_CTRL_C (3)
+#define VCP_CHAR_CTRL_D (4)
+#endif
+
+int readline(vstr_t *line, const char *prompt) {
+    stdout_tx_str(prompt);
+    int len = vstr_len(line);
+    int escape = 0;
+    int hist_num = 0;
+    for (;;) {
+        int c = stdin_rx_chr();
+        if (escape == 0) {
+            if (VCP_CHAR_CTRL_A <= c && c <= VCP_CHAR_CTRL_D && vstr_len(line) == len) {
+                return c;
+            } else if (c == '\r') {
+                stdout_tx_str("\r\n");
+                for (int i = READLINE_HIST_SIZE - 1; i > 0; i--) {
+                    readline_hist[i] = readline_hist[i - 1];
+                }
+                readline_hist[0] = str_dup(vstr_str(line));
+                return 0;
+            } else if (c == 27) {
+                escape = true;
+            } else if (c == 127) {
+                if (vstr_len(line) > len) {
+                    vstr_cut_tail(line, 1);
+                    stdout_tx_str("\b \b");
+                }
+            } else if (32 <= c && c <= 126) {
+                vstr_add_char(line, c);
+                stdout_tx_str(line->buf + line->len - 1);
+            }
+        } else if (escape == 1) {
+            if (c == '[') {
+                escape = 2;
+            } else {
+                escape = 0;
+            }
+        } else if (escape == 2) {
+            escape = 0;
+            if (c == 'A') {
+                // up arrow
+                if (hist_num < READLINE_HIST_SIZE && readline_hist[hist_num] != NULL) {
+                    // erase line
+                    for (int i = line->len - len; i > 0; i--) {
+                        stdout_tx_str("\b \b");
+                    }
+                    // set line to history
+                    line->len = len;
+                    vstr_add_str(line, readline_hist[hist_num]);
+                    // draw line
+                    stdout_tx_str(readline_hist[hist_num]);
+                    // increase hist num
+                    hist_num += 1;
+                }
+            }
+        } else {
+            escape = 0;
+        }
+        sys_tick_delay_ms(1);
+    }
+}
+
+// parses, compiles and executes the code in the lexer
+// frees the lexer before returning
+bool parse_compile_execute(mp_lexer_t *lex, mp_parse_input_kind_t input_kind, bool is_repl) {
+    mp_parse_error_kind_t parse_error_kind;
+    mp_parse_node_t pn = mp_parse(lex, input_kind, &parse_error_kind);
+    qstr source_name = mp_lexer_source_name(lex);
+
+    if (pn == MP_PARSE_NODE_NULL) {
+        // parse error
+        mp_parse_show_exception(lex, parse_error_kind);
+        mp_lexer_free(lex);
+        return false;
+    }
+
+    mp_lexer_free(lex);
+
+    mp_obj_t module_fun = mp_compile(pn, source_name, is_repl);
+    mp_parse_node_free(pn);
+
+    if (module_fun == mp_const_none) {
+        return false;
+    }
+
+    nlr_buf_t nlr;
+    bool ret;
+    uint32_t start = HAL_GetTick();
+    if (nlr_push(&nlr) == 0) {
+#if 0
+        usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C); // allow ctrl-C to interrupt us
+#endif
+        rt_call_function_0(module_fun);
+#if 0
+        usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
+#endif
+        nlr_pop();
+        ret = true;
+    } else {
+        // uncaught exception
+        // FIXME it could be that an interrupt happens just before we disable it here
+#if 0
+        usb_vcp_set_interrupt_char(VCP_CHAR_NONE); // disable interrupt
+#endif
+        mp_obj_print_exception((mp_obj_t)nlr.ret_val);
+        ret = false;
+    }
+
+    // display debugging info if wanted
+    if (is_repl && repl_display_debugging_info) {
+        uint32_t ticks = HAL_GetTick() - start; // TODO implement a function that does this properly
+        printf("took %lu ms\n", ticks);
+        gc_collect();
+        // qstr info
+        {
+            uint n_pool, n_qstr, n_str_data_bytes, n_total_bytes;
+            qstr_pool_info(&n_pool, &n_qstr, &n_str_data_bytes, &n_total_bytes);
+            printf("qstr:\n  n_pool=%u\n  n_qstr=%u\n  n_str_data_bytes=%u\n  n_total_bytes=%u\n", n_pool, n_qstr, n_str_data_bytes, n_total_bytes);
+        }
+
+        // GC info
+        {
+            gc_info_t info;
+            gc_info(&info);
+            printf("GC:\n");
+            printf("  %lu total\n", info.total);
+            printf("  %lu : %lu\n", info.used, info.free);
+            printf("  1=%lu 2=%lu m=%lu\n", info.num_1block, info.num_2block, info.max_block);
+        }
+    }
+
+    return ret;
+}
+
+void pyexec_raw_repl(void) {
+    vstr_t line;
+    vstr_init(&line, 32);
+
+raw_repl_reset:
+    stdout_tx_str("raw REPL; CTRL-C to exit\r\n");
+
+    for (;;) {
+        vstr_reset(&line);
+        stdout_tx_str(">");
+        for (;;) {
+            char c = stdin_rx_chr();
+            if (c == VCP_CHAR_CTRL_A) {
+                goto raw_repl_reset;
+            } else if (c == VCP_CHAR_CTRL_C) {
+                vstr_reset(&line);
+                break;
+            } else if (c == VCP_CHAR_CTRL_D) {
+                break;
+            } else if (c == '\r') {
+                vstr_add_char(&line, '\n');
+            } else if (32 <= c && c <= 126) {
+                vstr_add_char(&line, c);
+            }
+        }
+
+        stdout_tx_str("OK");
+
+        if (vstr_len(&line) == 0) {
+            // finished
+            break;
+        }
+
+        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
+        parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
+
+        stdout_tx_str("\004");
+    }
+
+    vstr_clear(&line);
+    stdout_tx_str("\r\n");
+}
+
+void pyexec_repl(void) {
+#if defined(USE_HOST_MODE) && MICROPY_HW_HAS_LCD
+    // in host mode, we enable the LCD for the repl
+    mp_obj_t lcd_o = rt_call_function_0(rt_load_name(qstr_from_str("LCD")));
+    rt_call_function_1(rt_load_attr(lcd_o, qstr_from_str("light")), mp_const_true);
+#endif
+
+    stdout_tx_str("Micro Python build <git hash> on 25/1/2014; " MICROPY_HW_BOARD_NAME " with STM32F405RG\r\n");
+    stdout_tx_str("Type \"help()\" for more information.\r\n");
+
+    // to test ctrl-C
+    /*
+    {
+        uint32_t x[4] = {0x424242, 0xdeaddead, 0x242424, 0xdeadbeef};
+        for (;;) {
+            nlr_buf_t nlr;
+            printf("pyexec_repl: %p\n", x);
+            usb_vcp_set_interrupt_char(VCP_CHAR_CTRL_C);
+            if (nlr_push(&nlr) == 0) {
+                for (;;) {
+                }
+            } else {
+                printf("break\n");
+            }
+        }
+    }
+    */
+
+    vstr_t line;
+    vstr_init(&line, 32);
+
+    for (;;) {
+        vstr_reset(&line);
+        int ret = readline(&line, ">>> ");
+
+        if (ret == VCP_CHAR_CTRL_A) {
+            pyexec_raw_repl();
+            continue;
+        } else if (ret == VCP_CHAR_CTRL_C) {
+            stdout_tx_str("\r\n");
+            continue;
+        } else if (ret == VCP_CHAR_CTRL_D) {
+            // EOF
+            break;
+        } else if (vstr_len(&line) == 0) {
+            continue;
+        }
+
+        if (mp_repl_is_compound_stmt(vstr_str(&line))) {
+            for (;;) {
+                vstr_add_char(&line, '\n');
+                int len = vstr_len(&line);
+                int ret = readline(&line, "... ");
+                if (ret == VCP_CHAR_CTRL_D || vstr_len(&line) == len) {
+                    // done entering compound statement
+                    break;
+                }
+            }
+        }
+
+        mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, vstr_str(&line), vstr_len(&line), 0);
+        parse_compile_execute(lex, MP_PARSE_SINGLE_INPUT, true);
+    }
+
+    stdout_tx_str("\r\n");
+}
+
+bool pyexec_file(const char *filename) {
+    mp_lexer_t *lex = mp_lexer_new_from_file(filename);
+
+    if (lex == NULL) {
+        printf("could not open file '%s' for reading\n", filename);
+        return false;
+    }
+
+    return parse_compile_execute(lex, MP_PARSE_FILE_INPUT, false);
+}
+
+mp_obj_t pyb_set_repl_info(mp_obj_t o_value) {
+    repl_display_debugging_info = mp_obj_get_int(o_value);
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_1(pyb_set_repl_info_obj, pyb_set_repl_info);
diff --git a/stmhal/pyexec.h b/stmhal/pyexec.h
new file mode 100644
index 000000000..cad15af6f
--- /dev/null
+++ b/stmhal/pyexec.h
@@ -0,0 +1,5 @@
+void pyexec_raw_repl(void);
+void pyexec_repl(void);
+bool pyexec_file(const char *filename);
+
+MP_DECLARE_CONST_FUN_OBJ(pyb_set_repl_info_obj);
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
new file mode 100644
index 000000000..13532892a
--- /dev/null
+++ b/stmhal/qstrdefsport.h
@@ -0,0 +1,57 @@
+// qstrs specific to this port
+
+Q(help)
+Q(pyb)
+Q(info)
+Q(sd_test)
+Q(stop)
+Q(standby)
+Q(source_dir)
+Q(main)
+Q(sync)
+Q(gc)
+Q(repl_info)
+Q(delay)
+Q(udelay)
+Q(switch)
+Q(SW)
+Q(servo)
+Q(pwm)
+Q(accel)
+Q(accel_read)
+Q(accel_mode)
+Q(hid)
+Q(time)
+Q(rand)
+Q(Led)
+Q(LCD)
+Q(Servo)
+Q(SD)
+Q(SDcard)
+Q(I2C)
+Q(gpio)
+Q(gpio_in)
+Q(gpio_out)
+Q(Usart)
+Q(ADC)
+Q(ADC_all)
+Q(Audio)
+Q(open)
+Q(File)
+// Entries for sys.path
+Q(0:/)
+Q(0:/src)
+Q(0:/lib)
+Q(Pin)
+Q(PinMap)
+Q(PinAF)
+Q(PinNamed)
+Q(Exti)
+Q(ExtiMeta)
+Q(rtc_info)
+Q(millis)
+Q(PULL_NONE)
+Q(PULL_UP)
+Q(PULL_DOWN)
+Q(PUSH_PULL)
+Q(OPEN_DRAIN)
diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c
index 96b12bfe4..61c4b7172 100644
--- a/stmhal/stm32f4xx_it.c
+++ b/stmhal/stm32f4xx_it.c
@@ -151,6 +151,7 @@ void PendSV_Handler(void)
 {
 }
 
+#if 0 // defined in systick.c
 /**
   * @brief  This function handles SysTick Handler.
   * @param  None
@@ -160,6 +161,7 @@ void SysTick_Handler(void)
 {
   HAL_IncTick();
 }
+#endif
 
 /******************************************************************************/
 /*                 STM32F4xx Peripherals Interrupt Handlers                   */
diff --git a/stmhal/string0.c b/stmhal/string0.c
new file mode 100644
index 000000000..61350bd97
--- /dev/null
+++ b/stmhal/string0.c
@@ -0,0 +1,137 @@
+#include <stdint.h>
+#include "std.h"
+
+void *memcpy(void *dest, const void *src, size_t n) {
+    // TODO align and copy 32 bits at a time
+    uint8_t *d = dest;
+    const uint8_t *s = src;
+    for (; n > 0; n--) {
+        *d++ = *s++;
+    }
+    return dest;
+}
+
+void *memmove(void *dest, const void *src, size_t n) {
+    if (src < dest && dest < src + n) {
+        // need to copy backwards
+        uint8_t *d = dest + n - 1;
+        const uint8_t *s = src + n - 1;
+        for (; n > 0; n--) {
+            *d-- = *s--;
+        }
+        return dest;
+    } else {
+        // can use normal memcpy
+        return memcpy(dest, src, n);
+    }
+}
+
+void *memset(void *s, int c, size_t n) {
+    uint8_t *s2 = s;
+    for (; n > 0; n--) {
+        *s2++ = c;
+    }
+    return s;
+}
+
+int memcmp(const char *s1, const char *s2, size_t n) {
+    while (n--) {
+        char c1 = *s1++;
+        char c2 = *s2++;
+        if (c1 < c2) return -1;
+        else if (c1 > c2) return 1;
+    }
+    return 0;
+}
+
+size_t strlen(const char *str) {
+    int len = 0;
+    for (const char *s = str; *s; s++) {
+        len += 1;
+    }
+    return len;
+}
+
+int strcmp(const char *s1, const char *s2) {
+    while (*s1 && *s2) {
+        char c1 = *s1++; // XXX UTF8 get char, next char
+        char c2 = *s2++; // XXX UTF8 get char, next char
+        if (c1 < c2) return -1;
+        else if (c1 > c2) return 1;
+    }
+    if (*s2) return -1;
+    else if (*s1) return 1;
+    else return 0;
+}
+
+int strncmp(const char *s1, const char *s2, size_t n) {
+    while (*s1 && *s2 && n > 0) {
+        char c1 = *s1++; // XXX UTF8 get char, next char
+        char c2 = *s2++; // XXX UTF8 get char, next char
+        n--;
+        if (c1 < c2) return -1;
+        else if (c1 > c2) return 1;
+    }
+    if (n == 0) return 0;
+    else if (*s2) return -1;
+    else if (*s1) return 1;
+    else return 0;
+}
+
+char *strcpy(char *dest, const char *src) {
+    char *d = dest;
+    while (*src) {
+        *d++ = *src++;
+    }
+    *d = '\0';
+    return dest;
+}
+
+// needed because gcc optimises strcpy + strcat to this
+char *stpcpy(char *dest, const char *src) {
+    while (*src) {
+        *dest++ = *src++;
+    }
+    *dest = '\0';
+    return dest;
+}
+
+char *strcat(char *dest, const char *src) {
+    char *d = dest;
+    while (*d) {
+        d++;
+    }
+    while (*src) {
+        *d++ = *src++;
+    }
+    *d = '\0';
+    return dest;
+}
+
+// Public Domain implementation of strchr from:
+// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strchr_function
+char *strchr(const char *s, int c)
+{
+    /* Scan s for the character.  When this loop is finished,
+       s will either point to the end of the string or the
+       character we were looking for.  */
+    while (*s != '\0' && *s != (char)c)
+        s++;
+    return ((*s == c) ? (char *) s : 0);
+}
+
+
+// Public Domain implementation of strstr from:
+// http://en.wikibooks.org/wiki/C_Programming/Strings#The_strstr_function
+char *strstr(const char *haystack, const char *needle)
+{
+    size_t needlelen;
+    /* Check for the null needle case.  */
+    if (*needle == '\0')
+        return (char *) haystack;
+    needlelen = strlen(needle);
+    for (; (haystack = strchr(haystack, *needle)) != 0; haystack++)
+        if (strncmp(haystack, needle, needlelen) == 0)
+            return (char *) haystack;
+    return 0;
+}
diff --git a/stmhal/system_stm32f4xx.c b/stmhal/system_stm32f4xx.c
index aa9c98473..8d806041c 100644
--- a/stmhal/system_stm32f4xx.c
+++ b/stmhal/system_stm32f4xx.c
@@ -65,6 +65,8 @@
 
 #include "stm32f4xx_hal.h"
 
+void __fatal_error(const char *msg);
+
 /**
   * @}
   */
@@ -257,8 +259,64 @@ void SystemCoreClockUpdate(void)
 }
 
 /**
-  * @}
+  * @brief  System Clock Configuration
+  *         The system Clock is configured as follow : 
+  *            System Clock source            = PLL (HSE)
+  *            SYSCLK(Hz)                     = 168000000
+  *            HCLK(Hz)                       = 168000000
+  *            AHB Prescaler                  = 1
+  *            APB1 Prescaler                 = 4
+  *            APB2 Prescaler                 = 2
+  *            HSE Frequency(Hz)              = 8000000
+  *            PLL_M                          = 8
+  *            PLL_N                          = 336
+  *            PLL_P                          = 2
+  *            PLL_Q                          = 7
+  *            VDD(V)                         = 3.3
+  *            Main regulator output voltage  = Scale1 mode
+  *            Flash Latency(WS)              = 5
+  * @param  None
+  * @retval None
   */
+void SystemClock_Config(void)
+{
+  RCC_ClkInitTypeDef RCC_ClkInitStruct;
+  RCC_OscInitTypeDef RCC_OscInitStruct;
+
+  /* Enable Power Control clock */
+  __PWR_CLK_ENABLE();
+  
+  /* The voltage scaling allows optimizing the power consumption when the device is 
+     clocked below the maximum system frequency, to update the voltage scaling value 
+     regarding system frequency refer to product datasheet.  */
+  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
+  
+  /* Enable HSE Oscillator and activate PLL with HSE as source */
+  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
+  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
+  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
+  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
+  RCC_OscInitStruct.PLL.PLLM = 8;
+  RCC_OscInitStruct.PLL.PLLN = 336;
+  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
+  RCC_OscInitStruct.PLL.PLLQ = 7;
+  if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
+  {
+    __fatal_error("HAL_RCC_OscConfig");
+  }
+
+  /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 
+     clocks dividers */
+  RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
+  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
+  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
+  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;  
+  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;  
+  if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
+  {
+    __fatal_error("HAL_RCC_ClockConfig");
+  }
+}
 
 /**
   * @}
diff --git a/stmhal/systick.c b/stmhal/systick.c
new file mode 100644
index 000000000..55c22dab0
--- /dev/null
+++ b/stmhal/systick.c
@@ -0,0 +1,54 @@
+#include <stm32f4xx_hal.h>
+#include "misc.h"
+#include "systick.h"
+
+void sys_tick_init(void) {
+    // SysTick_Config is now called from HAL_RCC_ClockConfig, which is called
+    // from SystemClock_Config
+    HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); // make it highest priority
+}
+
+// called on SysTick interrupt
+void SysTick_Handler(void) {
+    HAL_IncTick();
+    HAL_SYSTICK_IRQHandler();
+    // hack!
+    //void audio_drain(void);
+    //audio_drain();
+}
+
+void sys_tick_delay_ms(uint32_t delay_ms) {
+    sys_tick_wait_at_least(HAL_GetTick(), delay_ms);
+}
+
+// waits until at least delay_ms milliseconds have passed from the sampling of stc
+// handles overflow properl
+// assumes stc was taken from HAL_GetTick() some time before calling this function
+// eg stc <= HAL_GetTick() for the case of no wrap around of HAL_GetTick()
+void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms) {
+    // stc_wait is the value of HAL_GetTick() that we wait for
+    uint32_t stc_wait = stc + delay_ms;
+    if (stc_wait < stc) {
+        // stc_wait wrapped around
+        while (stc <= HAL_GetTick() || HAL_GetTick() < stc_wait) {
+            __WFI(); // enter sleep mode, waiting for interrupt
+        }
+    } else {
+        // stc_wait did not wrap around
+        while (stc <= HAL_GetTick() && HAL_GetTick() < stc_wait) {
+            __WFI(); // enter sleep mode, waiting for interrupt
+        }
+    }
+}
+
+bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms) {
+    // stc_wait is the value of HAL_GetTick() that we wait for
+    uint32_t stc_wait = stc + delay_ms;
+    if (stc_wait < stc) {
+        // stc_wait wrapped around
+        return !(stc <= HAL_GetTick() || HAL_GetTick() < stc_wait);
+    } else {
+        // stc_wait did not wrap around
+        return !(stc <= HAL_GetTick() && HAL_GetTick() < stc_wait);
+    }
+}
diff --git a/stmhal/systick.h b/stmhal/systick.h
new file mode 100644
index 000000000..ce33e849b
--- /dev/null
+++ b/stmhal/systick.h
@@ -0,0 +1,5 @@
+void sys_tick_init(void);
+void SysTick_Handler(void);
+void sys_tick_delay_ms(uint32_t delay_ms);
+void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
+bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
diff --git a/stmhal/usart.c b/stmhal/usart.c
new file mode 100644
index 000000000..16b23240a
--- /dev/null
+++ b/stmhal/usart.c
@@ -0,0 +1,269 @@
+#include <stdio.h>
+#include <string.h>
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "usart.h"
+
+pyb_usart_t pyb_usart_global_debug = PYB_USART_NONE;
+
+#if 0
+#else
+// This needs to be fixed. Right now its just a hack to get REPL working
+static UART_HandleTypeDef UartHandle;
+#endif
+
+#if 0
+static USART_TypeDef *usart_get_base(pyb_usart_t usart_id) {
+    USART_TypeDef *USARTx=NULL;
+
+    switch (usart_id) {
+        case PYB_USART_NONE:
+            break;
+        case PYB_USART_1:
+            USARTx = USART1;
+            break;
+        case PYB_USART_2:
+            USARTx = USART2;
+            break;
+        case PYB_USART_3:
+            USARTx = USART3;
+            break;
+        case PYB_USART_6:
+            USARTx = USART6;
+            break;
+    }
+
+    return USARTx;
+}
+#endif
+
+void usart_init(pyb_usart_t usart_id, uint32_t baudrate) {
+    USART_TypeDef *USARTx=NULL;
+
+    uint32_t GPIO_Pin=0;
+    uint8_t  GPIO_AF_USARTx=0;
+    GPIO_TypeDef* GPIO_Port=NULL;
+
+    switch (usart_id) {
+        case PYB_USART_NONE:
+            return;
+
+        case PYB_USART_1:
+            USARTx = USART1;
+
+            GPIO_Port = GPIOA;
+            GPIO_AF_USARTx = GPIO_AF7_USART1;
+            GPIO_Pin = GPIO_PIN_9 | GPIO_PIN_10;
+
+            __USART1_CLK_ENABLE();
+            break;
+        case PYB_USART_2:
+            USARTx = USART2;
+
+            GPIO_Port = GPIOD;
+            GPIO_AF_USARTx = GPIO_AF7_USART2;
+            GPIO_Pin = GPIO_PIN_5 | GPIO_PIN_6;
+
+            __USART2_CLK_ENABLE();
+            break;
+        case PYB_USART_3:
+            USARTx = USART3;
+
+#if defined(PYBOARD3) || defined(PYBOARD4)
+            GPIO_Port = GPIOB;
+            GPIO_AF_USARTx = GPIO_AF7_USART3;
+            GPIO_Pin = GPIO_PIN_10 | GPIO_PIN_11;
+#else
+            GPIO_Port = GPIOD;
+            GPIO_AF_USARTx = GPIO_AF7_USART3;
+            GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
+#endif
+            __USART3_CLK_ENABLE();
+            break;
+        case PYB_USART_6:
+            USARTx = USART6;
+
+            GPIO_Port = GPIOC;
+            GPIO_AF_USARTx = GPIO_AF8_USART6;
+            GPIO_Pin = GPIO_PIN_6 | GPIO_PIN_7;
+
+            __USART6_CLK_ENABLE();
+            break;
+    }
+
+    /* Initialize USARTx */
+    
+    GPIO_InitTypeDef GPIO_InitStructure;
+    GPIO_InitStructure.Pin = GPIO_Pin;
+    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
+    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
+    GPIO_InitStructure.Pull = GPIO_PULLUP;
+    GPIO_InitStructure.Alternate = GPIO_AF_USARTx;
+    HAL_GPIO_Init(GPIO_Port, &GPIO_InitStructure);
+
+    memset(&UartHandle, 0, sizeof(UartHandle));
+    UartHandle.Instance = USARTx;
+    UartHandle.Init.BaudRate = baudrate;
+    UartHandle.Init.WordLength = USART_WORDLENGTH_8B;
+    UartHandle.Init.StopBits = USART_STOPBITS_1;
+    UartHandle.Init.Parity = USART_PARITY_NONE;
+    UartHandle.Init.Mode = USART_MODE_TX_RX;
+    UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
+    UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
+    HAL_UART_Init(&UartHandle);
+}
+
+bool usart_rx_any(pyb_usart_t usart_id) {
+#if 0
+    USART_TypeDef *USARTx = usart_get_base(usart_id);
+    return USART_GetFlagStatus(USARTx, USART_FLAG_RXNE) == SET;
+#else
+    return __HAL_UART_GET_FLAG(&UartHandle, USART_FLAG_RXNE);
+#endif
+}
+
+int usart_rx_char(pyb_usart_t usart_id) {
+#if 0
+    USART_TypeDef *USARTx = usart_get_base(usart_id);
+    return USART_ReceiveData(USARTx);
+#else
+    uint8_t ch;
+    if (HAL_UART_Receive(&UartHandle, &ch, 1, 0) != HAL_OK) {
+        ch = 0;
+    }
+    return ch;
+#endif
+}
+
+void usart_tx_char(pyb_usart_t usart_id, int c) {
+#if 0
+    USART_TypeDef *USARTx = usart_get_base(usart_id);
+    // wait until the end of any previous transmission
+    uint32_t timeout = 100000;
+    while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET && --timeout > 0) {
+    }
+    USART_SendData(USARTx, c);
+#else
+    uint8_t ch = c;
+    HAL_UART_Transmit(&UartHandle, &ch, 1, 100000);
+#endif
+}
+
+void usart_tx_str(pyb_usart_t usart_id, const char *str) {
+    for (; *str; str++) {
+        usart_tx_char(usart_id, *str);
+    }
+}
+
+void usart_tx_bytes(pyb_usart_t usart_id, const char *data, uint len) {
+    for (; len > 0; data++, len--) {
+        usart_tx_char(usart_id, *data);
+    }
+}
+
+void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len) {
+    for (const char *top = str + len; str < top; str++) {
+        if (*str == '\n') {
+            usart_tx_char(usart_id, '\r');
+        }
+        usart_tx_char(usart_id, *str);
+    }
+}
+
+#if 0
+/******************************************************************************/
+/* Micro Python bindings                                                      */
+
+typedef struct _pyb_usart_obj_t {
+    mp_obj_base_t base;
+    pyb_usart_t usart_id;
+    bool is_enabled;
+} pyb_usart_obj_t;
+
+static mp_obj_t usart_obj_status(mp_obj_t self_in) {
+    pyb_usart_obj_t *self = self_in;
+    if (usart_rx_any(self->usart_id)) {
+        return mp_const_true;
+    } else {
+        return mp_const_false;
+    }
+}
+
+static mp_obj_t usart_obj_rx_char(mp_obj_t self_in) {
+    mp_obj_t ret = mp_const_none;
+    pyb_usart_obj_t *self = self_in;
+
+    if (self->is_enabled) {
+        ret =  mp_obj_new_int(usart_rx_char(self->usart_id));
+    }
+    return ret;
+}
+
+static mp_obj_t usart_obj_tx_char(mp_obj_t self_in, mp_obj_t c) {
+    pyb_usart_obj_t *self = self_in;
+    uint len;
+    const char *str = mp_obj_str_get_data(c, &len);
+    if (len == 1 && self->is_enabled) {
+        usart_tx_char(self->usart_id, str[0]);
+    }
+    return mp_const_none;
+}
+
+static mp_obj_t usart_obj_tx_str(mp_obj_t self_in, mp_obj_t s) {
+    pyb_usart_obj_t *self = self_in;
+    if (self->is_enabled) {
+        if (MP_OBJ_IS_STR(s)) {
+            uint len;
+            const char *data = mp_obj_str_get_data(s, &len);
+            usart_tx_bytes(self->usart_id, data, len);
+        }
+    }
+    return mp_const_none;
+}
+
+static void usart_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    pyb_usart_obj_t *self = self_in;
+    print(env, "<Usart %lu>", self->usart_id);
+}
+
+static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_status_obj, usart_obj_status);
+static MP_DEFINE_CONST_FUN_OBJ_1(usart_obj_rx_char_obj, usart_obj_rx_char);
+static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_char_obj, usart_obj_tx_char);
+static MP_DEFINE_CONST_FUN_OBJ_2(usart_obj_tx_str_obj, usart_obj_tx_str);
+
+STATIC const mp_method_t usart_methods[] = {
+    { "status", &usart_obj_status_obj },
+    { "recv_chr", &usart_obj_rx_char_obj },
+    { "send_chr", &usart_obj_tx_char_obj },
+    { "send", &usart_obj_tx_str_obj },
+    { NULL, NULL },
+};
+
+STATIC const mp_obj_type_t usart_obj_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_Usart,
+    .print = usart_obj_print,
+    .methods = usart_methods,
+};
+
+STATIC mp_obj_t pyb_Usart(mp_obj_t usart_id, mp_obj_t baudrate) {
+    if (mp_obj_get_int(usart_id)>PYB_USART_MAX) {
+        return mp_const_none;
+    }
+
+    /* init USART */
+    usart_init(mp_obj_get_int(usart_id), mp_obj_get_int(baudrate));
+
+    pyb_usart_obj_t *o = m_new_obj(pyb_usart_obj_t);
+    o->base.type = &usart_obj_type;
+    o->usart_id = mp_obj_get_int(usart_id);
+    o->is_enabled = true;
+    return o;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_2(pyb_Usart_obj, pyb_Usart);
+#endif
diff --git a/stmhal/usart.h b/stmhal/usart.h
new file mode 100644
index 000000000..2b1b60bfd
--- /dev/null
+++ b/stmhal/usart.h
@@ -0,0 +1,25 @@
+typedef enum {
+    PYB_USART_NONE = 0,
+    PYB_USART_1 = 1,
+    PYB_USART_2 = 2,
+    PYB_USART_3 = 3,
+    PYB_USART_6 = 4,
+    PYB_USART_MAX = 4,
+
+    //PYB_USART_XA =  // USART4 on X1, X2 = PA0, PA1
+    PYB_USART_XB = 1, // USART1 on X9, X10 = PB6, PB7
+    PYB_USART_YA = 4, // USART6 on Y1, Y2 = PC6, PC7
+    PYB_USART_YB = 3, // USART3 on Y9, Y10 = PB10, PB11
+} pyb_usart_t;
+
+extern pyb_usart_t pyb_usart_global_debug;
+
+void usart_init(pyb_usart_t usart_id, uint32_t baudrate);
+bool usart_rx_any(pyb_usart_t usart_id);
+int usart_rx_char(pyb_usart_t usart_id);
+void usart_tx_str(pyb_usart_t usart_id, const char *str);
+void usart_tx_strn_cooked(pyb_usart_t usart_id, const char *str, int len);
+
+#if 0
+MP_DECLARE_CONST_FUN_OBJ(pyb_Usart_obj);
+#endif
-- 
GitLab