mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 02:08:32 +08:00
782 lines
No EOL
54 KiB
HTML
782 lines
No EOL
54 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
|
||
<head>
|
||
<link rel="stylesheet" type="text/css" href="/_static/css/banner-styles.css?v=bsmaklHF" />
|
||
<link rel="stylesheet" type="text/css" href="/_static/css/iconochive.css?v=qtvMKcIJ" />
|
||
<link rel="canonical" href="https://lupyuen.org/articles/stm32-blue-pill-shrink-your-math-libraries-with-qfplib.html" />
|
||
<!-- End Wayback Rewrite JS Include -->
|
||
<title data-rh="true">STM32 Blue Pill – Shrink your math libraries with Qfplib</title>
|
||
<meta data-rh="true" charset="utf-8" />
|
||
<meta data-rh="true" name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
|
||
<meta data-rh="true" name="theme-color" content="#000000" />
|
||
<meta data-rh="true" property="og:type" content="article" />
|
||
<meta data-rh="true" property="article:published_time" content="2019-01-30T09:53:36.711Z" />
|
||
<meta data-rh="true" name="title" content="STM32 Blue Pill – Shrink your math libraries with Qfplib" />
|
||
<meta data-rh="true" property="og:title" content="STM32 Blue Pill – Shrink your math libraries with Qfplib" />
|
||
<meta data-rh="true" property="twitter:title" content="STM32 Blue Pill – Shrink your math libraries with Qfplib" />
|
||
<meta data-rh="true" name="description"
|
||
content="Floating-point math libraries can bloat your Blue Pill code. Here’s one way to fix that" />
|
||
<meta data-rh="true" property="og:description"
|
||
content="Floating-point math libraries can bloat your Blue Pill code. Here’s one way to fix that" />
|
||
<meta data-rh="true" property="twitter:description"
|
||
content="Floating-point math libraries can bloat your Blue Pill code. Here’s one way to fix that" />
|
||
<meta data-rh="true" name="twitter:card" content="summary_large_image" />
|
||
<meta data-rh="true" name="twitter:creator" content="@MisterTechBlog" />
|
||
<meta data-rh="true" name="author" content="Lup Yuen Lee 李立源" />
|
||
<meta data-rh="true" name="robots" content="index,follow" />
|
||
<meta data-rh="true" name="referrer" content="unsafe-url" />
|
||
<meta data-rh="true" name="twitter:label1" value="Reading time" />
|
||
<meta data-rh="true" name="twitter:data1" value="9 min read" />
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/legacy2/m1.png">
|
||
|
||
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
|
||
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../prism.css">
|
||
<script src="../storage.js"></script><noscript>
|
||
<link rel="stylesheet" href="../noscript.css"></noscript>
|
||
<link rel="shortcut icon" href="../favicon.ico">
|
||
<style type="text/css">
|
||
#crate-search {
|
||
background-image: url("../down-arrow.svg");
|
||
}
|
||
a {
|
||
color: #77d;
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
</head>
|
||
|
||
<body>
|
||
<div id="root">
|
||
<div class="a b c">
|
||
<article>
|
||
<section class="cj ck cl cm ak cn ce n co"></section><span class="r"></span>
|
||
<div>
|
||
<div class="cp u cq cr cs ct"></div>
|
||
<section class="cu cv cw cx cy">
|
||
<div class="cz ak">
|
||
<div class="figure da cz ak paragraph-image">
|
||
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m1.png" /></p>
|
||
|
||
|
||
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<div>
|
||
<div id="457c" class="dq dr ds bk dt b du dv dw dx dy dz ea">
|
||
<h1 class="dt b du eb ds">STM32 Blue Pill – Shrink your math libraries with Qfplib</h1>
|
||
</div>
|
||
<div class="ec">
|
||
<div class="n ed ee ef eg">
|
||
<div class="o n">
|
||
<div><a rel="noopener"
|
||
href="https://lupyuen.github.io">
|
||
<div class="di eh ei">
|
||
<div class="bs n ej o p cp ek el em en eo ct"></div>
|
||
|
||
</div>
|
||
</a></div>
|
||
<div class="eq ak r">
|
||
<div class="n">
|
||
<div style="flex:1"><span class="bj b bk bl bm bn r ds q">
|
||
<div class="er n o es"><span class="bj et eu bl de ev ew ex ey ez ds"><a
|
||
class="at au av aw ax ay az ba bb bc fa bf bg bh bi" rel="noopener"
|
||
href="https://lupyuen.github.io">Lup
|
||
Yuen Lee 李立源</a></span>
|
||
|
||
</div>
|
||
</span></div>
|
||
</div><span class="bj b bk bl bm bn r bo bp"><span class="bj et eu bl de ev ew ex ey ez bo">
|
||
<div><a class="at au av aw ax ay az ba bb bc fa bf bg bh bi" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/stm32-blue-pill-shrink-your-math-libraries-with-qfplib">
|
||
30 Jan 2019</a> <!-- -->·
|
||
<!-- -->
|
||
<!-- -->9
|
||
<!-- --> min read
|
||
</div>
|
||
</span></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p id="7318" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Check out this magic trick… Why
|
||
does <a
|
||
href="http://wiki.stm32duino.com/index.php?title=Blue_Pill"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Blue Pill</a> think that <strong
|
||
class="gb gr">123</strong> times <strong class="gb gr">456</strong> is <strong
|
||
class="gb gr">123,456</strong> ???!!! <a
|
||
href="https://github.com/lupyuen/stm32bluepill-math-hack"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Here’s the full source code</a>.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gs gt gu gv gw cz">
|
||
<div class="dh r di">
|
||
<div class="gx r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F3AedU60qGFI%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D3AedU60qGFI&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F3AedU60qGFI%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400" title="STM32 Blue Pill Math Hack"
|
||
class="cp t u dd ak" scrolling="auto"></iframe></div>
|
||
</div>
|
||
<figcaption><p><em>Blue Pill thinks that 123 times 456 is 123,456
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<p id="c4ff" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">This article explains how we
|
||
hacked Blue Pill to create this interesting behaviour, and how we may exploit this hack to cut down
|
||
the size of our math libraries…</p>
|
||
<ol class="">
|
||
<li id="2b57" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm hd he hf">What are <strong
|
||
class="gb gr">Math Libraries</strong>? How does Blue Pill perform math computations?</li>
|
||
<li id="e9d5" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf"><strong
|
||
class="gb gr">Qfplib</strong> the tiny math library</li>
|
||
<li id="9fb2" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf"><strong
|
||
class="gb gr">Single vs Double-Precision</strong> numbers. Do we really need Double-Precision?
|
||
</li>
|
||
<li id="c835" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf">Filling in the
|
||
missing math functions with <code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">nano-float</strong></code></li>
|
||
<li id="7992" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf"><strong
|
||
class="gb gr">Testing</strong> Qfplib and nano-float</li>
|
||
<li id="1735" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf"><strong
|
||
class="gb gr">My experience</strong> with Qfplib and nano-float</li>
|
||
</ol>
|
||
<p id="5c62" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><strong class="gb gr"><em
|
||
class="hp">This article covers experimental topics that have not been tested in production
|
||
systems, so be very careful if you decide to use any tips from this article.</em></strong></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="4b56" class="hz ia ds bk bj ib ic id ie if ig ih ii ij ik il im">What are Math Libraries? Why so
|
||
huge?</h1>
|
||
<p id="def5" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">If you have used math functions
|
||
like <code class="dj hl hm hn ho b">sin(), log(), floor(), ...</code> then you would have used the
|
||
<code class="dj hl hm hn ho b"><strong class="gb gr">libm.a</strong></code><strong class="gb gr">
|
||
Standard Math Library for C</strong>. It’s a bunch of common math functions that we may call from C
|
||
and C++ programs running on Blue Pill and virtually any microcontroller and any device.</p>
|
||
<p id="0d38" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">But there’s a catch… The math
|
||
functions will perform better on some microcontrollers and devices — those that support <strong
|
||
class="gb gr">hardware floating-point operations in their processors</strong>.</p>
|
||
<p id="5701" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Unfortunately <strong
|
||
class="gb gr">Blue Pill is not in that list.</strong> The math libraries are implemented in
|
||
software, not hardware. So a single call to <code class="dj hl hm hn ho b">sin()</code> could actually
|
||
keep the Blue Pill busy for a (short) while because of the <a
|
||
href="https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/ieee754/dbl-64/s_sin.c;h=7584afcd2b016fd94f8452d30f5d3542a831b5b3;hb=refs/heads/master"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">complicated library code</a>. And
|
||
the complicated math code also causes Blue Pill programs to bloat beyond their ROM limit (64 KB).</p>
|
||
<p id="f95a" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Is there a better way to do math
|
||
on Blue Pill? The secret lies in the Magic Trick…</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<div class="figure gs gt gu gv gw cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/757429ba987bdaafc0f62f31757698a1.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/src/main.c"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/src/main.c</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<h1 id="b691" class="hz ia ds bk bj ib ic it ie iu ig iv ii iw ik ix im">Magic Trick Revealed</h1>
|
||
<p id="6695" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">Remember the above code from the
|
||
Magic Trick… Why does Blue Pill think that 123 times 456 is 123,456? Let’s look at the <a
|
||
href="https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/firmware.dump"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Assembly Code</a> (check <a
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/stm32-blue-pill-analyse-and-optimise-your-ram-and-rom">my
|
||
previous article</a> for the “Disassemble” task)…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="iy iz ja jb jc jd ag je ah jf aj ak">
|
||
<div class="figure gs gt gu gv gw cz jh ji paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m2.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em>Assembly Code for the magic trick. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/firmware.dump"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/firmware.dump</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<p id="03df" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Something suspicious is happening
|
||
here… the line</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="9af6" class="jq ia ds bk ho b eu jr js r jt">r = x * y</span></pre>
|
||
<p id="bf8a" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">has actually been compiled into a
|
||
function call that looks like…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="1620" class="jq ia ds bk ho b eu jr js r jt">r = __wrap___aeabi_dmul(x, y)</span></pre>
|
||
<p id="498b" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Multiplication of numbers looks
|
||
<em class="hp">simple and harmless</em> when we write it as <code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">x * y</strong></code>. But remember that <code
|
||
class="dj hl hm hn ho b">x</code> and <code class="dj hl hm hn ho b">y</code> are floating-point
|
||
numbers. And Blue Pill can’t compute floating-point numbers in hardware. <strong class="gb gr">So Blue
|
||
Pill needs to call a math library function </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">__wrap___aeabi_dmul</strong></code><strong
|
||
class="gb gr"> to compute </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">x * y !</strong></code></p>
|
||
<p id="bbfb" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><em class="hp">It looks more
|
||
sinister now…</em></p>
|
||
<p id="caeb" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Remember this function that
|
||
appears at the end of the magic trick?</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="87d8" class="jq ia ds bk ho b eu jr js r jt">double __wrap___aeabi_dmul(double x, double y) { <br/> return 123456; <br/>}</span></pre>
|
||
<p id="da9c" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">That’s where the magic happens —
|
||
<strong class="gb gr">it returns </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">123456</strong></code><strong class="gb gr"> for any
|
||
multiplication of </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">doubles</strong></code> in the program. We have
|
||
intercepted the multiplication operation to return a hacked result.</p>
|
||
<p id="cf7a" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><code
|
||
class="dj hl hm hn ho b">__wrap___aeabi_dmul</code> is typically a function with lots of computation
|
||
code inside… <strong class="gb gr">1 KB of compiled code</strong>. So our code size will bloat
|
||
significantly once we start using floating-point computation on Blue Pill.</p>
|
||
<p id="e8c5" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Now what if we do this…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="f5c4" class="jq ia ds bk ho b eu jr js r jt">double __wrap___aeabi_dmul(double x, double y) { <br/> return qfp_fmul(x, y); <br/>}</span></pre>
|
||
<p id="34c5" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><strong class="gb gr">What if we
|
||
could find a tiny function </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">qfp_fmul</strong></code><strong class="gb gr"> that
|
||
multiplies floating-point numbers without bloating the code size?</strong> That would be perfect for
|
||
Blue Pill! <code class="dj hl hm hn ho b">qfp_fmul</code> actually exists and it’s part of the <strong
|
||
class="gb gr">Qfplib</strong> library, coming up next…</p>
|
||
<blockquote class="ju jv jw">
|
||
<p id="0df5" class="fz ga ds hp gb b gc gd ge gf gg gh gi gj gk gl gm">💎 About the <code
|
||
class="dj hl hm hn ho b">wrap</code>: The <code class="dj hl hm hn ho b">wrap</code> prefix was
|
||
inserted because we used this linker option in <a
|
||
href="https://github.com/lupyuen/stm32bluepill-math-hack/blob/master/platformio.ini"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">platformio.ini</a>:<code
|
||
class="dj hl hm hn ho b"> -Wl,-wrap,__aeabi_dmul</code>. Without <code
|
||
class="dj hl hm hn ho b">wrap</code>, the function name is actually <code
|
||
class="dj hl hm hn ho b"><em class="bk">__aeabi_dmul</em></code><em class="bk">. </em>By using
|
||
<code class="dj hl hm hn ho b">wrap</code> we can easily identify the functions that we have
|
||
intercepted. <a
|
||
href="http://infocenter.arm.com/help/topic/com.arm.doc.ihi0043d/IHI0043D_rtabi.pdf"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Check this doc for more info on
|
||
AEABI functions</a>.</p>
|
||
</blockquote>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<div class="gs gt gu gv gw jx"><a
|
||
href="https://www.quinapalus.com/qfplib.html?source=post_page-----55093aab163a----------------------"
|
||
rel="noopener nofollow">
|
||
<section class="ka cl cm ak ce n ar kb kc kd ke kf kg kh ki kj kk kl km kn ko kp">
|
||
<div class="kq n co p kr ks">
|
||
<h2 class="bj ib kt bl ds">
|
||
<div class="de jy ew ex jz ez">Qfplib: an ARM Cortex-M0 floating-point library in 1 kbyte
|
||
</div>
|
||
</h2>
|
||
</div>
|
||
<div class="kw r">
|
||
<div class="kx r ky kz la kw lb lc ld"></div>
|
||
</div>
|
||
</section>
|
||
</a></div>
|
||
<h1 id="90cc" class="hz ia ds bk bj ib ic it ie iu ig iv ii iw ik ix im">Qfplib the tiny floating-point
|
||
library</h1>
|
||
<p id="2a56" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm"><a
|
||
href="https://www.quinapalus.com/qfplib.html"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Qfplib</a> is a floating-point
|
||
math library by Dr Mark Owen that’s incredibly small. In a mere <strong class="gb gr">1,224
|
||
bytes</strong> we get Assembly Code functions (specific to Arm Cortex-M0 and above) that compute…
|
||
</p>
|
||
<ul class="">
|
||
<li id="9f39" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm le he hf"><code
|
||
class="dj hl hm hn ho b">qfp_fadd, qfp_fsub, qfp_fmul, qfp_fdiv_fast</code>: Floating-point
|
||
addition, subtraction, multiplication, division</li>
|
||
<li id="caaf" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm le he hf"><code
|
||
class="dj hl hm hn ho b">qfp_fsin, qfp_fcos, qfp_ftan, qfp_fatan2</code>: sine, cosine, tangent,
|
||
inverse tangent</li>
|
||
<li id="c763" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm le he hf"><code
|
||
class="dj hl hm hn ho b">qfp_fexp, qfp_fln</code>: Natural exponential, logarithm</li>
|
||
<li id="ff17" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm le he hf"><code
|
||
class="dj hl hm hn ho b">qfp_fsqrt_fast, qfp_fcmp</code>: Square root, comparison of floats</li>
|
||
</ul>
|
||
<p id="d8a8" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Plus conversion functions for
|
||
integers, fixed-point and floating-point numbers. What a gem!</p>
|
||
<p id="cf8d" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">With Qfplib we may now intercept
|
||
any floating-point operation (using the <code class="dj hl hm hn ho b">__wrap___aeabi_dmul</code>
|
||
method above) and <strong class="gb gr">substitute a smaller, optimised version</strong> of the
|
||
computation code.</p>
|
||
<p id="db22" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Be careful: There are <strong
|
||
class="gb gr">limitations in the Qfplib functions</strong>, <a
|
||
href="https://www.quinapalus.com/qfplib.html"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">as described here</a>. And Qfplib
|
||
only handles <strong class="gb gr">single-precision math, not double-precision</strong>. More about
|
||
this…</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="5ed2" class="hz ia ds bk bj ib ic id ie if ig ih ii ij ik il im">Single vs Double-Precision
|
||
Floating-Point Numbers</h1>
|
||
<p id="4a0f" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">You should have seen
|
||
single-precision (<code class="dj hl hm hn ho b">float</code>) and double-precision (<code
|
||
class="dj hl hm hn ho b">double</code>) numbers in C programs…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="0b44" class="jq ia ds bk ho b eu jr js r jt">float x = 123.456; // Single precision (32 bits)<br/>double y = 123.456789012345; // Double precision (64 bits)</span></pre>
|
||
<p id="8f4c" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Double-precision numbers are more
|
||
precise in representing floating-point numbers because they have twice the number of bits (<strong
|
||
class="gb gr">64 bits</strong>) compared with single-precision numbers (<strong class="gb gr">32
|
||
bits</strong>).</p>
|
||
<p id="89d1" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">To be more specific…
|
||
single-precision numbers are stored in the <a
|
||
href="https://en.wikipedia.org/wiki/Single-precision_floating-point_format"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">IEEE 754 Single-Precision
|
||
format</a> which gives us <strong class="gb gr">6 significant decimal digits</strong>. So this <code
|
||
class="dj hl hm hn ho b">float</code> value is OK because it’s only 6 decimal digits…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="8454" class="jq ia ds bk ho b eu jr js r jt">float x = 123.456; // OK for Single Precision</span></pre>
|
||
<p id="86c1" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">But we may lose the seventh digit
|
||
in this <code class="dj hl hm hn ho b">float</code> value because 32 bits can’t fully accommodate 7
|
||
decimal digits…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="62a8" class="jq ia ds bk ho b eu jr js r jt">float y = 123.4567; // Last digit may be truncated for Single Precision</span></pre>
|
||
<p id="cbf7" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">And Blue Pill may think that
|
||
<code class="dj hl hm hn ho b">x</code> has the same value as <code class="dj hl hm hn ho b">y</code>.
|
||
We wouldn’t use <code class="dj hl hm hn ho b">float</code> to count 10 million dollars (7 decimal
|
||
digits or more).</p>
|
||
<p id="22ca" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">With double-precision numbers
|
||
(stored as <a
|
||
href="https://en.wikipedia.org/wiki/Double-precision_floating-point_format"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">IEEE 754 Double-Precision
|
||
format</a>) we have room for <strong class="gb gr">15 significant decimal digits</strong>…</p>
|
||
<pre
|
||
class="gs gt gu gv gw jn jo jp"><span id="873e" class="jq ia ds bk ho b eu jr js r jt">double y = 123.456789012345; // OK for Double Precision</span></pre>
|
||
<p id="fd0a" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Double precision is indeed more
|
||
precise than single precision. BUT…</p>
|
||
<ol class="">
|
||
<li id="5194" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm hd he hf"><code
|
||
class="dj hl hm hn ho b">doubles</code> take up <strong class="gb gr">twice the storage</strong>
|
||
</li>
|
||
<li id="c915" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf"><code
|
||
class="dj hl hm hn ho b">doubles</code> also require <strong class="gb gr">more processor
|
||
time</strong> to compute</li>
|
||
</ol>
|
||
<p id="eb7a" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">This causes problems for
|
||
constrained microcontrollers like Blue Pill. Also if we use common math functions like <code
|
||
class="dj hl hm hn ho b">sin(), log(), floor()</code>, … we will actually introduce <code
|
||
class="dj hl hm hn ho b">doubles</code> into our code because the common math functions are declared
|
||
as <code class="dj hl hm hn ho b">double</code>. (The single-precision equivalent functions are
|
||
available, but we need to consciously select them as <code
|
||
class="dj hl hm hn ho b">sinf(), logf(), floorf()</code>, …)</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="51e0" class="hz ia ds bk bj ib ic id ie if ig ih ii ij ik il im">Do we really need Double
|
||
Precision numbers?</h1>
|
||
<p id="7b5a" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">I teach IoT. When my students
|
||
measure ambient temperature with a long string of digits like 28.12345, I’m pretty sure they’re not
|
||
doing it right.</p>
|
||
<p id="f724" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Sensors are inherently noisy so I
|
||
won’t trust them to produce such precise double-precision numbers. Instead I would use a Time Series
|
||
Database to <strong class="gb gr">aggregate sensor values (single-precision) over time and compute an
|
||
aggregated sensor value</strong> (say, moving average for the past minute) that’s more resistant to
|
||
sensor noise.</p>
|
||
<p id="4213" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">If you’re doing Scientific
|
||
Computing, then <code class="dj hl hm hn ho b">doubles</code> are for you. Then again you probably
|
||
won’t be using a lower-class microcontroller like Blue Pill. It’s my hunch that most Blue Pill
|
||
programmers will be perfectly happy with <code class="dj hl hm hn ho b">floats</code> instead of <code
|
||
class="dj hl hm hn ho b">doubles</code> (though I have no proof).</p>
|
||
<p id="d650" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Always exercise caution when
|
||
using <code class="dj hl hm hn ho b">floats</code> instead of <code
|
||
class="dj hl hm hn ho b">doubles</code>. There’s a possibility that some <strong
|
||
class="gb gr">intermediate computation will overflow the 6-digit limitation of </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">floats,</strong></code> l<a
|
||
href="https://github.com/adafruit/Adafruit_BME280_Library/blob/master/Adafruit_BME280.cpp#L591"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">ike this computation</a>. GPS
|
||
coordinates (latitude, longitude) may require <code class="dj hl hm hn ho b">doubles</code> as well.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<div class="figure gs gt gu gv gw cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m3.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em>nano-float function derived from Qfplib and
|
||
the unit test cases below. From <a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L555-L585"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L555-L585</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<h1 id="d9db" class="hz ia ds bk bj ib ic it ie iu ig iv ii iw ik ix im">Complete Math Library:
|
||
nano-float</h1>
|
||
<div class="figure gs gt gu gv gw cz do li cd lj lk ll lm ln ba lo lp lq lr ls lt paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m4.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em>Functions provided by qfplib</em></p></figcaption>
|
||
</div>
|
||
<p id="31a6" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Qfplib provides the basic
|
||
float-point math functions. Many other math functions are missing: <code
|
||
class="dj hl hm hn ho b">sinh</code>, <code class="dj hl hm hn ho b">asinh</code>, … <strong
|
||
class="gb gr">Can we synthesise the other math functions</strong>?</p>
|
||
<p id="eff7" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Yes we can! And here’s the proof…
|
||
</p>
|
||
<p id="f29b" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><code
|
||
class="dj hl hm hn ho b">https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c</code>
|
||
</p>
|
||
<p id="2dd9" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">nano-float</strong></code> is a thin layer of code I
|
||
wrote (not 100% tested) that fills in the remaining math functions by calling Qfplib. <code
|
||
class="dj hl hm hn ho b">nano-float</code> is a drop-in replacement for the standard math library,
|
||
so the function signatures for the math functions are the same… just link your program with <code
|
||
class="dj hl hm hn ho b">nano-float</code> instead of the default math library, no recompilation
|
||
needed.</p>
|
||
<p id="3a62" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">This looks like a math textbook
|
||
exercise but let’s derive the missing functions based on Qfplib…</p>
|
||
<p id="bed3" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">1️⃣ <code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L373-L408" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">log2</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L373-L408"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow"> and </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L373-L408" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">log10</a></code>
|
||
were derived from Qfplib’s <code class="dj hl hm hn ho b">qfp_fln</code> (natural logarithm function)
|
||
because…</p>
|
||
<div class="figure gs gt gu gv gw cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m5.png" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em><a
|
||
href="https://en.wikipedia.org/wiki/Logarithm"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://en.wikipedia.org/wiki/Logarithm</a></em></p></figcaption>
|
||
</div>
|
||
<p id="947f" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">2️⃣ <code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L555-L629" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">asin</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L555-L629"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow"> and </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L555-L629" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">acos</a></code>
|
||
(inverse sine / cosine) were derived from Qfplib’s <code
|
||
class="dj hl hm hn ho b">qfp_fsqrt_fast</code> (square root) and <code
|
||
class="dj hl hm hn ho b">qfp_fatan2</code> (inverse tangent) because…</p>
|
||
<div class="figure gs gt gu gv gw cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m6.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em><a
|
||
href="https://en.wikipedia.org/wiki/Inverse_trigonometric_functions"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://en.wikipedia.org/wiki/Inverse_trigonometric_functions</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="8a59" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">3️⃣ <code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L631-L717" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">sinh</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L631-L717"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">, </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L631-L717" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">cosh</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L631-L717"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow"> and </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L631-L717" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">tanh</a></code>
|
||
(hyperbolic sine / cosine / tangent) were derived from Qfplib’s <code
|
||
class="dj hl hm hn ho b">qfp_fexp</code> (natural exponential) because…</p>
|
||
<div class="figure gs gt gu gv gw cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m7.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em><a
|
||
href="https://en.wikipedia.org/wiki/Hyperbolic_function"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://en.wikipedia.org/wiki/Hyperbolic_function</a></em></p></figcaption>
|
||
</div>
|
||
<p id="a3f7" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">4️⃣ <code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L719-L819" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">asinh</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L719-L819"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">, </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L719-L819" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">acosh</a></code><a
|
||
href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L719-L819"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow"> and </a><code
|
||
class="dj hl hm hn ho b"><a href="https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/src/functions.c#L719-L819" class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">atanh</a></code>
|
||
(inverse hyperbolic sine / cosine / tangent) were derived from <code
|
||
class="dj hl hm hn ho b">qfplib’s</code> <code class="dj hl hm hn ho b">qfp_fln</code> (natural
|
||
logarithm) and <code class="dj hl hm hn ho b">qfp_fsqrt_fast</code> (square root) because…</p>
|
||
<div class="figure gs gt gu gv gw cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m8.png" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em><a
|
||
href="https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="1b50" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">So you can see that it’s indeed
|
||
possible for <code class="dj hl hm hn ho b">nano-float</code> to fill in the missing math functions by
|
||
simply calling Qfplib!</p>
|
||
<p id="c6f6" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><strong class="gb gr">But watch
|
||
out for Boundary Conditions</strong> — the code in <code class="dj hl hm hn ho b">nano-float</code>
|
||
may not cover all of the special cases like <code
|
||
class="dj hl hm hn ho b">0, +infinity, -infinity, NaN</code> (not a number), …</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="cz ak">
|
||
<div class="figure gs gt gu gv gw cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m9.png" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em>nano-float unit tests automatically extracted
|
||
from the nano-float source code. From <a
|
||
href="https://docs.google.com/spreadsheets/d/1Uogm7SpgWVA4AiP6gqFkluaozFtlaEGMc4K2Mbfee7U/edit#gid=1740497564"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/1Uogm7SpgWVA4AiP6gqFkluaozFtlaEGMc4K2Mbfee7U/edit#gid=1740497564</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="6b1b" class="hz ia ds bk bj ib ic it ie iu ig iv ii iw ik ix im">Unit Test with Qemu Blue Pill
|
||
Emulator</h1>
|
||
<p id="5521" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">Replacing the standard math
|
||
library by <code class="dj hl hm hn ho b">nano-float</code> is an onerous tasks. How can we really be
|
||
sure that the above formulae were <strong class="gb gr">correctly programmed</strong>? And that the
|
||
<code class="dj hl hm hn ho b">nano-float</code> computation results (single precision) <strong
|
||
class="gb gr">won’t deviate too drastically</strong> from the original math functions (double
|
||
precision)?</p>
|
||
<p id="0cce" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">It’s not a perfect solution but
|
||
we have <strong class="gb gr">Unit Tests for </strong><code
|
||
class="dj hl hm hn ho b"><strong class="gb gr">nano-float</strong>: https://github.com/lupyuen/codal-libopencm3/blob/master/lib/nano-float/test/test.c</code>
|
||
</p>
|
||
<p id="49e8" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">These test cases are meant to be
|
||
run again and again to verify that the results are identical whenever we make changes to the code. The
|
||
test cases were automatically extracted from the <code class="dj hl hm hn ho b">nano-float</code>
|
||
source code by this Google Sheets spreadsheet…</p>
|
||
<div class="me mf mg mh mi jx"><a
|
||
href="https://docs.google.com/spreadsheets/d/1Uogm7SpgWVA4AiP6gqFkluaozFtlaEGMc4K2Mbfee7U/edit?source=post_page-----55093aab163a----------------------#gid=1740497564"
|
||
rel="noopener nofollow">
|
||
<section class="ka cl cm ak ce n ar kb kc kd ke kf kg kh ki kj kk kl km kn ko kp">
|
||
<div class="kq n co p kr ks">
|
||
<h2 class="bj ib kt bl ds">
|
||
<div class="de jy ew ex jz ez">nano-float Unit Test</div>
|
||
</h2>
|
||
</div>
|
||
<div class="kw r">
|
||
<div class="mj r ky kz la kw lb lc ld"></div>
|
||
</div>
|
||
</section>
|
||
</a></div>
|
||
<p id="42c3" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">Unit tests are also meant to be
|
||
run automatically at every rebuild. But the code requires a Blue Pill to execute. The solution:
|
||
<strong class="gb gr">Use the </strong><a
|
||
href="http://beckus.github.io/qemu_stm32/"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow"><strong class="gb gr">Qemu Blue
|
||
Pill Emulator</strong></a><strong class="gb gr"> to execute the test cases</strong>, by simulating
|
||
a Blue Pill in software.</p>
|
||
<p id="af40" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">So far the test cases confirm
|
||
that Qfplib is accurate up to 6 decimal digits, when compared with the standard math library
|
||
(double-precision). Which sounds right because Qfplib uses single-precision math (accurate to 6
|
||
decimal digits).</p>
|
||
<p id="5738" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">We’ll cover <strong
|
||
class="gb gr">Blue Pill Unit Testing and Blue Pill Emulation</strong> in the next article.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="cz ak">
|
||
<div class="figure gs gt gu gv gw cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m10.png" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em>Memory usage of the MakeCode application on Blue
|
||
Pill, without Qfplib and nano-float. From <a
|
||
href="https://docs.google.com/spreadsheets/d/1DWFoh0Ui9j294htHzQrH-s6MuPRXct2zN8M9pj53CBk/edit#gid=381366828&fvid=1359565135"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/1DWFoh0Ui9j294htHzQrH-s6MuPRXct2zN8M9pj53CBk/edit#gid=381366828&fvid=1359565135</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="1fae" class="hz ia ds bk bj ib ic it ie iu ig iv ii iw ik ix im">How I used Qfplib and
|
||
nano-float</h1>
|
||
<p id="4874" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm"><a
|
||
href="https://makecode.com/docs"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">MakeCode</a> is visual programming
|
||
tool for creating embedded programs for microcontrollers (like the BBC micro:bit), simply by dragging
|
||
and dropping code blocks in a web browser. It’s the perfect way to teach embedded programming to
|
||
beginners.</p>
|
||
<p id="f798" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><a class="at cg gn go gp gq"
|
||
target="_blank" rel="noopener"
|
||
href="https://web.archive.org/web/20191204194221/https://medium.com/@ly.lee/work-in-progress-stm32-blue-pill-visual-programming-with-makecode-codal-and-libopencm3-422d308f252e?source=friends_link&sk=b39519335652415d5f4aa17c9e4af1d2">While
|
||
porting MakeCode to Blue Pill</a>, I had trouble squeezing all the code into Blue Pill’s 64 KB ROM.
|
||
(The BBC micro:bit has 256 KB of ROM, with plenty of room for large libraries.) After compiling for
|
||
Blue Pill, I noticed that the <strong class="gb gr">math libraries were taking huge chunks of ROM
|
||
storage</strong> (roughly 17 KB), which you can see in the spreadsheet above. So I made these
|
||
changes…</p>
|
||
<ol class="">
|
||
<li id="725b" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm hd he hf">Using <code
|
||
class="dj hl hm hn ho b">__wrap___aeabi_dmul</code> method described earlier, I intercepted the
|
||
single-precision and double-precision comparison and arithmetic operations (multiply, divide) and
|
||
used Qfplib instead. <a
|
||
href="https://github.com/lupyuen/newlib/blob/master/CMakeLists.txt#L28-L61"
|
||
class="at cg gn go gp gq" target="_blank" rel="noopener nofollow">Here’s the complete list of
|
||
intercepted functions</a>.</li>
|
||
<li id="d282" class="fz ga ds bk gb b gc hg ge hh gg hi gi hj gk hk gm hd he hf">I used <code
|
||
class="dj hl hm hn ho b">nano-float</code> as a drop-in replacement for the standard math library
|
||
<code class="dj hl hm hn ho b">libm.a</code>. So all calls to common math functions like <code
|
||
class="dj hl hm hn ho b">sin(), log(), floor()</code>, … were handled by <code
|
||
class="dj hl hm hn ho b">nano-float</code>.</li>
|
||
</ol>
|
||
<p id="5c40" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">After optimisation, the ROM usage
|
||
has dropped drastically, as shown below. So MakeCode might actually run on Blue Pill, assuming we
|
||
don’t need double-precision math. I haven’t completed my testing of MakeCode on Blue Pill yet — I’m
|
||
taking a break from the coding and testing to document my MakeCode porting experience, which is what
|
||
you’re reading now (and more to come).</p>
|
||
<p id="063d" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><a class="at cg gn go gp gq"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/stm32-blue-pill-analyse-and-optimise-your-ram-and-rom">Read
|
||
about Blue Pill memory optimisation in my previous article</a>.</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gs gt gu gv gw cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/m11.png" /></p>
|
||
|
||
|
||
|
||
|
||
<figcaption><p><em>Memory usage of the MakeCode application on Blue
|
||
Pill, with Qfplib and nano-float. From <a
|
||
href="https://docs.google.com/spreadsheets/d/1OmD1XmUQJTIiXklYx-eui27MFBBhnXrCNaJwSUFDiN8/edit#gid=381366828&fvid=1359565135"
|
||
class="at cg gn go gp gq" target="_blank"
|
||
rel="noopener nofollow">https://docs.google.com/spreadsheets/d/1OmD1XmUQJTIiXklYx-eui27MFBBhnXrCNaJwSUFDiN8/edit#gid=381366828&fvid=1359565135</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="hq et hr hs ht ha hu hv hw hx hy" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dp aj ak">
|
||
<h1 id="f67f" class="hz ia ds bk bj ib ic id ie if ig ih ii ij ik il im">The Daring Proposition</h1>
|
||
<p id="b9cb" class="fz ga ds bk gb b gc in ge io gg ip gi iq gk ir gm">In this article I have argued
|
||
that<strong class="gb gr"> we don’t need highly-precise double-precision math libraries all the
|
||
time</strong>. It’s plausible that <strong class="gb gr">single-precision math (optimised with
|
||
Qfplib) is sufficient for IoT and for Blue Pill embedded programs</strong>. If we accept this, then
|
||
the lowly Blue Pill microcontroller will be able to run math programs that were previously too big to
|
||
fit on Blue Pill. Like the MakeCode visual programming tool.</p>
|
||
<p id="eda3" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm">But this needs to be validated
|
||
through real-world testing (I’ll be validating shortly through MakeCode). For the daring embedded
|
||
programmers… All the code you need is already in this article, so go ahead and try it out!</p>
|
||
<p id="0017" class="fz ga ds bk gb b gc gd ge gf gg gh gi gj gk gl gm"><em class="hp">Many thanks to
|
||
Fabien Petitgrand for the precious feedback</em></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</div>
|
||
</article>
|
||
</div>
|
||
</div>
|
||
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/sponsors/lupyuen">Sponsor me a coffee</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io">Check out my articles</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml">RSS Feed</a></p>
|
||
</li>
|
||
</ul>
|
||
|
||
</body>
|
||
|
||
</html>
|
||
<!--
|
||
FILE ARCHIVED ON 19:42:30 Dec 04, 2019 AND RETRIEVED FROM THE
|
||
INTERNET ARCHIVE ON 01:30:43 Feb 23, 2021.
|
||
JAVASCRIPT APPENDED BY WAYBACK MACHINE, COPYRIGHT INTERNET ARCHIVE.
|
||
|
||
ALL OTHER CONTENT MAY ALSO BE PROTECTED BY COPYRIGHT (17 U.S.C.
|
||
SECTION 108(a)(3)).
|
||
-->
|
||
<!--
|
||
playback timings (ms):
|
||
esindex: 0.014
|
||
captures_list: 100.415
|
||
load_resource: 57.386
|
||
RedisCDXSource: 26.735
|
||
LoadShardBlock: 44.154 (3)
|
||
exclusion.robots: 0.514
|
||
PetaboxLoader3.datanode: 54.081 (4)
|
||
exclusion.robots.policy: 0.495
|
||
CDXLines.iter: 25.262 (3)
|
||
PetaboxLoader3.resolve: 38.045
|
||
--> |