diff --git a/py/format-float.c b/py/format-float.c
new file mode 100644
index 0000000000000000000000000000000000000000..5411ae24f69d2df4b9f660a810dbcf0c58200c3f
--- /dev/null
+++ b/py/format-float.c
@@ -0,0 +1,311 @@
+/*********************************************************************** 
+ 
+  format-float.c  - Ruutine for converting a single-precision floating
+                    point number into a string.
+ 
+  The code in this funcion was inspired from Fred Bayer's pdouble.c.
+  Since pdouble.c was released as Public Domain, I'm releasing this
+  code as public domain as well.
+ 
+  The original code can be found in https://github.com/dhylands/format-float
+ 
+  Dave Hylands
+ 
+***********************************************************************/
+
+#include <stdint.h> 
+#include <stdlib.h>
+
+#include "mpconfig.h"
+
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+#include "format-float.h"
+
+// 1 sign bit, 8 exponent bits, and 23 mantissa bits.
+// exponent values 0 and 255 are reserved, exponent can be 1 to 254.
+// exponent is stored with a bias of 127.
+// The min and max floats are on the order of 1x10^37 and 1x10^-37
+
+#define FLT_SIGN_MASK   0x80000000
+#define FLT_EXP_MASK    0x7F800000
+#define FLT_MAN_MASK    0x007FFFFF
+
+static const float g_pos_pow[] = {
+    1e32, 1e16, 1e8, 1e4, 1e2, 1e1
+};
+static const float g_neg_pow[] = {
+    1e-32, 1e-16, 1e-8, 1e-4, 1e-2, 1e-1
+};
+
+int format_float(float f, char *buf, size_t buf_size, char fmt, int prec, char sign) {
+
+    char *s = buf;
+    int buf_remaining = buf_size - 1;
+
+    union {
+        float f;
+        uint32_t u;
+    } num = {f};
+
+    if (buf_size < 7) {
+        // Smallest exp notion is -9e+99 which is 6 chars plus terminating
+        // nulll.
+
+        if (buf_size >= 2) {
+            *s++ = '?';
+        }
+        if (buf_size >= 1) {
+            *s++ = '\0';
+        }
+        return buf_size >= 2;
+    }
+    if (num.u & FLT_SIGN_MASK) {
+        *s++ = '-';
+        num.u &= ~FLT_SIGN_MASK;
+    } else {
+        if (sign) {
+            *s++ = sign;
+        }
+    }
+    buf_remaining -= (s - buf); // Adjust for sign
+
+    if ((num.u & FLT_EXP_MASK) == FLT_EXP_MASK) {
+        char uc = fmt & 0x20;
+        if ((num.u & FLT_MAN_MASK) == 0) {
+            *s++ = 'I' ^ uc;
+            *s++ = 'N' ^ uc;
+            *s++ = 'F' ^ uc;
+        } else {
+            *s++ = 'N' ^ uc;
+            *s++ = 'A' ^ uc;
+            *s++ = 'N' ^ uc;
+        }
+        *s = '\0';
+        return s - buf;
+    }
+
+    if (prec < 0) {
+        prec = 6;
+    }
+    char e_char = 'E' | (fmt & 0x20);   // e_char will match case of fmt
+    fmt |= 0x20; // Force fmt to be lowercase
+    char org_fmt = fmt;
+    if (fmt == 'g' && prec == 0) {
+        prec = 1;
+    }
+    int e, e1; 
+    int dec = 0;
+    char e_sign = '\0';
+    int num_digits = 0;
+    const float *pos_pow = g_pos_pow;
+    const float *neg_pow = g_neg_pow;
+
+    if (num.u == 0) {
+        e = 0;
+        if (fmt == 'e') {
+            e_sign = '+';
+        } else if (fmt == 'f') {
+            num_digits = prec + 1;
+        }
+    } else if (num.u < 0x3f800000) { // f < 1.0
+        // Build negative exponent
+        for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+            if (*neg_pow > num.f) {
+                e += e1;
+                num.f *= *pos_pow;
+            }
+        }
+        if (num.f < 1.0F && num.f >= 0.9999995F) {
+            num.f = 1.0F;
+        } else {
+            e++; 
+            num.f *= 10.0F;
+        }
+
+        // If the user specified 'g' format, and e is <= 4, then we'll switch
+        // to the fixed format ('f')
+
+        if (fmt == 'f' || (fmt == 'g' && e <= 4)) {
+            fmt = 'f';
+            dec = -1;
+            *s++ = '0';
+
+            if (prec + e + 1 > buf_remaining) {
+                prec = buf_remaining - e - 1;
+            }
+
+            if (org_fmt == 'g') {
+                prec += (e - 1);
+            }
+            num_digits = prec;
+            if (num_digits) {
+                *s++ = '.'; 
+                while (--e && num_digits) {
+                    *s++ = '0';
+                    num_digits--;
+                }
+            }
+        } else {
+            // For e & g formats, we'll be printing the exponent, so set the
+            // sign.
+            e_sign = '-';
+            dec = 0;
+
+            if (prec > (buf_remaining - 6)) {
+                prec = buf_remaining - 6;
+                if (fmt == 'g') {
+                    prec++;
+                }
+            }
+        }
+    } else {
+        // Build positive exponent
+        for (e = 0, e1 = 32; e1; e1 >>= 1, pos_pow++, neg_pow++) {
+            if (*pos_pow <= num.f) {
+                e += e1;
+                num.f *= *neg_pow;
+            }
+        }
+
+        // If the user specified fixed format (fmt == 'f') and e makes the 
+        // number too big to fit into the available buffer, then we'll
+        // switch to the 'e' format.
+
+        if (fmt == 'f') {
+            if (e >= buf_remaining) {
+                fmt = 'e';
+            } else if ((e + prec + 2) > buf_remaining) {
+                prec = buf_remaining - e - 2;
+                if (prec < 0) {
+                    // This means no decimal point, so we can add one back
+                    // for the decimal.
+                    prec++;
+                }
+            }
+        }
+        if (fmt == 'e' && prec > (buf_remaining - 6)) {
+            prec = buf_remaining - 6;
+        }
+        // If the user specified 'g' format, and e is < prec, then we'll switch
+        // to the fixed format.
+
+        if (fmt == 'g' && e < prec) {
+            fmt = 'f';
+            prec -= (e + 1);
+        }
+        if (fmt == 'f') {
+            dec = e;
+            num_digits = prec + e + 1;
+        } else {
+            e_sign = '+';
+        }
+    }
+    if (prec < 0) {
+        // This can happen when the prec is trimmed to prevent buffer overflow
+        prec = 0;
+    }
+
+    // We now have num.f as a floating point number between >= 1 and < 10
+    // (or equal to zero), and e contains the absolute value of the power of
+    // 10 exponent. and (dec + 1) == the number of dgits before the decimal.
+
+    // For e, prec is # digits after the decimal
+    // For f, prec is # digits after the decimal
+    // For g, prec is the max number of significant digits
+    //
+    // For e & g there will be a single digit before the decimal
+    // for f there will be e digits before the decimal
+
+    if (fmt == 'e') {
+        num_digits = prec + 1;
+    } else if (fmt == 'g') {
+        if (prec == 0) {
+            prec = 1;
+        }
+        num_digits = prec; 
+    }
+
+    // Print the digits of the mantissa
+    for (int i = 0; i < num_digits; ++i, --dec) {
+        int32_t d = num.f;
+        *s++ = '0' + d;
+        if (dec == 0 && prec > 0) {
+            *s++ = '.';
+        }
+        num.f -= (float)d;
+        num.f *= 10.0F;
+    }
+
+    // Round
+    if (num.f >= 5.0F) {
+        char *rs = s;
+        rs--;
+        while (1) {
+            if (*rs == '.') {
+                rs--;
+                continue;
+            }
+            if (*rs < '0' || *rs > '9') {
+                // + or -
+                rs++; // So we sit on the digit to the right of the sign
+                break;
+            }
+            if (*rs < '9') {
+                (*rs)++;
+                break;
+            }
+            *rs = '0';
+            if (rs == buf) {
+                break;
+            }
+            rs--; 
+        }
+        if (*rs == '0') {
+            // We need to insert a 1
+            if (rs[1] == '.' && fmt != 'f') {
+                // We're going to round 9.99 to 10.00
+                // Move the decimal point
+                rs[0] = '.';
+                rs[1] = '0';
+                if (e_sign == '-') {
+                    e--;
+                } else {
+                    e++; 
+                }
+            }
+            s++;
+            char *ss = s; 
+            while (ss > rs) {
+                *ss = ss[-1];
+                ss--;
+            }
+            *rs = '1';
+        }
+        if (num.u < 0x3f800000 && fmt == 'f') {
+            // We rounded up to 1.0
+            prec--;
+        }
+    }
+
+    if (org_fmt == 'g' && prec > 0) {
+        // Remove trailing zeros and a trailing decimal point
+        while (s[-1] == '0') {
+            s--;
+        }
+        if (s[-1] == '.') {
+            s--;
+        }
+    }
+    // Append the exponent
+    if (e_sign) {
+        *s++ = e_char;
+        *s++ = e_sign;
+        *s++ = '0' + (e / 10);
+        *s++ = '0' + (e % 10);
+    }
+    *s = '\0';
+
+    return s - buf;
+}
+
+#endif
diff --git a/py/format-float.h b/py/format-float.h
new file mode 100644
index 0000000000000000000000000000000000000000..590fb0e91d75db9e8646910083dac30d0682444f
--- /dev/null
+++ b/py/format-float.h
@@ -0,0 +1,3 @@
+int format_float(float f, char *buf, size_t bufSize, char fmt, int prec, char sign);
+
+
diff --git a/py/objfloat.c b/py/objfloat.c
index 8ba9946b7ea59283db24ec6d0eae90a0d5eeaa5c..5b953f05eb12cea3257e39bd605a6e63a3954520 100644
--- a/py/objfloat.c
+++ b/py/objfloat.c
@@ -12,12 +12,21 @@
 #include "runtime0.h"
 
 #if MICROPY_ENABLE_FLOAT
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+#include "format-float.h"
+#endif
 
 mp_obj_t mp_obj_new_float(mp_float_t value);
 
 STATIC void float_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t o_in, mp_print_kind_t kind) {
     mp_obj_float_t *o = o_in;
+#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
+    char buf[32];
+    format_float(o->value, buf, sizeof(buf), 'g', 6, '\0');
+    print(env, "%s", buf);
+#else
     print(env, "%.8g", (double) o->value);
+#endif
 }
 
 STATIC mp_obj_t float_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
diff --git a/py/py.mk b/py/py.mk
index 579375e7d2dec168e2a72498f85aeb69866c3eb9..4fd295f8e50e0bf3999fe3ec697edb3c031e8d3f 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -32,6 +32,7 @@ PY_O_BASENAME = \
 	asmthumb.o \
 	emitnthumb.o \
 	emitinlinethumb.o \
+	format-float.o \
 	parsenumbase.o \
 	parsenum.o \
 	runtime.o \
diff --git a/stm/mpconfigport.h b/stm/mpconfigport.h
index 3f48c43f04f169c18c037df25d39faf235018ca4..57c92181b8b1f7996e4b19389e11fffc0acda9d3 100644
--- a/stm/mpconfigport.h
+++ b/stm/mpconfigport.h
@@ -7,6 +7,7 @@
 #define MICROPY_ENABLE_GC           (1)
 #define MICROPY_ENABLE_REPL_HELPERS (1)
 #define MICROPY_LONGINT_IMPL        (MICROPY_LONGINT_IMPL_MPZ)
+#define MICROPY_ENABLE_FLOAT        (1)
 #define MICROPY_FLOAT_IMPL          (MICROPY_FLOAT_IMPL_FLOAT)
 #define MICROPY_PATH_MAX            (128)
 /* Enable FatFS LFNs
diff --git a/stm/printf.c b/stm/printf.c
index abbc58b669ee7864893cd7203cd76d9f44a513ce..56a5d864cfa1891e0513b6b2dc2a44ccf103b2b6 100644
--- a/stm/printf.c
+++ b/stm/printf.c
@@ -11,6 +11,9 @@
 #include "lcd.h"
 #include "usart.h"
 #include "usb.h"
+#if MICROPY_ENABLE_FLOAT
+#include "format-float.h"
+#endif
 
 #define PF_FLAG_LEFT_ADJUST (0x01)
 #define PF_FLAG_SHOW_SIGN   (0x02)
@@ -210,29 +213,40 @@ int pfenv_printf(const pfenv_t *pfenv, const char *fmt, va_list args) {
                 chrs += pfenv_print_int(pfenv, va_arg(args, int), 0, 16, 'A', flags, width);
                 break;
 #if MICROPY_ENABLE_FLOAT
+            case 'e':
+            case 'E':
+            case 'f':
+            case 'F':
             case 'g':
+            case 'G':
             {
-                // This is a very hacky approach to printing floats. Micropython
-                // uses %g when using print, and I just wanted to see somthing
-                // usable. I expect that this will be replaced with something
-                // more appropriate.
-                char dot = '.';
-                mp_float_t d = va_arg(args, double);
-                int left = (int)d;
-                int right = (int)((d - (mp_float_t)(int)d) * 1000000.0);
-                if (right < 0) {
-                    if (left == 0) {
-                        chrs += pfenv_print_strn(pfenv, "-0", 2, flags, width);
-                    } else {
-                        chrs += pfenv_print_int(pfenv, left, 1, 10, 'a', flags, width); 
-                    }
-                    chrs += pfenv_print_strn(pfenv, &dot, 1, flags, width);
-                    chrs += pfenv_print_int(pfenv, -right, 0, 10, 'a', PF_FLAG_ZERO_PAD, 6);
-                } else {
-                    chrs += pfenv_print_int(pfenv, left, 1, 10, 'a', flags, width); 
-                    chrs += pfenv_print_strn(pfenv, &dot, 1, flags, width);
-                    chrs += pfenv_print_int(pfenv, right, 0, 10, 'a', PF_FLAG_ZERO_PAD, 6);
+                char buf[32];
+                char sign = '\0';
+
+                if (flags & PF_FLAG_SHOW_SIGN) {
+                    sign = '+';
+                }
+                else
+                if (flags & PF_FLAG_SPACE_SIGN) {
+                    sign = ' ';
+                }
+                float f = va_arg(args, double);
+                int len = format_float(f, buf, sizeof(buf), *fmt, prec, sign);
+                char *s = buf;
+
+                // buf[0] < '0' returns true if the first character is space, + or -
+                // buf[1] < '9' matches a digit, and doesn't match when we get back +nan or +inf
+                if (buf[0] < '0' && buf[1] <= '9' && (flags & PF_FLAG_ZERO_PAD)) {
+                    chrs += pfenv_print_strn(pfenv, &buf[0], 1, 0, 1);
+                    s++;
+                    width--;
+                    len--;
+                }
+                if (*s < '0' || *s >= '9') {
+                    // For inf or nan, we don't want to zero pad.
+                    flags &= ~PF_FLAG_ZERO_PAD;
                 }
+                chrs += pfenv_print_strn(pfenv, s, len, flags, width); 
                 break;
             }
 #endif