diff --git a/py/builtin.c b/py/builtin.c
index 2e0627fa5fc7a11f1c90bcba9a1190c96485fbe8..93e91072c4aa0cbd89c81f56f2efecfb47a8dc2b 100644
--- a/py/builtin.c
+++ b/py/builtin.c
@@ -375,28 +375,6 @@ STATIC mp_obj_t mp_builtin_sorted(uint n_args, const mp_obj_t *args, mp_map_t *k
 
 MP_DEFINE_CONST_FUN_OBJ_KW(mp_builtin_sorted_obj, 1, mp_builtin_sorted);
 
-STATIC mp_obj_t mp_builtin_str(mp_obj_t o_in) {
-    vstr_t *vstr = vstr_new();
-    mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, o_in, PRINT_STR);
-    mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
-    vstr_free(vstr);
-    return s;
-}
-
-MP_DEFINE_CONST_FUN_OBJ_1(mp_builtin_str_obj, mp_builtin_str);
-
-// TODO: This should be type, this is just quick CPython compat hack
-STATIC mp_obj_t mp_builtin_bytes(uint n_args, const mp_obj_t *args) {
-    if (!MP_OBJ_IS_QSTR(args[0]) && !MP_OBJ_IS_TYPE(args[0], &str_type)) {
-        assert(0);
-    }
-    // Currently, MicroPython strings are mix between CPython byte and unicode
-    // strings. So, conversion is null so far.
-    return args[0];
-}
-
-MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mp_builtin_bytes_obj, 1, 3, mp_builtin_bytes);
-
 STATIC mp_obj_t mp_builtin_id(mp_obj_t o_in) {
     return mp_obj_new_int((machine_int_t)o_in);
 }
diff --git a/py/builtinmath.c b/py/builtinmath.c
index fd1368ce3c609644d2a7432a7a6a40fdb7ec688f..59af5a021d851a6df906c0c2545565e6cbb87b23 100644
--- a/py/builtinmath.c
+++ b/py/builtinmath.c
@@ -46,9 +46,9 @@ MATH_FUN_1(fabs, fabs)
 MATH_FUN_1(floor, floor) //TODO: delegate to x.__floor__() if x is not a float
 MATH_FUN_2(fmod, fmod)
 //MATH_FUN_1(frexp, frexp)
-MATH_FUN_1(isfinite, isfinite)
-MATH_FUN_1(isinf, isinf)
-MATH_FUN_1(isnan, isnan)
+//MATH_FUN_1(isfinite, isfinite)
+//MATH_FUN_1(isinf, isinf)
+//MATH_FUN_1(isnan, isnan)
 MATH_FUN_1(trunc, trunc)
 
 //TODO: factorial, fsum, frexp, ldexp, modf
@@ -83,9 +83,9 @@ STATIC const mp_map_elem_t mp_module_math_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&mp_math_floor_obj },
     { MP_OBJ_NEW_QSTR(MP_QSTR_fmod), (mp_obj_t)&mp_math_fmod_obj },
     //{ MP_OBJ_NEW_QSTR(MP_QSTR_frexp), (mp_obj_t)&mp_math_frexp_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&mp_math_isfinite_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&mp_math_isinf_obj },
-    { MP_OBJ_NEW_QSTR(MP_QSTR_isnan), (mp_obj_t)&mp_math_isnan_obj },
+    //{ MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&mp_math_isfinite_obj },
+    //{ MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&mp_math_isinf_obj },
+    //{ MP_OBJ_NEW_QSTR(MP_QSTR_isnan), (mp_obj_t)&mp_math_isnan_obj },
     { MP_OBJ_NEW_QSTR(MP_QSTR_trunc), (mp_obj_t)&mp_math_trunc_obj },
 };
 
diff --git a/py/objcomplex.c b/py/objcomplex.c
index 65957cbf60dc7721537931c767d4ec504838d4c2..2ba52261504c749023ac4b9b2e3575550f5bb92c 100644
--- a/py/objcomplex.c
+++ b/py/objcomplex.c
@@ -6,6 +6,7 @@
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
+#include "parsenum.h"
 #include "runtime0.h"
 #include "map.h"
 
@@ -36,15 +37,20 @@ STATIC mp_obj_t complex_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const
             return mp_obj_new_complex(0, 0);
 
         case 1:
-            // TODO allow string as first arg and parse it
-            if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
+            if (MP_OBJ_IS_STR(args[0])) {
+                // a string, parse it
+                uint l;
+                const char *s = mp_obj_str_get_data(args[0], &l);
+                return mp_parse_num_decimal(s, l, true, true);
+            } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
+                // a complex, just return it
                 return args[0];
             } else {
+                // something else, try to cast it to a complex
                 return mp_obj_new_complex(mp_obj_get_float(args[0]), 0);
             }
 
-        case 2:
-        {
+        case 2: {
             mp_float_t real, imag;
             if (MP_OBJ_IS_TYPE(args[0], &mp_type_complex)) {
                 mp_obj_complex_get(args[0], &real, &imag);
diff --git a/py/objfloat.c b/py/objfloat.c
index 704b3d5998a7ccde7ca05732c3b3f7d43844947d..c4567c4a38d16cfee079f8595b8d2d397203c16d 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -39,10 +39,12 @@ STATIC mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const m
                 // a string, parse it
                 uint l;
                 const char *s = mp_obj_str_get_data(args[0], &l);
-                return mp_parse_num_decimal(s, l);
+                return mp_parse_num_decimal(s, l, false, false);
             } else if (MP_OBJ_IS_TYPE(args[0], &mp_type_float)) {
+                // a float, just return it
                 return args[0];
             } else {
+                // something else, try to cast it to a float
                 return mp_obj_new_float(mp_obj_get_float(args[0]));
             }
 
diff --git a/py/objstr.c b/py/objstr.c
index d660bf952b7c058ee2fd29703ac7ff88e78bb32a..35a948700c856d6fc17970562f91c6baca12be3d 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -14,9 +14,11 @@ typedef struct _mp_obj_str_t {
     mp_obj_base_t base;
     machine_uint_t hash : 16; // XXX here we assume the hash size is 16 bits (it is at the moment; see qstr.c)
     machine_uint_t len : 16; // len == number of bytes used in data, alloc = len + 1 because (at the moment) we also append a null byte
-    byte data[];
+    const byte *data;
 } mp_obj_str_t;
 
+const mp_obj_t mp_const_empty_bytes;
+
 // use this macro to extract the string hash
 #define GET_STR_HASH(str_obj_in, str_hash) uint str_hash; if (MP_OBJ_IS_QSTR(str_obj_in)) { str_hash = qstr_hash(MP_OBJ_QSTR_VALUE(str_obj_in)); } else { str_hash = ((mp_obj_str_t*)str_obj_in)->hash; }
 
@@ -28,6 +30,7 @@ typedef struct _mp_obj_str_t {
 
 STATIC mp_obj_t mp_obj_new_str_iterator(mp_obj_t str);
 STATIC mp_obj_t mp_obj_new_bytes_iterator(mp_obj_t str);
+STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len);
 
 /******************************************************************************/
 /* str                                                                        */
@@ -78,6 +81,109 @@ STATIC void str_print(void (*print)(void *env, const char *fmt, ...), void *env,
     }
 }
 
+STATIC mp_obj_t str_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    switch (n_args) {
+        case 0:
+            return MP_OBJ_NEW_QSTR(MP_QSTR_);
+
+        case 1:
+        {
+            vstr_t *vstr = vstr_new();
+            mp_obj_print_helper((void (*)(void*, const char*, ...))vstr_printf, vstr, args[0], PRINT_STR);
+            mp_obj_t s = mp_obj_new_str((byte*)vstr->buf, vstr->len, false);
+            vstr_free(vstr);
+            return s;
+        }
+
+        case 2:
+        case 3:
+        {
+            // TODO: validate 2nd/3rd args
+            if (!MP_OBJ_IS_TYPE(args[0], &bytes_type)) {
+                nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "bytes expected"));
+            }
+            GET_STR_DATA_LEN(args[0], str_data, str_len);
+            GET_STR_HASH(args[0], str_hash);
+            mp_obj_str_t *o = str_new(&str_type, NULL, str_len);
+            o->data = str_data;
+            o->hash = str_hash;
+            return o;
+        }
+
+        default:
+            nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "str takes at most 3 arguments"));
+    }
+}
+
+STATIC mp_obj_t bytes_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
+    if (n_args == 0) {
+        return mp_const_empty_bytes;
+    }
+
+    if (MP_OBJ_IS_STR(args[0])) {
+        if (n_args < 2 || n_args > 3) {
+            goto wrong_args;
+        }
+        GET_STR_DATA_LEN(args[0], str_data, str_len);
+        GET_STR_HASH(args[0], str_hash);
+        mp_obj_str_t *o = str_new(&bytes_type, NULL, str_len);
+        o->data = str_data;
+        o->hash = str_hash;
+        return o;
+    }
+
+    if (n_args > 1) {
+        goto wrong_args;
+    }
+
+    if (MP_OBJ_IS_SMALL_INT(args[0])) {
+        uint len = MP_OBJ_SMALL_INT_VALUE(args[0]);
+        byte *data;
+
+        mp_obj_t o = mp_obj_str_builder_start(&bytes_type, len, &data);
+        memset(data, 0, len);
+        return mp_obj_str_builder_end(o);
+    }
+
+    int len;
+    byte *data;
+    vstr_t *vstr = NULL;
+    mp_obj_t o = NULL;
+    // Try to create array of exact len if initializer len is known
+    mp_obj_t len_in = mp_obj_len_maybe(args[0]);
+    if (len_in == MP_OBJ_NULL) {
+        len = -1;
+        vstr = vstr_new();
+    } else {
+        len = MP_OBJ_SMALL_INT_VALUE(len_in);
+        o = mp_obj_str_builder_start(&bytes_type, len, &data);
+    }
+
+    mp_obj_t iterable = rt_getiter(args[0]);
+    mp_obj_t item;
+    while ((item = rt_iternext(iterable)) != mp_const_stop_iteration) {
+        if (len == -1) {
+            vstr_add_char(vstr, MP_OBJ_SMALL_INT_VALUE(item));
+        } else {
+            *data++ = MP_OBJ_SMALL_INT_VALUE(item);
+        }
+    }
+
+    if (len == -1) {
+        vstr_shrink(vstr);
+        // TODO: Optimize, borrow buffer from vstr
+        len = vstr_len(vstr);
+        o = mp_obj_str_builder_start(&bytes_type, len, &data);
+        memcpy(data, vstr_str(vstr), len);
+        vstr_free(vstr);
+    }
+
+    return mp_obj_str_builder_end(o);
+
+wrong_args:
+        nlr_jump(mp_obj_new_exception_msg(&mp_type_TypeError, "wrong number of arguments"));
+}
+
 // like strstr but with specified length and allows \0 bytes
 // TODO replace with something more efficient/standard
 STATIC const byte *find_subbytes(const byte *haystack, uint hlen, const byte *needle, uint nlen) {
@@ -520,6 +626,62 @@ STATIC mp_obj_t str_count(uint n_args, const mp_obj_t *args) {
     return MP_OBJ_NEW_SMALL_INT(num_occurrences);
 }
 
+STATIC mp_obj_t str_partitioner(mp_obj_t self_in, mp_obj_t arg, machine_int_t direction) {
+    assert(MP_OBJ_IS_STR(self_in));
+    if (!MP_OBJ_IS_STR(arg)) {
+        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
+                                               "Can't convert '%s' object to str implicitly", mp_obj_get_type_str(arg)));
+    }
+
+    GET_STR_DATA_LEN(self_in, str, str_len);
+    GET_STR_DATA_LEN(arg, sep, sep_len);
+
+    if (sep_len == 0) {
+        nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "empty separator"));
+    }
+
+    mp_obj_t result[] = {MP_OBJ_NEW_QSTR(MP_QSTR_), MP_OBJ_NEW_QSTR(MP_QSTR_), MP_OBJ_NEW_QSTR(MP_QSTR_)};
+
+    if (direction > 0) {
+        result[0] = self_in;
+    } else {
+        result[2] = self_in;
+    }
+
+    if (str_len >= sep_len) {
+        machine_uint_t str_index, str_index_end;
+        if (direction > 0) {
+            str_index = 0;
+            str_index_end = str_len - sep_len;
+        } else {
+            str_index = str_len - sep_len;
+            str_index_end = 0;
+        }
+        for (;;) {
+            if (memcmp(&str[str_index], sep, sep_len) == 0) {
+                result[0] = mp_obj_new_str(str, str_index, false);
+                result[1] = arg;
+                result[2] = mp_obj_new_str(str + str_index + sep_len, str_len - str_index - sep_len, false);
+                break;
+            }
+            if (str_index == str_index_end) {
+                break;
+            }
+            str_index += direction;
+        }
+    }
+
+    return mp_obj_new_tuple(3, result);
+}
+
+STATIC mp_obj_t str_partition(mp_obj_t self_in, mp_obj_t arg) {
+    return str_partitioner(self_in, arg, 1);
+}
+
+STATIC mp_obj_t str_rpartition(mp_obj_t self_in, mp_obj_t arg) {
+    return str_partitioner(self_in, arg, -1);
+}
+
 STATIC machine_int_t str_get_buffer(mp_obj_t self_in, buffer_info_t *bufinfo, int flags) {
     if (flags == BUFFER_READ) {
         GET_STR_DATA_LEN(self_in, str_data, str_len);
@@ -542,6 +704,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_strip_obj, 1, 2, str_strip);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR(str_format_obj, 1, str_format);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_replace_obj, 3, 4, str_replace);
 STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(str_count_obj, 2, 4, str_count);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_partition_obj, str_partition);
+STATIC MP_DEFINE_CONST_FUN_OBJ_2(str_rpartition_obj, str_rpartition);
 
 STATIC const mp_method_t str_type_methods[] = {
     { "find", &str_find_obj },
@@ -552,6 +716,8 @@ STATIC const mp_method_t str_type_methods[] = {
     { "format", &str_format_obj },
     { "replace", &str_replace_obj },
     { "count", &str_count_obj },
+    { "partition", &str_partition_obj },
+    { "rpartition", &str_rpartition_obj },
     { NULL, NULL }, // end-of-list sentinel
 };
 
@@ -559,6 +725,7 @@ const mp_obj_type_t str_type = {
     { &mp_type_type },
     .name = MP_QSTR_str,
     .print = str_print,
+    .make_new = str_make_new,
     .binary_op = str_binary_op,
     .getiter = mp_obj_new_str_iterator,
     .methods = str_type_methods,
@@ -570,34 +737,45 @@ const mp_obj_type_t bytes_type = {
     { &mp_type_type },
     .name = MP_QSTR_bytes,
     .print = str_print,
+    .make_new = bytes_make_new,
     .binary_op = str_binary_op,
     .getiter = mp_obj_new_bytes_iterator,
     .methods = str_type_methods,
 };
 
+// the zero-length bytes
+STATIC const mp_obj_str_t empty_bytes_obj = {{&bytes_type}, 0, 0, NULL};
+const mp_obj_t mp_const_empty_bytes = (mp_obj_t)&empty_bytes_obj;
+
 mp_obj_t mp_obj_str_builder_start(const mp_obj_type_t *type, uint len, byte **data) {
-    mp_obj_str_t *o = m_new_obj_var(mp_obj_str_t, byte, len + 1);
+    mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
     o->base.type = type;
     o->len = len;
-    *data = o->data;
+    byte *p = m_new(byte, len + 1);
+    o->data = p;
+    *data = p;
     return o;
 }
 
 mp_obj_t mp_obj_str_builder_end(mp_obj_t o_in) {
-    assert(MP_OBJ_IS_STR(o_in));
     mp_obj_str_t *o = o_in;
     o->hash = qstr_compute_hash(o->data, o->len);
-    o->data[o->len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
+    byte *p = (byte*)o->data;
+    p[o->len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
     return o;
 }
 
 STATIC mp_obj_t str_new(const mp_obj_type_t *type, const byte* data, uint len) {
-    mp_obj_str_t *o = m_new_obj_var(mp_obj_str_t, byte, len + 1);
+    mp_obj_str_t *o = m_new_obj(mp_obj_str_t);
     o->base.type = type;
-    o->hash = qstr_compute_hash(data, len);
     o->len = len;
-    memcpy(o->data, data, len * sizeof(byte));
-    o->data[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
+    if (data) {
+        o->hash = qstr_compute_hash(data, len);
+        byte *p = m_new(byte, len + 1);
+        o->data = p;
+        memcpy(p, data, len * sizeof(byte));
+        p[len] = '\0'; // for now we add null for compatibility with C ASCIIZ strings
+    }
     return o;
 }
 
diff --git a/py/parsenum.c b/py/parsenum.c
index c9cef5fcd839ca5ad9006bb6a38efd9bd9901949..7be53897a76f9d90b05d4a409259e61c889447c5 100644
--- a/py/parsenum.c
+++ b/py/parsenum.c
@@ -9,139 +9,217 @@
 #include "parsenumbase.h"
 #include "parsenum.h"
 
-#if defined(UNIX)
-
-#include <ctype.h>
-#include <errno.h>
+#if MICROPY_ENABLE_FLOAT
+#include <math.h>
+#endif
 
 mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
-    // TODO at the moment we ignore len; we should honour it!
-    // TODO detect integer overflow and return bignum
-
-    int c, neg = 0;
-    const char *p = str;
-    char *num;
-    long found;
+    const char *restrict top = str + len;
+    bool neg = false;
 
     // check radix base
     if ((base != 0 && base < 2) || base > 36) {
         nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "ValueError: int() arg 2 must be >=2 and <= 36"));
     }
-    // skip surrounded whitespace
-    while (isspace((c = *(p++))));
-    if (c == 0) {
-        goto value_error;
+
+    // skip leading space
+    for (; str < top && unichar_isspace(*str); str++) {
     }
-    // preced sign
-    if (c == '+' || c == '-') {
-        neg = - (c == '-');
-    } else {
-        p--;
+
+    // parse optional sign
+    if (str < top) {
+        if (*str == '+') {
+            str++;
+        } else if (*str == '-') {
+            str++;
+            neg = true;
+        }
     }
 
-    len -= p - str;
-    int skip = mp_parse_num_base(p, len, &base);
-    p += skip;
-    len -= skip;
+    // parse optional base prefix
+    str += mp_parse_num_base(str, top - str, &base);
 
-    errno = 0;
-    found = strtol(p, &num, base);
-    if (errno) {
-        goto value_error;
-    } else if (found && *(num) == 0) {
-        goto done;
-    } else if (found || num != p) {
-        goto check_tail_space;
-    } else {
+    // string should be an integer number
+    machine_int_t int_val = 0;
+    const char *restrict str_val_start = str;
+    for (; str < top; str++) {
+        machine_int_t old_val = int_val;
+        int dig = *str;
+        if (unichar_isdigit(dig) && dig - '0' < base) {
+            // 0-9 digit
+            int_val = base * int_val + dig - '0';
+        } else if (base == 16) {
+            dig |= 0x20;
+            if ('a' <= dig && dig <= 'f') {
+                // a-f hex digit
+                int_val = base * int_val + dig - 'a' + 10;
+            } else {
+                // unknown character
+                break;
+            }
+        } else {
+            // unknown character
+            break;
+        }
+        if (int_val < old_val) {
+            // If new value became less than previous, it's overflow
+            goto overflow;
+        } else if ((old_val ^ int_val) & WORD_MSBIT_HIGH) {
+            // If signed number changed sign - it's overflow
+            goto overflow;
+        }
+    }
+
+    // check we parsed something
+    if (str == str_val_start) {
         goto value_error;
     }
 
-check_tail_space:
-    if (*(num) != 0) {
-        while (isspace((c = *(num++))));
-        if (c != 0) {
-            goto value_error;
-        }
+    // negate value if needed
+    if (neg) {
+        int_val = -int_val;
+    }
+
+    // skip trailing space
+    for (; str < top && unichar_isspace(*str); str++) {
+    }
+
+    // check we reached the end of the string
+    if (str != top) {
+        goto value_error;
     }
 
-done:
-    return MP_OBJ_NEW_SMALL_INT((found ^ neg) - neg);
+    // return the object
+    return MP_OBJ_NEW_SMALL_INT(int_val);
 
 value_error:
     nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "invalid literal for int() with base %d: '%s'", base, str));
-}
 
-#else /* defined(UNIX) */
-
-mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base) {
-    // TODO port strtol to stm
-    return MP_OBJ_NEW_SMALL_INT(0);
+overflow:
+    // TODO reparse using bignum
+    nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "overflow parsing integer"));
 }
 
-#endif /* defined(UNIX) */
-
 #define PARSE_DEC_IN_INTG (1)
 #define PARSE_DEC_IN_FRAC (2)
 #define PARSE_DEC_IN_EXP  (3)
 
-mp_obj_t mp_parse_num_decimal(const char *str, uint len) {
+mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex) {
 #if MICROPY_ENABLE_FLOAT
-    int in = PARSE_DEC_IN_INTG;
+    const char *top = str + len;
     mp_float_t dec_val = 0;
-    bool exp_neg = false;
-    int exp_val = 0;
-    int exp_extra = 0;
+    bool dec_neg = false;
     bool imag = false;
-    const char *top = str + len;
-    for (; str < top; str++) {
-        int dig = *str;
-        if ('0' <= dig && dig <= '9') {
-            dig -= '0';
-            if (in == PARSE_DEC_IN_EXP) {
-                exp_val = 10 * exp_val + dig;
-            } else {
-                dec_val = 10 * dec_val + dig;
-                if (in == PARSE_DEC_IN_FRAC) {
-                    exp_extra -= 1;
-                }
+
+    // skip leading space
+    for (; str < top && unichar_isspace(*str); str++) {
+    }
+
+    // parse optional sign
+    if (str < top) {
+        if (*str == '+') {
+            str++;
+        } else if (*str == '-') {
+            str++;
+            dec_neg = true;
+        }
+    }
+
+    // determine what the string is
+    if (str < top && (str[0] | 0x20) == 'i') {
+        // string starts with 'i', should be 'inf' or 'infinity' (case insensitive)
+        if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
+            // inf
+            str += 3;
+            dec_val = INFINITY;
+            if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
+                // infinity
+                str += 5;
             }
-        } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
-            in = PARSE_DEC_IN_FRAC;
-        } else if (in != PARSE_DEC_IN_EXP && (dig == 'E' || dig == 'e')) {
-            in = PARSE_DEC_IN_EXP;
-            if (str[1] == '+') {
-                str++;
-            } else if (str[1] == '-') {
+        }
+    } else if (str < top && (str[0] | 0x20) == 'n') {
+        // string starts with 'n', should be 'nan' (case insensitive)
+        if (str + 2 < top && (str[1] | 0x20) == 'a' && (str[2] | 0x20) == 'n') {
+            // NaN
+            str += 3;
+            dec_val = MICROPY_FLOAT_C_FUN(nan)("");
+        }
+    } else {
+        // string should be a decimal number
+        int in = PARSE_DEC_IN_INTG;
+        bool exp_neg = false;
+        int exp_val = 0;
+        int exp_extra = 0;
+        for (; str < top; str++) {
+            int dig = *str;
+            if ('0' <= dig && dig <= '9') {
+                dig -= '0';
+                if (in == PARSE_DEC_IN_EXP) {
+                    exp_val = 10 * exp_val + dig;
+                } else {
+                    dec_val = 10 * dec_val + dig;
+                    if (in == PARSE_DEC_IN_FRAC) {
+                        exp_extra -= 1;
+                    }
+                }
+            } else if (in == PARSE_DEC_IN_INTG && dig == '.') {
+                in = PARSE_DEC_IN_FRAC;
+            } else if (in != PARSE_DEC_IN_EXP && ((dig | 0x20) == 'e')) {
+                in = PARSE_DEC_IN_EXP;
+                if (str[1] == '+') {
+                    str++;
+                } else if (str[1] == '-') {
+                    str++;
+                    exp_neg = true;
+                }
+            } else if (allow_imag && (dig | 0x20) == 'j') {
                 str++;
-                exp_neg = true;
+                imag = true;
+                break;
+            } else {
+                // unknown character
+                break;
             }
-        } else if (dig == 'J' || dig == 'j') {
-            str++;
-            imag = true;
-            break;
-        } else {
-            // unknown character
-            break;
+        }
+
+        // work out the exponent
+        if (exp_neg) {
+            exp_val = -exp_val;
+        }
+        exp_val += exp_extra;
+
+        // apply the exponent
+        for (; exp_val > 0; exp_val--) {
+            dec_val *= 10;
+        }
+        for (; exp_val < 0; exp_val++) {
+            dec_val *= 0.1;
         }
     }
-    if (*str != 0) {
-        nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
-    }
-    if (exp_neg) {
-        exp_val = -exp_val;
+
+    // negate value if needed
+    if (dec_neg) {
+        dec_val = -dec_val;
     }
-    exp_val += exp_extra;
-    for (; exp_val > 0; exp_val--) {
-        dec_val *= 10;
+
+    // skip trailing space
+    for (; str < top && unichar_isspace(*str); str++) {
     }
-    for (; exp_val < 0; exp_val++) {
-        dec_val *= 0.1;
+
+    // check we reached the end of the string
+    if (str != top) {
+        nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "invalid syntax for number"));
     }
+
+    // return the object
     if (imag) {
         return mp_obj_new_complex(0, dec_val);
+    } else if (force_complex) {
+        return mp_obj_new_complex(dec_val, 0);
     } else {
         return mp_obj_new_float(dec_val);
     }
+
 #else
     nlr_jump(mp_obj_new_exception_msg(&mp_type_SyntaxError, "decimal numbers not supported"));
 #endif
diff --git a/py/parsenum.h b/py/parsenum.h
index 5a2e42da50515ebb2aeceb4b34e0cc28935c8b70..97578423c706bec7dbf5d5497950613992dfd869 100644
--- a/py/parsenum.h
+++ b/py/parsenum.h
@@ -1,2 +1,2 @@
 mp_obj_t mp_parse_num_integer(const char *restrict str, uint len, int base);
-mp_obj_t mp_parse_num_decimal(const char *str, uint len);
+mp_obj_t mp_parse_num_decimal(const char *str, uint len, bool allow_imag, bool force_complex);
diff --git a/py/runtime.c b/py/runtime.c
index b57a74fa38be4993898f4d7ae198a142d34ea901..68edf545675ae54a42debd1cadff88f6c17f3958 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -89,6 +89,7 @@ STATIC const mp_builtin_elem_t builtin_table[] = {
 
     // built-in types
     { MP_QSTR_bool, (mp_obj_t)&bool_type },
+    { MP_QSTR_bytes, (mp_obj_t)&bytes_type },
 #if MICROPY_ENABLE_FLOAT
     { MP_QSTR_complex, (mp_obj_t)&mp_type_complex },
 #endif
@@ -102,6 +103,7 @@ STATIC const mp_builtin_elem_t builtin_table[] = {
     { MP_QSTR_list, (mp_obj_t)&list_type },
     { MP_QSTR_map, (mp_obj_t)&map_type },
     { MP_QSTR_set, (mp_obj_t)&set_type },
+    { MP_QSTR_str, (mp_obj_t)&str_type },
     { MP_QSTR_super, (mp_obj_t)&super_type },
     { MP_QSTR_tuple, (mp_obj_t)&tuple_type },
     { MP_QSTR_type, (mp_obj_t)&mp_type_type },
@@ -114,7 +116,6 @@ STATIC const mp_builtin_elem_t builtin_table[] = {
     { MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj },
     { MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj },
     { MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj },
-    { MP_QSTR_bytes, (mp_obj_t)&mp_builtin_bytes_obj },
     { MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj },
     { MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj },
     { MP_QSTR_dir, (mp_obj_t)&mp_builtin_dir_obj },
@@ -137,7 +138,6 @@ STATIC const mp_builtin_elem_t builtin_table[] = {
     { MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj },
     { MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj },
     { MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj },
-    { MP_QSTR_str, (mp_obj_t)&mp_builtin_str_obj },
     { MP_QSTR_bytearray, (mp_obj_t)&mp_builtin_bytearray_obj },
 
     // built-in exceptions
@@ -376,7 +376,7 @@ mp_obj_t rt_load_const_dec(qstr qstr) {
     DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
     uint len;
     const byte* data = qstr_data(qstr, &len);
-    return mp_parse_num_decimal((const char*)data, len);
+    return mp_parse_num_decimal((const char*)data, len, true, false);
 }
 
 mp_obj_t rt_load_const_str(qstr qstr) {
diff --git a/py/showbc.c b/py/showbc.c
index bc81086c7dbdcc1f707c7c1408b695c4f205c2ea..9bdf811d9aebc932bbf9ef53fc2f1c94649f6b50 100644
--- a/py/showbc.c
+++ b/py/showbc.c
@@ -394,6 +394,10 @@ void mp_byte_code_print(const byte *ip, int len) {
                 printf("YIELD_VALUE");
                 break;
 
+            case MP_BC_YIELD_FROM:
+                printf("YIELD_FROM");
+                break;
+
             case MP_BC_IMPORT_NAME:
                 DECODE_QSTR;
                 printf("IMPORT_NAME %s", qstr_str(qstr));
diff --git a/stm/math.c b/stm/math.c
index 8e2c6fc7533a7305f5d14c77aefecfa1e3ce519e..0809a3f2c52eb8e290a6af8a51edc13d5f8a340c 100644
--- a/stm/math.c
+++ b/stm/math.c
@@ -44,6 +44,10 @@ 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; }
+float ceilf(float x) { return 0.0; }
+float floorf(float x) { return 0.0; }
+float truncf(float x) { return 0.0; }
+float fmodf(float x, float y) { return 0.0; }
 
 /*****************************************************************************/
 // from musl-0.9.15 libm.h
diff --git a/stmhal/Makefile b/stmhal/Makefile
index 9f3e365a19e1cec31b1c159afcc71729f0555f8d..86791607a95b21294152db6b6aa16aa4d5036466 100644
--- a/stmhal/Makefile
+++ b/stmhal/Makefile
@@ -21,7 +21,7 @@ INC += -I$(PY_SRC)
 INC += -I$(CMSIS_DIR)/inc
 INC += -I$(CMSIS_DIR)/devinc
 INC += -I$(HAL_DIR)/inc
-INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc/inc
+INC += -I$(USBDEV_DIR)/core/inc -I$(USBDEV_DIR)/class/cdc/inc -I$(USBDEV_DIR)/class/msc/inc
 #INC += -I$(USBHOST_DIR)
 INC += -I$(FATFS_DIR)/src
 #INC += -I$(CC3K_DIR)
@@ -56,8 +56,10 @@ SRC_C = \
 	stm32f4xx_it.c \
 	stm32f4xx_hal_msp.c \
 	usbd_conf.c \
-	usbd_desc.c \
+	usbd_desc_vcp.c \
 	usbd_cdc_interface.c \
+	usbd_desc_msc.c \
+	usbd_msc_storage.c \
 	pendsv.c \
 	systick.c  \
 	led.c \
@@ -84,9 +86,9 @@ SRC_C = \
 	sdcard.c \
 	diskio.c \
 	lcd.c \
+	accel.c \
 
 #	servo.c \
-#	accel.c \
 #	timer.c \
 #	audio.c \
 #	i2c.c \
@@ -104,6 +106,7 @@ SRC_HAL = $(addprefix $(HAL_DIR)/src/,\
 	stm32f4xx_hal_flash.c \
 	stm32f4xx_hal_flash_ex.c \
 	stm32f4xx_hal_gpio.c \
+	stm32f4xx_hal_i2c.c \
 	stm32f4xx_hal_pcd.c \
 	stm32f4xx_hal_rcc.c \
 	stm32f4xx_hal_rcc_ex.c \
@@ -122,6 +125,10 @@ SRC_USBDEV = $(addprefix $(USBDEV_DIR)/,\
 	core/src/usbd_ctlreq.c \
 	core/src/usbd_ioreq.c \
 	class/cdc/src/usbd_cdc.c \
+	class/msc/src/usbd_msc.c \
+	class/msc/src/usbd_msc_bot.c \
+	class/msc/src/usbd_msc_scsi.c \
+	class/msc/src/usbd_msc_data.c \
 	)
 
 #	usbd_core.c \
diff --git a/stmhal/accel.c b/stmhal/accel.c
new file mode 100644
index 0000000000000000000000000000000000000000..f380242bf6f82d57d20775bf98a4a4464fd375b8
--- /dev/null
+++ b/stmhal/accel.c
@@ -0,0 +1,137 @@
+#include <stdio.h>
+#include <string.h>
+
+#include <stm32f4xx_hal.h>
+
+#include "misc.h"
+#include "mpconfig.h"
+#include "qstr.h"
+#include "obj.h"
+#include "runtime.h"
+#include "accel.h"
+
+#define MMA_ADDR (0x98)
+#define MMA_REG_MODE (7)
+
+STATIC I2C_HandleTypeDef I2cHandle;
+
+void accel_init(void) {
+    GPIO_InitTypeDef GPIO_InitStructure;
+
+    // PB5 is connected to AVDD; pull high to enable MMA accel device
+    GPIOB->BSRRH = GPIO_PIN_5; // turn off AVDD
+    GPIO_InitStructure.Pin = GPIO_PIN_5;
+    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
+    GPIO_InitStructure.Speed = GPIO_SPEED_LOW;
+    GPIO_InitStructure.Pull = GPIO_NOPULL;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+    // wait 20ms, then turn on AVDD, then wait 20ms again
+    HAL_Delay(20);
+    GPIOB->BSRRL = GPIO_PIN_5;
+    HAL_Delay(20);
+
+    // PB6=SCL, PB7=SDA
+    GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7;
+    GPIO_InitStructure.Mode = GPIO_MODE_AF_OD;
+    GPIO_InitStructure.Speed = GPIO_SPEED_FAST;
+    GPIO_InitStructure.Pull = GPIO_NOPULL; // have external pull-up resistors on both lines
+    GPIO_InitStructure.Alternate = GPIO_AF4_I2C1;
+    HAL_GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+    // enable the I2C1 clock
+    __I2C1_CLK_ENABLE();
+
+    // set up the I2C1 device
+    memset(&I2cHandle, 0, sizeof(I2C_HandleTypeDef));
+    I2cHandle.Instance = I2C1;
+    I2cHandle.Init.AddressingMode  = I2C_ADDRESSINGMODE_7BIT;
+    I2cHandle.Init.ClockSpeed      = 400000;
+    I2cHandle.Init.DualAddressMode = I2C_DUALADDRESS_DISABLED;
+    I2cHandle.Init.DutyCycle       = I2C_DUTYCYCLE_16_9;
+    I2cHandle.Init.GeneralCallMode = I2C_GENERALCALL_DISABLED;
+    I2cHandle.Init.NoStretchMode   = I2C_NOSTRETCH_DISABLED;
+    I2cHandle.Init.OwnAddress1     = 0xfe; // unused
+    I2cHandle.Init.OwnAddress2     = 0xfe; // unused
+
+    if (HAL_I2C_Init(&I2cHandle) != HAL_OK) {
+        // init error
+        printf("accel_init: HAL_I2C_Init failed\n");
+        return;
+    }
+
+    HAL_StatusTypeDef status;
+
+    //printf("IsDeviceReady\n");
+    for (int i = 0; i < 10; i++) {
+        status = HAL_I2C_IsDeviceReady(&I2cHandle, MMA_ADDR, 10, 200);
+        //printf("  got %d\n", status);
+        if (status == HAL_OK) {
+            break;
+        }
+    }
+
+    //printf("MemWrite\n");
+    uint8_t data[1];
+    data[0] = 1; // active mode
+    status = HAL_I2C_Mem_Write(&I2cHandle, MMA_ADDR, MMA_REG_MODE, I2C_MEMADD_SIZE_8BIT, data, 1, 200);
+    //printf("  got %d\n", status);
+}
+
+/******************************************************************************/
+/* Micro Python bindings                                                      */
+
+int accel_buf[12];
+
+mp_obj_t pyb_accel_read(void) {
+    for (int i = 0; i <= 6; i += 3) {
+        accel_buf[0 + i] = accel_buf[0 + i + 3];
+        accel_buf[1 + i] = accel_buf[1 + i + 3];
+        accel_buf[2 + i] = accel_buf[2 + i + 3];
+    }
+
+    uint8_t data_[4];
+    HAL_I2C_Mem_Read(&I2cHandle, MMA_ADDR, 0, I2C_MEMADD_SIZE_8BIT, data_, 4, 200);
+    accel_buf[9] = data_[0] & 0x3f; if (accel_buf[9] & 0x20) accel_buf[9] |= ~0x1f;
+    accel_buf[10] = data_[1] & 0x3f; if (accel_buf[10] & 0x20) accel_buf[10] |= ~0x1f;
+    accel_buf[11] = data_[2] & 0x3f; if (accel_buf[11] & 0x20) accel_buf[11] |= ~0x1f;
+    int jolt_info = data_[3];
+
+    mp_obj_t data[4];
+    data[0] = mp_obj_new_int(accel_buf[0] + accel_buf[3] + accel_buf[6] + accel_buf[9]);
+    data[1] = mp_obj_new_int(accel_buf[1] + accel_buf[4] + accel_buf[7] + accel_buf[10]);
+    data[2] = mp_obj_new_int(accel_buf[2] + accel_buf[5] + accel_buf[8] + accel_buf[11]);
+    data[3] = mp_obj_new_int(jolt_info);
+
+    return rt_build_tuple(4, data);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_obj, pyb_accel_read);
+
+/*
+mp_obj_t pyb_accel_read_all(void) {
+    mp_obj_t data[11];
+    accel_start(MMA_ADDR, 1);
+    accel_send_byte(0);
+    accel_restart(MMA_ADDR, 0);
+    for (int i = 0; i <= 9; i++) {
+        data[i] = mp_obj_new_int(accel_read_ack());
+    }
+    data[10] = mp_obj_new_int(accel_read_nack());
+
+    return rt_build_tuple(11, data);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_0(pyb_accel_read_all_obj, pyb_accel_read_all);
+
+mp_obj_t pyb_accel_write_mode(mp_obj_t o_int, mp_obj_t o_mode) {
+    accel_start(MMA_ADDR, 1);
+    accel_send_byte(6); // start at int
+    accel_send_byte(mp_obj_get_int(o_int));
+    accel_send_byte(mp_obj_get_int(o_mode));
+    accel_stop();
+    return mp_const_none;
+}
+
+MP_DEFINE_CONST_FUN_OBJ_2(pyb_accel_write_mode_obj, pyb_accel_write_mode);
+*/
diff --git a/stmhal/accel.h b/stmhal/accel.h
new file mode 100644
index 0000000000000000000000000000000000000000..c2320f1a4ef19672485ce316f3d8fce2ff4c8abd
--- /dev/null
+++ b/stmhal/accel.h
@@ -0,0 +1,11 @@
+void accel_init(void);
+void accel_restart(uint8_t addr, int write);
+void accel_start(uint8_t addr, int write);
+void accel_send_byte(uint8_t data);
+uint8_t accel_read_ack(void);
+uint8_t accel_read_nack(void);
+void accel_stop(void);
+
+MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_obj);
+MP_DECLARE_CONST_FUN_OBJ(pyb_accel_read_all_obj);
+MP_DECLARE_CONST_FUN_OBJ(pyb_accel_write_mode_obj);
diff --git a/stmhal/import.c b/stmhal/import.c
index f2fd3b3deeaf93ec07c0c276c1189994c7f8e26e..c977dcf2ec40fe62f1923893116ebdd18c915e78 100644
--- a/stmhal/import.c
+++ b/stmhal/import.c
@@ -1,16 +1,18 @@
+#include <stdio.h>
 #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;
+#if _USE_LFN
+    fno.lfname = NULL;
+    fno.lfsize = 0;
+#endif
     FRESULT res = f_stat(path, &fno);
     if (res == FR_OK) {
         if ((fno.fattrib & AM_DIR) != 0) {
@@ -19,6 +21,5 @@ mp_import_stat_t mp_import_stat(const char *path) {
             return MP_IMPORT_STAT_FILE;
         }
     }
-#endif
     return MP_IMPORT_STAT_NO_EXIST;
 }
diff --git a/stmhal/led.c b/stmhal/led.c
index 677c151b335ac420ccdccb0379dfdece4b4d17bc..80c1e145f149bfb5d4cfad240f40c19a13d6fc91 100644
--- a/stmhal/led.c
+++ b/stmhal/led.c
@@ -73,6 +73,14 @@ void led_toggle(pyb_led_t led) {
     }
 }
 
+void led_debug(int n, int delay) {
+    led_state(1, n & 1);
+    led_state(2, n & 2);
+    led_state(3, n & 4);
+    led_state(4, n & 8);
+    HAL_Delay(delay);
+}
+
 /******************************************************************************/
 /* Micro Python bindings                                                      */
 
diff --git a/stmhal/led.h b/stmhal/led.h
index 44c68d4ebe0cb9241bf17ba66dd209e5184dd862..b3762271c1d39f43c4faae4d93dbb4928821627b 100644
--- a/stmhal/led.h
+++ b/stmhal/led.h
@@ -19,5 +19,6 @@ typedef enum {
 void led_init(void);
 void led_state(pyb_led_t led, int state);
 void led_toggle(pyb_led_t led);
+void led_debug(int value, int delay);
 
 MP_DECLARE_CONST_FUN_OBJ(pyb_Led_obj);
diff --git a/stmhal/main.c b/stmhal/main.c
index d77733429bdf22d88bddb7b3e56cf05dd6a20e39..d92ccdd5b1b7a01daebea79b1a358614f0483614 100644
--- a/stmhal/main.c
+++ b/stmhal/main.c
@@ -33,9 +33,9 @@
 #include "sdcard.h"
 #include "ff.h"
 #include "lcd.h"
+#include "accel.h"
 #if 0
 #include "servo.h"
-#include "accel.h"
 #include "timer.h"
 #include "pybwlan.h"
 #include "pin.h"
@@ -170,22 +170,6 @@ int main(void) {
     // enable the CCM RAM
     __CCMDATARAMEN_CLK_ENABLE();
 
-    // some test code to flash LEDs
-    led_init();
-
-    led_state(0, 1);
-    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);
-    }
-#endif
-
 #if 0
 #if defined(NETDUINO_PLUS_2)
     {
@@ -348,6 +332,11 @@ soft_reset:
     // make sure we have a /boot.py
     {
         FILINFO fno;
+#if _USE_LFN
+        fno.lfname = NULL;
+        fno.lfsize = 0;
+#endif
+        led_debug(0, 500);
         FRESULT res = f_stat("0:/boot.py", &fno);
         if (res == FR_OK) {
             if (fno.fattrib & AM_DIR) {
@@ -382,18 +371,13 @@ soft_reset:
         flash_error(4);
     }
 
-    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_GREEN, 0);
 
+#if defined(USE_DEVICE_MODE)
+    usbd_storage_medium_kind_t usbd_medium_kind = USBD_STORAGE_MEDIUM_FLASH;
+#endif
+
 #if MICROPY_HW_HAS_SDCARD
     // if an SD card is present then mount it on 1:/
     if (sdcard_is_present()) {
@@ -403,8 +387,8 @@ soft_reset:
         } else {
             if (first_soft_reset) {
                 // use SD card as medium for the USB MSD
-#if 0
-                usbd_storage_select_medium(USBD_STORAGE_MEDIUM_SDCARD);
+#if defined(USE_DEVICE_MODE)
+                usbd_medium_kind = USBD_STORAGE_MEDIUM_SDCARD;
 #endif
             }
         }
@@ -416,7 +400,12 @@ soft_reset:
     pyb_usb_host_init();
 #elif defined(USE_DEVICE_MODE)
     // USB device
-    pyb_usb_dev_init(PYB_USB_DEV_VCP_MSC);
+    pyb_usb_dev_init(USBD_DEVICE_MSC, usbd_medium_kind);
+#endif
+
+#if MICROPY_HW_HAS_MMA7660
+    // MMA accel: init and reset
+    accel_init();
 #endif
 
     // run main script
diff --git a/stmhal/math.c b/stmhal/math.c
index 8e2c6fc7533a7305f5d14c77aefecfa1e3ce519e..0809a3f2c52eb8e290a6af8a51edc13d5f8a340c 100644
--- a/stmhal/math.c
+++ b/stmhal/math.c
@@ -44,6 +44,10 @@ 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; }
+float ceilf(float x) { return 0.0; }
+float floorf(float x) { return 0.0; }
+float truncf(float x) { return 0.0; }
+float fmodf(float x, float y) { return 0.0; }
 
 /*****************************************************************************/
 // from musl-0.9.15 libm.h
diff --git a/stmhal/pybmodule.c b/stmhal/pybmodule.c
index b6b269b0658d0022723dd476470ae62369d495f3..3db23dc6de9f9c30b528a1df2e0fecd60d9e3e67 100644
--- a/stmhal/pybmodule.c
+++ b/stmhal/pybmodule.c
@@ -21,10 +21,10 @@
 #include "usart.h"
 #include "storage.h"
 #include "sdcard.h"
+#include "accel.h"
 #if 0
 #include "servo.h"
 #include "usb.h"
-#include "accel.h"
 #include "i2c.h"
 #include "adc.h"
 #include "audio.h"
@@ -256,13 +256,13 @@ STATIC const mp_map_elem_t pyb_module_globals_table[] = {
     { MP_OBJ_NEW_QSTR(MP_QSTR_SD), (mp_obj_t)&pyb_sdcard_obj },
 #endif
 
-#if 0
 #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 },
+    //{ 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
 
+#if 0
     { MP_OBJ_NEW_QSTR(MP_QSTR_hid), (mp_obj_t)&pyb_hid_send_report_obj },
 #endif
     { MP_OBJ_NEW_QSTR(MP_QSTR_Led), (mp_obj_t)&pyb_Led_obj },
diff --git a/stmhal/usb.c b/stmhal/usb.c
index 5cf7b5f32c784ebb88540f1f7790d9edf89596aa..c14a5ad688a72c743dec0a90808bb3f473f64d71 100644
--- a/stmhal/usb.c
+++ b/stmhal/usb.c
@@ -1,21 +1,16 @@
 #include <string.h>
 
-/*
-#include "usb_core.h"
-#include "usbd_cdc_core.h"
-#include "usbd_pyb_core.h"
-#include "usbd_usr.h"
-*/
 #include "usbd_core.h"
 #include "usbd_desc.h"
 #include "usbd_cdc.h"
 #include "usbd_cdc_interface.h"
+#include "usbd_msc.h"
+#include "usbd_msc_storage.h"
 
 #include "misc.h"
 #include "mpconfig.h"
 #include "qstr.h"
 #include "obj.h"
-//#include "pendsv.h"
 #include "usb.h"
 
 #ifdef USE_DEVICE_MODE
@@ -26,12 +21,12 @@ static int dev_is_enabled = 0;
 uint32_t APP_dev_is_connected = 0; /* used by usbd_cdc_vcp */
 mp_obj_t mp_const_vcp_interrupt = MP_OBJ_NULL;
 
-void pyb_usb_dev_init(int usb_dev_type) {
+void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t medium_kind) {
 #ifdef USE_DEVICE_MODE
     if (!dev_is_enabled) {
         // only init USB once in the device's power-lifetime
-        switch (usb_dev_type) {
-            case PYB_USB_DEV_VCP_MSC:
+        switch (device_kind) {
+            case USBD_DEVICE_CDC:
                 // XXX USBD_CDC_Init (called by one of these functions below) uses malloc,
                 // so the memory is invalid after a soft reset (which resets the GC).
                 USBD_Init(&hUSBDDevice, &VCP_Desc, 0);
@@ -41,7 +36,20 @@ void pyb_usb_dev_init(int usb_dev_type) {
                 //USBD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_PYB_cb, &USR_cb);
                 break;
 
-            case PYB_USB_DEV_HID:
+            case USBD_DEVICE_MSC:
+                // XXX USBD_CDC_Init (called by one of these functions below) uses malloc,
+                // so the memory is invalid after a soft reset (which resets the GC).
+                USBD_Init(&hUSBDDevice, &MSC_Desc, 0);
+                USBD_RegisterClass(&hUSBDDevice, &USBD_MSC);
+                if (medium_kind == USBD_STORAGE_MEDIUM_FLASH) {
+                    USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_FLASH_STORAGE_fops);
+                } else {
+                    USBD_MSC_RegisterStorage(&hUSBDDevice, (USBD_StorageTypeDef*)&USBD_SDCARD_STORAGE_fops);
+                }
+                USBD_Start(&hUSBDDevice);
+                break;
+
+            case USBD_DEVICE_HID:
                 //USBD_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID, &USR_desc, &USBD_PYB_HID_cb, &USR_cb);
                 // TODO
                 break;
diff --git a/stmhal/usb.h b/stmhal/usb.h
index 3e6bdccec2a5edb7de2576a4ef6f4add744933ea..bb6283c89ab773f2996e00c641600dbdc7e140a6 100644
--- a/stmhal/usb.h
+++ b/stmhal/usb.h
@@ -4,10 +4,18 @@
 #define VCP_CHAR_CTRL_C (3)
 #define VCP_CHAR_CTRL_D (4)
 
-#define PYB_USB_DEV_VCP_MSC (0)
-#define PYB_USB_DEV_HID (1)
+typedef enum {
+    USBD_DEVICE_CDC,
+    USBD_DEVICE_MSC,
+    USBD_DEVICE_HID,
+} usbd_device_kind_t;
 
-void pyb_usb_dev_init(int usb_dev_type);
+typedef enum {
+    USBD_STORAGE_MEDIUM_FLASH,
+    USBD_STORAGE_MEDIUM_SDCARD,
+} usbd_storage_medium_kind_t;
+
+void pyb_usb_dev_init(usbd_device_kind_t device_kind, usbd_storage_medium_kind_t medium_kind);
 bool usb_vcp_is_enabled(void);
 bool usb_vcp_is_connected(void);
 void usb_vcp_set_interrupt_char(int c);
diff --git a/stmhal/usbd_conf.h b/stmhal/usbd_conf.h
index 8c02ad0ec21b7e1fc4fb85609da22de30fe8e315..cc3ad73f98422dd7af8649faeaa1e5addcafe04b 100644
--- a/stmhal/usbd_conf.h
+++ b/stmhal/usbd_conf.h
@@ -48,6 +48,9 @@
 #define USBD_SELF_POWERED                     0
 #define USBD_DEBUG_LEVEL                      0
  
+// for MSC device
+#define MSC_MEDIA_PACKET                      8192
+
 /* Exported macro ------------------------------------------------------------*/
 /* Memory management macros */
 #define USBD_malloc               gc_alloc
diff --git a/stmhal/usbd_desc.h b/stmhal/usbd_desc.h
index 8b2d8f103422f2e5a6966bc3bced8182800f592e..a54e427e310dd8c70cdf74a04fa4cab1133c1a8d 100644
--- a/stmhal/usbd_desc.h
+++ b/stmhal/usbd_desc.h
@@ -1,43 +1,2 @@
-/**
-  ******************************************************************************
-  * @file    USB_Device/CDC_Standalone/Inc/usbd_desc.h
-  * @author  MCD Application Team
-  * @version V1.0.1
-  * @date    26-February-2014
-  * @brief   Header for usbd_desc.c module
-  ******************************************************************************
-  * @attention
-  *
-  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
-  *
-  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
-  * You may not use this file except in compliance with the License.
-  * You may obtain a copy of the License at:
-  *
-  *        http://www.st.com/software_license_agreement_liberty_v2
-  *
-  * Unless required by applicable law or agreed to in writing, software 
-  * distributed under the License is distributed on an "AS IS" BASIS, 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  * See the License for the specific language governing permissions and
-  * limitations under the License.
-  *
-  ******************************************************************************
-  */
-
-/* Define to prevent recursive inclusion -------------------------------------*/
-#ifndef __USBD_DESC_H
-#define __USBD_DESC_H
-
-/* Includes ------------------------------------------------------------------*/
-#include "usbd_def.h"
-
-/* Exported types ------------------------------------------------------------*/
-/* Exported constants --------------------------------------------------------*/
-/* Exported macro ------------------------------------------------------------*/
-/* Exported functions ------------------------------------------------------- */
-extern USBD_DescriptorsTypeDef VCP_Desc;
-
-#endif /* __USBD_DESC_H */
- 
-/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+extern USBD_DescriptorsTypeDef VCP_Desc;
+extern USBD_DescriptorsTypeDef MSC_Desc;
diff --git a/stmhal/usbd_desc_msc.c b/stmhal/usbd_desc_msc.c
new file mode 100644
index 0000000000000000000000000000000000000000..7d0911e82caf493ca1f97b0267047b7b23bed2cf
--- /dev/null
+++ b/stmhal/usbd_desc_msc.c
@@ -0,0 +1,227 @@
+/**
+  ******************************************************************************
+  * @file    USB_Device/MSC_Standalone/Src/usbd_desc.c
+  * @author  MCD Application Team
+  * @version V1.0.1
+  * @date    26-February-2014
+  * @brief   This file provides the USBD descriptors and string formating method.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  ******************************************************************************
+  */
+
+/* Includes ------------------------------------------------------------------*/
+#include "usbd_core.h"
+#include "usbd_desc.h"
+#include "usbd_conf.h"
+
+/* Private typedef -----------------------------------------------------------*/
+/* Private define ------------------------------------------------------------*/
+#define USBD_VID                      0x0483
+#define USBD_PID                      0x5720
+#define USBD_LANGID_STRING            0x409
+#define USBD_MANUFACTURER_STRING      "STMicroelectronics"
+#define USBD_PRODUCT_HS_STRING        "Mass Storage in HS Mode"
+#define USBD_SERIALNUMBER_HS_STRING   "00000000001A"
+#define USBD_PRODUCT_FS_STRING        "Mass Storage in FS Mode"
+#define USBD_SERIALNUMBER_FS_STRING   "00000000001B"
+#define USBD_CONFIGURATION_HS_STRING  "MSC Config"
+#define USBD_INTERFACE_HS_STRING      "MSC Interface"
+#define USBD_CONFIGURATION_FS_STRING  "MSC Config"
+#define USBD_INTERFACE_FS_STRING      "MSC Interface"
+
+/* Private macro -------------------------------------------------------------*/
+/* Private function prototypes -----------------------------------------------*/
+uint8_t *USBD_MSC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+uint8_t *USBD_MSC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length);
+#ifdef USB_SUPPORT_USER_STRING_DESC
+uint8_t *USBD_MSC_USRStringDesc(USBD_SpeedTypeDef speed, uint8_t idx, uint16_t *length);  
+#endif /* USB_SUPPORT_USER_STRING_DESC */
+
+/* Private variables ---------------------------------------------------------*/
+USBD_DescriptorsTypeDef MSC_Desc = {
+  USBD_MSC_DeviceDescriptor,
+  USBD_MSC_LangIDStrDescriptor, 
+  USBD_MSC_ManufacturerStrDescriptor,
+  USBD_MSC_ProductStrDescriptor,
+  USBD_MSC_SerialStrDescriptor,
+  USBD_MSC_ConfigStrDescriptor,
+  USBD_MSC_InterfaceStrDescriptor,  
+};
+
+/* USB Standard Device Descriptor */
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t USBD_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
+  0x12,                       /* bLength */
+  USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
+  0x00,                       /* bcdUSB */
+  0x02,
+  0x00,                       /* bDeviceClass */
+  0x00,                       /* bDeviceSubClass */
+  0x00,                       /* bDeviceProtocol */
+  USB_MAX_EP0_SIZE,           /* bMaxPacketSize */
+  LOBYTE(USBD_VID),           /* idVendor */
+  HIBYTE(USBD_VID),           /* idVendor */
+  LOBYTE(USBD_PID),           /* idVendor */
+  HIBYTE(USBD_PID),           /* idVendor */
+  0x00,                       /* bcdDevice rel. 2.00 */
+  0x02,
+  USBD_IDX_MFC_STR,           /* Index of manufacturer string */
+  USBD_IDX_PRODUCT_STR,       /* Index of product string */
+  USBD_IDX_SERIAL_STR,        /* Index of serial number string */
+  USBD_MAX_NUM_CONFIGURATION  /* bNumConfigurations */
+}; /* USB_DeviceDescriptor */
+
+/* USB Standard Device Descriptor */
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
+  USB_LEN_LANGID_STR_DESC,         
+  USB_DESC_TYPE_STRING,       
+  LOBYTE(USBD_LANGID_STRING),
+  HIBYTE(USBD_LANGID_STRING), 
+};
+
+#if defined ( __ICCARM__ ) /*!< IAR Compiler */
+  #pragma data_alignment=4   
+#endif
+__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+
+/* Private functions ---------------------------------------------------------*/
+
+/**
+  * @brief  Returns the device descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_DeviceDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  *length = sizeof(USBD_DeviceDesc);
+  return USBD_DeviceDesc;
+}
+
+/**
+  * @brief  Returns the LangID string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_LangIDStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  *length = sizeof(USBD_LangIDDesc);  
+  return USBD_LangIDDesc;
+}
+
+/**
+  * @brief  Returns the product string descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_ProductStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {   
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_PRODUCT_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);    
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the manufacturer string descriptor. 
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  USBD_GetString((uint8_t *)(uint8_t *)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the serial number string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == USBD_SPEED_HIGH)
+  {    
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_SERIALNUMBER_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_SERIALNUMBER_FS_STRING, USBD_StrDesc, length);    
+  }
+  return USBD_StrDesc;
+}
+
+/**
+  * @brief  Returns the configuration string descriptor.    
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_ConfigStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == USBD_SPEED_HIGH)
+  {  
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_CONFIGURATION_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length); 
+  }
+  return USBD_StrDesc;  
+}
+
+/**
+  * @brief  Returns the interface string descriptor.        
+  * @param  speed: Current device speed
+  * @param  length: Pointer to data length variable
+  * @retval Pointer to descriptor buffer
+  */
+uint8_t *USBD_MSC_InterfaceStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length)
+{
+  if(speed == 0)
+  {
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_INTERFACE_HS_STRING, USBD_StrDesc, length);
+  }
+  else
+  {
+    USBD_GetString((uint8_t *)(uint8_t *)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
+  }
+  return USBD_StrDesc;  
+}
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
diff --git a/stmhal/usbd_desc.c b/stmhal/usbd_desc_vcp.c
similarity index 94%
rename from stmhal/usbd_desc.c
rename to stmhal/usbd_desc_vcp.c
index ca9ea487d989a374bc7b1a273447afd3e541e2f3..edcb4b343145fd51e91b72cef1351078f2c66c30 100644
--- a/stmhal/usbd_desc.c
+++ b/stmhal/usbd_desc_vcp.c
@@ -73,7 +73,7 @@ USBD_DescriptorsTypeDef VCP_Desc = {
 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
   #pragma data_alignment=4   
 #endif
-__ALIGN_BEGIN uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
+__ALIGN_BEGIN static uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
   0x12,                       /* bLength */
   USB_DESC_TYPE_DEVICE,       /* bDescriptorType */
   0x00,                       /* bcdUSB */
@@ -98,7 +98,7 @@ __ALIGN_BEGIN uint8_t hUSBDDeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
   #pragma data_alignment=4   
 #endif
-__ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
+__ALIGN_BEGIN static uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
   USB_LEN_LANGID_STR_DESC,         
   USB_DESC_TYPE_STRING,       
   LOBYTE(USBD_LANGID_STRING),
@@ -108,7 +108,7 @@ __ALIGN_BEGIN uint8_t USBD_LangIDDesc[USB_LEN_LANGID_STR_DESC] __ALIGN_END = {
 #if defined ( __ICCARM__ ) /*!< IAR Compiler */
   #pragma data_alignment=4   
 #endif
-__ALIGN_BEGIN uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
+__ALIGN_BEGIN static uint8_t USBD_StrDesc[USBD_MAX_STR_DESC_SIZ] __ALIGN_END;
 
 /* Private functions ---------------------------------------------------------*/
 
diff --git a/stmhal/usbd_msc_storage.c b/stmhal/usbd_msc_storage.c
new file mode 100644
index 0000000000000000000000000000000000000000..e5c75e27c7b8cbbcee9d2349691b7cab3507e5f1
--- /dev/null
+++ b/stmhal/usbd_msc_storage.c
@@ -0,0 +1,320 @@
+/**
+  ******************************************************************************
+  * @file    usbd_storage_msd.c
+  * @author  MCD application Team
+  * @version V1.1.0
+  * @date    19-March-2012
+  * @brief   This file provides the disk operations functions.
+  ******************************************************************************
+  * @attention
+  *
+  * <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
+  *
+  * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
+  * You may not use this file except in compliance with the License.
+  * You may obtain a copy of the License at:
+  *
+  *        http://www.st.com/software_license_agreement_liberty_v2
+  *
+  * Unless required by applicable law or agreed to in writing, software 
+  * distributed under the License is distributed on an "AS IS" BASIS, 
+  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  * See the License for the specific language governing permissions and
+  * limitations under the License.
+  *
+  * Heavily modified by dpgeorge for Micro Python.
+  *
+  ******************************************************************************
+  */
+
+#include "usbd_msc.h"
+#include "usbd_msc_storage.h"
+
+#include "misc.h"
+#include "storage.h"
+#include "diskio.h"
+#include "sdcard.h"
+
+/******************************************************************************/
+// Callback functions for when the internal flash is the mass storage device
+
+static const int8_t FLASH_STORAGE_Inquirydata[] = { // 36 bytes
+    // LUN 0
+    0x00,
+    0x00, // 0x00 for a fixed drive, 0x80 for a removable drive
+    0x02,
+    0x02,
+    (STANDARD_INQUIRY_DATA_LEN - 5),
+    0x00,
+    0x00,
+    0x00,
+    'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
+    'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product      : 16 Bytes
+    'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
+    '1', '.', '0' ,'0',                     // Version      : 4 Bytes
+};
+
+/**
+  * @brief  Initialize the storage medium
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_Init(uint8_t lun) {
+    storage_init();
+    return 0;
+}
+
+/**
+  * @brief  return medium capacity and block size
+  * @param  lun : logical unit number
+  * @param  block_num :  number of physical block
+  * @param  block_size : size of a physical block
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
+    *block_size = storage_get_block_size();
+    *block_num = storage_get_block_count();
+    return 0;
+}
+
+/**
+  * @brief  check whether the medium is ready
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_IsReady(uint8_t lun) {
+    return 0;
+}
+
+/**
+  * @brief  check whether the medium is write-protected
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_IsWriteProtected(uint8_t lun) {
+    return  0;
+}
+
+/**
+  * @brief  Read data from the medium
+  * @param  lun : logical unit number
+  * @param  buf : Pointer to the buffer to save data
+  * @param  blk_addr :  address of 1st block to be read
+  * @param  blk_len : nmber of blocks to be read
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+    disk_read(0, buf, blk_addr, blk_len);
+    /*
+    for (int i = 0; i < blk_len; i++) {
+        if (!storage_read_block(buf + i * FLASH_BLOCK_SIZE, blk_addr + i)) {
+            return -1;
+        }
+    }
+    */
+    return 0;
+}
+
+/**
+  * @brief  Write data to the medium
+  * @param  lun : logical unit number
+  * @param  buf : Pointer to the buffer to write from
+  * @param  blk_addr :  address of 1st block to be written
+  * @param  blk_len : nmber of blocks to be read
+  * @retval Status
+  */
+int8_t FLASH_STORAGE_Write (uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+    disk_write(0, buf, blk_addr, blk_len);
+    /*
+    for (int i = 0; i < blk_len; i++) {
+        if (!storage_write_block(buf + i * FLASH_BLOCK_SIZE, blk_addr + i)) {
+            return -1;
+        }
+    }
+    */
+    storage_flush(); // XXX hack for now so that the cache is always flushed
+    return 0;
+}
+
+/**
+  * @brief  Return number of supported logical unit
+  * @param  None
+  * @retval number of logical unit
+  */
+int8_t FLASH_STORAGE_GetMaxLun(void) {
+    return 0;
+}
+
+const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops = {
+    FLASH_STORAGE_Init,
+    FLASH_STORAGE_GetCapacity,
+    FLASH_STORAGE_IsReady,
+    FLASH_STORAGE_IsWriteProtected,
+    FLASH_STORAGE_Read,
+    FLASH_STORAGE_Write,
+    FLASH_STORAGE_GetMaxLun,
+    (int8_t *)FLASH_STORAGE_Inquirydata,
+};
+
+/******************************************************************************/
+// Callback functions for when the SD card is the mass storage device
+
+static const int8_t SDCARD_STORAGE_Inquirydata[] = { // 36 bytes
+    // LUN 0
+    0x00,
+    0x80, // 0x00 for a fixed drive, 0x80 for a removable drive
+    0x02,
+    0x02,
+    (STANDARD_INQUIRY_DATA_LEN - 5),
+    0x00,
+    0x00,
+    0x00,
+    'u', 'P', 'y', ' ', ' ', ' ', ' ', ' ', // Manufacturer : 8 bytes
+    'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', // Product      : 16 Bytes
+    'S', 'D', ' ', 'c', 'a', 'r', 'd', ' ',
+    '1', '.', '0' ,'0',                     // Version      : 4 Bytes
+};
+
+/**
+  * @brief  Initialize the storage medium
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_Init(uint8_t lun) {
+    /*
+#ifndef USE_STM3210C_EVAL 
+  NVIC_InitTypeDef NVIC_InitStructure;
+  NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;
+  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
+  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
+  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
+  NVIC_Init(&NVIC_InitStructure);
+#endif
+  if( SD_Init() != 0)
+  {
+    return (-1);
+  }
+  */
+    if (!sdcard_power_on()) {
+        return -1;
+    }
+
+    return 0;
+
+}
+
+/**
+  * @brief  return medium capacity and block size
+  * @param  lun : logical unit number
+  * @param  block_num :  number of physical block
+  * @param  block_size : size of a physical block
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_GetCapacity(uint8_t lun, uint32_t *block_num, uint16_t *block_size) {
+/*
+#ifdef USE_STM3210C_EVAL   
+  SD_CardInfo SDCardInfo;
+  SD_GetCardInfo(&SDCardInfo);  
+#else
+  if(SD_GetStatus() != 0 ) {
+    return (-1); 
+  }   
+#endif  
+  */
+
+    *block_size = SDCARD_BLOCK_SIZE;
+    *block_num =  sdcard_get_capacity_in_bytes() / SDCARD_BLOCK_SIZE;
+
+    return 0;
+}
+
+/**
+  * @brief  check whether the medium is ready
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_IsReady(uint8_t lun) {
+    /*
+#ifndef USE_STM3210C_EVAL  
+  
+  static int8_t last_status = 0;
+
+  if(last_status  < 0)
+  {
+    SD_Init();
+    last_status = 0;
+  }
+  
+  if(SD_GetStatus() != 0)
+  {
+    last_status = -1;
+    return (-1); 
+  }  
+#else
+  if( SD_Init() != 0)
+  {
+    return (-1);
+  }  
+#endif
+*/
+    return 0;
+}
+
+/**
+  * @brief  check whether the medium is write-protected
+  * @param  lun : logical unit number
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_IsWriteProtected(uint8_t lun) {
+    return 0;
+}
+
+/**
+  * @brief  Read data from the medium
+  * @param  lun : logical unit number
+  * @param  buf : Pointer to the buffer to save data
+  * @param  blk_addr :  address of 1st block to be read
+  * @param  blk_len : nmber of blocks to be read
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_Read(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+    if (!sdcard_read_blocks(buf, blk_addr, blk_len)) {
+        return -1;
+    }
+    return 0;
+}
+
+/**
+  * @brief  Write data to the medium
+  * @param  lun : logical unit number
+  * @param  buf : Pointer to the buffer to write from
+  * @param  blk_addr :  address of 1st block to be written
+  * @param  blk_len : nmber of blocks to be read
+  * @retval Status
+  */
+int8_t SDCARD_STORAGE_Write(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len) {
+    if (!sdcard_write_blocks(buf, blk_addr, blk_len)) {
+        return -1;
+    }
+    return 0;
+}
+
+/**
+  * @brief  Return number of supported logical unit
+  * @param  None
+  * @retval number of logical unit
+  */
+int8_t SDCARD_STORAGE_GetMaxLun(void) {
+    return 0;
+}
+
+const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops = {
+    SDCARD_STORAGE_Init,
+    SDCARD_STORAGE_GetCapacity,
+    SDCARD_STORAGE_IsReady,
+    SDCARD_STORAGE_IsWriteProtected,
+    SDCARD_STORAGE_Read,
+    SDCARD_STORAGE_Write,
+    SDCARD_STORAGE_GetMaxLun,
+    (int8_t *)SDCARD_STORAGE_Inquirydata,
+};
diff --git a/stmhal/usbd_msc_storage.h b/stmhal/usbd_msc_storage.h
new file mode 100644
index 0000000000000000000000000000000000000000..7cc79ca79348d9723b336d96d8ebffbd659a607d
--- /dev/null
+++ b/stmhal/usbd_msc_storage.h
@@ -0,0 +1,2 @@
+extern const USBD_StorageTypeDef USBD_FLASH_STORAGE_fops;
+extern const USBD_StorageTypeDef USBD_SDCARD_STORAGE_fops;
diff --git a/stmhal/usbdev/class/MSC/Inc/usbd_msc.h b/stmhal/usbdev/class/msc/inc/usbd_msc.h
similarity index 100%
rename from stmhal/usbdev/class/MSC/Inc/usbd_msc.h
rename to stmhal/usbdev/class/msc/inc/usbd_msc.h
diff --git a/stmhal/usbdev/class/MSC/Inc/usbd_msc_bot.h b/stmhal/usbdev/class/msc/inc/usbd_msc_bot.h
similarity index 100%
rename from stmhal/usbdev/class/MSC/Inc/usbd_msc_bot.h
rename to stmhal/usbdev/class/msc/inc/usbd_msc_bot.h
diff --git a/stmhal/usbdev/class/MSC/Inc/usbd_msc_data.h b/stmhal/usbdev/class/msc/inc/usbd_msc_data.h
similarity index 100%
rename from stmhal/usbdev/class/MSC/Inc/usbd_msc_data.h
rename to stmhal/usbdev/class/msc/inc/usbd_msc_data.h
diff --git a/stmhal/usbdev/class/MSC/Inc/usbd_msc_scsi.h b/stmhal/usbdev/class/msc/inc/usbd_msc_scsi.h
similarity index 100%
rename from stmhal/usbdev/class/MSC/Inc/usbd_msc_scsi.h
rename to stmhal/usbdev/class/msc/inc/usbd_msc_scsi.h
diff --git a/stmhal/usbdev/class/MSC/Inc/usbd_msc_storage_template.h b/stmhal/usbdev/class/msc/inc/usbd_msc_storage_template.h
similarity index 100%
rename from stmhal/usbdev/class/MSC/Inc/usbd_msc_storage_template.h
rename to stmhal/usbdev/class/msc/inc/usbd_msc_storage_template.h
diff --git a/stmhal/usbdev/class/MSC/Src/usbd_msc.c b/stmhal/usbdev/class/msc/src/usbd_msc.c
similarity index 100%
rename from stmhal/usbdev/class/MSC/Src/usbd_msc.c
rename to stmhal/usbdev/class/msc/src/usbd_msc.c
diff --git a/stmhal/usbdev/class/MSC/Src/usbd_msc_bot.c b/stmhal/usbdev/class/msc/src/usbd_msc_bot.c
similarity index 100%
rename from stmhal/usbdev/class/MSC/Src/usbd_msc_bot.c
rename to stmhal/usbdev/class/msc/src/usbd_msc_bot.c
diff --git a/stmhal/usbdev/class/MSC/Src/usbd_msc_data.c b/stmhal/usbdev/class/msc/src/usbd_msc_data.c
similarity index 100%
rename from stmhal/usbdev/class/MSC/Src/usbd_msc_data.c
rename to stmhal/usbdev/class/msc/src/usbd_msc_data.c
diff --git a/stmhal/usbdev/class/MSC/Src/usbd_msc_scsi.c b/stmhal/usbdev/class/msc/src/usbd_msc_scsi.c
similarity index 100%
rename from stmhal/usbdev/class/MSC/Src/usbd_msc_scsi.c
rename to stmhal/usbdev/class/msc/src/usbd_msc_scsi.c
diff --git a/stmhal/usbdev/class/MSC/Src/usbd_msc_storage_template.c b/stmhal/usbdev/class/msc/src/usbd_msc_storage_template.c
similarity index 100%
rename from stmhal/usbdev/class/MSC/Src/usbd_msc_storage_template.c
rename to stmhal/usbdev/class/msc/src/usbd_msc_storage_template.c
diff --git a/tests/basics/bytes.py b/tests/basics/bytes.py
index 7d0cf22d44e13de20bed977c5a0196c8432e17ae..a084bc39949c4c29500b12a2a1fb51857d039002 100644
--- a/tests/basics/bytes.py
+++ b/tests/basics/bytes.py
@@ -4,8 +4,36 @@ print(str(a))
 print(repr(a))
 print(a[0], a[2])
 print(a[-1])
+print(str(a, "utf-8"))
+print(str(a, "utf-8", "ignore"))
+try:
+    str(a, "utf-8", "ignore", "toomuch")
+except TypeError:
+    print("TypeError")
 
 s = 0
 for i in a:
     s += i
 print(s)
+
+
+print(bytes("abc", "utf-8"))
+print(bytes("abc", "utf-8", "replace"))
+try:
+    bytes("abc")
+except TypeError:
+    print("TypeError")
+try:
+    bytes("abc", "utf-8", "replace", "toomuch")
+except TypeError:
+    print("TypeError")
+
+print(bytes(3))
+
+print(bytes([3, 2, 1]))
+print(bytes(range(5)))
+
+def gen():
+    for i in range(4):
+        yield i
+print(bytes(gen()))
diff --git a/tests/basics/int-long.py b/tests/basics/int-long.py
index f867d8037d2eb70e83d1e0b397791386a75d924f..3567e08b2debe87ddb9c770f26b97a8afc0c9a9e 100644
--- a/tests/basics/int-long.py
+++ b/tests/basics/int-long.py
@@ -37,3 +37,10 @@ a <<= 5
 print(a)
 a >>= 1
 print(a)
+
+# Test referential integrity of long ints
+a = 0x1ffffffff
+b = a
+a += 1
+print(a)
+print(b)
diff --git a/tests/basics/math.py b/tests/basics/math-fun.py
similarity index 100%
rename from tests/basics/math.py
rename to tests/basics/math-fun.py
diff --git a/tests/basics/string_partition.py b/tests/basics/string_partition.py
new file mode 100644
index 0000000000000000000000000000000000000000..ad70d02509fde35c2e5adcbbb5f12dcee56dcc2c
--- /dev/null
+++ b/tests/basics/string_partition.py
@@ -0,0 +1,29 @@
+print("asdf".partition('g'))
+print("asdf".partition('a'))
+print("asdf".partition('s'))
+print("asdf".partition('f'))
+print("asdf".partition('d'))
+print("asdf".partition('asd'))
+print("asdf".partition('sdf'))
+print("asdf".partition('as'))
+print("asdf".partition('df'))
+print("asdf".partition('asdf'))
+print("asdf".partition('asdfa'))
+print("asdf".partition('fasdf'))
+print("asdf".partition('fasdfa'))
+print("abba".partition('a'))
+print("abba".partition('b'))
+
+try:
+    print("asdf".partition(1))
+except TypeError:
+    print("Raised TypeError")
+else:
+    print("Did not raise TypeError")
+
+try:
+    print("asdf".partition(''))
+except ValueError:
+    print("Raised ValueError")
+else:
+    print("Did not raise ValueError")
diff --git a/tests/basics/string_rpartition.py b/tests/basics/string_rpartition.py
new file mode 100644
index 0000000000000000000000000000000000000000..656121c94dbff6b7a3aa8e0ad4c09bfbe69e9e5f
--- /dev/null
+++ b/tests/basics/string_rpartition.py
@@ -0,0 +1,29 @@
+print("asdf".rpartition('g'))
+print("asdf".rpartition('a'))
+print("asdf".rpartition('s'))
+print("asdf".rpartition('f'))
+print("asdf".rpartition('d'))
+print("asdf".rpartition('asd'))
+print("asdf".rpartition('sdf'))
+print("asdf".rpartition('as'))
+print("asdf".rpartition('df'))
+print("asdf".rpartition('asdf'))
+print("asdf".rpartition('asdfa'))
+print("asdf".rpartition('fasdf'))
+print("asdf".rpartition('fasdfa'))
+print("abba".rpartition('a'))
+print("abba".rpartition('b'))
+
+try:
+    print("asdf".rpartition(1))
+except TypeError:
+    print("Raised TypeError")
+else:
+    print("Did not raise TypeError")
+
+try:
+    print("asdf".rpartition(''))
+except ValueError:
+    print("Raised ValueError")
+else:
+    print("Did not raise ValueError")