diff --git a/ports/card10/Makefile b/ports/card10/Makefile
index c77001c7910c618866bf7910cc4c50f1243490c1..08d623493edcd83338240395bd2cbeed53e7d539 100644
--- a/ports/card10/Makefile
+++ b/ports/card10/Makefile
@@ -46,6 +46,7 @@ SRC_C = \
 	main.c \
 	uart_core.c \
 	buzzer.c \
+	leds.c \
 	modutime.c \
 	systick.c \
 	lib/utils/printf.c \
@@ -56,8 +57,8 @@ SRC_C = \
 
 OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
 
-SRC_QSTR += buzzer.c modutime.c
-USER_C_MODULES += buzzer.c modutime.c
+SRC_QSTR += buzzer.c leds.c modutime.c
+USER_C_MODULES += buzzer.c leds.c modutime.c
 
 # SDK compilation hack
 
diff --git a/ports/card10/leds.c b/ports/card10/leds.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7a670fe974129c8154935736bbe300e85182470
--- /dev/null
+++ b/ports/card10/leds.c
@@ -0,0 +1,63 @@
+#include "py/obj.h"
+#include "py/runtime.h"
+#include "py/builtin.h"
+#include <stdio.h>
+
+STATIC mp_obj_t mp_leds_set(size_t n_args, const mp_obj_t *args)
+{
+	assert (n_args == 4);
+	int led = mp_obj_get_int (args[0]);
+	int r = mp_obj_get_int (args[1]);
+	int g = mp_obj_get_int (args[2]);
+	int b = mp_obj_get_int (args[3]);
+
+	if ( (0 > led || 256 < led) &&
+	     (0 >   r || 256 <   r) &&
+	     (0 >   g || 256 <   g) &&
+	     (0 >   b || 256 <   b) )
+	{
+		mp_raise_ValueError("out of bounds");
+	}
+	printf("Set %u to (%x %x %x)\n", led, r, g, b);
+	leds_set (led, r, g, b);
+	leds_update ();
+
+	return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(leds_set_obj, 4, 4, mp_leds_set);
+
+STATIC mp_obj_t mp_leds_set_dim(mp_obj_t led_obj, mp_obj_t dim_obj)
+{
+	int led = mp_obj_get_int (led_obj);
+	int dim = mp_obj_get_int (dim_obj);
+
+	if ( (0 > led || 256 < led) &&
+	     (0 > dim || 256 < dim) )
+	{
+		mp_raise_ValueError("out of bounds");
+	}
+	leds_set_dim (led, dim);
+	return mp_const_none;
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(leds_set_dim_obj, mp_leds_set_dim);
+
+// Define all properties of the example module.
+// Table entries are key/value pairs of the attribute name (a string)
+// and the MicroPython object reference.
+// All identifiers and strings are written as MP_QSTR_xxx and will be
+// optimized to word-sized integers by the build system (interned strings).
+STATIC const mp_rom_map_elem_t leds_module_globals_table[] = {
+	{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_leds) },
+	{ MP_ROM_QSTR(MP_QSTR_set), MP_ROM_PTR(&leds_set_obj) },
+	{ MP_ROM_QSTR(MP_QSTR_set_dim), MP_ROM_PTR(&leds_set_dim_obj) },
+};
+STATIC MP_DEFINE_CONST_DICT(leds_module_globals, leds_module_globals_table);
+
+// Define module object.
+const mp_obj_module_t leds_module = {
+	.base = { &mp_type_module },
+	.globals = (mp_obj_dict_t*)&leds_module_globals,
+};
+
+// Register the module to make it available in Python
+MP_REGISTER_MODULE(MP_QSTR_leds, leds_module, MODULE_LEDS_ENABLED);
diff --git a/ports/card10/mpconfigport.h b/ports/card10/mpconfigport.h
index 39a2bdcbbb5859aee248ce6dc4475fe72d00ac66..2f7cca2b46d67e82d59f901c92a4c3777c9b2a34 100644
--- a/ports/card10/mpconfigport.h
+++ b/ports/card10/mpconfigport.h
@@ -61,6 +61,7 @@
 #define MICROPY_PY_UTIME_MP_HAL     (1)
 #define MODULE_BUZZER_ENABLED       (1)
 #define MODULE_UTIME_ENABLED        (1)
+#define MODULE_LEDS_ENABLED         (1)
 
 // type definitions for the specific machine