mbed library sources

Dependents:   frdm_kl05z_gpio_test

Fork of mbed-src by mbed official

Revision:
51:7838415c99e7
Parent:
20:4263a77256ae
Child:
140:ca60b7a31055
diff -r b08ceb75017d -r 7838415c99e7 targets/hal/TARGET_NXP/TARGET_LPC13XX/serial_api.c
--- a/targets/hal/TARGET_NXP/TARGET_LPC13XX/serial_api.c	Tue Nov 26 15:30:05 2013 +0000
+++ b/targets/hal/TARGET_NXP/TARGET_LPC13XX/serial_api.c	Mon Dec 02 10:00:04 2013 +0000
@@ -124,22 +124,47 @@
     uint16_t dlv;
     uint8_t mv, dav;
     if ((PCLK % (16 * baudrate)) != 0) {     // Checking for zero remainder
-        float err_best = (float) baudrate;
-        uint16_t dlmax = DL;
-        for ( dlv = (dlmax/2); (dlv <= dlmax) && !hit; dlv++) {
-            for ( mv = 1; mv <= 15; mv++) {
-                for ( dav = 1; dav < mv; dav++) {
-                    float ratio = 1.0f + ((float) dav / (float) mv);
-                    float calcbaud = (float)PCLK / (16.0f * (float) dlv * ratio);
-                    float err = fabs(((float) baudrate - calcbaud) / (float) baudrate);
-                    if (err < err_best) {
-                        DL = dlv;
-                        DivAddVal = dav;
-                        MulVal = mv;
-                        err_best = err;
-                        if (err < 0.001f) {
-                            hit = 1;
-                        }
+        int err_best = baudrate, b;
+        for (mv = 1; mv < 16 && !hit; mv++)
+        {
+            for (dav = 0; dav < mv; dav++)
+            {
+                // baudrate = PCLK / (16 * dlv * (1 + (DivAdd / Mul))
+                // solving for dlv, we get dlv = mul * PCLK / (16 * baudrate * (divadd + mul))
+                // mul has 4 bits, PCLK has 27 so we have 1 bit headroom which can be used for rounding
+                // for many values of mul and PCLK we have 2 or more bits of headroom which can be used to improve precision
+                // note: X / 32 doesn't round correctly. Instead, we use ((X / 16) + 1) / 2 for correct rounding
+
+                if ((mv * PCLK * 2) & 0x80000000) // 1 bit headroom
+                    dlv = ((((2 * mv * PCLK) / (baudrate * (dav + mv))) / 16) + 1) / 2;
+                else // 2 bits headroom, use more precision
+                    dlv = ((((4 * mv * PCLK) / (baudrate * (dav + mv))) / 32) + 1) / 2;
+
+                // datasheet says if DLL==DLM==0, then 1 is used instead since divide by zero is ungood
+                if (dlv == 0)
+                    dlv = 1;
+
+                // datasheet says if dav > 0 then DL must be >= 2
+                if ((dav > 0) && (dlv < 2))
+                    dlv = 2;
+
+                // integer rearrangement of the baudrate equation (with rounding)
+                b = ((PCLK * mv / (dlv * (dav + mv) * 8)) + 1) / 2;
+
+                // check to see how we went
+                b = abs(b - baudrate);
+                if (b < err_best)
+                {
+                    err_best  = b;
+
+                    DL        = dlv;
+                    MulVal    = mv;
+                    DivAddVal = dav;
+
+                    if (b == baudrate)
+                    {
+                        hit = 1;
+                        break;
                     }
                 }
             }