blob: 47cc6de7779b3bd33f0698a33071c034fe922510 [file] [log] [blame]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Adding an Analog Sensor on nRF52 &mdash; Apache Mynewt latest documentation</title>
<link rel="shortcut icon" href="../../_static/mynewt-logo-only-newt32x32.png"/>
<link rel="stylesheet" href="../../_static/css/theme.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/sphinx_theme.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/bootstrap-3.0.3.min.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/v2.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/custom.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/restructuredtext.css" type="text/css" />
<link rel="stylesheet" href="../../_static/css/overrides.css" type="text/css" />
<link rel="index" title="Index"
href="../../genindex.html"/>
<link rel="search" title="Search" href="../../search.html"/>
<link rel="top" title="Apache Mynewt latest documentation" href="../../index.html"/>
<link rel="up" title="Sensors" href="sensors.html"/>
<link rel="next" title="Enabling and Calibrating Off-Board DRV2605 LRA Actuator" href="sensor_nrf52_drv2605.html"/>
<link rel="prev" title="Air Quality Sensor Project via Bluetooth" href="air_quality_ble.html"/>
<script src="../../_static/js/modernizr.min.js"></script>
<script>
(function(i, s, o, g, r, a, m) {
i["GoogleAnalyticsObject"] = r;
(i[r] =
i[r] ||
function() {
(i[r].q = i[r].q || []).push(arguments);
}),
(i[r].l = 1 * new Date());
(a = s.createElement(o)), (m = s.getElementsByTagName(o)[0]);
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m);
})(window, document, "script", "//www.google-analytics.com/analytics.js", "ga");
ga("create", "UA-72162311-1", "auto");
ga("send", "pageview");
</script>
</head>
<body class="not-front page-documentation" role="document" >
<div id="wrapper">
<div class="container">
<div id="banner" class="row v2-main-banner">
<a class="logo-cell" href="/">
<img class="logo" src="../../_static/img/logo.png">
</a>
<div class="tagline-cell">
<h4 class="tagline">An OS to build, deploy and securely manage billions of devices</h4>
</div>
<div class="news-cell">
<div class="well">
<h4>Latest News:</h4> <a href="/download">Apache Mynewt 1.12.0, Apache NimBLE 1.7.0 </a> released April 4, 2024)
</div>
</div>
</div>
</div>
<header>
<nav id="navbar" class="navbar navbar-inverse" role="navigation">
<div class="container">
<!-- Collapsed navigation -->
<div class="navbar-header">
<!-- Expander button -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<!-- Expanded navigation -->
<div class="navbar-collapse collapse">
<!-- Main navigation -->
<ul class="nav navbar-nav navbar-right">
<li>
<a href="/"><i class="fa fa-home" style="font-size: larger;"></i></a>
</li>
<li class="important">
<a href="/quick-start/">Quick Start</a>
</li>
<li>
<a href="/about/">About</a>
</li>
<li>
<a href="/talks/">Talks</a>
</li>
<li class="active">
<a href="/documentation/">Documentation</a>
</li>
<li>
<a href="/download/">Download</a>
</li>
<li>
<a href="/community/">Community</a>
</li>
<li>
<a href="/events/">Events</a>
</li>
</ul>
<!-- Search, Navigation and Repo links -->
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
</div>
</nav>
</header>
<!-- STARTS MAIN CONTENT -->
<div id="main-content">
<div id="breadcrumb">
<div class="container">
<a href="/documentation/">Docs</a> /
<a href="../tutorials.html">Tutorials</a> /
<a href="sensors.html">Sensors</a> /
Adding an Analog Sensor on nRF52
<div class="sourcelink">
<a href="https://github.com/apache/mynewt-documentation/edit/master/docs/tutorials/sensors/nrf52_adc.rst" class="icon icon-github"
rel="nofollow"> Edit on GitHub</a>
</div>
</div>
</div>
<!-- STARTS CONTAINER -->
<div class="container">
<!-- STARTS .content -->
<div id="content" class="row">
<!-- STARTS .container-sidebar -->
<div class="container-sidebar col-xs-12 col-sm-3">
<div id="docSidebar" class="sticky-container">
<div role="search" class="sphinx-search">
<form id="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search documentation" class="search-documentation" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
<!-- Note: only works when deployed -->
<select class="form-control" onchange="if (this.value) window.location.href=this.value">
<option value="/latest" selected>
Version: latest
</option>
<option value="/v1_12_0" >
Version: 1.12.0
</option>
<option value="/v1_11_0" >
Version: 1.11.0
</option>
<option value="/v1_10_0" >
Version: 1.10.0
</option>
<option value="/v1_9_0" >
Version: 1.9.0
</option>
<option value="/v1_8_0" >
Version: 1.8.0
</option>
<option value="/v1_7_0" >
Version: 1.7.0
</option>
<option value="/v1_6_0" >
Version: 1.6.0
</option>
<option value="/v1_5_0" >
Version: 1.5.0
</option>
<option value="/v1_4_0" selected="selected" >
Version: 1.4.0
</option>
<option value="/v1_3_0/os/introduction" >
Version: 1.3.0
</option>
<option value="/v1_2_0/os/introduction" >
Version: 1.2.0
</option>
<option value="/v1_1_0/os/introduction" >
Version: 1.1.0
</option>
<option value="/v1_0_0/os/introduction" >
Version: 1.0.0
</option>
<option value="/v0_9_0/os/introduction" >
Version: 0.9.0
</option>
</select>
<div class="region region-sidebar">
<div class="docs-menu">
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../../index.html">Introduction</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../get_started/index.html">Setup &amp; Get Started</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../concepts.html">Concepts</a></li>
<li class="toctree-l1 current"><a class="reference internal" href="../tutorials.html">Tutorials</a><ul class="current">
<li class="toctree-l2"><a class="reference internal" href="../blinky/blinky.html">Project Blinky</a></li>
<li class="toctree-l2"><a class="reference internal" href="../repo/add_repos.html">Working with repositories</a></li>
<li class="toctree-l2"><a class="reference internal" href="../slinky/project-slinky.html">Project Slinky for Remote Comms</a></li>
<li class="toctree-l2"><a class="reference internal" href="../ble/ble.html">Bluetooth Low Energy</a></li>
<li class="toctree-l2"><a class="reference internal" href="../lora/lorawanapp.html">LoRa</a></li>
<li class="toctree-l2"><a class="reference internal" href="../os_fundamentals/os_fundamentals.html">OS Fundamentals</a></li>
<li class="toctree-l2"><a class="reference internal" href="../devmgmt/devmgmt.html">Remote Device Management</a></li>
<li class="toctree-l2 current"><a class="reference internal" href="sensors.html">Sensors</a><ul class="current">
<li class="toctree-l3"><a class="reference internal" href="sensors_framework.html">Sensor Framework</a></li>
<li class="toctree-l3"><a class="reference internal" href="air_quality.html">Air Quality Sensor Project</a></li>
<li class="toctree-l3 current"><a class="current reference internal" href="#">Add an Analog Sensor</a></li>
<li class="toctree-l3"><a class="reference internal" href="sensor_nrf52_drv2605.html">Connect a DRV2605 actuator device</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="../tooling/tooling.html">Tooling</a></li>
<li class="toctree-l2"><a class="reference internal" href="../other/other.html">Other</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../external_links.html">Third-party Resources</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../os/os_user_guide.html">OS User Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../network/index.html">BLE User Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../newt/index.html">Newt Tool Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../newtmgr/index.html">Newt Manager Guide</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../mynewt_faq/index.html">Mynewt FAQ</a></li>
<li class="toctree-l1"><a class="reference internal" href="../../misc/index.html">Appendix</a></li>
</ul>
</div>
</div>
</div>
<!-- ENDS STICKY CONTAINER -->
</div>
<!-- ENDS .container-sidebar -->
<div class="col-xs-12 col-sm-9">
<div class="alert alert-warning">
<p>
Version 1.4.0 is not the most recent version of the
Apache Mynewt documentation. Click <a href="/latest">here</a> to
read the latest version.
</p>
</div>
<div class="">
<div class="rst-content">
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<div class="section" id="adding-an-analog-sensor-on-nrf52">
<h1>Adding an Analog Sensor on nRF52<a class="headerlink" href="#adding-an-analog-sensor-on-nrf52" title="Permalink to this headline"></a></h1>
<p>We will be adding an analog sensor to the NRF52DK development board and
using the Analog to Digital Converter (ADC) to read the values from the
sensor. It’s also using Bluetooth to allow you to connect to the app and
read the value of the sensor.</p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><p><a class="reference internal" href="#required-hardware" id="id5">Required Hardware</a></p></li>
<li><p><a class="reference internal" href="#create-a-project" id="id6">Create a Project</a></p></li>
<li><p><a class="reference internal" href="#building-a-driver" id="id7">Building a Driver</a></p></li>
<li><p><a class="reference internal" href="#building-the-ble-services" id="id8">Building the BLE Services</a></p></li>
<li><p><a class="reference internal" href="#adding-the-etape-water-sensor" id="id9">Adding the eTape Water Sensor</a></p></li>
<li><p><a class="reference internal" href="#view-data-remotely-via-bluetooth" id="id10">View Data Remotely via Bluetooth</a></p></li>
<li><p><a class="reference internal" href="#conclusion" id="id11">Conclusion</a></p></li>
</ul>
</div>
<div class="section" id="required-hardware">
<h2><a class="toc-backref" href="#id5">Required Hardware</a><a class="headerlink" href="#required-hardware" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>nRF52 Development Kit (one of the following)</p>
<ul>
<li><p>Dev Kit from Nordic - PCA 10040</p></li>
<li><p>Eval Kit from Rigado - BMD-300-EVAL-ES</p></li>
</ul>
</li>
<li><p>eTape Liquid Sensor – buy from
<a class="reference external" href="https://www.adafruit.com/products/1786">Adafruit</a></p></li>
<li><p>Laptop running Mac OS</p></li>
<li><p>It is assumed you have already installed newt tool.</p></li>
<li><p>It is assumed you already installed native tools as described
<a class="reference internal" href="../../get_started/native_install/native_tools.html"><span class="doc">here</span></a></p></li>
</ul>
</div>
<div class="section" id="create-a-project">
<h2><a class="toc-backref" href="#id6">Create a Project</a><a class="headerlink" href="#create-a-project" title="Permalink to this headline"></a></h2>
<p>Create a new project to hold your work. For a deeper understanding, you
can read about project creation in <a class="reference internal" href="../../get_started/project_create.html"><span class="doc">Get Started – Creating Your First
Project</span></a> or just follow the
commands below.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mkdir<span class="w"> </span>~/dev
<span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span>~/dev
<span class="gp">$ </span>newt<span class="w"> </span>new<span class="w"> </span>myadc
<span class="go">Downloading project skeleton from apache/mynewt-blinky...</span>
<span class="go">Downloading repository mynewt-blinky (commit: master) ...</span>
<span class="go">Installing skeleton in myadc...</span>
<span class="go">Project myadc successfully created.</span>
<span class="gp">$ </span><span class="nb">cd</span><span class="w"> </span>myadc
</pre></div>
</div>
<div class="section" id="change-the-repo-version-in-project-yml">
<h3>Change the Repo Version in <code class="docutils literal notranslate"><span class="pre">project.yml</span></code><a class="headerlink" href="#change-the-repo-version-in-project-yml" title="Permalink to this headline"></a></h3>
<p>Recently, members of the Mynewt community have contributed great efforts to integrate the nrfx drivers, but to take advantage of such resources, we will need to use the master of the Mynewt repo (pre v1.4.0 release). To be set at the master of the Mynewt repo, we will need to change the repo version in our <code class="docutils literal notranslate"><span class="pre">project.yml</span></code> file. If you’re not familiar with using repositories,
see the section on <a class="reference internal" href="../repo/add_repos.html"><span class="doc">repositories</span></a> before continuing.</p>
<p>In your <code class="docutils literal notranslate"><span class="pre">project.yml</span></code> file, change the <code class="docutils literal notranslate"><span class="pre">vers</span></code> field under <code class="docutils literal notranslate"><span class="pre">repository.apache-mynewt-core</span></code> from <code class="docutils literal notranslate"><span class="pre">1-latest</span></code> to <code class="docutils literal notranslate"><span class="pre">0-dev</span></code>. When you’re done, your <code class="docutils literal notranslate"><span class="pre">project.yml</span></code> file should look like this:</p>
<div class="highlight-yaml notranslate"><div class="highlight"><pre><span></span><span class="nt">project.name</span><span class="p">:</span><span class="w"> </span><span class="s">&quot;my_project&quot;</span>
<span class="nt">project.repositories</span><span class="p">:</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apache-mynewt-core</span>
<span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mynewt_nordic</span>
<span class="c1"># Use github&#39;s distribution mechanism for core ASF libraries.</span>
<span class="c1"># This provides mirroring automatically for us.</span>
<span class="nt">repository.apache-mynewt-core</span><span class="p">:</span>
<span class="w"> </span><span class="nt">type</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">github</span>
<span class="w"> </span><span class="nt">vers</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">0-dev</span>
<span class="w"> </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">apache</span>
<span class="w"> </span><span class="nt">repo</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">mynewt-core</span>
</pre></div>
</div>
<p>If you already have newt previously installed, you can still change the repo version in your <code class="docutils literal notranslate"><span class="pre">project.yml</span></code> file, but you will need to run <code class="docutils literal notranslate"><span class="pre">newt</span> <span class="pre">upgrade</span></code> for the change to take effect.</p>
</div>
<div class="section" id="install-everything">
<h3>Install Everything<a class="headerlink" href="#install-everything" title="Permalink to this headline"></a></h3>
<p>Now that you have defined the needed repositories, it’s time to install everything so
that you can get started.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>upgrade<span class="w"> </span>-v
<span class="go">Downloading repository mynewt-core (commit: master) ...</span>
<span class="go">Downloading repository mynewt-nimble (commit: master) ...</span>
<span class="go">Downloading repository mynewt-mcumgr (commit: master) ...</span>
<span class="go">Downloading repository mcuboot (commit: master) ...</span>
<span class="go">apache-mynewt-core successfully installed version 0.0.0</span>
<span class="go">apache-mynewt-nimble successfully installed version 0.0.0</span>
<span class="go">apache-mynewt-mcumgr successfully installed version 0.0.0</span>
<span class="go">mcuboot successfully installed version 0.0.0</span>
</pre></div>
</div>
</div>
<div class="section" id="create-the-app-and-targets">
<h3>Create the App and Targets<a class="headerlink" href="#create-the-app-and-targets" title="Permalink to this headline"></a></h3>
<p>For the sensor app we will be building and modifying on top of the <span class="xref std std-doc">bleprph</span> app so that we get the Bluetooth communications built in. The first thing we’ll need to do is copy that app into our own app directory:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mkdir<span class="w"> </span>-p<span class="w"> </span>apps/nrf52_adc
<span class="gp">$ </span>cp<span class="w"> </span>-Rp<span class="w"> </span>repos/apache-mynewt-core/apps/bleprph/*<span class="w"> </span>apps/nrf52_adc
</pre></div>
</div>
<p>Next, you’ll modify the <code class="docutils literal notranslate"><span class="pre">pkg.yml</span></code> file for your app. Note the change in <code class="docutils literal notranslate"><span class="pre">pkg.name</span></code> and <code class="docutils literal notranslate"><span class="pre">pkg.description</span></code>. Also make sure that you specify the full path of all the packages with the prefix <code class="docutils literal notranslate"><span class="pre">&#64;apache-mynewt-core/</span></code> as shown in the third highlighted line.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>cat<span class="w"> </span>apps/nrf52_adc/pkg.yml
<span class="go">...</span>
<span class="go">pkg.name: apps/nrf52_adc</span>
<span class="go">pkg.type: app</span>
<span class="go">pkg.description: Simple BLE peripheral</span>
<span class="go">application for ADC Sensors.</span>
<span class="go">pkg.author: &quot;Apache Mynewt &lt;dev@mynewt.incubator.apache.org&gt;&quot;</span>
<span class="go">pkg.homepage: &quot;http://mynewt.apache.org/&quot;</span>
<span class="go">pkg.keywords:</span>
<span class="go">pkg.deps:</span>
<span class="go"> - &quot;@apache-mynewt-core/boot/split&quot;</span>
<span class="go"> - &quot;@mcuboot/boot/bootutil&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/kernel/os&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/imgmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/ans&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gap&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gatt&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/store/config&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/util&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/transport&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/console/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/log/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/stats/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/sysinit&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/id&quot;</span>
</pre></div>
</div>
<p>Create two targets - one for the bootloader and one for the nrf52 board.</p>
<p><strong>Note</strong>: The correct bsp must be chosen for the board you are using.</p>
<ul class="simple">
<li><p>For the Nordic Dev Kit choose <code class="docutils literal notranslate"><span class="pre">&#64;apache-mynewt-core/hw/bsp/nrf52dk</span></code> for the bsp</p></li>
<li><p>For the Rigado Eval Kit choose <code class="docutils literal notranslate"><span class="pre">&#64;apache-mynewt-core/hw/bsp/bmd300eval</span></code> for the bsp</p></li>
</ul>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span>create<span class="w"> </span>nrf52_adc
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_adc<span class="w"> </span><span class="nv">app</span><span class="o">=</span>apps/nrf52_adc
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_adc<span class="w"> </span><span class="nv">bsp</span><span class="o">=</span>@apache-mynewt-core/hw/bsp/nrf52dk
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_adc<span class="w"> </span><span class="nv">build_profile</span><span class="o">=</span>debug
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span>create<span class="w"> </span>nrf52_boot
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_boot<span class="w"> </span><span class="nv">app</span><span class="o">=</span>@mcuboot/boot/mynewt
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_boot<span class="w"> </span><span class="nv">bsp</span><span class="o">=</span>@apache-mynewt-core/hw/bsp/nrf52dk
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span><span class="nb">set</span><span class="w"> </span>nrf52_boot<span class="w"> </span><span class="nv">build_profile</span><span class="o">=</span>optimized
<span class="gp">$ </span>newt<span class="w"> </span>target<span class="w"> </span>show
<span class="go">targets nrf52_adc</span>
<span class="go"> app=apps/nrf52_adc</span>
<span class="go"> bsp=@apache-mynewt-core/hw/bsp/nrf52dk</span>
<span class="go"> build_profile=debug</span>
<span class="go">targets nrf52_boot</span>
<span class="go"> app=@mcuboot/boot/mynewt</span>
<span class="go"> bsp=@apache-mynewt-core/hw/bsp/nrf52dk</span>
<span class="go"> build_profile=optimized</span>
</pre></div>
</div>
<p><strong>Note</strong>: If you’ve already built and installed a bootloader for your NRF52dk then you do
not need to create a target, build and load it here.</p>
</div>
<div class="section" id="build-the-target-executables">
<h3>Build the Target Executables<a class="headerlink" href="#build-the-target-executables" title="Permalink to this headline"></a></h3>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>build<span class="w"> </span>nrf52_boot
<span class="go">...</span>
<span class="go">Compiling boot.c</span>
<span class="go">Archiving boot.a</span>
<span class="go">Linking boot.elf</span>
<span class="go">App successfully built: ~/dev/myadc/bin/nrf52_boot/boot/mynewt/mynewt.elf</span>
</pre></div>
</div>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>build<span class="w"> </span>nrf52_adc
<span class="go">...</span>
<span class="go">Compiling main.c</span>
<span class="go">Archiving nrf52_adc.a</span>
<span class="go">Linking nrf52_adc.elf</span>
<span class="go">App successfully built: ~/dev/myadc/bin/nrf52\_adc/apps/nrf52_adc/nrf52_adc.elf</span>
</pre></div>
</div>
</div>
<div class="section" id="sign-and-create-the-nrf52-adc-application-image">
<h3>Sign and Create the <code class="docutils literal notranslate"><span class="pre">nrf52_adc</span></code> Application Image<a class="headerlink" href="#sign-and-create-the-nrf52-adc-application-image" title="Permalink to this headline"></a></h3>
<p>You must sign and version your application image to download it using newt to the board.
Use the <code class="docutils literal notranslate"><span class="pre">newt</span> <span class="pre">create-image</span></code> command to perform this action. You may assign an arbitrary
version (e.g. 1.0.0) to the image.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>create-image<span class="w"> </span>nrf52_adc<span class="w"> </span><span class="m">1</span>.0.0
<span class="go">App image successfully generated: ~/dev/myadc/bin/nrf52_adc/apps/nrf52_adc/nrf52_adc.img</span>
<span class="go">Build manifest: ~/dev/myadc/bin/nrf52_adc/apps/nrf52_adc/manifest.json</span>
</pre></div>
</div>
</div>
<div class="section" id="connect-the-board">
<h3>Connect the Board<a class="headerlink" href="#connect-the-board" title="Permalink to this headline"></a></h3>
<p>Connect the evaluation board via micro-USB to your PC via USB cable.</p>
</div>
<div class="section" id="download-to-the-target">
<h3>Download to the Target<a class="headerlink" href="#download-to-the-target" title="Permalink to this headline"></a></h3>
<p>Download the bootloader first and then the nrf52_adc executable to the target platform.
Don’t forget to reset the board if you don’t see the LED blinking right away!</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>newt<span class="w"> </span>load<span class="w"> </span>nrf52_boot
<span class="gp">$ </span>newt<span class="w"> </span>load<span class="w"> </span>nrf52_adc
</pre></div>
</div>
<p><strong>Note:</strong> If you want to erase the flash and load the image again, you can use JLinkExe to issue an <cite>erase</cite> command.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>JLinkExe<span class="w"> </span>-device<span class="w"> </span>nRF52<span class="w"> </span>-speed<span class="w"> </span><span class="m">4000</span><span class="w"> </span>-if<span class="w"> </span>SWD
<span class="go">SEGGER J-Link Commander</span>
<span class="go">V5.12c (Compiled Apr 21 2016 16:05:51)</span>
<span class="go">DLL version V5.12c, compiled Apr 21 2016 16:05:45</span>
<span class="go">Connecting to J-Link via USB...O.K.</span>
<span class="go">Firmware: J-Link</span>
<span class="go">OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17</span>
<span class="go">Hardware version: V1.00</span>
<span class="go">S/N: 682863966</span>
<span class="go">VTref = 3.300V</span>
<span class="go">Type &quot;connect&quot; to establish a target connection, &#39;?&#39; for help</span>
<span class="go">J-Link&gt;erase</span>
<span class="go">Cortex-M4 identified.</span>
<span class="go">Erasing device (0;?i?)...</span>
<span class="go">Comparing flash [100%] Done.</span>
<span class="go">Erasing flash [100%] Done.</span>
<span class="go">Verifying flash [100%] Done.</span>
<span class="go">J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000</span>
<span class="go">s, Verify: 0.000s, Restore: 0.008s)</span>
<span class="go">Erasing done.</span>
<span class="go">J-Link&gt;exit</span>
<span class="gp">$</span>
</pre></div>
</div>
<p>So you have a BLE app, but really all you’ve done is change the name of
the <strong>bleprph</strong> app to <strong>nrf52_adc</strong> and load that. Not all that
impressive, and it certainly won’t read an Analog Sensor right now. So
let’s do that next. In order to read an ADC sensor, we’ll create a driver
for it here in our app that will leverage the existing nrfx driver. It adds another layer of indirection, but it will
also give us a look at building our own driver, so we’ll do it this way.</p>
</div>
</div>
<div class="section" id="building-a-driver">
<h2><a class="toc-backref" href="#id7">Building a Driver</a><a class="headerlink" href="#building-a-driver" title="Permalink to this headline"></a></h2>
<p>The first thing to do is to create the directory structure for your
driver:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>mkdir<span class="w"> </span>-p<span class="w"> </span>libs/my_drivers/myadc/include/myadc
<span class="gp">$ </span>mkdir<span class="w"> </span>-p<span class="w"> </span>libs/my_drivers/myadc/src
</pre></div>
</div>
<p>Now you can add the files you need. You’ll need a pkg.yml to describe
the driver, and then header stub followed by source stub.</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>cat<span class="w"> </span>libs/my_drivers/myadc/pkg.yml
</pre></div>
</div>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">#</span>
<span class="gp"># </span>Licensed<span class="w"> </span>to<span class="w"> </span>the<span class="w"> </span>Apache<span class="w"> </span>Software<span class="w"> </span>Foundation<span class="w"> </span><span class="o">(</span>ASF<span class="o">)</span><span class="w"> </span>under<span class="w"> </span>one
<span class="gp"># </span>or<span class="w"> </span>more<span class="w"> </span>contributor<span class="w"> </span>license<span class="w"> </span>agreements.<span class="w"> </span>See<span class="w"> </span>the<span class="w"> </span>NOTICE<span class="w"> </span>file
<span class="gp"># </span>distributed<span class="w"> </span>with<span class="w"> </span>this<span class="w"> </span>work<span class="w"> </span><span class="k">for</span><span class="w"> </span>additional<span class="w"> </span>information
<span class="gp"># </span>regarding<span class="w"> </span>copyright<span class="w"> </span>ownership.<span class="w"> </span>The<span class="w"> </span>ASF<span class="w"> </span>licenses<span class="w"> </span>this<span class="w"> </span>file
<span class="gp"># </span>to<span class="w"> </span>you<span class="w"> </span>under<span class="w"> </span>the<span class="w"> </span>Apache<span class="w"> </span>License,<span class="w"> </span>Version<span class="w"> </span><span class="m">2</span>.0<span class="w"> </span><span class="o">(</span>the
<span class="gp"># </span><span class="s2">&quot;License&quot;</span><span class="o">)</span><span class="p">;</span><span class="w"> </span>you<span class="w"> </span>may<span class="w"> </span>not<span class="w"> </span>use<span class="w"> </span>this<span class="w"> </span>file<span class="w"> </span>except<span class="w"> </span><span class="k">in</span><span class="w"> </span>compliance
<span class="gp"># </span>with<span class="w"> </span>the<span class="w"> </span>License.<span class="w"> </span>You<span class="w"> </span>may<span class="w"> </span>obtain<span class="w"> </span>a<span class="w"> </span>copy<span class="w"> </span>of<span class="w"> </span>the<span class="w"> </span>License<span class="w"> </span>at
<span class="gp">#</span>
<span class="gp"># </span>http://www.apache.org/licenses/LICENSE-2.0
<span class="gp">#</span>
<span class="gp"># </span>Unless<span class="w"> </span>required<span class="w"> </span>by<span class="w"> </span>applicable<span class="w"> </span>law<span class="w"> </span>or<span class="w"> </span>agreed<span class="w"> </span>to<span class="w"> </span><span class="k">in</span><span class="w"> </span>writing,
<span class="gp"># </span>software<span class="w"> </span>distributed<span class="w"> </span>under<span class="w"> </span>the<span class="w"> </span>License<span class="w"> </span>is<span class="w"> </span>distributed<span class="w"> </span>on<span class="w"> </span>an
<span class="gp"># </span><span class="s2">&quot;AS IS&quot;</span><span class="w"> </span>BASIS,<span class="w"> </span>WITHOUT<span class="w"> </span>WARRANTIES<span class="w"> </span>OR<span class="w"> </span>CONDITIONS<span class="w"> </span>OF<span class="w"> </span>ANY
<span class="gp"># </span>KIND,<span class="w"> </span>either<span class="w"> </span>express<span class="w"> </span>or<span class="w"> </span>implied.<span class="w"> </span>See<span class="w"> </span>the<span class="w"> </span>License<span class="w"> </span><span class="k">for</span><span class="w"> </span>the
<span class="gp"># </span>specific<span class="w"> </span>language<span class="w"> </span>governing<span class="w"> </span>permissions<span class="w"> </span>and<span class="w"> </span>limitations
<span class="gp"># </span>under<span class="w"> </span>the<span class="w"> </span>License.
<span class="gp">#</span>
<span class="go">pkg.name: libs/my_drivers/myadc</span>
<span class="go">pkg.deps:</span>
<span class="go"> - &quot;@apache-mynewt-core/hw/hal&quot;</span>
</pre></div>
</div>
<p>First, let’s create the required header file <code class="docutils literal notranslate"><span class="pre">myadc.h</span></code> in the include
directory (i.e. <code class="docutils literal notranslate"><span class="pre">libs/my_drivers/myadc/include/myadc/myadc.h</span></code>). It’s a
pretty straightforward header file, since we only need to do 2 things:</p>
<ul class="simple">
<li><p>Initialize the ADC device</p></li>
<li><p>Read ADC Values</p></li>
</ul>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#ifndef _NRF52_ADC_H_</span>
<span class="cp">#define _NRF52_ADC_H_</span>
<span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="nf">adc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="kt">int</span><span class="w"> </span><span class="nf">adc_read</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">);</span>
<span class="cp">#endif </span><span class="cm">/* _NRF52_ADC_H_ */</span>
</pre></div>
</div>
<p>Next we’ll need a corresponding source file <code class="docutils literal notranslate"><span class="pre">myadc.c</span></code> in the src
directory. This is where we’ll implement the specifics of the driver:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;assert.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;os/os.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;string.h&gt;</span>
<span class="cm">/* ADC */</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;myadc/myadc.h&quot;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;nrf.h&quot;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;adc/adc.h&gt;</span>
<span class="cm">/* Nordic headers */</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;nrfx.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;nrf_saadc.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;nrfx_saadc.h&gt;</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;nrfx_config.h&gt;</span>
<span class="cp">#define ADC_NUMBER_SAMPLES (2)</span>
<span class="cp">#define ADC_NUMBER_CHANNELS (1)</span>
<span class="n">nrfx_saadc_config_t</span><span class="w"> </span><span class="n">adc_config</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRFX_SAADC_DEFAULT_CONFIG</span><span class="p">;</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">adc_dev</span><span class="w"> </span><span class="o">*</span><span class="n">adc</span><span class="p">;</span>
<span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">sample_buffer1</span><span class="p">;</span>
<span class="kt">uint8_t</span><span class="w"> </span><span class="o">*</span><span class="n">sample_buffer2</span><span class="p">;</span>
<span class="kt">void</span><span class="w"> </span><span class="o">*</span>
<span class="nf">adc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">nrf_saadc_channel_config_t</span><span class="w"> </span><span class="n">cc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE</span><span class="p">(</span><span class="n">NRF_SAADC_INPUT_AIN1</span><span class="p">);</span>
<span class="w"> </span><span class="n">cc</span><span class="p">.</span><span class="n">gain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRF_SAADC_GAIN1_6</span><span class="p">;</span>
<span class="w"> </span><span class="n">cc</span><span class="p">.</span><span class="n">reference</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRF_SAADC_REFERENCE_INTERNAL</span><span class="p">;</span>
<span class="w"> </span><span class="n">adc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">adc_dev</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">os_dev_open</span><span class="p">(</span><span class="s">&quot;adc0&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">adc_config</span><span class="p">);</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">adc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">adc_chan_config</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">cc</span><span class="p">);</span>
<span class="w"> </span><span class="n">sample_buffer1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">sample_buffer2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="n">sample_buffer1</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="n">sample_buffer2</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">adc_buf_set</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">sample_buffer1</span><span class="p">,</span><span class="w"> </span><span class="n">sample_buffer2</span><span class="p">,</span>
<span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">adc</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">int</span>
<span class="nf">adc_read</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">adc_result</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">my_result_mv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_buf_read</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">adc_result</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">err</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">my_result_mv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_result_mv</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_result</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">adc_buf_release</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">my_result_mv</span><span class="p">;</span>
<span class="nl">err</span><span class="p">:</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>There’s a lot going on in here, so let’s walk through it step by step.</p>
<p>First, we don’t need to define a default configuration for our ADC - this has already been created. So we initialize the ADC in <code class="docutils literal notranslate"><span class="pre">adc_init()</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="o">*</span>
<span class="nf">adc_init</span><span class="p">(</span><span class="kt">void</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="n">nrf_saadc_channel_config_t</span><span class="w"> </span><span class="n">cc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE</span><span class="p">(</span><span class="n">NRF_SAADC_INPUT_AIN1</span><span class="p">);</span>
<span class="w"> </span><span class="n">cc</span><span class="p">.</span><span class="n">gain</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRF_SAADC_GAIN1_6</span><span class="p">;</span>
<span class="w"> </span><span class="n">cc</span><span class="p">.</span><span class="n">reference</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">NRF_SAADC_REFERENCE_INTERNAL</span><span class="p">;</span>
<span class="w"> </span><span class="n">adc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">adc_dev</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="n">os_dev_open</span><span class="p">(</span><span class="s">&quot;adc0&quot;</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">adc_config</span><span class="p">);</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">adc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">adc_chan_config</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">cc</span><span class="p">);</span>
<span class="w"> </span><span class="n">sample_buffer1</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">sample_buffer2</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">malloc</span><span class="p">(</span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="n">sample_buffer1</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">memset</span><span class="p">(</span><span class="n">sample_buffer2</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="n">adc_buf_set</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">sample_buffer1</span><span class="p">,</span><span class="w"> </span><span class="n">sample_buffer2</span><span class="p">,</span>
<span class="w"> </span><span class="n">adc_buf_size</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_CHANNELS</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">));</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">adc</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>A few things need to be said about this part, as it is the most
confusing. First, we’re using a <strong>default</strong> configuration for the ADC
Channel via the <code class="docutils literal notranslate"><span class="pre">NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE</span></code> macro. The
important part here is that we’re actually using <code class="docutils literal notranslate"><span class="pre">AIN1</span></code>. I know what
you’re thinking, “But we want ADC-0!” and that’s true. The board is
actually labelled ‘A0, A1, A2’ etc., and the actual pin numbers are also
listed on the board, which seems handy. At first. But it gets messy very
quickly.</p>
<p>If you try to use AIN0, and then go poke around in the registers while
this is running,</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp gp-VirtualEnv">(gdb)</span> <span class="go">p/x {NRF_SAADC_Type}0x40007000</span>
<span class="go">...</span>
<span class="go"> CH = {{</span>
<span class="go"> PSELP = 0x1,</span>
<span class="go"> PSELN = 0x0,</span>
<span class="go"> CONFIG = 0x20000,</span>
<span class="go"> LIMIT = 0x7fff8000</span>
<span class="go"> },</span>
</pre></div>
</div>
<p>You’ll see that the pin for channel 0 is set to 1, which corresponds to
AIN0, but that’s <strong>NOT</strong> the same as A0 – pin P0.03, the one we’re
using. For that, you use AIN1, which would set the pin value to 2.
Messy. Someone, somewhere, thought this made sense.</p>
<p>The only other thing to note here is that we’re using the internal
reference voltage, rather than setting our own. There’s nothing wrong
with that, but since we are, we’ll have to crank up the gain a bit by
using <code class="docutils literal notranslate"><span class="pre">NRF_SAADC_GAIN1_6</span></code>.</p>
<p>Then, in <code class="docutils literal notranslate"><span class="pre">adc_read()</span></code> we will take readings, convert the raw readings
to a millivolt equivalent, and return the result.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
<span class="nf">adc_read</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">i</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">adc_result</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">my_result_mv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="o">&lt;</span><span class="w"> </span><span class="n">ADC_NUMBER_SAMPLES</span><span class="p">;</span><span class="w"> </span><span class="n">i</span><span class="o">++</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_buf_read</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">adc_result</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">err</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">my_result_mv</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_result_mv</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="n">adc_result</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">adc_buf_release</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">my_result_mv</span><span class="p">;</span>
<span class="nl">err</span><span class="p">:</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Finally, we’ll need to enable the ADC, which is disabled by default. To override this setting, we need to add a <code class="docutils literal notranslate"><span class="pre">syscfg.yml</span></code> file to our nrf52_adc target:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$ </span>cat<span class="w"> </span>targets/nrf52_adc/syscfg.yml
<span class="go">syscfg.vals:</span>
<span class="gp"> # </span>Enable<span class="w"> </span>ADC<span class="w"> </span><span class="m">0</span>
<span class="go"> ADC_0: 1</span>
</pre></div>
</div>
<p>Once that’s all done, you should have a working ADC Driver for your
nRF52dk board. The last step in getting the driver set up is to include
it in the package dependency defined by <code class="docutils literal notranslate"><span class="pre">pkg.deps</span></code> in the <code class="docutils literal notranslate"><span class="pre">pkg.yml</span></code>
file of your app. You will also need to add the <code class="docutils literal notranslate"><span class="pre">mcu/nordic</span></code> package. Add them in <code class="docutils literal notranslate"><span class="pre">apps/nrf52_adc/pkg.yml</span></code> as shown below:</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp"># </span>Licensed<span class="w"> </span>to<span class="w"> </span>the<span class="w"> </span>Apache<span class="w"> </span>Software<span class="w"> </span>Foundation<span class="w"> </span><span class="o">(</span>ASF<span class="o">)</span><span class="w"> </span>under<span class="w"> </span>one
<span class="gp"># </span>&lt;snip&gt;
<span class="go">pkg.name: apps/nrf52_adc</span>
<span class="go">pkg.type: app</span>
<span class="go">pkg.description: Simple BLE peripheral application for ADC sensor.</span>
<span class="go">pkg.author: &quot;Apache Mynewt &lt;dev@mynewt.incubator.apache.org&gt;&quot;</span>
<span class="go">pkg.homepage: &quot;http://mynewt.apache.org/&quot;</span>
<span class="go">pkg.keywords:</span>
<span class="go">pkg.deps:</span>
<span class="go"> - &quot;@apache-mynewt-core/boot/split&quot;</span>
<span class="go"> - &quot;@mcuboot/boot/bootutil&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/kernel/os&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/imgmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/mgmt/newtmgr/transport/ble&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/ans&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gap&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/services/gatt&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/store/config&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/host/util&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/net/nimble/transport&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/console/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/log/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/stats/full&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/sysinit&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/sys/id&quot;</span>
<span class="go"> - &quot;@apache-mynewt-core/hw/mcu/nordic&quot;</span>
<span class="go"> - &quot;libs/my_drivers/myadc&quot;</span>
</pre></div>
</div>
<div class="section" id="creating-the-adc-task">
<h3>Creating the ADC Task<a class="headerlink" href="#creating-the-adc-task" title="Permalink to this headline"></a></h3>
<p>Now that the driver is done, we’ll need to add calls to the main app’s
<code class="docutils literal notranslate"><span class="pre">main.c</span></code> file, as well as a few other things. First, we’ll need to
update the includes, and add a task for our ADC sampling.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&lt;adc/adc.h&gt;</span>
<span class="p">....</span>
<span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;myadc/myadc.h&quot;</span>
<span class="p">....</span>
<span class="cm">/* ADC Task settings */</span>
<span class="cp">#define ADC_TASK_PRIO 5</span>
<span class="cp">#define ADC_STACK_SIZE (OS_STACK_ALIGN(336))</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">os_eventq</span><span class="w"> </span><span class="n">adc_evq</span><span class="p">;</span>
<span class="k">struct</span><span class="w"> </span><span class="nc">os_task</span><span class="w"> </span><span class="n">adc_task</span><span class="p">;</span>
<span class="n">bssnz_t</span><span class="w"> </span><span class="n">os_stack_t</span><span class="w"> </span><span class="n">adc_stack</span><span class="p">[</span><span class="n">ADC_STACK_SIZE</span><span class="p">];</span>
</pre></div>
</div>
<p>Next we’ll need to initialize the task <code class="docutils literal notranslate"><span class="pre">event_q</span></code> so we’ll add the
highlighted code to <code class="docutils literal notranslate"><span class="pre">main()</span></code> as shown below. You can also change the name of your Bluetooth device in <code class="docutils literal notranslate"><span class="pre">ble_svc_gap_device_name_set</span></code>:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/* Set the default device name. */</span>
<span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ble_svc_gap_device_name_set</span><span class="p">(</span><span class="s">&quot;nimble-adc&quot;</span><span class="p">);</span>
<span class="n">assert</span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="cp">#if MYNEWT_VAL(BLEPRPH_LE_PHY_SUPPORT)</span>
<span class="w"> </span><span class="n">phy_init</span><span class="p">();</span>
<span class="cp">#endif</span>
<span class="n">conf_load</span><span class="p">();</span>
<span class="cm">/* Initialize adc sensor task eventq */</span>
<span class="n">os_eventq_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">adc_evq</span><span class="p">);</span>
<span class="cm">/* Create the ADC reader task.</span>
<span class="cm"> * All sensor operations are performed in this task.</span>
<span class="cm"> */</span>
<span class="n">os_task_init</span><span class="p">(</span><span class="o">&amp;</span><span class="n">adc_task</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;sensor&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">adc_task_handler</span><span class="p">,</span>
<span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_TASK_PRIO</span><span class="p">,</span><span class="w"> </span><span class="n">OS_WAIT_FOREVER</span><span class="p">,</span>
<span class="w"> </span><span class="n">adc_stack</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_STACK_SIZE</span><span class="p">);</span>
</pre></div>
</div>
<p>We’ll need that <code class="docutils literal notranslate"><span class="pre">adc_task_handler()</span></code> function to exist, and that’s where
we’ll initialize the ADC Device and set the event handler. In the task’s
while() loop, we’ll just make a call to``adc_sample()`` to cause the ADC
driver to sample the adc device.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * Event loop for the sensor task.</span>
<span class="cm"> */</span>
<span class="k">static</span><span class="w"> </span><span class="kt">void</span>
<span class="nf">adc_task_handler</span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">unused</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">adc_dev</span><span class="w"> </span><span class="o">*</span><span class="n">adc</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="cm">/* ADC init */</span>
<span class="w"> </span><span class="n">adc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_init</span><span class="p">();</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_event_handler_set</span><span class="p">(</span><span class="n">adc</span><span class="p">,</span><span class="w"> </span><span class="n">adc_read_event</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="p">)</span><span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">while</span><span class="w"> </span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">adc_sample</span><span class="p">(</span><span class="n">adc</span><span class="p">);</span>
<span class="w"> </span><span class="cm">/* Wait 2 second */</span>
<span class="w"> </span><span class="n">os_time_delay</span><span class="p">(</span><span class="n">OS_TICKS_PER_SEC</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mi">2</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Above the <code class="docutils literal notranslate"><span class="pre">adc_task_handler</span></code>, add code to handle the
<code class="docutils literal notranslate"><span class="pre">adc_read_event()</span></code> calls:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="kt">int</span>
<span class="nf">adc_read_event</span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">adc_dev</span><span class="w"> </span><span class="o">*</span><span class="n">dev</span><span class="p">,</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">,</span><span class="w"> </span><span class="kt">uint8_t</span><span class="w"> </span><span class="n">etype</span><span class="p">,</span>
<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">chr_val_handle</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="n">value</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">adc_read</span><span class="p">(</span><span class="n">buffer</span><span class="p">,</span><span class="w"> </span><span class="n">buffer_len</span><span class="p">);</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">value</span><span class="w"> </span><span class="o">&gt;=</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;Got %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">console_printf</span><span class="p">(</span><span class="s">&quot;Error while reading: %d</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">value</span><span class="p">);</span>
<span class="w"> </span><span class="k">goto</span><span class="w"> </span><span class="n">err</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="n">gatt_adc_val</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">value</span><span class="p">;</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ble_gatts_find_chr</span><span class="p">(</span><span class="o">&amp;</span><span class="n">gatt_svr_svc_adc_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">ADC_SNS_VAL</span><span class="p">),</span><span class="w"> </span><span class="nb">NULL</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">chr_val_handle</span><span class="p">);</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="n">ble_gatts_chr_updated</span><span class="p">(</span><span class="n">chr_val_handle</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="nl">err</span><span class="p">:</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="p">(</span><span class="n">rc</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
<p>This is where we actually read the ADC value and then update the BLE
Characteristic for that value.</p>
<p>But wait, we haven’t defined those BLE services and characteristics yet!
Right, so don’t try to build and run this app just yet or it will surely
fail. Instead, move on to the next section and get all of those services
defined.</p>
</div>
</div>
<div class="section" id="building-the-ble-services">
<h2><a class="toc-backref" href="#id8">Building the BLE Services</a><a class="headerlink" href="#building-the-ble-services" title="Permalink to this headline"></a></h2>
<p>If the <code class="docutils literal notranslate"><span class="pre">nrf52_adc</span></code> app is going to be a Bluetooth-enabled sensor app that
will allow you to read the value of the eTape Water Level Sensor via
Bluetooth we’ll need to actually define those Services and
Characteristics.</p>
<p>As with the <span class="xref std std-doc">ble peripheral</span> app, we will
advertise a couple of values from our app. The first is not strictly
necessary, but it will help us build an iOS app later. We’ve defined a
service and the characteristics in that service in <code class="docutils literal notranslate"><span class="pre">bleprph.h</span></code> in the
<code class="docutils literal notranslate"><span class="pre">apps/nrf52_adc/src/</span></code> directory. Make sure to include the <code class="docutils literal notranslate"><span class="pre">host/ble_uuid.h</span></code> header:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span><span class="w"> </span><span class="cpf">&quot;host/ble_uuid.h&quot;</span>
<span class="p">....</span>
<span class="cm">/* Sensor Data */</span>
<span class="cm">/* e761d2af-1c15-4fa7-af80-b5729002b340 */</span>
<span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">ble_uuid128_t</span><span class="w"> </span><span class="n">gatt_svr_svc_adc_uuid</span><span class="w"> </span><span class="o">=</span>
<span class="w"> </span><span class="n">BLE_UUID128_INIT</span><span class="p">(</span><span class="mh">0x40</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb3</span><span class="p">,</span><span class="w"> </span><span class="mh">0x20</span><span class="p">,</span><span class="w"> </span><span class="mh">0x90</span><span class="p">,</span><span class="w"> </span><span class="mh">0x72</span><span class="p">,</span><span class="w"> </span><span class="mh">0xb5</span><span class="p">,</span><span class="w"> </span><span class="mh">0x80</span><span class="p">,</span><span class="w"> </span><span class="mh">0xaf</span><span class="p">,</span>
<span class="w"> </span><span class="mh">0xa7</span><span class="p">,</span><span class="w"> </span><span class="mh">0x4f</span><span class="p">,</span><span class="w"> </span><span class="mh">0x15</span><span class="p">,</span><span class="w"> </span><span class="mh">0x1c</span><span class="p">,</span><span class="w"> </span><span class="mh">0xaf</span><span class="p">,</span><span class="w"> </span><span class="mh">0xd2</span><span class="p">,</span><span class="w"> </span><span class="mh">0x61</span><span class="p">,</span><span class="w"> </span><span class="mh">0xe7</span><span class="p">);</span>
<span class="cp">#define ADC_SNS_TYPE 0xDEAD</span>
<span class="cp">#define ADC_SNS_STRING &quot;eTape Liquid Level Sensor&quot;</span>
<span class="cp">#define ADC_SNS_VAL 0xBEAD</span>
<span class="kt">uint16_t</span><span class="w"> </span><span class="n">gatt_adc_val</span><span class="p">;</span>
</pre></div>
</div>
<p>The first is the UUID of the service, followed by the 2 characteristics
we are going to offer. The first characteristic is going to advertise
the <em>type</em> of sensor we are advertising, and it will be a read-only
characteristic. The second characteristic will be the sensor value
itself, and we will allow connected devices to ‘subscribe’ to it in
order to get constantly-updated values.</p>
<p><strong>Note:</strong> You can choose any valid Characteristic UUIDs to go here.
We’re using these values for illustrative purposes only.</p>
<p>The value that we’ll be updating is also defined here as
<code class="docutils literal notranslate"><span class="pre">gatt_adc_val</span></code>.</p>
<p>If we then go look at <code class="docutils literal notranslate"><span class="pre">gatt_svr.c</span></code> we can see the structure of the
service and characteristic offering that we set up:</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_svc_def</span><span class="w"> </span><span class="n">gatt_svr_svcs</span><span class="p">[]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Service: Security test. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_SVC_TYPE_PRIMARY</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_svc_sec_test_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">characteristics</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_chr_def</span><span class="p">[])</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Characteristic: Random number generator. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_chr_sec_test_rand_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_access_sec_test</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ_ENC</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** Characteristic: Static value. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_chr_sec_test_static_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_access_sec_test</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="w"> </span><span class="o">|</span>
<span class="w"> </span><span class="n">BLE_GATT_CHR_F_WRITE</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_WRITE_ENC</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more characteristics in this service. */</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="cm">/*** ADC Level Notification Service. */</span>
<span class="w"> </span><span class="p">.</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_SVC_TYPE_PRIMARY</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_svr_svc_adc_uuid</span><span class="p">.</span><span class="n">u</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">characteristics</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_chr_def</span><span class="p">[])</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">ADC_SNS_TYPE</span><span class="p">),</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_sns_access</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_READ</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">.</span><span class="n">uuid</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_UUID16_DECLARE</span><span class="p">(</span><span class="n">ADC_SNS_VAL</span><span class="p">),</span>
<span class="w"> </span><span class="p">.</span><span class="n">access_cb</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_sns_access</span><span class="p">,</span>
<span class="w"> </span><span class="p">.</span><span class="n">flags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BLE_GATT_CHR_F_NOTIFY</span><span class="p">,</span>
<span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more characteristics in this service. */</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">},</span>
<span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="cm">/* No more services. */</span>
<span class="w"> </span><span class="p">},</span>
<span class="p">};</span>
</pre></div>
</div>
<p>You should recognize the first services from the <span class="xref std std-doc">BLE
Peripheral</span> tutorial earlier. We’re just
adding another Service, with 2 new Characteristics, to that application.</p>
<p>We’ll need to fill in the function that will be called for this service,
<code class="docutils literal notranslate"><span class="pre">gatt_svr_sns_access</span></code> next so that the service knows what to do.</p>
<div class="highlight-c notranslate"><div class="highlight"><pre><span></span><span class="k">static</span><span class="w"> </span><span class="kt">int</span>
<span class="nf">gatt_svr_sns_access</span><span class="p">(</span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">conn_handle</span><span class="p">,</span><span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">attr_handle</span><span class="p">,</span>
<span class="w"> </span><span class="k">struct</span><span class="w"> </span><span class="nc">ble_gatt_access_ctxt</span><span class="w"> </span><span class="o">*</span><span class="n">ctxt</span><span class="p">,</span>
<span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="o">*</span><span class="n">arg</span><span class="p">)</span>
<span class="p">{</span>
<span class="w"> </span><span class="kt">uint16_t</span><span class="w"> </span><span class="n">uuid16</span><span class="p">;</span>
<span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="n">uuid16</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ble_uuid_u16</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">chr</span><span class="o">-&gt;</span><span class="n">uuid</span><span class="p">);</span>
<span class="w"> </span><span class="k">switch</span><span class="w"> </span><span class="p">(</span><span class="n">uuid16</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">ADC_SNS_TYPE</span><span class="p">:</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_READ_CHR</span><span class="p">);</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">os_mbuf_append</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_SNS_STRING</span><span class="p">,</span><span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">ADC_SNS_STRING</span><span class="p">);</span>
<span class="w"> </span><span class="n">BLEPRPH_LOG</span><span class="p">(</span><span class="n">INFO</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;ADC SENSOR TYPE READ: %s</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span><span class="w"> </span><span class="n">ADC_SNS_STRING</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">BLE_ATT_ERR_INSUFFICIENT_RES</span><span class="p">;</span>
<span class="w"> </span><span class="k">case</span><span class="w"> </span><span class="no">ADC_SNS_VAL</span><span class="p">:</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_WRITE_CHR</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">gatt_svr_chr_write</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">gatt_adc_val</span><span class="p">,</span>
<span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_adc_val</span><span class="p">,</span>
<span class="w"> </span><span class="nb">NULL</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">op</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="n">BLE_GATT_ACCESS_OP_READ_CHR</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">os_mbuf_append</span><span class="p">(</span><span class="n">ctxt</span><span class="o">-&gt;</span><span class="n">om</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="n">gatt_adc_val</span><span class="p">,</span>
<span class="w"> </span><span class="k">sizeof</span><span class="w"> </span><span class="n">gatt_adc_val</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">rc</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">?</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">BLE_ATT_ERR_INSUFFICIENT_RES</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="k">default</span><span class="o">:</span>
<span class="w"> </span><span class="n">assert</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">BLE_ATT_ERR_UNLIKELY</span><span class="p">;</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>You can see that when request is for the <code class="docutils literal notranslate"><span class="pre">ADC_SNS_TYPE</span></code>, we return the
Sensor Type we defined earlier. If the request if for <code class="docutils literal notranslate"><span class="pre">ADC_SNS_VAL</span></code>
we’ll return the <code class="docutils literal notranslate"><span class="pre">gatt_adc_val</span></code> value.</p>
<p>If you build, load and run this application now, you will see all those
Services and Characteristics advertised, and you will even be able to
read the “Sensor Type” String via the <code class="docutils literal notranslate"><span class="pre">ADC_SNS_TYPE</span></code> Characteristic.</p>
</div>
<div class="section" id="adding-the-etape-water-sensor">
<h2><a class="toc-backref" href="#id9">Adding the eTape Water Sensor</a><a class="headerlink" href="#adding-the-etape-water-sensor" title="Permalink to this headline"></a></h2>
<p>Now that we have a fully functioning BLE App that we can subscribe to
sensor values from, it’s time to actually wire up the sensor!</p>
<p>As previously mentioned, we’re going to be using an eTape Water Level
Sensor. You can get one from
<a class="reference external" href="https://www.adafruit.com/products/1786">Adafruit</a>.</p>
<p>We’re going to use the sensor as a resistive sensor, and the setup is
very simple. I’ll be using a breadboard to put this all together for
illustrative purposes. First, attach a jumper-wire from V<sub>DD</sub> on the board
to the breadboard. Next, attach a jumper wire from pin P0.03 on the
board to the breadboard. This will be our ADC-in. The sensor should have
come with a 560 ohm resistor, so plug that into the board between V<sub>DD</sub> and ADC-in holes. Finally, attach a jumper from GND on the board to your
breadboard. At this point, your breadboard should look like this:</p>
<div class="figure align-default" id="id1">
<img alt="Bread Board Setup" src="../../_images/breadboard.png" />
<p class="caption"><span class="caption-text">Bread Board Setup</span><a class="headerlink" href="#id1" title="Permalink to this image"></a></p>
</div>
<p>Now attach one of the middle 2 leads from the sensor to ground on the
breadboard and the other middle lead to the ADC-in on the breadboard.
Your breadboard should now look like this:</p>
<div class="figure align-default" id="id2">
<img alt="Bread Board Final" src="../../_images/adc-demo-1.png" />
<p class="caption"><span class="caption-text">Bread Board Final</span><a class="headerlink" href="#id2" title="Permalink to this image"></a></p>
</div>
<p>And your eTape Sensor should look like this (at least if you have it
mounted in a graduated cylinder as I do).</p>
<div class="figure align-default" id="id3">
<img alt="eTape Sensor Setup" src="../../_images/adc-demo-2.png" />
<p class="caption"><span class="caption-text">eTape Sensor Setup</span><a class="headerlink" href="#id3" title="Permalink to this image"></a></p>
</div>
<p>That concludes the hardware portion. Easy!</p>
<p>At this point you should be able to build, create-image and load your
application and see it properly sending readings.</p>
</div>
<div class="section" id="view-data-remotely-via-bluetooth">
<h2><a class="toc-backref" href="#id10">View Data Remotely via Bluetooth</a><a class="headerlink" href="#view-data-remotely-via-bluetooth" title="Permalink to this headline"></a></h2>
<p>To view these sensor readings via Bluetooth, you can use LightBlue or a similar app that can connect to Bluetooth devices and read data. Once your sensor application is running, you should see your device show up in LightBlue as <code class="docutils literal notranslate"><span class="pre">nimble-adc</span></code> (or whatever you named your Bluetooth device):</p>
<div class="figure align-default" id="id4">
<img alt="LightBlue connected to the ADC app" src="../../_images/lightblue-adc.png" />
<p class="caption"><span class="caption-text">LightBlue connected to the ADC app</span><a class="headerlink" href="#id4" title="Permalink to this image"></a></p>
</div>
</div>
<div class="section" id="conclusion">
<h2><a class="toc-backref" href="#id11">Conclusion</a><a class="headerlink" href="#conclusion" title="Permalink to this headline"></a></h2>
<p>Congratulations, you’ve now completed both a hardware project and a
software project by connecting a sensor to your device and using Mynewt
to read data from that sensor and send it via Bluetooth to a connected
device. That’s no small feat!</p>
<p>If you see anything missing or want to send us feedback, please do so by
signing up for appropriate mailing lists on our <span class="xref std std-doc">Community
Page</span>.</p>
<p>Keep on hacking and sensing!</p>
<p>Enjoy!</p>
</div>
</div>
</div>
</div>
<div class="rst-footer-buttons row" role="navigation" aria-label="footer navigation">
<a href="sensor_nrf52_drv2605.html" class="btn btn-neutral float-right" title="Enabling and Calibrating Off-Board DRV2605 LRA Actuator" accesskey="n">Next: Enabling and Calibrating Off-Board DRV2605 LRA Actuator <span class="fa fa-arrow-circle-right"></span></a>
<a href="air_quality_ble.html" class="btn btn-neutral" title="Air Quality Sensor Project via Bluetooth" accesskey="p"><span class="fa fa-arrow-circle-left"></span> Previous: Air Quality Sensor Project via Bluetooth</a>
</div>
</div>
</div>
</div>
<!-- ENDS CONTENT SECTION -->
</div>
<!-- ENDS .content -->
</div>
</div>
<footer>
<div class="container">
<div class="row">
<div class="col-xs-12">
<p class="copyright">Apache Mynewt is available under Apache License, version 2.0.</p>
</div>
<div class="col-xs-12">
<div class="logos">
<img src="../../_static/img/asf_logo_wide_small.png" alt="Apache" title="Apache">
<small class="footnote">
Apache Mynewt, Mynewt, Apache, the Apache feather logo, and the Apache Mynewt project logo are either
registered trademarks or trademarks of the Apache Software Foundation in the United States and other countries.
</small>
<a href="">
<img src="../../_static/img/add_to_slack.png" alt="Slack Icon" title="Join our Slack Community" />
</a>
</div>
</div>
</div>
</div>
</footer>
</div>
<!-- ENDS #wrapper -->
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT:'../../',
VERSION:'latest',
COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
LINK_SUFFIX: '.html'
};
</script>
<script type="text/javascript" src="../../_static/jquery.js"></script>
<script type="text/javascript" src="../../_static/underscore.js"></script>
<script type="text/javascript" src="../../_static/doctools.js"></script>
<script type="text/javascript" src="../../_static/js/bootstrap-3.0.3.min.js"></script>
<script type="text/javascript" src="../../_static/js/affix.js"></script>
<script type="text/javascript" src="../../_static/js/main.js"></script>
</body>
</html>