diff --git a/stmhal/Makefile b/stmhal/Makefile
index 85f4ce2e33482ba220e3d66e298b1fd1d9f6d7ff..75f080587f197bb228d34bab51cc196ad841d469 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -238,6 +238,7 @@ GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
 GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
 GEN_PINS_QSTR = $(BUILD)/pins_qstr.h
 GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
+GEN_PINS_AF_PY = $(BUILD)/pins_af.py
 
 INSERT_USB_IDS = ../tools/insert-usb-ids.py
 FILE2H = ../tools/file2h.py
@@ -260,7 +261,7 @@ $(BUILD)/main.o: $(GEN_CDCINF_HEADER)
 # both pins_$(BOARD).c and pins.h
 $(BUILD)/%_$(BOARD).c $(HEADER_BUILD)/%.h $(HEADER_BUILD)/%_af_const.h $(BUILD)/%_qstr.h: boards/$(BOARD)/%.csv $(MAKE_PINS) $(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
 	$(ECHO) "Create $@"
-	$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) > $(GEN_PINS_SRC)
+	$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af $(AF_FILE) --prefix $(PREFIX_FILE) --hdr $(GEN_PINS_HDR) --qstr $(GEN_PINS_QSTR) --af-const $(GEN_PINS_AF_CONST) --af-py $(GEN_PINS_AF_PY) > $(GEN_PINS_SRC)
 
 $(BUILD)/pins_$(BOARD).o: $(BUILD)/pins_$(BOARD).c
 	$(call compile_c)
diff --git a/stmhal/boards/make-pins.py b/stmhal/boards/make-pins.py
index cc580f7cd7d1b30caf17e12b291ead09a92a5c09..44da266ae14e9ff963d723351ee88f79e495a7c6 100755
--- a/stmhal/boards/make-pins.py
+++ b/stmhal/boards/make-pins.py
@@ -315,6 +315,17 @@ class Pins(object):
                 print('    { %-*s %s },' % (mux_name_width + 26, key, val),
                       file=af_const_file)
 
+    def print_af_py(self, af_py_filename):
+        with open(af_py_filename,  'wt') as af_py_file:
+            print('PINS_AF = (', file=af_py_file);
+            for named_pin in self.board_pins:
+                print("  ('%s', " % named_pin.name(), end='', file=af_py_file)
+                for af in named_pin.pin().alt_fn:
+                    if af.is_supported():
+                        print("(%d, '%s'), " % (af.idx, af.af_str), end='', file=af_py_file)
+                print('),', file=af_py_file)
+            print(')',  file=af_py_file)
+
 
 def main():
     parser = argparse.ArgumentParser(
@@ -334,6 +345,12 @@ def main():
         help="Specifies header file for alternate function constants.",
         default="build/pins_af_const.h"
     )
+    parser.add_argument(
+        "--af-py",
+        dest="af_py_filename",
+        help="Specifies the filename for the python alternate function mappings.",
+        default="build/pins_af.py"
+    )
     parser.add_argument(
         "-b", "--board",
         dest="board_filename",
@@ -383,6 +400,7 @@ def main():
     pins.print_header(args.hdr_filename)
     pins.print_qstr(args.qstr_filename)
     pins.print_af_hdr(args.af_const_filename)
+    pins.print_af_py(args.af_py_filename)
 
 
 if __name__ == "__main__":
diff --git a/stmhal/pin.c b/stmhal/pin.c
index bf64d40e87499394608c0194ffed7dded9741cd5..3cbb3a3b49e201f1adc93f0c56bc8742ef768b87 100644
--- a/stmhal/pin.c
+++ b/stmhal/pin.c
@@ -508,6 +508,33 @@ STATIC mp_obj_t pin_gpio(mp_obj_t self_in) {
 }
 STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_gpio_obj, pin_gpio);
 
+/// \method mode()
+/// Returns the currently configured mode of the pin. The integer returned
+/// will match one of the allowed constants for the mode argument to the init
+/// function.
+STATIC mp_obj_t pin_mode(mp_obj_t self_in) {
+    return MP_OBJ_NEW_SMALL_INT(pin_get_mode(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_mode_obj, pin_mode);
+
+/// \method pull()
+/// Returns the currently configured pull of the pin. The integer returned
+/// will match one of the allowed constants for the pull argument to the init
+/// function.
+STATIC mp_obj_t pin_pull(mp_obj_t self_in) {
+    return MP_OBJ_NEW_SMALL_INT(pin_get_pull(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_pull_obj, pin_pull);
+
+/// \method af()
+/// Returns the currently configured af of the pin. The integer returned
+/// will match one of the allowed constants for the af argument to the init
+/// function.
+STATIC mp_obj_t pin_af(mp_obj_t self_in) {
+    return MP_OBJ_NEW_SMALL_INT(pin_get_af(self_in));
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_1(pin_af_obj, pin_af);
+
 STATIC const mp_map_elem_t pin_locals_dict_table[] = {
     // instance methods
     { MP_OBJ_NEW_QSTR(MP_QSTR_init),    (mp_obj_t)&pin_init_obj },
@@ -520,6 +547,9 @@ STATIC const mp_map_elem_t pin_locals_dict_table[] = {
     { 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 },
     { MP_OBJ_NEW_QSTR(MP_QSTR_gpio),    (mp_obj_t)&pin_gpio_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_mode),    (mp_obj_t)&pin_mode_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_pull),    (mp_obj_t)&pin_pull_obj },
+    { MP_OBJ_NEW_QSTR(MP_QSTR_af),      (mp_obj_t)&pin_af_obj },
 
     // class methods
     { MP_OBJ_NEW_QSTR(MP_QSTR_mapper),  (mp_obj_t)&pin_mapper_obj },