mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 02:08:32 +08:00
1475 lines
No EOL
112 KiB
HTML
1475 lines
No EOL
112 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/build-an-nb-iot-gps-tracker-on-stm32-l476-with-apache-mynewt-and-embedded-rust.html" />
|
||
<!-- End Wayback Rewrite JS Include -->
|
||
<title data-rh="true">Build an NB-IoT GPS Tracker on STM32 L476 with Apache Mynewt and Embedded Rust</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-09-22T12:24:41.202Z" />
|
||
<meta data-rh="true" name="title"
|
||
content="Build an NB-IoT GPS Tracker on STM32 L476 with Apache Mynewt and Embedded Rust" />
|
||
<meta data-rh="true" property="og:title"
|
||
content="Build an NB-IoT GPS Tracker on STM32 L476 with Apache Mynewt and Embedded Rust" />
|
||
<meta data-rh="true" property="twitter:title"
|
||
content="Build an NB-IoT GPS Tracker on STM32 L476 with Apache Mynewt and Embedded Rust" />
|
||
<meta data-rh="true" name="description"
|
||
content=" Let’s build an NB-IoT GPS Tracker! A simple gadget that determines its current location based on received GPS signals… And transmits the location to a server via NB-IoT. We shall take an existing…" />
|
||
<meta data-rh="true" property="og:description"
|
||
content="Plus Quectel L70-R GPS, Quectel BC95 NB-IoT modules and thethings.io" />
|
||
<meta data-rh="true" property="twitter:description"
|
||
content="Plus Quectel L70-R GPS, Quectel BC95 NB-IoT modules and thethings.io" />
|
||
<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="16 min read" />
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/legacy/q1.jpeg">
|
||
|
||
<!-- 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/legacy/q1.jpeg" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em>NB-IoT GPS Tracker running on the Ghostyu
|
||
NB-EK-L476 Developer Kit with STM32L476RCT6 microcontroller, Quectel L70-R GPS module and Quectel BC95
|
||
NB-IoT module. Photo taken during the field test at Berlayer Creek Boardwalk (and mangrove swamp) in
|
||
Singapore.</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<div>
|
||
<div id="5984" class="ea eb ec bk ed b ee ef eg eh ei ej ek">
|
||
<h1 class="ed b ee el ec">Build an NB-IoT GPS Tracker on STM32 L476 with Apache Mynewt and Embedded
|
||
Rust</h1>
|
||
</div>
|
||
<div class="em">
|
||
<div class="n en eo ep eq">
|
||
<div class="o n">
|
||
<div><a rel="noopener"
|
||
href="https://lupyuen.github.io">
|
||
<div class="dd er es">
|
||
<div class="bs n et o p cp eu ev ew ex ey ct"></div>
|
||
</div>
|
||
</a></div>
|
||
<div class="fa ak r">
|
||
<div class="n">
|
||
<div style="flex:1"><span class="bj b bk bl bm bn r ec q">
|
||
<div class="fb n o fc"><span class="bj dy ds bl di fd fe ff fg fh ec"><a
|
||
class="at au av aw ax ay az ba bb bc fi 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 dy ds bl di fd fe ff fg fh bo">
|
||
<div><a class="at au av aw ax ay az ba bb bc fi bf bg bh bi" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/build-an-nb-iot-gps-tracker-on-stm32-l476-with-apache-mynewt-and-embedded-rust">
|
||
22 Sep 2019</a> <!-- -->·
|
||
<!-- -->
|
||
<!-- -->16
|
||
<!-- --> min read
|
||
</div>
|
||
</span></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<p id="c30e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><em class="gv">Plus Quectel L70-R
|
||
GPS, Quectel BC95 NB-IoT modules and thethings.io</em></p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q2.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>The Completed NB-IoT GPS Tracker Application
|
||
showing geolocation and sensor data (raw temperature)</em></p></figcaption>
|
||
</div>
|
||
<p id="20b9" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Let’s build an <strong
|
||
class="gj hp">NB-IoT GPS Tracker</strong>! A simple gadget that determines its current location
|
||
based on received GPS signals… And transmits the location to a server via NB-IoT.</p>
|
||
<p id="bdb6" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We shall take an existing <a
|
||
href="https://mynewt.apache.org/"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Apache Mynewt Embedded OS</a> +
|
||
Embedded Rust project from the article <em class="gv">“</em><a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt"><em
|
||
class="gv">Rust Rocks NB-IoT! STM32 Blue Pill with Quectel BC95-G on Apache Mynewt</em></a><em
|
||
class="gv">”</em>… And extend it with a GPS module: <a
|
||
href="https://www.quectel.com/product/l70r.htm"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">Quectel
|
||
L70-R</strong></a>.</p>
|
||
<p id="3c4a" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The project already includes the
|
||
<a href="https://www.quectel.com/product/bc95.htm"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">Quectel
|
||
BC95</strong></a> NB-IoT module for transmitting sensor data in CoAP format over NB-IoT.</p>
|
||
<p id="bc3b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">STM32 Blue Pill F103 doesn’t
|
||
support floating-point computations in hardware, so it will be inefficient to compute floating-point
|
||
latitude/longitude coordinates for the GPS module.</p>
|
||
<p id="7cde" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We’ll upgrade the STM32 F103
|
||
microcontroller to an <a
|
||
href="https://www.st.com/en/microcontrollers-microprocessors/stm32l476rc.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">STM32
|
||
L476</strong></a> because it supports floating-point computations in hardware.</p>
|
||
<p id="19d8" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Thankfully there’s already a
|
||
developer kit that contains the STM32 L476 microcontroller, Quectel L70-R GPS module and Quectel BC95
|
||
NB-IoT module… <a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/quick-peek-of-huawei-liteos-with-nb-iot-on-ghostyu-nb-ek-l476-developer-kit"><strong
|
||
class="gj hp">Ghostyu NB-EK-L476 Developer Kit</strong></a>, as described in the article <em
|
||
class="gv">“</em><a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/quick-peek-of-huawei-liteos-with-nb-iot-on-ghostyu-nb-ek-l476-developer-kit"><em
|
||
class="gv">Quick Peek of Huawei LiteOS with NB-IoT on Ghostyu NB-EK-L476 Developer Kit
|
||
(STM32L476RCT6)</em></a><em class="gv">”. </em>Perfect for our NB-IoT GPS Tracker!</p>
|
||
<p id="58ca" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Alternatively we may create your
|
||
own kit based on the same STM32L476RCT6 microcontroller and Quectel modules.</p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hu hv hw hx hn">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/43d550cda1ec4fc51a6de71f3b9cbce4.js"></script></p>
|
||
|
||
<figcaption><p><em>Upgrading from STM32 Blue Pill F103 to L476
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="3ab3" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><em class="gv">How hard is it to
|
||
switch microcontrollers and migrate a Mynewt + Rust project from STM32 Blue Pill F103 to L476?</em>
|
||
As we shall find out… Not that hard!</p>
|
||
<p id="da6d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Below is the overall map of
|
||
changes made to the Mynewt + Rust project while building the NB-IoT GPS Tracker. We’ll study each
|
||
block in the subsequent sections.</p>
|
||
<p id="358b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><em class="gv">Even if you’re new
|
||
to Mynewt or Rust, feel free to skim this article!</em> While building the NB-IoT GPS Tracker we
|
||
made changes to a number of components in Mynewt OS and the Rust application… You’ll soon understand
|
||
how the various parts of Mynewt and Rust work together to create an IoT gadget.</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q3.png" /></p>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="945d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The complete source code is
|
||
available at the <code class="dm ia ib ic id b">l476</code> branch of this repository…</p>
|
||
<div class="ie if ig ih ii ij"><a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476?source=post_page-----8c095a925546----------------------"
|
||
rel="noopener nofollow">
|
||
<section class="im cl cm ak ce n ar in io ip iq ir is it iu iv iw ix iy iz ja jb">
|
||
<div class="jc n co p jd je">
|
||
<h2 class="bj jf jg bl ec">
|
||
<div class="di ik fe ff il fh">lupyuen/stm32bluepill-mynewt-sensor</div>
|
||
</h2>
|
||
</div>
|
||
<div class="jj r">
|
||
<div class="jk r jl jm jn jj jo jp jq"></div>
|
||
</div>
|
||
</section>
|
||
</a></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q4.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Mynewt Board Support Package
|
||
</em></p></figcaption>
|
||
</div>
|
||
<h1 id="9d72" class="kc kd ec bk bj jf ke kf kg kh ki kj kk kl km kn ko">Mynewt Board Support Package
|
||
</h1>
|
||
<p id="689f" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">Every Mynewt project begins with
|
||
a <a
|
||
href="https://mynewt.apache.org/latest/os/core_os/porting/port_bsp.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Board Support Package</a>… Either
|
||
take an existing one, or adapt from one. <a
|
||
href="https://github.com/apache/mynewt-core/tree/master/hw/bsp"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Check out the Board Support
|
||
Packages</a></p>
|
||
<p id="9491" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">A Board Support Package contains
|
||
information, scripts and drivers necessary to build Mynewt for our microcontroller and the associated
|
||
peripherals on our microcontroller board: flash memory, LEDs, UART ports, …</p>
|
||
<p id="3036" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">For this project, we customised
|
||
an existing Board Support Package <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/apache/mynewt-core/tree/master/hw/bsp/nucleo-l476rg" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">nucleo-l476rg</a></code>
|
||
by copying into <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/hw/bsp/stm32l4" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/stm32l4</a></code>
|
||
and renaming it. (<a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">The
|
||
previous project</a> used the Board Support Package <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/hw/bsp/bluepill-64kb" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/bluepill-64kb</a></code>)
|
||
</p>
|
||
<p id="88d7" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Our board is similar to the <a
|
||
href="https://www.st.com/en/evaluation-tools/nucleo-l476rg.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Nucleo L476RG</a>, except that the
|
||
Nucleo has 1 MB of flash ROM while ours has only 256 KB. Here’s how we resized the flash ROM by
|
||
editing <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/bsp.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/stm32l4/bsp.yml</a></code>…
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q5.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Customising a Board Support Package for STM32
|
||
L476 on Mynewt</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="7cbd" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The Board Support Package for the
|
||
Nucleo defines two UART ports…</p>
|
||
<ul class="">
|
||
<li id="f73a" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu kv kw kx">The first is named
|
||
<code class="dm ia ib ic id b">UART_0</code> which points to port <code
|
||
class="dm ia ib ic id b">USART2</code> (connected to the Quectel BC95 NB-IoT module)</li>
|
||
<li id="0eec" class="gh gi ec bk gj b gk ky gm kz go la gq lb gs lc gu kv kw kx">The second is named
|
||
<code class="dm ia ib ic id b">UART_1</code> which points to port <code
|
||
class="dm ia ib ic id b">USART1</code> (not used)</li>
|
||
</ul>
|
||
<p id="1ecf" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><em class="gv">(Yep don’t confuse
|
||
the Mynewt port name with the actual UART port)</em></p>
|
||
<p id="485f" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">For our board we need a third
|
||
port…</p>
|
||
<ul class="">
|
||
<li id="6f0b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu kv kw kx"><code
|
||
class="dm ia ib ic id b">UART_2</code> which points to port <code
|
||
class="dm ia ib ic id b">LPUART1</code> (connected to the Quectel L70-R GPS module)</li>
|
||
</ul>
|
||
<p id="1e86" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Here’s how we add <code
|
||
class="dm ia ib ic id b">UART_2</code> by editing <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/syscfg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/stm32l4/syscfg.yml</a></code>…
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hu hv hw hx hn">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/747821c3cbde9175a479abcee8f05a91.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>Adding UART_2 to Board Support Package
|
||
Configuration. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/syscfg.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/syscfg.yml</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="38a3" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">But wait… This says that <code
|
||
class="dm ia ib ic id b">UART_2</code> will point to port <code
|
||
class="dm ia ib ic id b">USART3</code>, not <code class="dm ia ib ic id b">LPUART1</code>!</p>
|
||
<p id="45c5" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Mynewt doesn’t have the driver
|
||
code to support LPUARTs (Low Power UART) on the STM32 platform, so we used a quick hack…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q6.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>From STM32L476xx Datasheet <a
|
||
href="https://www.st.com/resource/en/datasheet/stm32l476je.pdf"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://www.st.com/resource/en/datasheet/stm32l476je.pdf</a> and Ghostyu
|
||
NB-EK-L476 Hardware Manual <a
|
||
href="https://drive.google.com/file/d/14KZqMO6cj20eKqM85iJNth8vf_WbI5VM/view?usp=sharing"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://drive.google.com/file/d/14KZqMO6cj20eKqM85iJNth8vf_WbI5VM/view?usp=sharing</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="0979" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The <a
|
||
href="https://www.st.com/resource/en/datasheet/stm32l476je.pdf"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">STM32L476 Datasheet</a> says that
|
||
<code class="dm ia ib ic id b">LPUART1</code> and <code class="dm ia ib ic id b">USART3</code> share
|
||
the same <code class="dm ia ib ic id b">TX</code> and <code class="dm ia ib ic id b">RX</code> pins,
|
||
except that they are flipped. <em class="gv">(How odd!)</em> STM32 programs may configure the UART
|
||
port such that the <code class="dm ia ib ic id b">TX</code> and <code
|
||
class="dm ia ib ic id b">RX</code> pins are swapped… That’s how we disguised <code
|
||
class="dm ia ib ic id b">USART3</code> as <code class="dm ia ib ic id b">LPUART1</code>! More about
|
||
swapping <code class="dm ia ib ic id b">TX</code> and <code class="dm ia ib ic id b">RX</code> in a
|
||
while.</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/6c9c8f09f15ef145d06902cd1b2a451e.js"></script></p>
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/src/hal_bsp.c"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/src/hal_bsp.c</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="4ffd" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We complete the UART
|
||
customisation by adding the above code to <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/hw/bsp/stm32l4/src/hal_bsp.c" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/stm32l4/src/hal_bsp.c</a></code>.
|
||
We are now ready to use our custom Board Support Package!</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q7.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Mynewt Hardware Abstraction
|
||
Layer</em></p></figcaption>
|
||
</div>
|
||
<h1 id="b33a" class="kc kd ec bk bj jf ke kf kg kh ki kj kk kl km kn ko">Mynewt Hardware Abstraction
|
||
Layer</h1>
|
||
<p id="c541" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">Let’s talk about the Hardware
|
||
Abstraction Layer (HAL) in Mynewt… Because there are two definitions of HAL used in Mynewt that may
|
||
confuse us…</p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q8.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>General HAL for STM32 in
|
||
repos/apache-mynewt-core/hw/mcu/stm/stm32_common</em></p></figcaption>
|
||
</div>
|
||
<p id="69f4" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ The first type of HAL is the
|
||
<strong class="gj hp">General HAL that abstracts all the hardware on our microcontroller.</strong> The
|
||
General HAL enables us to write Mynewt applications that are portable across microcontrollers. Here’s
|
||
an example of a General HAL that <a
|
||
href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">abstracts the GPIO interface</a>:
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">https://mynewt.apache.org/latest/os/modules/hal/hal_gpio/hal_gpio.html</a></code>
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/h0.png" /></p>
|
||
|
||
</div>
|
||
<div class="figure du cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q9.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Vendor-Specific HAL for STM32 in
|
||
repos/apache-mynewt-core/hw/mcu/stm/stm32l4xx</em></p></figcaption>
|
||
</div>
|
||
<p id="ac73" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ The second type of HAL is the
|
||
<strong class="gj hp">Vendor-Specific HAL provided by a microcontroller maker</strong> (like
|
||
STMicroelectronics) that abstracts the differences between various models of microcontrollers, e.g.
|
||
STM32 F103 vs L476. Here’s a <a
|
||
href="https://github.com/apache/mynewt-core/tree/master/hw/mcu/stm/stm32l4xx/src/ext/Drivers/STM32L4xx_HAL_Driver/Src"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Vendor-Specific HAL</a>: <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/apache/mynewt-core/tree/master/hw/mcu/stm/stm32l4xx/src/ext/Drivers/STM32L4xx_HAL_Driver/Src" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">https://github.com/apache/mynewt-core/tree/master/hw/mcu/stm/stm32l4xx/src/ext/Drivers/STM32L4xx_HAL_Driver/Src</a></code>
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy2/h0.png" /></p>
|
||
|
||
</div>
|
||
<p id="8171" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">From now on, when we mention
|
||
“HAL” we refer to 1️⃣ <strong class="gj hp">General HAL</strong>.</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q10.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>From STM32L4x6 Reference Manual: <a
|
||
href="https://www.st.com/content/ccc/resource/technical/document/reference_manual/02/35/09/0c/4f/f7/40/03/DM00083560.pdf/files/DM00083560.pdf/jcr:content/translations/en.DM00083560.pdf"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://www.st.com/content/ccc/resource/technical/document/reference_manual/02/35/09/0c/4f/f7/40/03/DM00083560.pdf/files/DM00083560.pdf/jcr:content/translations/en.DM00083560.pdf</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="4650" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Recall that we need to patch the
|
||
UART HAL so that the <code class="dm ia ib ic id b">TX</code> and <code
|
||
class="dm ia ib ic id b">RX</code> pins are swapped for port <code
|
||
class="dm ia ib ic id b">USART3</code> (so that it behaves like <code
|
||
class="dm ia ib ic id b">LPUART1</code>). The <a
|
||
href="https://www.st.com/content/ccc/resource/technical/document/reference_manual/02/35/09/0c/4f/f7/40/03/DM00083560.pdf/files/DM00083560.pdf/jcr:content/translations/en.DM00083560.pdf"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">STM32L4x6 Reference Manual</a>
|
||
says that we may set the <code class="dm ia ib ic id b">SWAP</code> bit of UART register <code
|
||
class="dm ia ib ic id b">CR2</code> to swap the <code class="dm ia ib ic id b">TX/RX</code> pins.
|
||
</p>
|
||
<p id="6956" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The UART HAL for STM32 is
|
||
implemented in <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/apache/mynewt-core/blob/master/hw/mcu/stm/stm32_common/src/hal_uart.c" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">apache-mynewt-core/hw/mcu/stm/stm32_common/src/hal_uart.c</a></code>
|
||
(inside the <code class="dm ia ib ic id b">repos</code> folder of our project). Edit the file at line
|
||
468 to set the <code class="dm ia ib ic id b">SWAP</code> bit of <code
|
||
class="dm ia ib ic id b">CR2</code> like this…</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/99e2127572672e4ef3ebe932163e8125.js"></script></p>
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/patch/hal_uart.c#L468-L471"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/patch/hal_uart.c#L468-L471</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="460b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">You may refer to this <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/patch/hal_uart.c#L468-L471"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">patched version of </a><code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/patch/hal_uart.c#L468-L471" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hal_uart.c</a></code>.
|
||
This patch depends on two conditions…</p>
|
||
<p id="ebb7" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <code
|
||
class="dm ia ib ic id b">UART_2_SWAP_TXRX</code> must be set to 1 in the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">syscfg.yml</a></code><a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"> configuration file</a>. Remember
|
||
that <code class="dm ia ib ic id b">UART_2</code> is the Mynewt name for port <code
|
||
class="dm ia ib ic id b">USART3</code>.</p>
|
||
<p id="3d79" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ UART port must be <code
|
||
class="dm ia ib ic id b">USART3</code></p>
|
||
<p id="8f80" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Where is <code
|
||
class="dm ia ib ic id b">USART_CR2_SWAP</code> defined? In the <a
|
||
href="https://github.com/apache/mynewt-core/blob/master/hw/mcu/stm/stm32l4xx/src/ext/Drivers/CMSIS/Device/ST/STM32L4xx/Include/stm32l4a6xx.h"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Vendor-Specific HAL</a>.</p>
|
||
<p id="78e7" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">In Visual Studio Code, the patch
|
||
should look like this…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q11.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Patching hal_uart.c to swap TX/RX pins for
|
||
USART3</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="b3f1" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Mynewt Targets</h1>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q12.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Mynewt Targets</em></p></figcaption>
|
||
</div>
|
||
<p id="6619" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Mynewt Applications are designed
|
||
to be portable across microcontrollers… The same application may be recompiled to run on STM32 Blue
|
||
Pill F103, STM32 F476, or even BBC micro:bit (based on Nordic nRF51).</p>
|
||
<p id="3977" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">To compile a Mynewt Application
|
||
for a specific microcontroller board, we run the <code class="dm ia ib ic id b">newt target</code>
|
||
command like this…</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/1ccf7b9927b5256b9ae785a228cacddb.js"></script></p>
|
||
|
||
|
||
</div>
|
||
<p id="4cd2" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">This creates two targets <code
|
||
class="dm ia ib ic id b">stm32l4_boot</code> (for the bootloader) and <code
|
||
class="dm ia ib ic id b">stm32l4_my_sensor</code> (for the application)…</p>
|
||
<p id="ef7d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_boot/pkg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">stm32l4_boot</a></code>
|
||
is based on the Stub Bootloader located at <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/apps/boot_stub" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">apps/boot_stub</a></code>
|
||
</p>
|
||
<p id="2117" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/targets/stm32l4_my_sensor" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">stm32l4_my_sensor</a></code>
|
||
is based on our platform-indepedent Sensor Application located at <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/apps/my_sensor_app" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">apps/my_sensor_app</a></code>
|
||
(which will be merged with the Rust application during compilation)</p>
|
||
<p id="4c2b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Both targets <code
|
||
class="dm ia ib ic id b">stm32l4_boot</code> and <code
|
||
class="dm ia ib ic id b">stm32l4_my_sensor</code> point to the same Board Support Package for STM32
|
||
L476 (<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/hw/bsp/stm32l4" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">hw/bsp/stm32l4</a></code>),
|
||
so they will produce Bootloader and Application Firmware Images that will run on our STM32 L476 board.
|
||
</p>
|
||
<p id="8484" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">(<a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">The
|
||
previous project</a> used targets <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/targets/bluepill_boot" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">bluepill_boot</a></code>
|
||
and <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/targets/bluepill_my_sensor" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">bluepill_my_sensor</a></code>)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz mf mg paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q13.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_boot/target.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_boot/target.yml</a>
|
||
and <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/target.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/target.yml</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="2cd8" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Instead of running the <code
|
||
class="dm ia ib ic id b">newt target</code> command to create the targets, we may copy the target
|
||
folders ourselves to create the targets. Be sure to update <code
|
||
class="dm ia ib ic id b">target.yml</code> to point to the correct Board Support Package (see
|
||
above).</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz mf mg paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q14.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_boot/pkg.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_boot/pkg.yml</a>
|
||
and <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/pkg.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/pkg.yml</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="5d5d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The package name <code
|
||
class="dm ia ib ic id b">pkg.name</code> in <code class="dm ia ib ic id b">pkg.yml</code> should be
|
||
updated. C Compiler Directives and Linker Directives should be specified in <code
|
||
class="dm ia ib ic id b">pkg.yml</code>, as shown above.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q15.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Mynewt Libraries</em></p></figcaption>
|
||
</div>
|
||
<h1 id="6c06" class="kc kd ec bk bj jf ke kf kg kh ki kj kk kl km kn ko">Mynewt Libraries</h1>
|
||
<p id="e85c" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">Let’s look at the changes made to
|
||
the Mynewt libraries and drivers (located in <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">libs</a></code>)
|
||
that are used by our NB-IoT GPS Tracker application. Recall that <a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">the
|
||
previous project</a> has already provided libraries for transmitting sensor data in CoAP format over
|
||
NB-IoT, also for reading the STM32 internal temperature sensor.</p>
|
||
<p id="9f25" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/gps_l70r" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_l70r</a></code>:
|
||
Driver for the Quectel L70-R GPS module. This is a new driver that connects to the UART port to
|
||
receive geolocation information (latitude, longitude, altitude) from the GPS module. It calls <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/tiny_gps_plus" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">tiny_gps_plus</a></code>
|
||
to parse the <a
|
||
href="https://en.wikipedia.org/wiki/NMEA_0183"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">NMEA</a> messages generated by the
|
||
GPS module.</p>
|
||
<p id="a55e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/tiny_gps_plus" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">tiny_gps_plus</a></code>:
|
||
<a href="http://arduiniana.org/libraries/tinygpsplus/"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">TinyGPS++</a> library that was
|
||
ported from Arduino. It parses NMEA messages generated by the GPS module to obtain geolocation
|
||
information.</p>
|
||
<p id="9c52" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">3️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/custom_sensor" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">custom_sensor</a></code>:
|
||
We added a custom Sensor Data Type for the GPS geolocation, which contains latitude, longitude and
|
||
altitude. This enables the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/gps_l70r" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_l70r</a></code>
|
||
GPS driver to be polled like any other sensor (e.g. internal temperature sensor) via <a
|
||
href="https://mynewt.apache.org/latest/os/modules/sensor_framework/sensor_framework.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Mynewt’s Sensor Framework</a>.</p>
|
||
<p id="438e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">4️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/mynewt_rust" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">mynewt_rust</a></code>:
|
||
Helper functions were added to allow the Rust application to read the new Geolocation Sensor Data Type
|
||
</p>
|
||
<p id="d5b3" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">5️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/buffered_serial" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">buffered_serial</a></code>:
|
||
Library that buffers data from the UART port for easier parsing. Used by the GPS driver <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/gps_l70r" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_l70r</a></code>
|
||
and the Quectel NB-IoT driver <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/bc95g" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">bc95g</a></code>
|
||
</p>
|
||
<p id="467d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">6️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/adc_stm32l4" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">adc_stm32l4</a></code>:
|
||
We added this driver to support the Analog-To-Digital Converter (ADC) found in the STM32 L476
|
||
microcontroller. The ADC driver is used by the internal temperature sensor <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/temp_stm32" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">temp_stm32</a></code>
|
||
</p>
|
||
<p id="e3e3" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">7️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/temp_stm32" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">temp_stm32</a></code>:
|
||
This is the driver for the internal temperature sensor. The driver has been updated to use <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/adc_stm32l4" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">adc_stm32l4</a></code>
|
||
to read the internal temperature sensor on the STM32 L476 microcontroller.</p>
|
||
<p id="ea30" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">With these updates, our Rust
|
||
application shall be able to <strong class="gj hp">poll the GPS sensor</strong> for the geolocation,
|
||
<strong class="gj hp">attach the geolocation</strong> to the internal temperature sensor data, and
|
||
<strong class="gj hp">transmit the geolocated sensor data</strong> to the CoAP Server at thethings.io
|
||
over NB-IoT.</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="4e38" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Application Configuration</h1>
|
||
<p id="a93b" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">Where do we configure the
|
||
settings for the libraries? In the System Configuration File for our Target Application <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">targets/stm32l4_my_sensor/syscfg.yml</a></code>…
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/b5a8b097532a3d083c2119a5fbf40303.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>Application Configuration. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="c935" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">(The System Configuration File
|
||
for <a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">the
|
||
previous project</a> was at <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/bluepill_my_sensor/syscfg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">targets/bluepill_my_sensor/syscfg.yml</a></code>)
|
||
</p>
|
||
<p id="ec7f" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Here we enable the drivers for
|
||
the GPS and NB-IoT modules, by setting <code class="dm ia ib ic id b">GPS_L70R</code> and <code
|
||
class="dm ia ib ic id b">BC95G</code> to <code class="dm ia ib ic id b">1</code>. We specify the
|
||
UART port for the GPS and NB-IoT modules like this…</p>
|
||
<pre
|
||
class="gx gy gz ha hb mk ml mm"><span id="38f7" class="mn kd ec bk id b ds mo mp r mq">GPS_L70R_UART: 0 # Connect to Quectel L70R module on USART2<br/>BC95G_UART: 2 # Connect to Quectel BC95-G module on LPUART1 <br/> # i.e. USART3 with TX/RX pins swapped</span></pre>
|
||
<p id="18b2" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Why <code
|
||
class="dm ia ib ic id b">0</code> and <code class="dm ia ib ic id b">2</code>? Because the Mynewt
|
||
UART ports are named like this…</p>
|
||
<pre
|
||
class="gx gy gz ha hb mk ml mm"><span id="1638" class="mn kd ec bk id b ds mo mp r mq"><strong class="id hp">UART_0 → USART2</strong><br/>UART_1 → USART1<br/><strong class="id hp">UART_2 → USART3</strong></span></pre>
|
||
<p id="2b96" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Recall that we need to swap the
|
||
<code class="dm ia ib ic id b">TX/RX</code> pins for port <code class="dm ia ib ic id b">USART3</code>
|
||
so that it behaves like <code class="dm ia ib ic id b">LPUART1</code>. We have applied a patch in
|
||
<code class="dm ia ib ic id b">hal_uart.c</code> that swaps the pins only if <code
|
||
class="dm ia ib ic id b">UART_2_SWAP_TXRX</code> is set to <code class="dm ia ib ic id b">1</code>…
|
||
</p>
|
||
<pre
|
||
class="gx gy gz ha hb mk ml mm"><span id="9da6" class="mn kd ec bk id b ds mo mp r mq"># Swap TX/RX pins for USART3 so that USART3 behaves like LPUART1<br/>UART_2_SWAP_TXRX: 1</span></pre>
|
||
<p id="e213" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">On the Ghostyu developer kit, the
|
||
GPS module is disabled by default. The GPS driver needs to set Pin PA1 to high to enable the GPS
|
||
module. We specify the pin like this…</p>
|
||
<pre
|
||
class="gx gy gz ha hb mk ml mm"><span id="2bcd" class="mn kd ec bk id b ds mo mp r mq"># GPIO Pin PA1 enables and disables the GPS module<br/>GPS_L70R_ENABLE_PIN: MCU_GPIO_PORTA(1)</span></pre>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="8fd9" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Rust Application</h1>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q16.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Rust Application</em></p></figcaption>
|
||
</div>
|
||
<p id="3bd5" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">In
|
||
the previous project</a> we have created an Embedded Rust application that polls the internal
|
||
temperature sensor every 10 seconds and transmits the temperature to the CoAP server (at
|
||
thethings.io). Now we’ll extend the Rust application to transmit the GPS Geolocation (latitude,
|
||
longitude) together with the temperature.</p>
|
||
<p id="c4e8" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We reused the Rust modules in
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/rust/app/src" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">rust/app/src</a></code>
|
||
from the previous application…</p>
|
||
<p id="cc5f" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/lib.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">lib.rs</a></code>:
|
||
Main program that starts the sensors and networking</p>
|
||
<p id="b0c4" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_sensor.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">app_sensor.rs</a></code>:
|
||
Poll the internal temperature sensor <code class="dm ia ib ic id b">temp_stm32</code> and call <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">app_network.rs</a></code>
|
||
to transmit the data</p>
|
||
<p id="b565" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">3️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">app_network.rs</a></code>:
|
||
Compose a CoAP Message with a JSON Payload to transmit the temperature data to the CoAP server at
|
||
thethings.io</p>
|
||
<p id="bca8" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We added a new module <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/gps_sensor.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_sensor.rs</a></code>
|
||
that instructs Mynewt to poll our GPS sensor every 11 seconds. This is possible because our GPS driver
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/gps_l70r" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_l70r</a></code>
|
||
has been integrated with <a
|
||
href="https://mynewt.apache.org/latest/os/modules/sensor_framework/sensor_framework.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Mynewt’s Sensor Framework</a> so
|
||
that it works like any other sensor (such as the internal temperature sensor).</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/97a2f74eaada70f55933d44290f93e6b.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/gps_sensor.rs"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/gps_sensor.rs</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="2773" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Now we have two sources of sensor
|
||
data in our Rust application…</p>
|
||
<p id="c413" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <strong
|
||
class="gj hp">Internal Temperature Sensor Data</strong>, generated by the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/temp_stm32" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">temp_stm32</a></code>
|
||
driver</p>
|
||
<p id="1ba8" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <strong class="gj hp">GPS
|
||
Geolocation (latitude, longitude, altitude)</strong>, generated by the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/libs/gps_l70r" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">gps_l70r</a></code>
|
||
driver</p>
|
||
<p id="0b38" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">To conserve NB-IoT packets, we’ll
|
||
aggregate the two types of sensor data and transmit as a single CoAP message. That’s why the Sensor
|
||
Listeners for both sensors have been updated to forward the polled sensor data to a new function <code
|
||
class="dm ia ib ic id b">aggregate_sensor_data()</code> defined in <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">app_network.rs</a></code>…
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/aae88e535fb9e7293cbde052e0134513.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="4a6e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">When <code
|
||
class="dm ia ib ic id b">aggregate_sensor_data()</code> receives a GPS Geolocation, it doesn’t
|
||
transmit the data to the server. Instead it stores the GPS Geolocation.</p>
|
||
<p id="4d32" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">When <code
|
||
class="dm ia ib ic id b">aggregate_sensor_data()</code> receives the temperature sensor data, it
|
||
attaches the stored GPS Geolocation to the sensor data, and transmits the geolocated sensor data like
|
||
this…</p>
|
||
<pre
|
||
class="gx gy gz ha hb mk ml mm"><span id="8438" class="mn kd ec bk id b ds mo mp r mq">{ "values": [<br/> { "key" : "t", <br/> "value": 960, <br/> "geo" : { "lat": 1.2701, "long": 103.8078 }}<br/> ...<br/>]}</span></pre>
|
||
<p id="7287" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">This <a
|
||
href="https://developers.thethings.io/docs/json-1"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">JSON Payload format</a> is
|
||
specified by thethings.io for transmitting sensor data (<code
|
||
class="dm ia ib ic id b">temperature t = 960</code>) with attached geolocation (<code
|
||
class="dm ia ib ic id b">latitude = 1.2701, longitude = 103.8078</code>).</p>
|
||
<p id="b9ef" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The Rust code for creating the
|
||
JSON Payload is exactly the same as before, based on the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/mynewt/src/encoding/macros.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">coap!</a></code>
|
||
macro…</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/de7c3586c823f16abe195456a72f7198.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_network.rs"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<div class="figure du cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q17.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Geolocated Sensor Data rendered in a dashboard
|
||
at thethings.io</em></p></figcaption>
|
||
</div>
|
||
<p id="81b5" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">How is this possible? Because the
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/mynewt/src/encoding/macros.rs" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">coap!</a></code>
|
||
macro has been updated to <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/mynewt/src/encoding/macros.rs#L535-L536"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">emit the GPS Geolocation</a>
|
||
attached to the sensor data in <code class="dm ia ib ic id b">val</code> (if the GPS Geolocation
|
||
exists).</p>
|
||
<p id="d174" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The screen shows how the
|
||
Geolocated Sensor Data transmitted by our device would be rendered in a dashboard at thethings.io.</p>
|
||
<p id="3ef0" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">That’s the power of creating a
|
||
Domain-Specific Language (like <code class="dm ia ib ic id b">coap!</code>) in Rust… We simply focus
|
||
on the intent of transmitting sensor data, and let the macro decide how to generate the right payload
|
||
to match our intent.</p>
|
||
<p id="38a7" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">One more enhancement implemented
|
||
in the Mynewt Rust Wrapper: The polling of Mynewt sensors in the Rust application has been made
|
||
simpler by introducing <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/mynewt/src/hw/sensor_mgr.rs"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Rust Iterators</a>…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q18.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Rust Iterators for polling Mynewt sensors. From
|
||
<a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_sensor.rs"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/rust/app/src/app_sensor.rs</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="4d93" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Mynewt Build and Flash Scripts
|
||
</h1>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q19.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Mynewt Build and Flash
|
||
Scripts</em></p></figcaption>
|
||
</div>
|
||
<p id="9523" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Mynewt provides the <a
|
||
href="https://mynewt.apache.org/latest/newt/newt_ops.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">command-line tool </a><code
|
||
class="dm ia ib ic id b"><a href="https://mynewt.apache.org/latest/newt/newt_ops.html" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">newt</a></code>
|
||
for building the firmware image and flashing it to the microcontroller. On Windows, <code
|
||
class="dm ia ib ic id b">newt</code> requires the <a
|
||
href="https://mynewt.apache.org/latest/newt/newt_ops.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">MSYS2 and MinGW toolchains to be
|
||
installed</a>.</p>
|
||
<p id="87a2" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">I wanted to simplify the
|
||
installation of the Mynewt build tools on Windows (and make them more robust), so I chose to write my
|
||
own build and flash scripts based on pure Windows, without MSYS2 and MinGW. Earlier I have
|
||
experimented with <code class="dm ia ib ic id b">newt</code> on <a
|
||
href="https://docs.microsoft.com/en-us/windows/wsl/about"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Windows Subsystem for Linux</a>
|
||
but the performance was awful so I dropped it.</p>
|
||
<p id="ce30" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The custom build scripts for
|
||
STM32 L476 are located in the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/scripts/stm32l4" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">scripts/stm32l4</a></code>
|
||
folder (except for <code class="dm ia ib ic id b">build-app</code>, which is located in <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/scripts" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">scripts</a></code>).
|
||
The <code class="dm ia ib ic id b">*.cmd</code> scripts are for Windows, <code
|
||
class="dm ia ib ic id b">*.sh</code> scripts are for macOS and Linux (though not extensively tested
|
||
for Linux). <code class="dm ia ib ic id b">*.ocd</code> are the <a
|
||
href="http://openocd.org/doc-release/html/About.html#About"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">OpenOCD</a> scripts for flashing
|
||
and debugging (they control the ST-Link interface).</p>
|
||
<p id="5b4e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/build-boot.cmd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">build-boot.cmd</a>, <a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/build-boot.sh" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.sh</a></code>:
|
||
Build the bootloader by running <code class="dm ia ib ic id b">newt build stm32l4_boot</code></p>
|
||
<p id="994d" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/build-app.cmd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">build-app.cmd</a>, <a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/build-app.sh" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.sh</a></code>:
|
||
Build the application by running <code class="dm ia ib ic id b">newt build stm32l4_my_sensor</code>.
|
||
Also builds the Rust application and injects the compiled Rust code into the build.</p>
|
||
<p id="6531" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Previously the Rust build for
|
||
STM32 Blue Pill F103 was targeted for <code class="dm ia ib ic id b">thumbv7m-none-eabi</code> (Arm
|
||
Cortex M3), now the Rust build for STM32 L476 is targeted for <code
|
||
class="dm ia ib ic id b">thumbv7em-none-eabihf</code> (Arm Cortex M4 with Hardware Floating-Point)
|
||
</p>
|
||
<p id="9e8e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">3️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/image-app.cmd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">image-app.cmd</a>, <a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/image-app.sh" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.sh</a></code>:
|
||
Create the application firmware image: <code
|
||
class="dm ia ib ic id b">newt create-image -v stm32l4_my_sensor 1.0.0</code></p>
|
||
<p id="54cf" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">4️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-boot.cmd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">flash-boot.cmd</a>, <a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-boot.sh" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.sh</a></code>:
|
||
Flash the bootloader with OpenOCD</p>
|
||
<p id="e032" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">5️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-boot.ocd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">flash-boot.ocd</a></code>:
|
||
OpenOCD script for flashing the bootloader</p>
|
||
<p id="a8b9" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">6️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-app.cmd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">flash-app.cmd</a>, <a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-app.sh" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.sh</a></code>:
|
||
Flash the application with OpenOCD</p>
|
||
<p id="70cc" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">7️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-app.ocd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">flash-app.ocd</a></code>:
|
||
OpenOCD script for flashing the application</p>
|
||
<p id="8778" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">8️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/flash-init.ocd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">flash-init.ocd</a></code>:
|
||
OpenOCD initialisation script called by <code class="dm ia ib ic id b">flash-boot.ocd</code> and <code
|
||
class="dm ia ib ic id b">flash-app.ocd</code></p>
|
||
<p id="6b74" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">9️⃣ <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/scripts/stm32l4/debug.ocd" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">debug.ocd</a></code>:
|
||
OpenOCD script for debugging the application. Called by the <a
|
||
href="https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Cortex-Debug Extension</a> in
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-stm32l4.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.vscode/launch-stm32l4.json</a></code>
|
||
</p>
|
||
<p id="3c78" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The <code
|
||
class="dm ia ib ic id b">newt</code> command in the Windows scripts refer to the <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/newt"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Windows build of </a><code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/newt" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">newt</a></code>,
|
||
which works without MSYS2 and MinGW.</p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q20.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Visual Studio Code Tasks in the Task Runner
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="a466" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The above scripts are linked into
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/tasks.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.vscode/tasks.json</a></code>
|
||
so that they will appear as Tasks in Visual Studio Code.</p>
|
||
<p id="c30c" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">If we’re using the <a
|
||
href="https://marketplace.visualstudio.com/items?itemName=SanaAjani.taskrunnercode"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Task Runner Extension</a>, the
|
||
tasks will appear like this.</p>
|
||
<p id="0978" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">(The custom build and flash
|
||
scripts from <a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">the
|
||
previous project</a> are located in the <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/tree/l476/scripts" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">scripts</a></code>
|
||
folder)</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="b94d" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Visual Studio Code
|
||
Configuration</h1>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q21.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Changes made for Visual Studio Code
|
||
Configuration</em></p></figcaption>
|
||
</div>
|
||
<p id="e969" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><a
|
||
href="https://marketplace.visualstudio.com/items?itemName=marus25.cortex-debug"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Cortex-Debug</a> is the debugger
|
||
we’re using in Visual Studio Code to debug our application. We added a new debugger configuration
|
||
<code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-stm32l4.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.vscode/launch-stm32l4.json</a></code>
|
||
for STM32 L476.</p>
|
||
<p id="e7b3" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The debugger configuration
|
||
specifies the <a
|
||
href="http://openocd.org/doc-release/html/About.html#About"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">OpenOCD</a> scripts and <a
|
||
href="https://www.gnu.org/software/gdb/"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">GDB</a> commands for debugging the
|
||
application. Note that <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">launch.json</a></code>,
|
||
the current debugger configuration, is overwritten by <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-stm32l4.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">launch-stm32l4.json</a></code>
|
||
whenever the application is rebuilt. So we should never edit <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">launch.json</a></code>.
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/923a4ebab9f6592ed963ac249e6e621d.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>Cortex-Debug Configuration. From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-stm32l4.json"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-stm32l4.json</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="a63e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">(The debugger configuration from
|
||
<a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/rust-rocks-nb-iot-stm32-blue-pill-with-quectel-bc95-g-on-apache-mynewt">the
|
||
previous project</a> is at <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/.vscode/launch-bluepill.json" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">.vscode/launch-bluepill.json</a></code>)
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="8249" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Connect the Hardware</h1>
|
||
<p id="81ea" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">To build the NB-IoT GPS Tracker
|
||
we’ll need the following hardware…</p>
|
||
<p id="7b4e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">1️⃣ <a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/quick-peek-of-huawei-liteos-with-nb-iot-on-ghostyu-nb-ek-l476-developer-kit"><strong
|
||
class="gj hp">Ghostyu NB-EK-L476 Developer Kit</strong></a>, as described in the article <em
|
||
class="gv">“</em><a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/quick-peek-of-huawei-liteos-with-nb-iot-on-ghostyu-nb-ek-l476-developer-kit"><em
|
||
class="gv">Quick Peek of Huawei LiteOS with NB-IoT on Ghostyu NB-EK-L476 Developer Kit
|
||
(STM32L476RCT6)</em></a><em class="gv">”</em></p>
|
||
<p id="b286" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The kit includes the <a
|
||
href="https://www.st.com/en/microcontrollers-microprocessors/stm32l476rc.html"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">STM32L476RCT6</a> microcontroller,
|
||
<a href="https://www.quectel.com/product/bc95.htm"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Quectel BC95</a> NB-IoT module
|
||
(with antenna) and <a
|
||
href="https://www.quectel.com/product/l70r.htm"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Quectel L70-R</a> GPS module (with
|
||
antenna).</p>
|
||
<p id="72aa" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><strong
|
||
class="gj hp">Alternatively</strong>: You may assemble your own kit based on the same STM32
|
||
microcontroller and Quectel modules.</p>
|
||
<p id="a0b2" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Remember to select a Quectel
|
||
NB-IoT module that works with your local NB-IoT Frequency Band. You may consider this <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20190725022150&SearchText=bc95-g+nb101&switch_new_app=y"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">Quectel
|
||
BC95-G Global NB-IoT Module</strong></a> (breakout board with antenna), which supports all global
|
||
bands.</p>
|
||
<p id="5bea" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">To connect the components in your
|
||
custom kit, refer to the <a
|
||
href="https://drive.google.com/file/d/14KZqMO6cj20eKqM85iJNth8vf_WbI5VM/view?usp=sharing"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Ghostyu NB-EK-L476 schematics</a>.
|
||
Note that the Quectel NB-IoT module may require additional power, like <a
|
||
href="https://www.linkedin.com/posts/lupyuen_quectel-nbiot-stm32-activity-6558362381049790464-rDgF"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">tapping the 5V pin from
|
||
ST-Link</a> instead of sharing the ST-Link’s 3.3V pin with the microcontroller.</p>
|
||
<p id="4ba1" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">2️⃣ <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180924134644&SearchText=st-link+v2"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">ST-Link V2
|
||
USB Adapter</strong></a><strong class="gj hp">: </strong>Under $2, search <a
|
||
href="https://www.aliexpress.com/wholesale?catId=0&initiative_id=SB_20180924134644&SearchText=st-link+v2&switch_new_app=y"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">AliExpress</a> for <code
|
||
class="dm ia ib ic id b">st-link v2</code></p>
|
||
<p id="c2cb" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">3️⃣ <strong class="gj hp">NB-IoT
|
||
SIM</strong> from your local NB-IoT network operator. <em class="gv">Many thanks to </em><a
|
||
href="https://www.starhub.com/" class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener nofollow"><strong class="gj hp"><em
|
||
class="gv">StarHub</em></strong></a><em class="gv"> for sponsoring the NB-IoT SIM that I used
|
||
for this tutorial!</em></p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q22.jpeg" /></p>
|
||
|
||
|
||
<figcaption><p><em>Pins connected from the SWD Debug Port to
|
||
ST-Link: SWDIO, SWCLK, VCC, GND</em></p></figcaption>
|
||
</div>
|
||
<div class="figure du cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q23.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>SWD Debug Port on Ghostyu NB-EK-L476
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="d88e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Connect the following pins from
|
||
the SWD Debug Port to ST-Link: <code class="dm ia ib ic id b">SWDIO</code>, <code
|
||
class="dm ia ib ic id b">SWCLK</code>, <code class="dm ia ib ic id b">VCC</code>, <code
|
||
class="dm ia ib ic id b">GND</code>.</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q24.jpeg" /></p>
|
||
|
||
|
||
|
||
<figcaption><p><em>Ghostyu STM32 L476 Development Kit powered by
|
||
both ST-Link and micro-USB port. At top left is a USB hub.</em></p></figcaption>
|
||
</div>
|
||
<p id="c713" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">For the Ghostyu NB-EK-L476, you
|
||
need to <strong class="gj hp">connect the micro-USB port on the board to another USB port</strong> on
|
||
your computer. This means that the board will have two power sources: 3.3V power from ST-Link, and 5V
|
||
power from micro-USB port. This ensures that the NB-IoT module will have sufficient power.</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q25.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>NB-IoT Module Power Supply for Ghostyu
|
||
NB-EK-L476. From <a
|
||
href="https://drive.google.com/file/d/14KZqMO6cj20eKqM85iJNth8vf_WbI5VM/view?usp=sharing"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://drive.google.com/file/d/14KZqMO6cj20eKqM85iJNth8vf_WbI5VM/view?usp=sharing</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<div class="figure du cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q26.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>SIM partially exposed to show the unusual
|
||
orientation</em></p></figcaption>
|
||
</div>
|
||
<p id="176a" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><strong class="gj hp">Insert the
|
||
NB-IoT SIM</strong> into the Quectel NB-IoT Breakout Board according to the orientation shown in the
|
||
photo. (Yes the SIM notch faces outward, not inward)</p>
|
||
<p id="e9f5" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><strong class="gj hp"><em
|
||
class="gv">Remember: Always connect the antenna before powering up the NB-IoT
|
||
module!</em></strong></p>
|
||
<p id="caaf" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><strong class="gj hp">If you’re
|
||
using Windows: </strong>Make sure that the ST-Link Driver has been installed before connecting
|
||
ST-Link to your computer</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="d5e7" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">Install and Run the NB-IoT GPS
|
||
Tracker</h1>
|
||
<p id="9bef" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu"><a class="at cg hq hr hs ht"
|
||
target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/install-apache-mynewt-and-embedded-rust-for-stm32-l476-and-visual-studio-code-on-windows">Follow
|
||
the instructions in this article</a> to install, build and run our application on the STM32 L476
|
||
development board (or equivalent).</p>
|
||
<p id="cb4f" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">While running the application,
|
||
the Console Log should look like this…</p>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hu hv hw hx hn">
|
||
|
||
<p><script src="https://gist.github.com/lupyuen/47f000f1e67a6356333180439903286e.js"></script></p>
|
||
|
||
|
||
<figcaption><p><em>Adapter Output Log from <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/logs/standalone-node.log"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/logs/standalone-node.log</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="27c9" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Here you can see the program
|
||
reading the internal temperature sensor.</p>
|
||
<p id="1050" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The temperature sensor data is
|
||
combined with the GPS geolocation into a JSON Payload.</p>
|
||
<p id="61d0" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The JSON Payload is then
|
||
transmitted as a CoAP Message to the CoAP server at thethings.io.</p>
|
||
<p id="7d55" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">In the Console Log, there is a
|
||
URL displayed: <code class="dm ia ib ic id b">http://blue-pill-geolocate.appspot.com/...</code></p>
|
||
<p id="d9c0" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Clicking this URL opens a web
|
||
page that displays the computed temperature (in degrees Celsius) and the GPS geolocation, based on the
|
||
sensor data received by thethings.io from your device over NB-IoT. This URL is randomly-generated each
|
||
time we restart our device.</p>
|
||
<p id="ad62" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We have installed a <a
|
||
href="https://github.com/lupyuen/thethingsio-wifi-geolocation"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">script at thethings.io</a> that
|
||
pushes the computed temperature and geolocation to <code
|
||
class="dm ia ib ic id b">blue-pill-geolocate.appspot.com</code>. For more details, check the section
|
||
<em class="gv">“Advanced Topic: WiFi Geolocation with thethings.io and Google App Engine”</em> in the
|
||
article <em class="gv">“</em><a class="at cg hq hr hs ht" target="_blank" rel="noopener"
|
||
href="https://lupyuen.github.io/articles/connect-stm32-blue-pill-to-esp8266-with-apache-mynewt"><em
|
||
class="gv">Connect STM32 Blue Pill to ESP8266 with Apache Mynewt</em></a><em class="gv">”</em>.
|
||
</p>
|
||
<div class="figure gx gy gz ha hb cz cl cm paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q27.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>Computed temperature and the GPS geolocation
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="d921" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><em class="gv">Does the
|
||
transmission of geolocation work when the device is on the move (say, when mounted on a vehicle?) If
|
||
the device moves between NB-IoT cells, will the transmission still succeed?</em></p>
|
||
<p id="fb06" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Yes! I have tested the NB-IoT GPS
|
||
Tracker while walking around… Geolocation updates are indeed transmitted correctly to thethings.io as
|
||
I walk.</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz ak">
|
||
<div class="figure gx gy gz ha hb cz ak paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q28.jpeg" /></p>
|
||
|
||
<figcaption><p><em>Field testing of the NB-IoT GPS Tracker
|
||
</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="bd64" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Here’s a video demo of the NB-IoT
|
||
GPS Tracker…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz">
|
||
<div class="dl r dd">
|
||
<div class="nn r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FBLfAq1FzUbs%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DBLfAq1FzUbs&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FBLfAq1FzUbs%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400"
|
||
title="Reading a Quectel GPS and transmitting over NB-IoT with Rust (3D Map)"
|
||
class="cp t u dh ak" scrolling="auto"></iframe></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="01c5" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">thethings.io Configuration</h1>
|
||
<p id="f1df" class="gh gi ec bk gj b gk kp gm kq go kr gq ks gs kt gu">If you’re happy to view the
|
||
sensor data using my server at <code class="dm ia ib ic id b">blue-pill-geolocate.appspot.com</code>,
|
||
you may skip this section. If you wish to configure your own account for thethings.io, read on…</p>
|
||
<p id="c423" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Follow the steps in the three
|
||
videos below to configure your thethings.io account and install the Cloud Code Scripts. Click <code
|
||
class="dm ia ib ic id b">CC</code> to view the instructions.</p>
|
||
<p id="1e4e" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu"><strong
|
||
class="gj hp">Note</strong>: There is one additional Cloud Code Function to be installed: <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/thethingsio-wifi-geolocation/blob/master/push_sensor_data.js" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">push_sensor_data</a></code>.
|
||
Copy the code <a
|
||
href="https://github.com/lupyuen/thethingsio-wifi-geolocation/blob/master/push_sensor_data.js"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">from this link</a> to create a new
|
||
Cloud Code Function named <code class="dm ia ib ic id b">push_sensor_data</code>.</p>
|
||
<p id="b211" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The Thing Token should be updated
|
||
in the <code class="dm ia ib ic id b">COAP_URI</code> setting of the System Configuration File <code
|
||
class="dm ia ib ic id b"><a href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/targets/stm32l4_my_sensor/syscfg.yml" class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">targets/stm32l4_my_sensor/syscfg.yml</a></code>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz">
|
||
<div class="dl r dd">
|
||
<div class="nn r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F4KJiZMboaUg%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D4KJiZMboaUg&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F4KJiZMboaUg%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400"
|
||
title="Transform sensor data with thethings.io (Part 1 of 3)" class="cp t u dh ak"
|
||
scrolling="auto"></iframe></div>
|
||
</div>
|
||
<figcaption><p><em>thethings.io Configuration: Part 1 of 3.
|
||
Click CC to view the instructions.</em></p></figcaption>
|
||
</div>
|
||
<div class="figure da cz">
|
||
<div class="dl r dd">
|
||
<div class="nn r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FszCHheKEC7I%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DszCHheKEC7I&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FszCHheKEC7I%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400"
|
||
title="Transform sensor data with thethings.io (Part 2 of 3)" class="cp t u dh ak"
|
||
scrolling="auto"></iframe></div>
|
||
</div>
|
||
<figcaption><p><em>thethings.io Configuration: Part 2 of 3.
|
||
Click CC to view the instructions.</em></p></figcaption>
|
||
</div>
|
||
<div class="figure da cz">
|
||
<div class="dl r dd">
|
||
<div class="nn r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FdMelHn4xTcM%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DdMelHn4xTcM&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FdMelHn4xTcM%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400"
|
||
title="Transform sensor data with thethings.io (Part 3 of 3)" class="cp t u dh ak"
|
||
scrolling="auto"></iframe></div>
|
||
</div>
|
||
<figcaption><p><em>thethings.io Configuration: Part 3 of 3.
|
||
Click CC to view the instructions.</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="68d4" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">At the dashboard page, create a
|
||
new Widget with the following settings…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="gx gy gz ha hb n et">
|
||
<div class="figure da cz no np mg mf nq paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q29.png" /></p>
|
||
|
||
|
||
</div>
|
||
<div class="figure da cz ns np mg mf nq paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q30.png" /></p>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="dc11" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">The geolocated temperature will
|
||
be shown in the Widget. Here’s how it looks…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz mf mg paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q31.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>thethings.io dashboard with geolocated
|
||
temperature sensor data</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<p id="468b" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">Here’s a video demo of
|
||
thethings.io dashboard with geolocated temperature sensor data…</p>
|
||
</div>
|
||
</div>
|
||
<div class="cz">
|
||
<div class="n p">
|
||
<div class="lw lx ly lz ma mb ag mc ah md aj ak">
|
||
<div class="figure gx gy gz ha hb cz">
|
||
<div class="dl r dd">
|
||
<div class="nn r"><iframe
|
||
src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F2-CWQju-Ffs%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D2-CWQju-Ffs&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F2-CWQju-Ffs%2Fhqdefault.jpg&key=a19fcc184b9711e1b4764040d3dc5c07&type=text%2Fhtml&schema=youtube"
|
||
allowfullscreen="" frameborder="0" height="300" width="400"
|
||
title="Reading a Quectel GPS and transmitting over NB-IoT with Rust" class="cp t u dh ak"
|
||
scrolling="auto"></iframe></div>
|
||
</div>
|
||
<figcaption><p><em>Video demo of thethings.io dashboard with
|
||
geolocated temperature sensor data</em></p></figcaption>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<hr class="jr dy js jt ju dv jv jw jx jy jz" />
|
||
<section class="cu cv cw cx cy">
|
||
<div class="n p">
|
||
<div class="ac ae af ag ah dz aj ak">
|
||
<h1 id="a059" class="kc kd ec bk bj jf ke lp kg lq ki lr kk ls km lt ko">What’s Next?</h1>
|
||
<div class="figure gx gy gz ha hb cz dr hc cd hd he hf hg hh ba hi hj hk hl hm hn paragraph-image">
|
||
|
||
<p><img src="https://lupyuen.github.io/images/legacy/q32.png" /></p>
|
||
|
||
|
||
<figcaption><p><em>RAM and ROM usage in Application Build Log.
|
||
From <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/logs/build-application.log"
|
||
class="at cg hq hr hs ht" target="_blank"
|
||
rel="noopener nofollow">https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/logs/build-application.log</a>
|
||
</em></p></figcaption>
|
||
</div>
|
||
<p id="4c07" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">We have created an NB-IoT GPS
|
||
Tracker in only <a
|
||
href="https://github.com/lupyuen/stm32bluepill-mynewt-sensor/blob/l476/logs/build-application.log"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow"><strong class="gj hp">84 KB of
|
||
Flash ROM</strong></a> (with debugging symbols included). Mighty impressive considering that it
|
||
includes Mynewt Embedded OS and the Embedded Rust Libraries!</p>
|
||
<p id="3d72" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">STM32 L476 is definitely a good
|
||
choice for building an NB-IoT GPS Tracker. Mynewt did a great job of shielding the
|
||
microcontroller-specific details and making embedded applications truly portable. And the application
|
||
was created with only a few lines of Rust application code… Rust is incredibly productive for creating
|
||
embedded applications!</p>
|
||
<p id="4263" class="gh gi ec bk gj b gk gl gm gn go gp gq gr gs gt gu">For my next article I shall be
|
||
taking a break from STM32 (since we have proved that it’s so easy to port Mynewt applications across
|
||
STM32 microcontrollers)… And explore <a
|
||
href="https://infocenter.nordicsemi.com/pdf/nRF52832_PS_v1.0.pdf"
|
||
class="at cg hq hr hs ht" target="_blank" rel="noopener nofollow">Nordic nRF52832</a> with Mynewt
|
||
and Rust!</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:41:00 Dec 04, 2019 AND RETRIEVED FROM THE
|
||
INTERNET ARCHIVE ON 23:13:41 Feb 22, 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):
|
||
LoadShardBlock: 206.117 (3)
|
||
PetaboxLoader3.datanode: 145.259 (4)
|
||
RedisCDXSource: 0.649
|
||
exclusion.robots.policy: 0.461
|
||
exclusion.robots: 0.472
|
||
CDXLines.iter: 22.513 (3)
|
||
captures_list: 232.651
|
||
esindex: 0.011
|
||
PetaboxLoader3.resolve: 26.915
|
||
load_resource: 117.202
|
||
--> |