diff --git a/stmhal/Makefile b/stmhal/Makefile
index 5501c4b8d9aca33d2e3cfba52fbf49c407b7c59a..dcffd164af01c404857653c707a13669109c50fb 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -65,7 +65,6 @@ SRC_C = \
 	timer.c \
 	led.c \
 	pin.c \
-	pin_map.c \
 	pin_named_pins.c \
 	usart.c \
 	usb.c \
@@ -84,8 +83,7 @@ SRC_C = \
 	modtime.c \
 	import.c \
 	lexerfatfs.c \
-	gpio.c \
-	exti.c \
+	extint.c \
 	usrsw.c \
 	rng.c \
 	rtc.c \
diff --git a/stmhal/adc.c b/stmhal/adc.c
index b0a7a0749add198a5da5f1afb1eb6bc25d62d19a..78f0820d696609d565283f64dab4ba65f68a3da2 100644
--- a/stmhal/adc.c
+++ b/stmhal/adc.c
@@ -18,7 +18,7 @@
 // adc = pyb.ADC(pin)
 // val = adc.read()
 //
-// adc = pyb.ADC_all(resolution)
+// adc = pyb.ADCAll(resolution)
 // val = adc.read_channel(channel)
 // val = adc.read_core_temp()
 // val = adc.read_core_vbat()
@@ -129,7 +129,7 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
     if (MP_OBJ_IS_INT(pin_obj)) {
         channel = mp_obj_get_int(pin_obj);
     } else {
-        const pin_obj_t *pin = pin_map_user_obj(pin_obj);
+        const pin_obj_t *pin = pin_find(pin_obj);
         if ((pin->adc_num & PIN_ADC1) == 0) {
             // No ADC1 function on that pin
             nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin %s does not have ADC capabilities", pin->name));
@@ -138,10 +138,10 @@ STATIC mp_obj_t adc_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_
     }
 
     if (!IS_ADC_CHANNEL(channel)) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Not a valid ADC Channel: %d", channel));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "not a valid ADC Channel: %d", channel));
     }
     if (pin_adc1[channel] == NULL) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Channel %d not available on this board", channel));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "channel %d not available on this board", channel));
     }
 
     pyb_obj_adc_t *o = m_new_obj(pyb_obj_adc_t);
@@ -211,12 +211,12 @@ const mp_obj_type_t pyb_adc_type = {
 /******************************************************************************/
 /* adc all object                                                             */
 
-typedef struct _pyb_obj_adc_all_t {
+typedef struct _pyb_adc_all_obj_t {
     mp_obj_base_t base;
     ADC_HandleTypeDef handle;
-} pyb_obj_adc_all_t;
+} pyb_adc_all_obj_t;
 
-void adc_init_all(pyb_obj_adc_all_t *adc_all, uint32_t resolution) {
+void adc_init_all(pyb_adc_all_obj_t *adc_all, uint32_t resolution) {
 
     switch (resolution) {
         case 6:  resolution = ADC_RESOLUTION6b;  break;
@@ -314,46 +314,49 @@ float adc_read_core_vref(ADC_HandleTypeDef *adcHandle) {
 /******************************************************************************/
 /* Micro Python bindings : adc_all object                                     */
 
-STATIC void adc_all_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
-    print(env, "<ADC all>");
+STATIC mp_obj_t adc_all_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    // check number of arguments
+    mp_check_nargs(n_args, 1, 1, n_kw, false);
+
+    // make ADCAll object
+    pyb_adc_all_obj_t *o = m_new_obj(pyb_adc_all_obj_t);
+    o->base.type = &pyb_adc_all_type;
+    adc_init_all(o, mp_obj_get_int(args[0])); // args[0] is the resolution
+
+    return o;
 }
 
 STATIC mp_obj_t adc_all_read_channel(mp_obj_t self_in, mp_obj_t channel) {
-    pyb_obj_adc_all_t *self = self_in;
-
+    pyb_adc_all_obj_t *self = self_in;
     uint32_t chan = mp_obj_get_int(channel);
     uint32_t data = adc_config_and_read_channel(&self->handle, chan);
     return mp_obj_new_int(data);
 }
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
 
 STATIC mp_obj_t adc_all_read_core_temp(mp_obj_t self_in) {
-    pyb_obj_adc_all_t *self = self_in;
-
+    pyb_adc_all_obj_t *self = self_in;
     int data  = adc_read_core_temp(&self->handle);
     return mp_obj_new_int(data);
 }
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
 
 STATIC mp_obj_t adc_all_read_core_vbat(mp_obj_t self_in) {
-    pyb_obj_adc_all_t *self = self_in;
-
+    pyb_adc_all_obj_t *self = self_in;
     float data = adc_read_core_vbat(&self->handle);
     return mp_obj_new_float(data);
 }
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
 
 STATIC mp_obj_t adc_all_read_core_vref(mp_obj_t self_in) {
-    pyb_obj_adc_all_t *self = self_in;
-
+    pyb_adc_all_obj_t *self = self_in;
     float data  = adc_read_core_vref(&self->handle);
     return mp_obj_new_float(data);
 }
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(adc_all_read_channel_obj, adc_all_read_channel);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_temp_obj, adc_all_read_core_temp);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vbat_obj, adc_all_read_core_vbat);
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(adc_all_read_core_vref_obj, adc_all_read_core_vref);
 
 STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
-    { MP_OBJ_NEW_QSTR(MP_QSTR_read_channel), (mp_obj_t)  &adc_all_read_channel_obj},
+    { MP_OBJ_NEW_QSTR(MP_QSTR_read_channel),   (mp_obj_t)&adc_all_read_channel_obj},
     { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_temp), (mp_obj_t)&adc_all_read_core_temp_obj},
     { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vbat), (mp_obj_t)&adc_all_read_core_vbat_obj},
     { MP_OBJ_NEW_QSTR(MP_QSTR_read_core_vref), (mp_obj_t)&adc_all_read_core_vref_obj},
@@ -361,18 +364,9 @@ STATIC const mp_map_elem_t adc_all_locals_dict_table[] = {
 
 STATIC MP_DEFINE_CONST_DICT(adc_all_locals_dict, adc_all_locals_dict_table);
 
-STATIC const mp_obj_type_t adc_all_type = {
+const mp_obj_type_t pyb_adc_all_type = {
     { &mp_type_type },
-    .name = MP_QSTR_ADC,
-    .print = adc_all_print,
+    .name = MP_QSTR_ADCAll,
+    .make_new = adc_all_make_new,
     .locals_dict = (mp_obj_t)&adc_all_locals_dict,
 };
-
-STATIC mp_obj_t pyb_ADC_all(mp_obj_t resolution) {
-    pyb_obj_adc_all_t *o = m_new_obj(pyb_obj_adc_all_t);
-    o->base.type = &adc_all_type;
-    adc_init_all(o, mp_obj_get_int(resolution));
-    return o;
-}
-
-MP_DEFINE_CONST_FUN_OBJ_1(pyb_ADC_all_obj, pyb_ADC_all);
diff --git a/stmhal/adc.h b/stmhal/adc.h
index c9f16932ebc8bcdf77c81c8c369c846e0d33e0cb..deedac011221cbd4804a5746cc5389c5896bb21c 100644
--- a/stmhal/adc.h
+++ b/stmhal/adc.h
@@ -1,3 +1,2 @@
 extern const mp_obj_type_t pyb_adc_type;
-
-MP_DECLARE_CONST_FUN_OBJ(pyb_ADC_all_obj);
+extern const mp_obj_type_t pyb_adc_all_type;
diff --git a/stmhal/boards/stm32f4xx-prefix.c b/stmhal/boards/stm32f4xx-prefix.c
index 989b8f0048141b0e21c72e291db22044cfd167fb..4d2313075a9bf2bc60d63a65bb5783fef846485b 100644
--- a/stmhal/boards/stm32f4xx-prefix.c
+++ b/stmhal/boards/stm32f4xx-prefix.c
@@ -2,18 +2,18 @@
 
 #include <stdio.h>
 #include <stdint.h>
-#include <stm32f4xx_hal.h>
+
+#include "stm32f4xx_hal.h"
 
 #include "misc.h"
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
-
 #include "pin.h"
 
 #define AF(af_idx, af_fn, af_unit, af_type, af_ptr) \
 { \
-    { &pin_af_obj_type }, \
+    { &pin_af_type }, \
     .idx = (af_idx), \
     .fn = AF_FN_ ## af_fn, \
     .unit = (af_unit), \
@@ -23,7 +23,7 @@
 
 #define PIN(p_port, p_pin, p_num_af, p_af, p_adc_num, p_adc_channel) \
 { \
-    { &pin_obj_type }, \
+    { &pin_type }, \
     .name = #p_port #p_pin, \
     .port = PORT_ ## p_port, \
     .pin = (p_pin), \
diff --git a/stmhal/exti.c b/stmhal/extint.c
similarity index 59%
rename from stmhal/exti.c
rename to stmhal/extint.c
index 5ea3db62bba0dc0a6e221dd93c91580edc9d241c..9ec599cf136bd5cddbb9296294cd669561b577a3 100644
--- a/stmhal/exti.c
+++ b/stmhal/extint.c
@@ -13,7 +13,7 @@
 #include "runtime.h"
 
 #include "pin.h"
-#include "exti.h"
+#include "extint.h"
 
 // Usage Model:
 //
@@ -27,8 +27,8 @@
 // def callback(line):
 //     print("line =", line)
 //
-// # Note: Exti will automatically configure the gpio line as an input.
-// exti = pyb.Exti(pin, pyb.Exti.MODE_IRQ_FALLING, pyb.PULLUP, callback)
+// # Note: ExtInt will automatically configure the gpio line as an input.
+// extint = pyb.ExtInt(pin, pyb.ExtInt.MODE_IRQ_FALLING, pyb.GPIO.PULL_UP, callback)
 //
 // Now every time a falling edge is seen on the X1 pin, the callback will be
 // called. Caution: mechanical pushbuttons have "bounce" and pushing or
@@ -44,27 +44,27 @@
 // All other pin objects go through the pin mapper to come up with one of the
 // gpio pins.
 //
-// exti = pyb.Exti(pin, mode, pull, callback)
+// extint = pyb.ExtInt(pin, mode, pull, callback)
 //
-// Valid modes are pyb.Exti.MODE_IRQ_RISING, pyb.Exti.MODE_IRQ_FALLING,
-// pyb.Exti.MODE_IRQ_RISING_FALLING, pyb.Exti.MODE_EVT_RISING,
-// pyb.Exti.MODE_EVT_FALLING, and pyb.Exti.MODE_EVT_RISING_FALLING.
+// Valid modes are pyb.ExtInt.MODE_IRQ_RISING, pyb.ExtInt.MODE_IRQ_FALLING,
+// pyb.ExtInt.MODE_IRQ_RISING_FALLING, pyb.ExtInt.MODE_EVT_RISING,
+// pyb.ExtInt.MODE_EVT_FALLING, and pyb.ExtInt.MODE_EVT_RISING_FALLING.
 //
-// Only the MODE_IRQ_xxx modes have been tested. The MODE_EVENT_xxx modes have
-// something to do with sleep mode and he WFE instruction.
+// Only the MODE_IRQ_xxx modes have been tested. The MODE_EVT_xxx modes have
+// something to do with sleep mode and the WFE instruction.
 //
-// Valid pull values are pyb.PULL_UP, pyb.PULL_DOWN, pyb.PULL_NONE.
+// Valid pull values are pyb.GPIO.PULL_UP, pyb.GPIO.PULL_DOWN, pyb.GPIO.PULL_NONE.
 //
-// exti.line() will return the line number that pin was mapped to.
-// exti.disable() can be use to disable the interrupt associated with a given
-//                exti object. This could be useful for debouncing.
-// exti.enable()  enables a disabled interrupt
-// exti.swint()   will allow the callback to be triggered from software.
+// extint.line() will return the line number that pin was mapped to.
+// extint.disable() can be use to disable the interrupt associated with a given
+//                  exti object. This could be useful for debouncing.
+// extint.enable()  enables a disabled interrupt
+// extint.swint()   will allow the callback to be triggered from software.
 //
-// pyb.Exti.regs() will dump the values of the EXTI registers.
+// pyb.ExtInt.regs() will dump the values of the EXTI registers.
 //
 // There is also a C API, so that drivers which require EXTI interrupt lines
-// can also use this code. See exti.h for the available functions and
+// can also use this code. See extint.h for the available functions and
 // usrsw.h for an example of using this.
 //
 // TODO Add python method to change callback object.
@@ -83,15 +83,15 @@
 typedef struct {
     mp_obj_base_t  base;
     mp_small_int_t line;
-} exti_obj_t;
+} extint_obj_t;
 
 typedef struct {
   mp_obj_t callback_obj;
   void *param;
   uint32_t mode;
-} exti_vector_t;
+} extint_vector_t;
 
-STATIC exti_vector_t exti_vector[EXTI_NUM_VECTORS];
+STATIC extint_vector_t extint_vector[EXTI_NUM_VECTORS];
 
 #if !defined(ETH)
 #define ETH_WKUP_IRQn   62  // The 405 doesn't have ETH, but we want a value to put in our table
@@ -110,7 +110,7 @@ STATIC const uint8_t nvic_irq_channel[EXTI_NUM_VECTORS] = {
 //
 // NOTE: param is for C callers. Python can use closure to get an object bound
 //       with the function.
-uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param) {
+uint extint_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param) {
     const pin_obj_t *pin = NULL;
     uint v_line;
 
@@ -120,13 +120,13 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob
         // get both the port number and line number.
         v_line = mp_obj_get_int(pin_obj);
         if (v_line < 16) {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d < 16, use a Pin object", v_line));
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d < 16, use a Pin object", v_line));
         }
         if (v_line >= EXTI_NUM_VECTORS) {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d >= max of %d", v_line, EXTI_NUM_VECTORS));
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d >= max of %d", v_line, EXTI_NUM_VECTORS));
         }
     } else {
-        pin = pin_map_user_obj(pin_obj);
+        pin = pin_find(pin_obj);
         v_line = pin->pin;
     }
     int mode = mp_obj_get_int(mode_obj);
@@ -136,24 +136,24 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob
         mode != GPIO_MODE_EVT_RISING &&
         mode != GPIO_MODE_EVT_FALLING &&
         mode != GPIO_MODE_EVT_RISING_FALLING) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Mode: %d", mode));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid ExtInt Mode: %d", mode));
     }
     int pull = mp_obj_get_int(pull_obj);
     if (pull != GPIO_NOPULL &&
         pull != GPIO_PULLUP &&
         pull != GPIO_PULLDOWN) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid EXTI Pull: %d", pull));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Invalid ExtInt Pull: %d", pull));
     }
 
-    exti_vector_t *v = &exti_vector[v_line];
+    extint_vector_t *v = &extint_vector[v_line];
     if (!override_callback_obj && v->callback_obj != mp_const_none && callback_obj != mp_const_none) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "EXTI vector %d is already in use", v_line));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "ExtInt vector %d is already in use", v_line));
     }
 
     // We need to update callback and param atomically, so we disable the line
     // before we update anything.
 
-    exti_disable(v_line);
+    extint_disable(v_line);
 
     v->callback_obj = callback_obj;
     v->param = param;
@@ -169,7 +169,7 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob
         exti.Speed = GPIO_SPEED_FAST;
         HAL_GPIO_Init(pin->gpio, &exti);
 
-        // Calling HAL_GPIO_Init does an implicit exti_enable
+        // Calling HAL_GPIO_Init does an implicit extint_enable
 
         /* Enable and set NVIC Interrupt to the lowest priority */
         HAL_NVIC_SetPriority(nvic_irq_channel[v_line], 0x0F, 0x0F);
@@ -178,17 +178,17 @@ uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t pull_obj, mp_ob
     return v_line;
 }
 
-void exti_enable(uint line) {
+void extint_enable(uint line) {
     if (line >= EXTI_NUM_VECTORS) {
         return;
     }
     // Since manipulating IMR/EMR is a read-modify-write, and we want this to
     // be atomic, we use the bit-band area to just affect the bit we're
     // interested in.
-    EXTI_MODE_BB(exti_vector[line].mode, line) = 1;
+    EXTI_MODE_BB(extint_vector[line].mode, line) = 1;
 }
 
-void exti_disable(uint line) {
+void extint_disable(uint line) {
     if (line >= EXTI_NUM_VECTORS) {
         return;
     }
@@ -199,37 +199,37 @@ void exti_disable(uint line) {
     EXTI_MODE_BB(EXTI_Mode_Event, line) = 0;
 }
 
-void exti_swint(uint line) {
+void extint_swint(uint line) {
     if (line >= EXTI_NUM_VECTORS) {
         return;
     }
     EXTI->SWIER = (1 << line);
 }
 
-STATIC mp_obj_t exti_obj_line(mp_obj_t self_in) {
-    exti_obj_t *self = self_in;
+STATIC mp_obj_t extint_obj_line(mp_obj_t self_in) {
+    extint_obj_t *self = self_in;
     return MP_OBJ_NEW_SMALL_INT(self->line);
 }
 
-STATIC mp_obj_t exti_obj_enable(mp_obj_t self_in) {
-    exti_obj_t *self = self_in;
-    exti_enable(self->line);
+STATIC mp_obj_t extint_obj_enable(mp_obj_t self_in) {
+    extint_obj_t *self = self_in;
+    extint_enable(self->line);
     return mp_const_none;
 }
 
-STATIC mp_obj_t exti_obj_disable(mp_obj_t self_in) {
-    exti_obj_t *self = self_in;
-    exti_disable(self->line);
+STATIC mp_obj_t extint_obj_disable(mp_obj_t self_in) {
+    extint_obj_t *self = self_in;
+    extint_disable(self->line);
     return mp_const_none;
 }
 
-STATIC mp_obj_t exti_obj_swint(mp_obj_t self_in) {
-    exti_obj_t *self = self_in;
-    exti_swint(self->line);
+STATIC mp_obj_t extint_obj_swint(mp_obj_t self_in) {
+    extint_obj_t *self = self_in;
+    extint_swint(self->line);
     return mp_const_none;
 }
 
-STATIC mp_obj_t exti_regs(void) {
+STATIC mp_obj_t extint_regs(void) {
     printf("EXTI_IMR   %08lx\n", EXTI->IMR);
     printf("EXTI_EMR   %08lx\n", EXTI->EMR);
     printf("EXTI_RTSR  %08lx\n", EXTI->RTSR);
@@ -239,62 +239,62 @@ STATIC mp_obj_t exti_regs(void) {
     return mp_const_none;
 }
 
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_line_obj,    exti_obj_line);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_enable_obj,  exti_obj_enable);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_disable_obj, exti_obj_disable);
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(exti_obj_swint_obj,   exti_obj_swint);
-STATIC MP_DEFINE_CONST_FUN_OBJ_0(exti_regs_fun_obj,    exti_regs);
-STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(exti_regs_obj, (mp_obj_t)&exti_regs_fun_obj);
-
-STATIC const mp_map_elem_t exti_locals_dict_table[] = {
-    { MP_OBJ_NEW_QSTR(MP_QSTR_line),    (mp_obj_t)&exti_obj_line_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_enable),  (mp_obj_t)&exti_obj_enable_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&exti_obj_disable_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_swint),   (mp_obj_t)&exti_obj_swint_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_regs),    (mp_obj_t)&exti_regs_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_IRQ_RISING),         MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_IRQ_FALLING),        MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_FALLING) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_IRQ_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING_FALLING) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_EVT_RISING),         MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_RISING) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_EVT_FALLING),        MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_FALLING) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_MODE_EVT_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_RISING_FALLING) },
-};
-
-STATIC MP_DEFINE_CONST_DICT(exti_locals_dict, exti_locals_dict_table);
-
-// line_obj = pyb.Exti(pin, mode, trigger, callback)
+// line_obj = pyb.ExtInt(pin, mode, trigger, callback)
 
-STATIC mp_obj_t exti_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
-    // type_in == exti_obj_type
+STATIC mp_obj_t extint_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    // type_in == extint_obj_type
 
     mp_check_nargs(n_args, 4, 4, n_kw, false);
 
-    exti_obj_t *self = m_new_obj(exti_obj_t);
+    extint_obj_t *self = m_new_obj(extint_obj_t);
     self->base.type = type_in;
     mp_obj_t line_obj = args[0];
     mp_obj_t mode_obj = args[1];
     mp_obj_t trigger_obj = args[2];
     mp_obj_t callback_obj = args[3];
-    self->line = exti_register(line_obj, mode_obj, trigger_obj, callback_obj, false, NULL);
+    self->line = extint_register(line_obj, mode_obj, trigger_obj, callback_obj, false, NULL);
 
     return self;
 }
 
-STATIC void exti_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
-    exti_obj_t *self = self_in;
-    print(env, "<Exti line=%u>", self->line);
+STATIC void extint_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    extint_obj_t *self = self_in;
+    print(env, "<ExtInt line=%u>", self->line);
 }
 
-const mp_obj_type_t exti_obj_type = {
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_line_obj,    extint_obj_line);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_enable_obj,  extint_obj_enable);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_disable_obj, extint_obj_disable);
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(extint_obj_swint_obj,   extint_obj_swint);
+STATIC MP_DEFINE_CONST_FUN_OBJ_0(extint_regs_fun_obj,    extint_regs);
+STATIC MP_DEFINE_CONST_STATICMETHOD_OBJ(extint_regs_obj, (mp_obj_t)&extint_regs_fun_obj);
+
+STATIC const mp_map_elem_t extint_locals_dict_table[] = {
+    { MP_OBJ_NEW_QSTR(MP_QSTR_line),    (mp_obj_t)&extint_obj_line_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_enable),  (mp_obj_t)&extint_obj_enable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_disable), (mp_obj_t)&extint_obj_disable_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_swint),   (mp_obj_t)&extint_obj_swint_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_regs),    (mp_obj_t)&extint_regs_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING),         MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_FALLING),        MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_FALLING) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_IRQ_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_IT_RISING_FALLING) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_EVT_RISING),         MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_RISING) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_EVT_FALLING),        MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_FALLING) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_EVT_RISING_FALLING), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_EVT_RISING_FALLING) },
+};
+
+STATIC MP_DEFINE_CONST_DICT(extint_locals_dict, extint_locals_dict_table);
+
+const mp_obj_type_t extint_type = {
     { &mp_type_type },
-    .name = MP_QSTR_Exti,
-    .print = exti_obj_print,
-    .make_new = exti_make_new,
-    .locals_dict = (mp_obj_t)&exti_locals_dict,
+    .name = MP_QSTR_ExtInt,
+    .print = extint_obj_print,
+    .make_new = extint_make_new,
+    .locals_dict = (mp_obj_t)&extint_locals_dict,
 };
 
-void exti_init(void) {
-    for (exti_vector_t *v = exti_vector; v < &exti_vector[EXTI_NUM_VECTORS]; v++) {
+void extint_init(void) {
+    for (extint_vector_t *v = extint_vector; v < &extint_vector[EXTI_NUM_VECTORS]; v++) {
         v->callback_obj = mp_const_none;
         v->param = NULL;
         v->mode = EXTI_Mode_Interrupt;
@@ -306,7 +306,7 @@ void Handle_EXTI_Irq(uint32_t line) {
     if (__HAL_GPIO_EXTI_GET_FLAG(1 << line)) {
         __HAL_GPIO_EXTI_CLEAR_FLAG(1 << line);
         if (line < EXTI_NUM_VECTORS) {
-            exti_vector_t *v = &exti_vector[line];
+            extint_vector_t *v = &extint_vector[line];
             if (v->callback_obj != mp_const_none) {
                 // When executing code within a handler we must lock the GC to prevent
                 // any memory allocations.  We must also catch any exceptions.
@@ -318,8 +318,8 @@ void Handle_EXTI_Irq(uint32_t line) {
                 } else {
                     // Uncaught exception; disable the callback so it doesn't run again.
                     v->callback_obj = mp_const_none;
-                    exti_disable(line);
-                    printf("Uncaught exception in EXTI interrupt handler line %lu\n", line);
+                    extint_disable(line);
+                    printf("Uncaught exception in ExtInt interrupt handler line %lu\n", line);
                     mp_obj_print_exception((mp_obj_t)nlr.ret_val);
                 }
                 gc_unlock();
diff --git a/stmhal/exti.h b/stmhal/extint.h
similarity index 70%
rename from stmhal/exti.h
rename to stmhal/extint.h
index 6feb9dceafc0c13fe9b26350304bc7b2d97f5767..c64931211f1df768f02df78ef5691c7280166fd3 100644
--- a/stmhal/exti.h
+++ b/stmhal/extint.h
@@ -20,19 +20,14 @@
 #define EXTI_TRIGGER_FALLING        (offsetof(EXTI_TypeDef, FTSR))
 #define EXTI_TRIGGER_RISING_FALLING (EXTI_TRIGGER_RISING + EXTI_TRIGGER_FALLING)  // just different from RISING or FALLING
 
-void exti_init(void);
+void extint_init(void);
 
-uint exti_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param);
+uint extint_register(mp_obj_t pin_obj, mp_obj_t mode_obj, mp_obj_t trigger_obj, mp_obj_t callback_obj, bool override_callback_obj, void *param);
 
-void exti_enable(uint line);
-void exti_disable(uint line);
-void exti_swint(uint line);
+void extint_enable(uint line);
+void extint_disable(uint line);
+void extint_swint(uint line);
 
 void Handle_EXTI_Irq(uint32_t line);
 
-typedef struct {
-  mp_obj_t callback;
-  void *param;
-} exti_t;
-
-extern const mp_obj_type_t exti_obj_type;
+extern const mp_obj_type_t extint_type;
diff --git a/stmhal/gpio.c b/stmhal/gpio.c
deleted file mode 100644
index 4548dca58773aef4da068cb9a78f61769576bc28..0000000000000000000000000000000000000000
--- a/stmhal/gpio.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// This is a woefully inadequate set of bindings for GPIO control, and
-// needs to be replaced with something much better.
-
-#include <stdio.h>
-#include <string.h>
-#include <stm32f4xx_hal.h>
-
-#include "nlr.h"
-#include "misc.h"
-#include "mpconfig.h"
-#include "qstr.h"
-#include "misc.h"
-#include "parse.h"
-#include "obj.h"
-#include "compile.h"
-#include "runtime0.h"
-#include "runtime.h"
-#include "systick.h"
-#include "gpio.h"
-#include "pin.h"
-
-mp_obj_t pyb_gpio(uint n_args, mp_obj_t *args) {
-    const pin_obj_t *pin = pin_map_user_obj(args[0]);
-    if (n_args == 1) {
-        // get pin
-        return MP_OBJ_NEW_SMALL_INT(HAL_GPIO_ReadPin(pin->gpio, pin->pin_mask));
-    }
-
-    // set pin
-    HAL_GPIO_WritePin(pin->gpio, pin->pin_mask, mp_obj_is_true(args[1]));
-    return mp_const_none;
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_obj, 1, 2, pyb_gpio);
-
-mp_obj_t pyb_gpio_input(uint n_args, mp_obj_t *args) {
-    const pin_obj_t *pin = pin_map_user_obj(args[0]);
-
-    uint32_t pull = GPIO_NOPULL;
-    if (n_args > 1) {
-        pull = mp_obj_get_int(args[1]);
-    }
-    GPIO_InitTypeDef GPIO_InitStructure;
-    GPIO_InitStructure.Pin = pin->pin_mask;
-    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
-    GPIO_InitStructure.Pull = pull;
-    HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
-
-    return mp_const_none;
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_input_obj, 1, 2, pyb_gpio_input);
-
-mp_obj_t pyb_gpio_output(uint n_args, mp_obj_t *args) {
-    const pin_obj_t *pin = pin_map_user_obj(args[0]);
-
-    uint32_t mode = GPIO_MODE_OUTPUT_PP;
-    if (n_args > 1) {
-        mode = mp_obj_get_int(args[1]) == GPIO_MODE_OUTPUT_OD ?
-                 GPIO_MODE_OUTPUT_OD: GPIO_MODE_OUTPUT_PP;
-    }
-    GPIO_InitTypeDef GPIO_InitStructure;
-    GPIO_InitStructure.Pin = pin->pin_mask;
-    GPIO_InitStructure.Mode = mode;
-    GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
-    GPIO_InitStructure.Pull = GPIO_NOPULL;
-    HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
-
-    return mp_const_none;
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_gpio_output_obj, 1, 2, pyb_gpio_output);
diff --git a/stmhal/gpio.h b/stmhal/gpio.h
deleted file mode 100644
index f43adfdac0cd27cb69d522b5b7554cfdef960b36..0000000000000000000000000000000000000000
--- a/stmhal/gpio.h
+++ /dev/null
@@ -1,7 +0,0 @@
-mp_obj_t pyb_gpio(uint n_args, mp_obj_t *args);
-mp_obj_t pyb_gpio_output(uint n_args, mp_obj_t *args);
-mp_obj_t pyb_gpio_input(uint n_args, mp_obj_t *args);
-
-MP_DECLARE_CONST_FUN_OBJ(pyb_gpio_obj);
-MP_DECLARE_CONST_FUN_OBJ(pyb_gpio_input_obj);
-MP_DECLARE_CONST_FUN_OBJ(pyb_gpio_output_obj);
diff --git a/stmhal/main.c b/stmhal/main.c
index 4fa5b2a436ff2ed30098174a8b86ac1d37145c71..5d405453b122afb5a5b6076d3880b280b449a39c 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -21,7 +21,8 @@
 #include "usart.h"
 #include "timer.h"
 #include "led.h"
-#include "exti.h"
+#include "pin.h"
+#include "extint.h"
 #include "usrsw.h"
 #include "usb.h"
 #include "rtc.h"
@@ -34,7 +35,6 @@
 #include "accel.h"
 #include "servo.h"
 #include "dac.h"
-#include "pin.h"
 #if 0
 #include "pybwlan.h"
 #endif
@@ -292,10 +292,11 @@ soft_reset:
 
     readline_init();
 
-    exti_init();
+    pin_init();
+    extint_init();
 
 #if MICROPY_HW_HAS_SWITCH
-    // must come after exti_init
+    // must come after extint_init
     switch_init();
 #endif
 
@@ -304,8 +305,6 @@ soft_reset:
     lcd_init();
 #endif
 
-    pin_map_init();
-
     // local filesystem init
     {
         // try to mount the flash
diff --git a/stmhal/modpyb.c b/stmhal/modpyb.c
index be747958efecaa4b72c5d0b84074815eddf321c0..bb41f3e355ebce2cf09d660fe244b9c158ce503e 100644
--- a/stmhal/modpyb.c
+++ b/stmhal/modpyb.c
@@ -1,7 +1,7 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#include <stm32f4xx_hal.h>
+#include "stm32f4xx_hal.h"
 
 #include "misc.h"
 #include "mpconfig.h"
@@ -15,7 +15,7 @@
 #include "led.h"
 #include "gpio.h"
 #include "pin.h"
-#include "exti.h"
+#include "extint.h"
 #include "usrsw.h"
 #include "rng.h"
 #include "rtc.h"
@@ -139,6 +139,20 @@ STATIC mp_obj_t pyb_wfi(void) {
 
 MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi);
 
+STATIC mp_obj_t pyb_disable_irq(void) {
+    __disable_irq();
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq);
+
+STATIC mp_obj_t pyb_enable_irq(void) {
+    __enable_irq();
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_enable_irq_obj, pyb_enable_irq);
+
 #if 0
 STATIC void SYSCLKConfig_STOP(void) {
     /* After wake-up from STOP reconfigure the system clock */
@@ -235,6 +249,9 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_repl_info), (mp_obj_t)&pyb_set_repl_info_obj },
 
     { MP_OBJ_NEW_QSTR(MP_QSTR_wfi), (mp_obj_t)&pyb_wfi_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_disable_irq), (mp_obj_t)&pyb_disable_irq_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_enable_irq), (mp_obj_t)&pyb_enable_irq_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 },
@@ -258,6 +275,9 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_rtc_info), (mp_obj_t)&pyb_rtc_info_obj },
 #endif
 
+    { MP_OBJ_NEW_QSTR(MP_QSTR_Pin), (mp_obj_t)&pin_type },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ExtInt), (mp_obj_t)&extint_type },
+
 #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 },
@@ -274,10 +294,10 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
 
     { MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_led_type },
     { MP_OBJ_NEW_QSTR(MP_QSTR_I2C), (mp_obj_t)&pyb_i2c_type },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_Usart), (mp_obj_t)&pyb_usart_type },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_USART), (mp_obj_t)&pyb_usart_type },
 
     { MP_OBJ_NEW_QSTR(MP_QSTR_ADC), (mp_obj_t)&pyb_adc_type },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_ADC_all), (mp_obj_t)&pyb_ADC_all_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ADCAll), (mp_obj_t)&pyb_adc_all_type },
 
 #if MICROPY_HW_ENABLE_DAC
     { MP_OBJ_NEW_QSTR(MP_QSTR_DAC), (mp_obj_t)&pyb_dac_type },
@@ -290,21 +310,6 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     // input
     { MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&pyb_input_obj },
 
-    // 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_NOPULL) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP), MP_OBJ_NEW_SMALL_INT(GPIO_PULLUP) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULLDOWN) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_PUSH_PULL), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_PP) },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_OPEN_DRAIN), MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_OD) },
-
-    // EXTI bindings
-    { MP_OBJ_NEW_QSTR(MP_QSTR_Exti), (mp_obj_t)&exti_obj_type },
 };
 
 STATIC const mp_obj_dict_t pyb_module_globals = {
diff --git a/stmhal/modstm.c b/stmhal/modstm.c
index 5e72a75bb2da5a97351f87fee833c0e35a1df248..9134063428a37f16ff0a362c322c9d59465428a4 100644
--- a/stmhal/modstm.c
+++ b/stmhal/modstm.c
@@ -1,7 +1,7 @@
 #include <stdio.h>
 #include <stdint.h>
 
-#include <stm32f4xx_hal.h>
+#include "stm32f4xx_hal.h"
 
 #include "nlr.h"
 #include "misc.h"
@@ -10,11 +10,17 @@
 #include "obj.h"
 #include "modstm.h"
 
+// To use compile-time constants we are restricted to 31-bit numbers (a small int,
+// so it fits in a Micro Python object pointer).  Thus, when extracting a constant
+// from an object, we must clear the MSB.
+
 STATIC uint32_t get_read_addr(mp_obj_t addr_o, uint align) {
     uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
+    /*
     if (addr < 0x10000000) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot read from address %08x", addr));
     }
+    */
     if ((addr & (align - 1)) != 0) {
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "address %08x is not aligned to %d bytes", addr, align));
     }
@@ -24,6 +30,8 @@ STATIC uint32_t get_read_addr(mp_obj_t addr_o, uint align) {
 STATIC uint32_t get_write_addr(mp_obj_t addr_o, uint align) {
     uint32_t addr = mp_obj_get_int(addr_o) & 0x7fffffff;
     if (addr < 0x10000000) {
+        // Everything below 0x10000000 is either ROM or aliased to something higher, so we don't
+        // lose anything by restricting writes to this area, and we gain some safety.
         nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "cannot write to address %08x", addr));
     }
     if ((addr & (align - 1)) != 0) {
@@ -32,66 +40,62 @@ STATIC uint32_t get_write_addr(mp_obj_t addr_o, uint align) {
     return addr;
 }
 
-STATIC mp_obj_t stm_read8(mp_obj_t addr) {
-    uint32_t a = get_read_addr(addr, 1);
-    uint32_t v = *(uint8_t*)a;
-    return mp_obj_new_int(v);
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read8_obj, stm_read8);
-
-STATIC mp_obj_t stm_read16(mp_obj_t addr) {
-    uint32_t a = get_read_addr(addr, 2);
-    uint32_t v = *(uint16_t*)a;
-    return mp_obj_new_int(v);
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read16_obj, stm_read16);
-
-STATIC mp_obj_t stm_read32(mp_obj_t addr) {
-    uint32_t a = get_read_addr(addr, 4);
-    uint32_t v = *(uint32_t*)a;
-    return mp_obj_new_int(v);
-}
-
-STATIC MP_DEFINE_CONST_FUN_OBJ_1(stm_read32_obj, stm_read32);
+typedef struct _stm_mem_obj_t {
+    mp_obj_base_t base;
+    uint32_t elem_size; // in bytes
+} stm_mem_obj_t;
 
-STATIC mp_obj_t stm_write8(mp_obj_t addr, mp_obj_t val) {
-    uint32_t a = get_write_addr(addr, 1);
-    uint32_t v = mp_obj_get_int(val);
-    *(uint8_t*)a = v;
-    return mp_const_none;
+STATIC void stm_mem_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+    stm_mem_obj_t *self = self_in;
+    print(env, "<%u-bit memory>", 8 * self->elem_size);
 }
 
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write8_obj, stm_write8);
-
-STATIC mp_obj_t stm_write16(mp_obj_t addr, mp_obj_t val) {
-    uint32_t a = get_write_addr(addr, 2);
-    uint32_t v = mp_obj_get_int(val);
-    *(uint16_t*)a = v;
-    return mp_const_none;
+STATIC mp_obj_t stm_mem_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
+    // TODO support slice index to read/write multiple values at once
+    stm_mem_obj_t *self = self_in;
+    if (value == MP_OBJ_NULL) {
+        // delete
+        return MP_OBJ_NOT_SUPPORTED;
+    } else if (value == MP_OBJ_SENTINEL) {
+        // load
+        uint32_t addr = get_read_addr(index, self->elem_size);
+        uint32_t val;
+        switch (self->elem_size) {
+            case 1: val = (*(uint8_t*)addr); break;
+            case 2: val = (*(uint16_t*)addr); break;
+            default: val = (*(uint32_t*)addr); break;
+        }
+        return mp_obj_new_int(val);
+    } else {
+        // store
+        uint32_t addr = get_write_addr(index, self->elem_size);
+        uint32_t val = mp_obj_get_int(value);
+        switch (self->elem_size) {
+            case 1: (*(uint8_t*)addr) = val; break;
+            case 2: (*(uint16_t*)addr) = val; break;
+            default: (*(uint32_t*)addr) = val; break;
+        }
+        return mp_const_none;
+    }
 }
 
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write16_obj, stm_write16);
-
-STATIC mp_obj_t stm_write32(mp_obj_t addr, mp_obj_t val) {
-    uint32_t a = get_write_addr(addr, 4);
-    uint32_t v = mp_obj_get_int(val);
-    *(uint32_t*)a = v;
-    return mp_const_none;
-}
+STATIC const mp_obj_type_t stm_mem_type = {
+    { &mp_type_type },
+    .name = MP_QSTR_mem,
+    .print = stm_mem_print,
+    .subscr = stm_mem_subscr,
+};
 
-STATIC MP_DEFINE_CONST_FUN_OBJ_2(stm_write32_obj, stm_write32);
+STATIC const stm_mem_obj_t stm_mem8_obj = {{&stm_mem_type}, 1};
+STATIC const stm_mem_obj_t stm_mem16_obj = {{&stm_mem_type}, 2};
+STATIC const stm_mem_obj_t stm_mem32_obj = {{&stm_mem_type}, 4};
 
 STATIC const mp_map_elem_t stm_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_stm) },
 
-    { MP_OBJ_NEW_QSTR(MP_QSTR_read8), (mp_obj_t)&stm_read8_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_read16), (mp_obj_t)&stm_read16_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_read32), (mp_obj_t)&stm_read32_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_write8), (mp_obj_t)&stm_write8_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_write16), (mp_obj_t)&stm_write16_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_write32), (mp_obj_t)&stm_write32_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mem8), (mp_obj_t)&stm_mem8_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mem16), (mp_obj_t)&stm_mem16_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mem32), (mp_obj_t)&stm_mem32_obj },
 
     { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOA), MP_OBJ_NEW_SMALL_INT(GPIOA_BASE) },
     { MP_OBJ_NEW_QSTR(MP_QSTR_GPIOB), MP_OBJ_NEW_SMALL_INT(GPIOB_BASE) },
diff --git a/stmhal/pin.c b/stmhal/pin.c
index 735901c3068352d131c93ed1b9af370bc7bb54bb..ed5865d796dd2fd10950916d4fd4a04359a8d2f7 100644
--- a/stmhal/pin.c
+++ b/stmhal/pin.c
@@ -1,78 +1,330 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
-#include <stm32f4xx_hal.h>
 
+#include "stm32f4xx_hal.h"
+
+#include "nlr.h"
 #include "misc.h"
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
-
+#include "runtime.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) {
+// Usage Model:
+//
+// All Board Pins are predefined as pyb.Pin.board.Name
+//
+//   x1_pin = pyb.Pin.board.X1
+//
+//   g = pyb.gpio(pyb.Pin.board.X1, 0)
+//
+// CPU pins which correspond to the board pins are available
+// as pyb.cpu.Name. For the CPU pins, the names are the port letter
+// followed by the pin number. On the PYBV4, pyb.Pin.board.X1 and
+// pyb.Pin.cpu.B6 are the same pin.
+//
+// You can also use strings:
+//
+//   g = pyb.gpio('X1', 0)
+//
+// Users can add their own names:
+//
+//   pyb.Pin("LeftMotorDir", pyb.Pin.cpu.C12)
+//   g = pyb.gpio("LeftMotorDir", 0)
+//
+// and can query mappings
+//
+//   pin = pyb.Pin("LeftMotorDir");
+//
+// Users can also add their own mapping function:
+//
+//   def MyMapper(pin_name):
+//      if pin_name == "LeftMotorDir":
+//          return pyb.Pin.cpu.A0
+//
+//   pyb.Pin.mapper(MyMapper)
+//
+// So, if you were to call: pyb.gpio("LeftMotorDir", 0)
+// then "LeftMotorDir" is passed directly to the mapper function.
+//
+// To summarize, the following order determines how things get mapped into
+// an ordinal pin number:
+//
+// 1 - Directly specify a pin object
+// 2 - User supplied mapping function
+// 3 - User supplied mapping (object must be usable as a dictionary key)
+// 4 - Supply a string which matches a board pin
+// 5 - Supply a string which matches a CPU port/pin
+//
+// You can set pyb.Pin.debug(True) to get some debug information about
+// how a particular object gets mapped to a pin.
+
+// Pin class variables
+STATIC mp_obj_t pin_class_mapper;
+STATIC mp_obj_t pin_class_map_dict;
+STATIC bool pin_class_debug;
+
+void pin_init(void) {
+    pin_class_mapper = MP_OBJ_NULL;
+    pin_class_map_dict = MP_OBJ_NULL;
+    pin_class_debug = false;
+}
+
+// C API used to convert a user-supplied pin name into an ordinal pin number.
+const pin_obj_t *pin_find(mp_obj_t user_obj) {
+    const pin_obj_t *pin_obj;
+
+    // If a pin was provided, then use it
+    if (MP_OBJ_IS_TYPE(user_obj, &pin_type)) {
+        pin_obj = user_obj;
+        if (pin_class_debug) {
+            printf("Pin map passed pin ");
+            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+            printf("\n");
+        }
+        return pin_obj;
+    }
+
+    if (pin_class_mapper != MP_OBJ_NULL) {
+        pin_obj = mp_call_function_1(pin_class_mapper, user_obj);
+        if (pin_obj != mp_const_none) {
+            if (!MP_OBJ_IS_TYPE(pin_obj, &pin_type)) {
+                nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object"));
+            }
+            if (pin_class_debug) {
+                printf("Pin.mapper maps ");
+                mp_obj_print(user_obj, PRINT_REPR);
+                printf(" to ");
+                mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+                printf("\n");
+            }
+            return pin_obj;
+        }
+        // The pin mapping function returned mp_const_none, fall through to
+        // other lookup methods.
+    }
+
+    if (pin_class_map_dict != MP_OBJ_NULL) {
+        mp_map_t *pin_map_map = mp_obj_dict_get_map(pin_class_map_dict);
+        mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP);
+        if (elem != NULL && elem->value != NULL) {
+            pin_obj = elem->value;
+            if (pin_class_debug) {
+                printf("Pin.map_dict maps ");
+                mp_obj_print(user_obj, PRINT_REPR);
+                printf(" to ");
+                mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+                printf("\n");
+            }
+            return pin_obj;
+        }
+    }
+
+    // See if the pin name matches a board pin
+    const char *pin_name = mp_obj_str_get_str(user_obj);
+    pin_obj = pin_find_named_pin(pin_board_pins, pin_name);
+    if (pin_obj) {
+        if (pin_class_debug) {
+            printf("Pin.board maps ");
+            mp_obj_print(user_obj, PRINT_REPR);
+            printf(" to ");
+            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+            printf("\n");
+        }
+        return pin_obj;
+    }
+
+    // See if the pin name matches a cpu pin
+    pin_obj = pin_find_named_pin(pin_cpu_pins, pin_name);
+    if (pin_obj) {
+        if (pin_class_debug) {
+            printf("Pin.cpu maps ");
+            mp_obj_print(user_obj, PRINT_REPR);
+            printf(" to ");
+            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
+            printf("\n");
+        }
+        return pin_obj;
+    }
+
+    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name));
+}
+
+STATIC void pin_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 constructor
+STATIC mp_obj_t pin_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    mp_check_nargs(n_args, 1, 3, n_kw, false);
+
+    // Run an argument through the mapper and return the result.
+    const pin_obj_t *pin = pin_find(args[0]);
+
+    if (n_args >= 2) {
+        // pin mode given, so configure this GPIO
+
+        // get io mode
+        uint mode = mp_obj_get_int(args[1]);
+        if (!IS_GPIO_MODE(mode)) {
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin mode: %d", mode));
+        }
+
+        // get pull mode
+        uint pull = GPIO_NOPULL;
+        if (n_args >= 3) {
+            pull = mp_obj_get_int(args[2]);
+            if (!IS_GPIO_PULL(pull)) {
+                nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid pin pull: %d", pull));
+            }
+        }
+
+        // configure the GPIO as requested
+        GPIO_InitTypeDef GPIO_InitStructure;
+        GPIO_InitStructure.Pin = pin->pin_mask;
+        GPIO_InitStructure.Mode = mode;
+        GPIO_InitStructure.Pull = pull;
+        GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+        GPIO_InitStructure.Alternate = 0;
+        HAL_GPIO_Init(pin->gpio, &GPIO_InitStructure);
+    }
+
+    return (mp_obj_t)pin;
+}
+
+// class method
+STATIC mp_obj_t pin_mapper(uint n_args, mp_obj_t *args) {
+    if (n_args > 1) {
+        pin_class_mapper = args[1];
+        return mp_const_none;
+    }
+    return pin_class_mapper;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_mapper_fun_obj, 1, 2, pin_mapper);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_mapper_obj, (mp_obj_t)&pin_mapper_fun_obj);
+
+// class method
+STATIC mp_obj_t pin_map_dict(uint n_args, mp_obj_t *args) {
+    if (n_args > 1) {
+        pin_class_map_dict = args[1];
+        return mp_const_none;
+    }
+    return pin_class_map_dict;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_dict_fun_obj, 1, 2, pin_map_dict);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_map_dict_obj, (mp_obj_t)&pin_map_dict_fun_obj);
+
+// class method
+STATIC mp_obj_t pin_debug(uint n_args, mp_obj_t *args) {
+    if (n_args > 1) {
+        pin_class_debug = mp_obj_is_true(args[1]);
+        return mp_const_none;
+    }
+    return MP_BOOL(pin_class_debug);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_debug_fun_obj, 1, 2, pin_debug);
+STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(pin_debug_obj, (mp_obj_t)&pin_debug_fun_obj);
+
+STATIC mp_obj_t pin_value(uint n_args, mp_obj_t *args) {
+    pin_obj_t *self = args[0];
+    if (n_args == 1) {
+        // get pin
+        return MP_OBJ_NEW_SMALL_INT((self->gpio->IDR >> self->port) & 1);
+    } else {
+        // set pin
+        if (mp_obj_is_true(args[1])) {
+            self->gpio->BSRRL = self->pin_mask;
+        } else {
+            self->gpio->BSRRH = self->pin_mask;
+        }
+        return mp_const_none;
+    }
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_value_obj, 1, 2, pin_value);
+
+STATIC mp_obj_t pin_low(mp_obj_t self_in) {
+    pin_obj_t *self = self_in;
+    self->gpio->BSRRH = self->pin_mask;
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_low_obj, pin_low);
+
+STATIC mp_obj_t pin_high(mp_obj_t self_in) {
+    pin_obj_t *self = self_in;
+    self->gpio->BSRRL = self->pin_mask;
+    return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_high_obj, pin_high);
+
+STATIC mp_obj_t pin_name(mp_obj_t self_in) {
     pin_obj_t *self = self_in;
     return MP_OBJ_NEW_QSTR(qstr_from_str(self->name));
 }
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_name_obj, pin_name);
 
-mp_obj_t pin_obj_port(mp_obj_t self_in) {
+STATIC mp_obj_t pin_port(mp_obj_t self_in) {
     pin_obj_t *self = self_in;
     return MP_OBJ_NEW_SMALL_INT((mp_small_int_t)self->port);
 }
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_port_obj, pin_port);
 
-mp_obj_t pin_obj_pin(mp_obj_t self_in) {
+STATIC mp_obj_t pin_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_pin_obj, pin_pin);
+
+STATIC const mp_map_elem_t pin_locals_dict_table[] = {
+    // instance methods
+    { MP_OBJ_NEW_QSTR(MP_QSTR_value),   (mp_obj_t)&pin_value_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_low),     (mp_obj_t)&pin_low_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_high),    (mp_obj_t)&pin_high_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_name),    (mp_obj_t)&pin_name_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_port),    (mp_obj_t)&pin_port_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pin),     (mp_obj_t)&pin_pin_obj },
+
+    // class methods
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mapper),  (mp_obj_t)&pin_mapper_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_dict),    (mp_obj_t)&pin_map_dict_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_debug),   (mp_obj_t)&pin_debug_obj },
 
-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);
+    // class attributes
+    { MP_OBJ_NEW_QSTR(MP_QSTR_board),   (mp_obj_t)&pin_board_pins_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_cpu),     (mp_obj_t)&pin_cpu_pins_obj },
 
-static const mp_method_t pin_methods[] = {
-    { "name", &pin_obj_name_obj },
-    { "port", &pin_obj_port_obj },
-    { "pin", &pin_obj_pin_obj },
-    { NULL, NULL },
+    // class constants
+    { MP_OBJ_NEW_QSTR(MP_QSTR_IN),        MP_OBJ_NEW_SMALL_INT(GPIO_MODE_INPUT) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_OUT_PP),    MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_PP) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_OUT_OD),    MP_OBJ_NEW_SMALL_INT(GPIO_MODE_OUTPUT_OD) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_AF_PP),     MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_PP) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_AF_OD),     MP_OBJ_NEW_SMALL_INT(GPIO_MODE_AF_OD) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_ANALOG),    MP_OBJ_NEW_SMALL_INT(GPIO_MODE_ANALOG) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_NONE), MP_OBJ_NEW_SMALL_INT(GPIO_NOPULL) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_UP),   MP_OBJ_NEW_SMALL_INT(GPIO_PULLUP) },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_PULL_DOWN), MP_OBJ_NEW_SMALL_INT(GPIO_PULLDOWN) },
 };
-#endif
 
-const mp_obj_type_t pin_obj_type = {
-#if 0
+STATIC MP_DEFINE_CONST_DICT(pin_locals_dict, pin_locals_dict_table);
+
+const mp_obj_type_t pin_type = {
     { &mp_type_type },
-#else
-    { NULL },
-#endif
     .name = MP_QSTR_Pin,
-#if 0
-    .print = pin_obj_print,
-    .methods = pin_methods,
-#endif
+    .print = pin_print,
+    .make_new = pin_make_new,
+    .locals_dict = (mp_obj_t)&pin_locals_dict,
 };
 
-#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) {
+STATIC 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
+const mp_obj_type_t pin_af_type = {
     { &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
index 2aa50655b4526b082b62a9a6357423f136c616cb..0617b13a723096cd893a73a70f4f0b640b34267c 100644
--- a/stmhal/pin.h
+++ b/stmhal/pin.h
@@ -86,40 +86,29 @@ typedef struct {
   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;
+extern const mp_obj_type_t pin_type;
+extern const mp_obj_type_t pin_af_type;
 
 typedef struct {
-  const char  *name;
+  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;
+//extern pin_map_obj_t pin_map_obj;
 
 typedef struct {
     mp_obj_base_t base;
-    const char *name;
+    qstr 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;
 
+void pin_init(void);
+const pin_obj_t *pin_find(mp_obj_t user_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/pin_map.c b/stmhal/pin_map.c
deleted file mode 100644
index c0c6910b2e04c3910b00f571d540f8168b044f91..0000000000000000000000000000000000000000
--- a/stmhal/pin_map.c
+++ /dev/null
@@ -1,226 +0,0 @@
-#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 "runtime.h"
-#include "nlr.h"
-
-#include "pin.h"
-
-// Usage Model:
-//
-// All Board Pins are predefined as pyb.Pin.board.Name
-//
-//   x1_pin = pyb.Pin.board.X1
-//
-//   g = pyb.gpio(pyb.Pin.board.X1, 0)
-//
-// CPU pins which correspond to the board pins are available
-// as pyb.cpu.Name. For the CPU pins, the names are the port letter
-// followed by the pin number. On the PYBV4, pyb.Pin.board.X1 and
-// pyb.Pin.cpu.B6 are the same pin.
-//
-// You can also use strings:
-//
-//   g = pyb.gpio('X1', 0)
-//
-// Users can add their own names:
-//
-//   pyb.Pin("LeftMotorDir", pyb.Pin.cpu.C12)
-//   g = pyb.gpio("LeftMotorDir", 0)
-//
-// and can query mappings
-//
-//   pin = pyb.Pin("LeftMotorDir");
-//
-// Users can also add their own mapping function:
-//
-//   def MyMapper(pin_name):
-//      if pin_name == "LeftMotorDir":
-//          return pyb.Pin.cpu.A0
-//
-//   pyb.Pin.mapper(MyMapper)
-//
-// So, if you were to call: pyb.gpio("LeftMotorDir", 0)
-// then "LeftMotorDir" is passed directly to the mapper function.
-//
-// To summarize, the following order determines how things get mapped into
-// an ordinal pin number:
-//
-// 1 - Directly specify a pin object
-// 2 - User supplied mapping function
-// 3 - User supplied mapping (object must be usable as a dictionary key)
-// 4 - Supply a string which matches a board pin
-// 5 - Supply a string which matches a CPU port/pin
-//
-// You can set pyb.Pin.debug(True) to get some debug information about
-// how a particular object gets mapped to a pin.
-
-static void pin_map_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
-    (void)self_in;
-    print(env, "<PinMap>");
-}
-
-static mp_obj_t pin_map_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
-    pin_map_obj_t *self = self_in;
-    mp_check_nargs(n_args, 1, 2, n_kw, false);
-
-    if (n_args > 1) {
-        if (!self->map_dict) {
-            self->map_dict = mp_obj_new_dict(1);
-        }
-        mp_obj_dict_store(self->map_dict, args[0], args[1]);
-        return mp_const_none;
-    }
-
-    // Run an argument through the mapper and return the result.
-    return (mp_obj_t)pin_map_user_obj(args[0]);
-}
-
-static mp_obj_t pin_map_obj_mapper(uint n_args, mp_obj_t *args) {
-    pin_map_obj_t *self = args[0];
-    if (n_args > 1) {
-        self->mapper = args[1];
-        return mp_const_none;
-    }
-    return self->mapper;
-}
-static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_obj_mapper_obj, 1, 2, pin_map_obj_mapper);
-
-static mp_obj_t pin_map_obj_debug(uint n_args, mp_obj_t *args) {
-    pin_map_obj_t *self = args[0];
-    if (n_args > 1) {
-        self->debug = mp_obj_is_true(args[1]);
-        return mp_const_none;
-    }
-    return MP_BOOL(self->debug);
-}
-static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pin_map_obj_debug_obj, 1, 2, pin_map_obj_debug);
-
-static void pin_map_load_attr(mp_obj_t self_in, qstr attr_qstr, mp_obj_t *dest) {
-    (void)self_in;
-    const char *attr = qstr_str(attr_qstr);
-
-    if (strcmp(attr, "mapper") == 0) {
-        dest[0] = (mp_obj_t)&pin_map_obj_mapper_obj;
-        dest[1] = self_in;
-    }
-    if (strcmp(attr, "debug") == 0) {
-        dest[0] = (mp_obj_t)&pin_map_obj_debug_obj;
-        dest[1] = self_in;
-    }
-    if (strcmp(attr, pin_board_pins_obj.name) == 0) {
-        dest[0] = (mp_obj_t)&pin_board_pins_obj;
-        dest[1] = MP_OBJ_NULL;
-    }
-    if (strcmp(attr, pin_cpu_pins_obj.name) == 0) {
-        dest[0] = (mp_obj_t)&pin_cpu_pins_obj;
-        dest[1] = MP_OBJ_NULL;
-    }
-}
-
-static const mp_obj_type_t pin_map_obj_type = {
-    { &mp_type_type },
-    .name = MP_QSTR_PinMap,
-    .print = pin_map_obj_print,
-    .call = pin_map_call,
-    .load_attr = pin_map_load_attr,
-};
-
-static const pin_map_obj_t pin_map_obj_init = {
-    { &pin_map_obj_type },
-    .mapper = MP_OBJ_NULL,
-    .map_dict = MP_OBJ_NULL,
-    .debug = false,
-};
-
-pin_map_obj_t pin_map_obj;
-
-void pin_map_init(void) {
-    pin_map_obj = pin_map_obj_init;
-}
-
-// C API used to convert a user-supplied pin name  into an ordinal pin number.
-const pin_obj_t *pin_map_user_obj(mp_obj_t user_obj) {
-    const pin_obj_t *pin_obj;
-
-    // If a pin was provided, then use it
-    if (MP_OBJ_IS_TYPE(user_obj, &pin_obj_type)) {
-        pin_obj = user_obj;
-        if (pin_map_obj.debug) {
-            printf("Pin map passed pin ");
-            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
-            printf("\n");
-        }
-        return pin_obj;
-    }
-
-    if (pin_map_obj.mapper) {
-        pin_obj = mp_call_function_1(pin_map_obj.mapper, user_obj);
-        if (pin_obj != mp_const_none) {
-            if (!MP_OBJ_IS_TYPE(pin_obj, &pin_obj_type)) {
-                nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Pin.mapper didn't return a Pin object"));
-            }
-            if (pin_map_obj.debug) {
-                printf("Pin.mapper maps ");
-                mp_obj_print(user_obj, PRINT_REPR);
-                printf(" to ");
-                mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
-                printf("\n");
-            }
-            return pin_obj;
-        }
-        // The pin mapping function returned mp_const_none, fall through to
-        // other lookup methods.
-    }
-
-    if (pin_map_obj.map_dict) {
-        mp_map_t *pin_map_map = mp_obj_dict_get_map(pin_map_obj.map_dict);
-        mp_map_elem_t *elem = mp_map_lookup(pin_map_map, user_obj, MP_MAP_LOOKUP);
-        if (elem != NULL && elem->value != NULL) {
-            pin_obj = elem->value;
-            if (pin_map_obj.debug) {
-                printf("Pin.map_dict maps ");
-                mp_obj_print(user_obj, PRINT_REPR);
-                printf(" to ");
-                mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
-                printf("\n");
-            }
-            return pin_obj;
-        }
-    }
-
-    // See if the pin name matches a board pin
-    const char *pin_name = mp_obj_str_get_str(user_obj);
-    pin_obj = pin_find_named_pin(pin_board_pins, pin_name);
-    if (pin_obj) {
-        if (pin_map_obj.debug) {
-            printf("Pin.board maps ");
-            mp_obj_print(user_obj, PRINT_REPR);
-            printf(" to ");
-            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
-            printf("\n");
-        }
-        return pin_obj;
-    }
-
-    // See if the pin name matches a cpu pin
-    pin_obj = pin_find_named_pin(pin_cpu_pins, pin_name);
-    if (pin_obj) {
-        if (pin_map_obj.debug) {
-            printf("Pin.cpu maps ");
-            mp_obj_print(user_obj, PRINT_REPR);
-            printf(" to ");
-            mp_obj_print((mp_obj_t)pin_obj, PRINT_STR);
-            printf("\n");
-        }
-        return pin_obj;
-    }
-
-    nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "pin '%s' not a valid pin identifier", pin_name));
-}
diff --git a/stmhal/pin_named_pins.c b/stmhal/pin_named_pins.c
index 48906ad8007c8aa4860f04c17191756144089aa1..6e81bb7424374ac229c05328659d0efd4c656e50 100644
--- a/stmhal/pin_named_pins.c
+++ b/stmhal/pin_named_pins.c
@@ -1,22 +1,22 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <string.h>
-#include <stm32f4xx_hal.h>
+
+#include "stm32f4xx_hal.h"
 
 #include "misc.h"
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
 #include "runtime.h"
-
 #include "pin.h"
 
-static void pin_named_pins_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
+STATIC void pin_named_pins_obj_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
     pin_named_pins_obj_t *self = self_in;
-    print(env, "<Pin.%s>", self->name);
+    print(env, "<Pin.%s>", qstr_str(self->name));
 }
 
-static void pin_named_pins_obj_load_attr(mp_obj_t self_in, qstr attr_qstr, mp_obj_t *dest) {
+STATIC void pin_named_pins_obj_load_attr(mp_obj_t self_in, qstr attr_qstr, mp_obj_t *dest) {
     pin_named_pins_obj_t *self = self_in;
     const char *attr = qstr_str(attr_qstr);
     const pin_obj_t *pin = pin_find_named_pin(self->named_pins, attr);
@@ -35,13 +35,13 @@ static const mp_obj_type_t pin_named_pins_obj_type = {
 
 const pin_named_pins_obj_t pin_board_pins_obj = {
     { &pin_named_pins_obj_type },
-    .name = "board",
+    .name = MP_QSTR_board,
     .named_pins = pin_board_pins,
 };
 
 const pin_named_pins_obj_t pin_cpu_pins_obj = {
     { &pin_named_pins_obj_type },
-    .name = "cpu",
+    .name = MP_QSTR_cpu,
     .named_pins = pin_cpu_pins,
 };
 
diff --git a/stmhal/qstrdefsport.h b/stmhal/qstrdefsport.h
index d64b0c2ddb3f2307270d12598b846d8e4c68ac5b..f2ba3669ecc61bc78b4f9ad5c29521996e25b96a 100644
--- a/stmhal/qstrdefsport.h
+++ b/stmhal/qstrdefsport.h
@@ -7,6 +7,8 @@ Q(sd_test)
 Q(present)
 Q(power)
 Q(wfi)
+Q(disable_irq)
+Q(enable_irq)
 Q(stop)
 Q(standby)
 Q(source_dir)
@@ -38,19 +40,34 @@ Q(gpio_out)
 Q(FileIO)
 // Entries for sys.path
 Q(0:/)
-Q(0:/src)
 Q(0:/lib)
+Q(rtc_info)
+Q(millis)
+
+// for Pin class
 Q(Pin)
-Q(PinMap)
 Q(PinAF)
 Q(PinNamed)
-Q(rtc_info)
-Q(millis)
+Q(value)
+Q(low)
+Q(high)
+Q(name)
+Q(port)
+Q(pin)
+Q(mapper)
+Q(dict)
+Q(debug)
+Q(board)
+Q(cpu)
+Q(IN)
+Q(OUT_PP)
+Q(OUT_OD)
+Q(AF_PP)
+Q(AF_OD)
+Q(ANALOG)
 Q(PULL_NONE)
 Q(PULL_UP)
 Q(PULL_DOWN)
-Q(PUSH_PULL)
-Q(OPEN_DRAIN)
 
 // for Led object
 Q(Led)
@@ -59,26 +76,26 @@ Q(off)
 Q(toggle)
 Q(intensity)
 
-// for Usart object
-Q(Usart)
+// for USART object
+Q(USART)
 Q(status)
 Q(recv_chr)
 Q(send_chr)
 Q(send)
 
-// for exti object
-Q(Exti)
+// for ExtInt class
+Q(ExtInt)
 Q(line)
 Q(enable)
 Q(disable)
 Q(swint)
 Q(regs)
-Q(MODE_IRQ_RISING)
-Q(MODE_IRQ_FALLING)
-Q(MODE_IRQ_RISING_FALLING)
-Q(MODE_EVT_RISING)
-Q(MODE_EVT_FALLING)
-Q(MODE_EVT_RISING_FALLING)
+Q(IRQ_RISING)
+Q(IRQ_FALLING)
+Q(IRQ_RISING_FALLING)
+Q(EVT_RISING)
+Q(EVT_FALLING)
+Q(EVT_RISING_FALLING)
 
 // for I2C object
 Q(I2C)
@@ -97,7 +114,7 @@ Q(filtered_xyz)
 
 // for ADC object
 Q(ADC)
-Q(ADC_all)
+Q(ADCAll)
 Q(read_timed)
 Q(read_channel)
 Q(read_core_temp)
@@ -137,12 +154,10 @@ Q(input)
 
 // for stm module
 Q(stm)
-Q(read8)
-Q(read16)
-Q(read32)
-Q(write8)
-Q(write16)
-Q(write32)
+Q(mem)
+Q(mem8)
+Q(mem16)
+Q(mem32)
 Q(GPIOA)
 Q(GPIOB)
 Q(GPIOC)
diff --git a/stmhal/stm32f4xx_it.c b/stmhal/stm32f4xx_it.c
index df69f52b8e5298a5f53ecb4fb203c5919c26a257..9b64f6165c32cfc53100757628469d27b9d3166e 100644
--- a/stmhal/stm32f4xx_it.c
+++ b/stmhal/stm32f4xx_it.c
@@ -47,7 +47,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
-#include "exti.h"
+#include "extint.h"
 #include "timer.h"
 #include "storage.h"
 
diff --git a/stmhal/usart.c b/stmhal/usart.c
index cc0a6112e659fcd79e99357925c3e57023336219..89770942be4f4214cf5d0307fb17a36cdd5b502b 100644
--- a/stmhal/usart.c
+++ b/stmhal/usart.c
@@ -165,13 +165,13 @@ void usart_tx_strn_cooked(pyb_usart_obj_t *usart_obj, const char *str, uint len)
 
 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);
+    print(env, "<USART %lu>", self->usart_id);
 }
 
 STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
     // check arguments
     if (!(n_args == 2 && n_kw == 0)) {
-        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "Usart accepts 2 arguments"));
+        nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "USART accepts 2 arguments"));
     }
 
     // create object
@@ -194,7 +194,7 @@ STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
             o->usart_id = PYB_USART_YB;
 #endif
         } else {
-            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Usart port %s does not exist", port));
+            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %s does not exist", port));
         }
     } else {
         o->usart_id = mp_obj_get_int(args[0]);
@@ -202,7 +202,7 @@ STATIC mp_obj_t usart_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, con
 
     // init USART (if it fails, it's because the port doesn't exist)
     if (!usart_init(o, mp_obj_get_int(args[1]))) {
-        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "Usart port %d does not exist", o->usart_id));
+        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "USART port %d does not exist", o->usart_id));
     }
 
     o->is_enabled = true;
@@ -267,7 +267,7 @@ STATIC MP_DEFINE_CONST_DICT(usart_locals_dict, usart_locals_dict_table);
 
 const mp_obj_type_t pyb_usart_type = {
     { &mp_type_type },
-    .name = MP_QSTR_Usart,
+    .name = MP_QSTR_USART,
     .print = usart_obj_print,
     .make_new = usart_obj_make_new,
     .locals_dict = (mp_obj_t)&usart_locals_dict,
diff --git a/stmhal/usrsw.c b/stmhal/usrsw.c
index 0ab407cd96ff5256b4c77e780b7196821123d022..6e73cf69b4d3adb6fe0b06b1714adebe7f276e83 100644
--- a/stmhal/usrsw.c
+++ b/stmhal/usrsw.c
@@ -8,7 +8,7 @@
 #include "runtime.h"
 #include "usrsw.h"
 
-#include "exti.h"
+#include "extint.h"
 #include "gpio.h"
 #include "pin.h"
 #include "genhdr/pins.h"
@@ -70,12 +70,11 @@ static mp_obj_t pyb_switch(uint n_args, mp_obj_t *args) {
         // Init the EXTI each time this function is called, since the EXTI
         // may have been disabled by an exception in the interrupt, or the
         // user disabling the line explicitly.
-        exti_register((mp_obj_t)&MICROPY_HW_USRSW_PIN,
-                      MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_EXTI_MODE),
-                      MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_PULL),
-                      switch_user_callback_obj == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
-                      true,
-                      NULL);
+        extint_register((mp_obj_t)&MICROPY_HW_USRSW_PIN,
+                        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_EXTI_MODE),
+                        MP_OBJ_NEW_SMALL_INT(MICROPY_HW_USRSW_PULL),
+                        switch_user_callback_obj == mp_const_none ? mp_const_none : (mp_obj_t)&switch_callback_obj,
+                        true, NULL);
         return mp_const_none;
     }
 }