mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 10:18:33 +08:00
971 lines
No EOL
68 KiB
HTML
971 lines
No EOL
68 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<meta name="generator" content="rustdoc">
|
||
<title>Mynewt GPIO ported to PineCone BL602 RISC-V Board</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="Mynewt GPIO ported to PineCone BL602 RISC-V Board"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="How we ported the BL602 RISC-V Hardware Abstraction Layer to Apache Mynewt ... Starting with GPIO"
|
||
data-rh="true">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/gpio-title.jpg">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical" href="https://lupyuen.org/articles/gpio.html" />
|
||
<!-- End scripts/articles/*-header.html -->
|
||
<!-- Begin scripts/rustdoc-header.html: Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<link rel="alternate" type="application/rss+xml" title="RSS Feed for lupyuen" href="/rss.xml" />
|
||
<link rel="stylesheet" type="text/css" href="../normalize.css">
|
||
<link rel="stylesheet" type="text/css" href="../rustdoc.css" id="mainThemeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../dark.css">
|
||
<link rel="stylesheet" type="text/css" href="../light.css" id="themeStyle">
|
||
<link rel="stylesheet" type="text/css" href="../prism.css">
|
||
<script src="../storage.js"></script><noscript>
|
||
<link rel="stylesheet" href="../noscript.css"></noscript>
|
||
<link rel="shortcut icon" href="../favicon.ico">
|
||
<style type="text/css">
|
||
#crate-search {
|
||
background-image: url("../down-arrow.svg");
|
||
}
|
||
</style>
|
||
<!-- End scripts/rustdoc-header.html -->
|
||
|
||
|
||
</head>
|
||
<body class="rustdoc">
|
||
<!--[if lte IE 8]>
|
||
<div class="warning">
|
||
This old browser is unsupported and will most likely display funky
|
||
things.
|
||
</div>
|
||
<![endif]-->
|
||
|
||
|
||
<!-- Begin scripts/rustdoc-before.html: Pre-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker -->
|
||
<div class="theme-picker" style="left: 0"><button id="theme-picker" aria-label="Pick another theme!"><img src="../brush.svg"
|
||
width="18" alt="Pick another theme!"></button>
|
||
<div id="theme-choices"></div>
|
||
</div>
|
||
<!-- Theme Picker -->
|
||
|
||
<!-- End scripts/rustdoc-before.html -->
|
||
|
||
|
||
<h1 class="title">Mynewt GPIO ported to PineCone BL602 RISC-V Board</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#our-mynewt-gpio-program" title="Our Mynewt GPIO Program">1 Our Mynewt GPIO Program</a><ul></ul></li>
|
||
<li><a href="#but-why-mynewt" title="But Why Mynewt?">2 But Why Mynewt?</a><ul></ul></li>
|
||
<li><a href="#mynewt-and-bl602-layers" title="Mynewt and BL602 Layers">3 Mynewt and BL602 Layers</a><ul></ul></li>
|
||
<li><a href="#calling-the-mynewt-and-bl602-layers" title="Calling the Mynewt and BL602 Layers">4 Calling the Mynewt and BL602 Layers</a><ul></ul></li>
|
||
<li><a href="#compile-bl602-sdk-under-mynewt" title="Compile BL602 SDK under Mynewt">5 Compile BL602 SDK under Mynewt</a><ul></ul></li>
|
||
<li><a href="#freertos-references-in-bl602-sdk" title="FreeRTOS References in BL602 SDK">6 FreeRTOS References in BL602 SDK</a><ul></ul></li>
|
||
<li><a href="#fix-bl602-sdk-for-mynewt" title="Fix BL602 SDK for Mynewt">7 Fix BL602 SDK for Mynewt</a><ul>
|
||
<li><a href="#mismatched-types" title="Mismatched Types">7.1 Mismatched Types</a><ul></ul></li>
|
||
<li><a href="#buffer-overflow" title="Buffer Overflow">7.2 Buffer Overflow</a><ul></ul></li>
|
||
<li><a href="#external-pointer-reference" title="External Pointer Reference">7.3 External Pointer Reference</a><ul></ul></li>
|
||
<li><a href="#pull-request-and-pending-analysis" title="Pull Request and Pending Analysis">7.4 Pull Request and Pending Analysis</a><ul></ul></li></ul></li>
|
||
<li><a href="#automated-build-with-github-actions" title="Automated Build with GitHub Actions">8 Automated Build with GitHub Actions</a><ul>
|
||
<li><a href="#trigger-conditions" title="Trigger Conditions">8.1 Trigger Conditions</a><ul></ul></li>
|
||
<li><a href="#build-environment" title="Build Environment">8.2 Build Environment</a><ul></ul></li>
|
||
<li><a href="#checkout-source-files" title="Checkout Source Files">8.3 Checkout Source Files</a><ul></ul></li>
|
||
<li><a href="#check-cache-for-newt" title="Check Cache for newt">8.4 Check Cache for newt</a><ul></ul></li>
|
||
<li><a href="#download-and-build-newt" title="Download and Build newt">8.5 Download and Build newt</a><ul></ul></li>
|
||
<li><a href="#show-files" title="Show Files">8.6 Show Files</a><ul></ul></li>
|
||
<li><a href="#check-cache-for-gcc-compiler" title="Check Cache for GCC Compiler">8.7 Check Cache for GCC Compiler</a><ul></ul></li>
|
||
<li><a href="#download-gcc-compiler" title="Download GCC Compiler">8.8 Download GCC Compiler</a><ul></ul></li>
|
||
<li><a href="#build-mynewt-firmware" title="Build Mynewt Firmware">8.9 Build Mynewt Firmware</a><ul></ul></li>
|
||
<li><a href="#upload-mynewt-firmware" title="Upload Mynewt Firmware">8.10 Upload Mynewt Firmware</a><ul></ul></li>
|
||
<li><a href="#show-output" title="Show Output">8.11 Show Output</a><ul></ul></li>
|
||
<li><a href="#caching-considerations" title="Caching Considerations">8.12 Caching Considerations</a><ul></ul></li></ul></li>
|
||
<li><a href="#run-mynewt-on-pinecone" title="Run Mynewt on PineCone">9 Run Mynewt on PineCone</a><ul>
|
||
<li><a href="#jtag-foiled-by-gpio" title="JTAG Foiled By GPIO">9.1 JTAG Foiled By GPIO</a><ul></ul></li></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">10 What’s Next</a><ul></ul></li>
|
||
<li><a href="#notes" title="Notes">11 Notes</a><ul></ul></li>
|
||
<li><a href="#appendix-inventory-of-sensors-and-actuators" title="Appendix: Inventory of Sensors and Actuators">12 Appendix: Inventory of Sensors and Actuators</a><ul>
|
||
<li><a href="#sensors" title="Sensors">12.1 Sensors</a><ul></ul></li>
|
||
<li><a href="#actuators" title="Actuators">12.2 Actuators</a><ul></ul></li>
|
||
<li><a href="#sensor--actuator" title="Sensor + Actuator">12.3 Sensor + Actuator</a><ul></ul></li></ul></li>
|
||
<li><a href="#appendix-github-actions-environment" title="Appendix: GitHub Actions Environment">13 Appendix: GitHub Actions Environment</a><ul>
|
||
<li><a href="#environment-variables" title="Environment Variables">13.1 Environment Variables</a><ul></ul></li>
|
||
<li><a href="#file-system" title="File System">13.2 File System</a><ul></ul></li></ul></li></ul></nav><p>📝 <em>15 Jan 2021</em></p>
|
||
<p>A month ago we started porting <a href="https://mynewt.apache.org/"><strong>Apache Mynewt</strong></a>, a modern embedded operating system, to PineCone BL602…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/mynewt"><strong>“Porting Mynewt to PineCone BL602”</strong></a></li>
|
||
</ul>
|
||
<p>Then last week we learnt about the <strong>Hardware Abstraction Layer</strong> provided by the <strong>BL602 IoT SDK</strong> for controlling GPIO…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/led"><strong>“Control PineCone BL602 RGB LED with GPIO and PWM”</strong></a></li>
|
||
</ul>
|
||
<p>Today we shall…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Embed BL602’s Hardware Abstraction Layer</strong> inside Mynewt</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Map Mynewt’s GPIO Functions</strong> to BL602’s Hardware Abstraction Layer</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Build Mynewt BL602 automatically</strong> with GitHub Actions</p>
|
||
</li>
|
||
</ol>
|
||
<p>If you’re new to PineCone BL602, check out my article…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/pinecone"><strong>“Quick Peek of PineCone BL602 RISC-V Evaluation Board”</strong></a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-title.jpg" alt="PineCone BL602 RISC-V Evaluation Board with LED controlled by Apache Mynewt" /></p>
|
||
<p><em>PineCone BL602 RISC-V Evaluation Board with LED controlled by Apache Mynewt</em></p>
|
||
<h1 id="our-mynewt-gpio-program"><a class="doc-anchor" href="#our-mynewt-gpio-program">§</a>1 Our Mynewt GPIO Program</h1>
|
||
<p>Here’s the Mynewt Program that actually runs on our PineCone BL602 Board and switches on the Blue LED: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/apps/blinky/src/main.c"><code>main.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>#include <sysinit/sysinit.h> // Init Functions
|
||
#include <os/os.h> // Mynewt Functions
|
||
#include <bsp/bsp.h> // Board Support Package
|
||
#include <hal/hal_gpio.h> // Mynewt HAL for GPIO
|
||
|
||
int main(int argc, char **argv) {
|
||
// Initialise Mynewt drivers
|
||
sysinit();
|
||
|
||
// Set the LED GPIOs to output mode.
|
||
// Switch off the LEDs (1 = Off)
|
||
hal_gpio_init_out(LED_BLUE_PIN, 1);
|
||
hal_gpio_init_out(LED_GREEN_PIN, 1);
|
||
hal_gpio_init_out(LED_RED_PIN, 1);
|
||
|
||
// Switch on Blue LED (0 = On)
|
||
hal_gpio_write(LED_BLUE_PIN, 0);
|
||
|
||
// Loop forever
|
||
for(;;) {}
|
||
}</code></pre></div>
|
||
<p>We’re looking at the beauty of Mynewt… Minimal fuss, easy to read, perfect for <strong>learning embedded programming!</strong></p>
|
||
<p>Mynewt Programs are <strong>Portable</strong> too… <code>hal_gpio_init_out</code> and <code>hal_gpio_write</code> will work on many microcontrollers: STM32 Blue Pill (Arm), Nordic Semi nRF52 (Arm too), SiFive HiFive1 (RISC-V)… And now PineCone BL602 (RISC-V yay!)</p>
|
||
<p>The GPIO Pin Numbers will differ. But on PineCone, this Mynewt Program lights up the Blue LED, exactly like the pic above.</p>
|
||
<p>The LED GPIOs are defined in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/include/bsp/bsp.h"><code>bsp/bsp.h</code></a>…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// Define the LED GPIOs: 11 (Blue), 14 (Green), 17 (Red)
|
||
#define LED_BLUE_PIN 11
|
||
#define LED_GREEN_PIN 14
|
||
#define LED_RED_PIN 17</code></pre></div>
|
||
<p>Let’s find out how we made this work.</p>
|
||
<h1 id="but-why-mynewt"><a class="doc-anchor" href="#but-why-mynewt">§</a>2 But Why Mynewt?</h1>
|
||
<blockquote>
|
||
<p><em>We have many options for learning Embedded Programming on PineCone BL602… Why Mynewt?</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>Let’s review the options available today for learning Embedded Programming on PineCone BL602…</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>BL602’s native IoT SDK looks easy for coding BL602 in C… Supports Multitasking through FreeRTOS (like reading sensor data and sending to network concurrently)</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p>But with <strong>BL602 IoT SDK</strong> we’ll be locked in to BL602. Our programs won’t run on other microcontrollers.</p>
|
||
<p>And we can’t easily port programs from other devices to BL602 either.</p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>What if we wrap up the BL602 IoT SDK with Arduino Libraries?</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Arduino</strong> is kinda ancient for embedded coding. (And the Bit Banging looks disturbing)</p>
|
||
<p>Could there be a modern alternative that works better with today’s multitasking microcontrollers?</p>
|
||
<p><a href="https://github.com/pine64/ArduinoCore-bouffalo">More about Arduino on BL602</a></p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>Like Mbed OS? The newer Arduino SAMD boards support mbed OS</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Mbed OS</strong> looks complex for learners. (Based on C++)</p>
|
||
<p>And Mbed OS was created by Arm so…</p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>Zephyr? It’s well supported by Linux Foundation and many microcontroller manufacturers</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p>Maybe something simpler than <strong>Zephyr</strong>? As simple as the program above?</p>
|
||
<p>Something that compiles easily on Linux, macOS and Windows… Without WSL and Docker?</p>
|
||
<p>(We’ll save Zephyr for the bravest embedded professionals)</p>
|
||
<p><a href="https://github.com/nandojve/zephyr/blob/bouffalo/boards/riscv/dt_bl10_devkit/doc/index.rst"><strong>UPDATE: Check out Zephyr for BL602</strong></a></p>
|
||
<p><a href="https://github.com/bouffalolab/bl_mcu_sdk/pull/18"><strong>UPDATE: Zephyr is being ported to BL602 MCU SDK</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>Alrighty Nitpicky… We’re left with Mynewt. But it’s not as popular as Zephyr</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Mynewt</strong> was designed as a simple tiny OS… And that’s OK!</p>
|
||
<p>(Mynewt is named after “minute” i.e. “small”, not the lizard)</p>
|
||
<p>Mynewt is easy to port to BL602. And our porting work will benefit Zephyr later.</p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>What about Embedded Rust? We have many fans.</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Embedded Rust</strong> looks very promising… Clean and safe embedded coding.</p>
|
||
<p>There’s ongoing work on Embedded Rust for BL602 so let’s wait for it. <a href="https://github.com/sipeed/bl602-hal">More details</a></p>
|
||
<p>Meanwhile I’ll do Rust the shortcut way… Run it on top of Mynewt. (Instead of Bare Metal)</p>
|
||
</li>
|
||
</ul>
|
||
<blockquote>
|
||
<p><em>So we’ll have Rust on Mynewt?</em></p>
|
||
</blockquote>
|
||
<ul>
|
||
<li>Yep! Very soon we shall write embedded programs for PineCone BL602 the simpler safer way in <strong>Rust and Mynewt</strong>. (Without the headaches of C Pointers!)</li>
|
||
</ul>
|
||
<p><a href="https://lupyuen.github.io/articles/nuttx"><strong>UPDATE: Check out Apache NuttX operating system for BL602</strong></a></p>
|
||
<h1 id="mynewt-and-bl602-layers"><a class="doc-anchor" href="#mynewt-and-bl602-layers">§</a>3 Mynewt and BL602 Layers</h1>
|
||
<p><em>How does Mynewt create programs that are portable to other microcontrollers?</em></p>
|
||
<p>By using layers of code that isolate the differences between microcontrollers (like BL602) and boards (like PineCone).</p>
|
||
<p>(Dressing in layers is a very good thing… Especially in Winter!)</p>
|
||
<p>Here’s how we layer the code in Mynewt…</p>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-stack.jpg" alt="Mynewt and BL602 IoT SDK Layers" /></p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Main Function</strong>: We’ve seen the Main Function at the top of the article… It lights up the Blue LED.</p>
|
||
<p>Assuming that the GPIO Pin Number is defined correctly, the same Main Function will light up the LED <strong>on any microcontroller</strong>.</p>
|
||
<p>That’s why this is portable, <strong>Hardware Independent</strong> code. A key feature of modern embedded operating systems.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/apps/blinky/src/main.c"><strong>Main Function: <code>main.c</code></strong></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>Board Support Package</strong>: This layer contains code that’s specific to the Hardware Board, like PineCone.</p>
|
||
<p>The Blue LED is connected at GPIO 11 on PineCone… And these details will vary depending on the BL602 Board that we use (say PineCone vs Pinenut).</p>
|
||
<p>So it makes sense to capture such <strong>Board Specific</strong> details inside the Board Support Package layer.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone"><strong>PineCone Board Support Package: <code>hw/bsp/pinecone</code></strong></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>Microcontroller Package</strong>: This layer is specific to the Microcontroller (like BL602). The Microcontroller Package is reused by all Boards that are based on the same Microcontroller (like PineCone and Pinenut).</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602"><strong>BL602 Microcontroller Package: <code>hw/mcu/bl/bl602</code></strong></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>Hardware Abstraction Layer</strong>: This layer is lifted directly from the <strong>BL602 IoT SDK</strong> (with minimal changes).</p>
|
||
<p>Here we find the functions that control the BL602 hardware: GPIO, PWM, UART, I2C, SPI, …</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal"><strong>BL602 Hardware Abstraction Layer: <code>components/hal_drv/bl602_hal</code></strong></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>Standard Driver</strong>: This layer is unique to BL602. The Hardware Abstraction Layer in BL602 calls this layer to access the Hardware Registers to perform hardware functions.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602_std/bl602_std/StdDriver/Src"><strong>BL602 Standard Driver: <code>components/bl602/ bl602_std/bl602_std/StdDriver</code></strong></a></li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<p><em>What about the rest of the BL602 IoT SDK?</em></p>
|
||
<p>We have integrated the smallest subset of functions from the BL602 SDK that are needed for Mynewt. The rest are not needed (yet).</p>
|
||
<p>In particular, we don’t compile under Mynewt the FreeRTOS driver code from the BL602 SDK. Because running two operating systems side by side would be a disaster!</p>
|
||
<h1 id="calling-the-mynewt-and-bl602-layers"><a class="doc-anchor" href="#calling-the-mynewt-and-bl602-layers">§</a>4 Calling the Mynewt and BL602 Layers</h1>
|
||
<p>To better understand the Mynewt and BL602 Layers, let’s walk through the chain of function calls for a GPIO operation…</p>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-stack2.png" alt="Mynewt and BL602 IoT SDK Layers" /></p>
|
||
<ol>
|
||
<li>
|
||
<p>In the Hardware-Agnostic <strong>Main Function</strong>, we set the LED GPIO to output mode like so: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/apps/blinky/src/main.c"><code>main.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int main(int argc, char **argv) {
|
||
// Set the Blue LED GPIO to output mode
|
||
hal_gpio_init_out(LED_BLUE_PIN, 1);</code></pre></div>
|
||
<p>The Mynewt GPIO Function <code>hal_gpio_init_out</code> works on any microcontroller.</p>
|
||
</li>
|
||
<li>
|
||
<p><strong><code>LED_BLUE_PIN</code></strong> is the GPIO Pin Number for the Blue LED.</p>
|
||
<p>The LED GPIO Pin Number will differ across Boards, so <code>LED_BLUE_PIN</code> is defined in the <strong>Board Support Package for PineCone</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/include/bsp/bsp.h"><code>bsp/bsp.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// Define the Blue LED GPIO
|
||
#define LED_BLUE_PIN 11</code></pre></div></li>
|
||
<li>
|
||
<p><strong><code>hal_gpio_init_out</code></strong> is a standard Mynewt GPIO Function that works on any microcontroller. But its implementation is specific to the microcontroller.</p>
|
||
<p>Here’s the implementation of <code>hal_gpio_init_out</code> in our <strong>Microcontroller Package for BL602</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/src/hal_gpio.c"><code>bl602/hal_gpio.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int hal_gpio_init_out(int pin, int val) {
|
||
int rc = bl_gpio_enable_output(pin, 0, 0);</code></pre></div></li>
|
||
<li>
|
||
<p>The above implementation calls <strong><code>bl_gpio_enable_output</code></strong>, which is defined in the <strong>Hardware Abstraction Layer from BL602 IoT SDK</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_gpio.c"><code>bl602_hal/bl_gpio.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int bl_gpio_enable_output(uint8_t pin, uint8_t pullup, uint8_t pulldown) {
|
||
...
|
||
GLB_GPIO_Init(&cfg);</code></pre></div></li>
|
||
<li>
|
||
<p>And finally we call <strong><code>GLB_GPIO_Init</code></strong>, which is defined in the <strong>Standard Driver from BL602 IoT SDK</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602_std/bl602_std/StdDriver/Src/bl602_glb.c"><code>StdDriver/bl602_glb.c</code></a></p>
|
||
<p>GLB refers to <strong>BL602’s Global Register</strong>.</p>
|
||
<p><code>GLB_GPIO_Init</code> manipulates the GLB Hardware Register to control the GPIO Hardware and switch GPIO 11 to output mode.</p>
|
||
</li>
|
||
</ol>
|
||
<h1 id="compile-bl602-sdk-under-mynewt"><a class="doc-anchor" href="#compile-bl602-sdk-under-mynewt">§</a>5 Compile BL602 SDK under Mynewt</h1>
|
||
<p><em>How do we specify which folders of BL602 IoT SDK to compile under Mynewt?</em></p>
|
||
<p>Remember that we’re compiling the smallest subset of functions from the BL602 IoT SDK that are needed for Mynewt…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>BL602 Hardware Abstraction Layer</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/components/hal_drv/bl602_hal"><code>hal_drv/bl602_hal</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>BL602 Standard Driver</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/components/bl602/bl602_std/bl602_std/StdDriver"><code>bl602/bl602_std/ bl602_std/StdDriver</code></a></p>
|
||
</li>
|
||
</ol>
|
||
<p>We specify these folders in Mynewt’s Microcontroller Package for BL602: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/pkg.yml"><code>hw/mcu/bl/ bl602/pkg.yml</code></a></p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>pkg.src_dirs:
|
||
- src
|
||
# Select the BL602 IoT SDK folders to be included for the build
|
||
- ext/bl_iot_sdk/components/hal_drv/bl602_hal
|
||
- ext/bl_iot_sdk/components/bl602/bl602_std/bl602_std/StdDriver/Src</code></pre></div>
|
||
<p>The Microcontroller Package for BL602 also specifies the Include Folders and the GCC Compiler Options: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/pkg.yml"><code>pkg.yml</code></a></p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>pkg.cflags:
|
||
- -march=rv32imac
|
||
- -mabi=ilp32
|
||
# BL602 IoT SDK definitions
|
||
- -DCONF_USER_ENABLE_PSRAM
|
||
- -DconfigUSE_TICKLESS_IDLE=0
|
||
- -DFEATURE_WIFI_DISABLE=1
|
||
- -DCFG_FREERTOS
|
||
- -DARCH_RISCV
|
||
- -DBL602
|
||
...
|
||
# Where the BL602 IoT SDK include files are located
|
||
- -Ihw/mcu/bl/bl602/ext/bl_iot_sdk/components/bl602/bl602_std/bl602_std/Common/partition
|
||
- -Ihw/mcu/bl/bl602/ext/bl_iot_sdk/components/bl602/bl602_std/bl602_std/Common/sim_print
|
||
- -Ihw/mcu/bl/bl602/ext/bl_iot_sdk/components/bl602/bl602_std/bl602_std/Common/soft_crc
|
||
...</code></pre></div>
|
||
<p>The above options were obtained by running <code>make</code> in Trace Mode when building the BL602 IoT SDK…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>make --trace</code></pre></div>
|
||
<p>To preserve the integrity of the BL602 IoT SDK, the entire SDK is mounted under the Mynewt Project as a Git Submodule at…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/ext"><code>hw/mcu/bl/bl602/ext</code></a></li>
|
||
</ul>
|
||
<h1 id="freertos-references-in-bl602-sdk"><a class="doc-anchor" href="#freertos-references-in-bl602-sdk">§</a>6 FreeRTOS References in BL602 SDK</h1>
|
||
<p><em>Does the BL602 IoT SDK depend on any External Library?</em></p>
|
||
<p>Unfortunately yes… The BL602 IoT SDK (Hardware Abstraction Layer) depends on FreeRTOS. And this complicates the porting to Mynewt.</p>
|
||
<p>Let’s look at this code from the BL602 Security (Crypto) HAL: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_sec.c"><code>bl602_hal/bl_sec.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int bl_sec_init(void) {
|
||
g_bl_sec_sha_mutex = xSemaphoreCreateMutexStatic(&sha_mutex_buf);</code></pre></div>
|
||
<p>This code calls FreeRTOS to create a Mutex (Mutually Exclusive Lock) to prevent tasks from accessing some shared data concurrently.</p>
|
||
<p>Mynewt fails to compile this because <code>xSemaphoreCreateMutexStatic</code> isn’t defined. To work around this, we gave Mynewt a Mock Declaration for the undefined function: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/include/semphr.h"><code>semphr.h</code></a></p>
|
||
<p>It compiles OK under Mynewt for now. But eventually we need to implement <code>xSemaphoreCreateMutexStatic</code> with a Mynewt Semaphore.</p>
|
||
<p>Here are the other Mock Declarations for FreeRTOS on Mynewt…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/include"><code>hw/mcu/bl/bl602/include</code></a></li>
|
||
</ul>
|
||
<p><em>Should the BL602 Hardware Abstraction Layer call FreeRTOS?</em></p>
|
||
<p>This is highly unusual… The Hardware Abstraction Layer (HAL) is Low-Level Code that’s meant to called by various Operating Systems. So we don’t expect BL602 HAL to call FreeRTOS directly.</p>
|
||
<p>(STM32 Blue Pill HAL and nRF52 HAL don’t call any Operating Systems either)</p>
|
||
<p>This unusual structure seems similar to ESP32, where FreeRTOS is embedded into the ESP32 HAL.</p>
|
||
<p>We can still go ahead and port Mynewt (and other Operating Systems) to BL602. Just that we need to emulate the FreeRTOS functions in Mynewt (and other Operating Systems).</p>
|
||
<h1 id="fix-bl602-sdk-for-mynewt"><a class="doc-anchor" href="#fix-bl602-sdk-for-mynewt">§</a>7 Fix BL602 SDK for Mynewt</h1>
|
||
<p>Mynewt is strict and uptight when compiling C code with GCC… Any warnings emitted by GCC will fail the Mynewt build.</p>
|
||
<p>We made the following fixes to the BL602 IoT SDK to resolve the warnings…</p>
|
||
<h2 id="mismatched-types"><a class="doc-anchor" href="#mismatched-types">§</a>7.1 Mismatched Types</h2>
|
||
<p>Here we’re passing <code>adc_pin</code> as a number: <a href="https://github.com/pine64/bl_iot_sdk/compare/master...lupyuen:fix-gcc-warnings#diff-50c41592b050878713231111ff6302905f1f2aa7bedff6b250ff6fd6d219cc33"><code>components/hal_drv/ bl602_hal/bl_adc.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>uint8_t adc_pin = gpio_num;
|
||
GLB_GPIO_Func_Init(GPIO_FUN_ANALOG, &adc_pin, 1);
|
||
// Fails because GCC expects adc_pin to be an enum, not a number</code></pre></div>
|
||
<p>Which displeases the GCC Compiler because the function <code>GLB_GPIO_Func_Init</code> expects an enum <code>GLB_GPIO_Type</code>, not a number.</p>
|
||
<p>The fix is simple…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// Declare as enum instead of number
|
||
GLB_GPIO_Type adc_pin = gpio_num;</code></pre></div><h2 id="buffer-overflow"><a class="doc-anchor" href="#buffer-overflow">§</a>7.2 Buffer Overflow</h2>
|
||
<p>This potential Buffer Overflow seems scary: <a href="https://github.com/pine64/bl_iot_sdk/compare/master...lupyuen:fix-gcc-warnings#diff-c60188dbf9788696071897d85f50ea1e97b474a7271f6f5de3b46241184c7902"><code>components/hal_drv/ bl602_hal/hal_button.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int i = ...;
|
||
char gpio_node[10] = "gpio";
|
||
sprintf(gpio_node, "gpio%d", i);
|
||
// Fails because gpio_node may overflow</code></pre></div>
|
||
<p>GCC thinks that <code>i</code> may exceed 5 digits (because it’s a 32-bit integer), causing <code>gpio_node</code> to overflow.</p>
|
||
<p>For our safety (and to placate GCC), we switch <code>sprintf</code> to <code>snprintf</code>, which limits the output size…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// Limit formatting to size of gpio_node
|
||
snprintf(gpio_node, sizeof(gpio_node), "gpio%d", i);</code></pre></div><h2 id="external-pointer-reference"><a class="doc-anchor" href="#external-pointer-reference">§</a>7.3 External Pointer Reference</h2>
|
||
<p>Here we use a pointer that’s defined in a GCC Linker Script: <a href="https://github.com/pine64/bl_iot_sdk/compare/master...lupyuen:fix-gcc-warnings#diff-29ee70160cf58784272419fe4769f988b944038e2d68800b3f51aa179feea412"><code>components/hal_drv/ bl602_hal/hal_sys.c</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>extern uint8_t __global_pointer_head$;
|
||
memset(&__global_pointer_head$, 0, 0x498);
|
||
// Fails because the pointer references a single byte, not 0x498 bytes</code></pre></div>
|
||
<p>GCC thinks that the pointer references a single byte… Copying <code>0x498</code> bytes to the pointer would surely cause an overflow!</p>
|
||
<p>Thus we do the right thing and tell GCC that it’s really a pointer to an array of <code>0x498</code> bytes…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// Pointer to an array of 0x498 bytes
|
||
extern uint8_t __global_pointer_head$[0x498];</code></pre></div><h2 id="pull-request-and-pending-analysis"><a class="doc-anchor" href="#pull-request-and-pending-analysis">§</a>7.4 Pull Request and Pending Analysis</h2>
|
||
<p>The above fixes (plus a few minor ones) have been submitted upstream as a Pull Request…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/pine64/bl_iot_sdk/pull/84"><strong>Fix GCC Warning for BL602 SDK on Mynewt</strong></a></li>
|
||
</ul>
|
||
<p>4 fixes have not been pushed upstream yet, because they need more Impact Analysis…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Variable set but not used</p>
|
||
<ul>
|
||
<li><a href="https://github.com/pine64/bl_iot_sdk/pull/84#discussion_r549207518"><code>components/hal_drv/ bl602_hal/hal_board.c</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Mismatched format strings</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/commit/2393379c2fd9177cd62484667a0ce07157370e43#diff-99dc1c18d04bd746c17e484406a6f9e5fe733c1f9751adb364ad636253f5c1ae"><code>components/bl602/bl602_std/ bl602_std/StdDriver/Src/ bl602_common.c</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Misplaced main function</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/commit/2393379c2fd9177cd62484667a0ce07157370e43#diff-d1eb6a16f4855132d64e9decec8de3b44d06d52c03e6825a0dc71dd595cbe157"><code>components/bl602/bl602_std/ bl602_std/StdDriver/Src/ bl602_mfg_flash.c</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Missing include</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/commit/2393379c2fd9177cd62484667a0ce07157370e43#diff-3b9ce4151983dedcd6bc4e3788a8b30b249ff106bd987df589b409cc72f9f2b9"><code>components/bl602/bl602_std/ bl602_std/StdDriver/Src/ bl602_romdriver.c</code></a></li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<h1 id="automated-build-with-github-actions"><a class="doc-anchor" href="#automated-build-with-github-actions">§</a>8 Automated Build with GitHub Actions</h1>
|
||
<p>When porting Mynewt to BL602, it’s good to make sure that we don’t <strong>break any existing code by accident</strong>. (Especially the BL602 IoT SDK, which we have tweaked slightly for Mynewt)</p>
|
||
<p>That’s why we use <strong>GitHub Actions to compile automatically</strong> the Mynewt code (plus the core parts of BL602 IoT SDK) whenever we <strong>commit any changes</strong>.</p>
|
||
<p><em>How long does GitHub take to compile our Mynewt + BL602 SDK Code?</em></p>
|
||
<p><strong>TWO MINUTES</strong>. Thus if we ever commit some bad code (that can’t be compiled) into the repo, GitHub will alert us in TWO MINUTES (via email) that something has gone terribly wrong in our repo.</p>
|
||
<p>We’ll see the results of the Automated Build here (please log in to GitHub first)…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/actions"><strong>GitHub Actions for <code>pinecone-rust-mynewt</code></strong></a></li>
|
||
</ul>
|
||
<p>To complete the build in TWO MINUTES, we use some caching magic inside our GitHub Actions Workflow.</p>
|
||
<p>Let’s learn how it works: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/.github/workflows/main.yml"><code>.github/workflows/main.yml</code></a></p>
|
||
<h2 id="trigger-conditions"><a class="doc-anchor" href="#trigger-conditions">§</a>8.1 Trigger Conditions</h2>
|
||
<p>At the top of the GitHub Actions Workflow, we state the conditions that will trigger the Automated Build…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>## Name of this Workflow
|
||
name: Build Firmware
|
||
|
||
## When to run this Workflow...
|
||
on:
|
||
## Run this Workflow when files are updated (Pushed) in this Branch
|
||
push:
|
||
branches: [ main ] </code></pre></div>
|
||
<p>This says that the Automated Build will be triggered whenever we commit code to the <code>main</code> branch.</p>
|
||
<h2 id="build-environment"><a class="doc-anchor" href="#build-environment">§</a>8.2 Build Environment</h2>
|
||
<p>We’ll use an Ubuntu x64 virtual machine (hosted at GitHub) to compile our code…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>## Steps to run for the Workflow
|
||
jobs:
|
||
build:
|
||
## Run these steps on Ubuntu
|
||
runs-on: ubuntu-latest</code></pre></div><h2 id="checkout-source-files"><a class="doc-anchor" href="#checkout-source-files">§</a>8.3 Checkout Source Files</h2>
|
||
<p>Here begins the steps for our Mynewt + BL602 SDK Automated Build with GitHub Actions.</p>
|
||
<p>First we check out the source files from the repo recursively, including the following submodules…</p>
|
||
<ol>
|
||
<li>
|
||
<p>BL602 IoT SDK at <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/ext"><code>hw/mcu/bl/bl602/ext</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Mynewt Core, NimBLE, MCU Manager and MCUBoot at <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/repos"><code>repos</code></a></p>
|
||
</li>
|
||
</ol>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> steps:
|
||
- name: Checkout source files
|
||
uses: actions/checkout@v2
|
||
with:
|
||
submodules: 'recursive'</code></pre></div><h2 id="check-cache-for-newt"><a class="doc-anchor" href="#check-cache-for-newt">§</a>8.4 Check Cache for newt</h2>
|
||
<p>Mynewt doesn’t use <code>make</code> to build… It uses its own <a href="https://github.com/apache/mynewt-newt/">build tool named <code>newt</code></a>.</p>
|
||
<p>Developed in Go, <code>newt</code> runs on Linux, macOS and Windows CMD.</p>
|
||
<p>We fetch the <code>newt</code> executable from our GitHub Actions Cache, if it exists…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Check cache for newt
|
||
id: cache-newt
|
||
uses: actions/cache@v2
|
||
env:
|
||
cache-name: cache-newt
|
||
with:
|
||
path: ${{ runner.temp }}/mynewt-newt
|
||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}</code></pre></div>
|
||
<p>(If <code>newt</code> isn’t found in our cache, we build <code>newt</code> and cache it in the next step)</p>
|
||
<p>Each cache has a name, ours is <code>cache-newt</code>…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> env:
|
||
cache-name: cache-newt</code></pre></div>
|
||
<p>The Cache Action <code>actions/cache</code> requires 3 parameters: <code>path</code>, <code>key</code> and <code>restore-keys</code>…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> with:
|
||
path: ${{ runner.temp }}/mynewt-newt
|
||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}</code></pre></div>
|
||
<p>Given that our GitHub Actions Environment is defined as…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>runner.temp = /home/runner/work/_temp
|
||
runner.os = Linux
|
||
env.cache-name = cache-newt</code></pre></div>
|
||
<p>Our parameters will get expanded to…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>path: /home/runner/work/_temp/mynewt-newt
|
||
key: Linux-build-cache-newt
|
||
restore-keys: Linux-build-cache-newt</code></pre></div>
|
||
<p>Thus the Cache Action will cache and restore the <code>newt</code> folder at this temporary folder…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>path: /home/runner/work/_temp/mynewt-newt</code></pre></div>
|
||
<p>And to avoid confusion with other caches in the same workflow, we give it a unique key…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>key: Linux-build-cache-newt</code></pre></div><h2 id="download-and-build-newt"><a class="doc-anchor" href="#download-and-build-newt">§</a>8.5 Download and Build newt</h2>
|
||
<p>Here’s how we download and build <code>newt</code> if it doesn’t exist in our cache…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Install newt
|
||
## Install newt if not found in cache
|
||
if: steps.cache-newt.outputs.cache-hit != 'true'
|
||
run: |
|
||
source scripts/install-version.sh
|
||
cd ${{ runner.temp }}
|
||
git clone --branch $mynewt_version https://github.com/apache/mynewt-newt/
|
||
cd mynewt-newt/
|
||
./build.sh
|
||
newt/newt version
|
||
export PATH=$PATH:${{ runner.temp }}/mynewt-newt/newt
|
||
newt version</code></pre></div>
|
||
<p>(We set <code>mynewt_version</code> to <code>mynewt_1_8_0_tag</code> in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/scripts/install-version.sh"><code>scripts/install-version.sh</code></a>)</p>
|
||
<p>Note the condition: We execute this step only when <code>newt</code> doesn’t exist in our cache…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> ## Install newt if not found in cache
|
||
if: steps.cache-newt.outputs.cache-hit != 'true'</code></pre></div>
|
||
<p>(<code>steps.cache-newt</code> refers to the cache checking from the previous step)</p>
|
||
<p>After building <code>newt</code>, the Cache Action <code>actions/cache</code> (from the previous step) caches our <code>newt</code> folder…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>path: /home/runner/work/_temp/mynewt-newt</code></pre></div>
|
||
<p>And restores the <code>newt</code> folder whenever we run the Automated Build.</p>
|
||
<p>This caching enables us to complete the Automated Build in two minutes. We’ll use caching again for the GCC Compiler.</p>
|
||
<h2 id="show-files"><a class="doc-anchor" href="#show-files">§</a>8.6 Show Files</h2>
|
||
<p>For troubleshooting our Automated Build, we dump the GitHub Actions Environmment Variables and the File System like so…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Show files
|
||
run: set ; pwd ; ls -l</code></pre></div>
|
||
<p>And here’s the output…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/gpio#appendix-github-actions-environment"><strong>GitHub Actions Environmment</strong></a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-action.png" alt="Mynewt Automated Build completed in 2 minutes" /></p>
|
||
<p><em>Mynewt Automated Build completed in 2 minutes</em></p>
|
||
<h2 id="check-cache-for-gcc-compiler"><a class="doc-anchor" href="#check-cache-for-gcc-compiler">§</a>8.7 Check Cache for GCC Compiler</h2>
|
||
<p>Remember how we cached the <code>newt</code> tool to cut down on the build time? We’ll do the same for our GCC Compiler…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Check cache for xPack RISC-V Toolchain xpack-riscv-none-embed-gcc
|
||
id: cache-toolchain
|
||
uses: actions/cache@v2
|
||
env:
|
||
cache-name: cache-toolchain
|
||
with:
|
||
path: xpack-riscv-none-embed-gcc
|
||
key: ${{ runner.os }}-build-${{ env.cache-name }}
|
||
restore-keys: ${{ runner.os }}-build-${{ env.cache-name }}</code></pre></div>
|
||
<p>First we try to load the GCC Compiler from the cache with these settings…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>path: xpack-riscv-none-embed-gcc
|
||
key: Linux-build-cache-toolchain
|
||
restore-keys: Linux-build-cache-toolchain</code></pre></div>
|
||
<p>If the GCC Compiler exists in our cache, the Cache Action will restore the GCC folder <code>xpack-riscv-none-embed-gcc</code> into the current directory (which is the root of our repo).</p>
|
||
<h2 id="download-gcc-compiler"><a class="doc-anchor" href="#download-gcc-compiler">§</a>8.8 Download GCC Compiler</h2>
|
||
<p>If the GCC Compiler doesn’t exist in our cache, we download the <a href="https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases"><strong>xPack RISC-V Toolchain: <code>xpack-riscv-none-embed-gcc</code></strong></a></p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Install xPack RISC-V Toolchain xpack-riscv-none-embed-gcc
|
||
## Install toolchain if not found in cache
|
||
if: steps.cache-toolchain.outputs.cache-hit != 'true'
|
||
run: |
|
||
wget -qO- https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/download/v8.3.0-2.3/xpack-riscv-none-embed-gcc-8.3.0-2.3-linux-x64.tar.gz | tar -xz
|
||
mv xpack-riscv-none-embed-gcc-* xpack-riscv-none-embed-gcc</code></pre></div>
|
||
<p>(Remember: We check <code>steps.cache-toolchain</code> and skip this step if the GCC Compiler is already in our cache)</p>
|
||
<p>After downloading the GCC Compiler, the Cache Action <code>actions/cache</code> (from the previous step) caches our GCC folder…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>path: xpack-riscv-none-embed-gcc</code></pre></div>
|
||
<p>Caching the GCC Compiler is essential for reducing the Automated Build time to 2 minutes… Because each download of the xPack RISC-V Toolchain takes a whopping <strong>400 MB!</strong> (Zipped!)</p>
|
||
<h2 id="build-mynewt-firmware"><a class="doc-anchor" href="#build-mynewt-firmware">§</a>8.9 Build Mynewt Firmware</h2>
|
||
<p>Now that we have the build tools ready (<code>newt</code> and GCC Compiler), let’s build Mynewt with GitHub Actions…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Build Application Firmware
|
||
run: |
|
||
export PATH=$PATH:${{ runner.temp }}/mynewt-newt/newt
|
||
./scripts/build-app.sh</code></pre></div>
|
||
<p>This sets the path of <code>newt</code> and calls the build script: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/scripts/build-app.sh"><code>scripts/build-app.sh</code></a></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Add GCC to the PATH
|
||
export PATH="$PWD/xpack-riscv-none-embed-gcc/bin:$PATH"
|
||
|
||
## Build the Mynewt Firmware
|
||
newt build pinecone_app
|
||
|
||
## Display the firmware size
|
||
newt size -v pinecone_app</code></pre></div>
|
||
<p>We can see the results of the Automated Build here (please log in to GitHub first)…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/actions"><strong>GitHub Actions for <code>pinecone-rust-mynewt</code></strong></a></li>
|
||
</ul>
|
||
<p>Here’s a peek at the Automated Build log at GitHub Actions…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Linking /home/runner/work/pinecone-rust-mynewt/pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf
|
||
Target successfully built: targets/pinecone_app
|
||
+ newt size -v pinecone_app
|
||
Size of Application Image: app
|
||
Mem flash: 0x22008000-0x22014000
|
||
Mem ram: 0x22014000-0x22020000</code></pre></div>
|
||
<p>Note that the “Flash Memory” actually points to the Cache Memory at <code>0x2200 8000</code>.</p>
|
||
<p>This means that our firmware is meant to be tested and debugged with OpenOCD and GDB (or VSCode). (Instead of being flashed to Flash Memory)</p>
|
||
<div class="example-wrap"><pre class="language-text"><code> flash ram
|
||
6 529 *fill*
|
||
172 0 @apache-mynewt-core_hw_hal.a
|
||
4442 8213 @apache-mynewt-core_kernel_os.a
|
||
80 0 @apache-mynewt-core_libc_baselibc.a
|
||
702 128 @apache-mynewt-core_sys_flash_map.a
|
||
2 0 @apache-mynewt-core_sys_log_modlog.a
|
||
782 29 @apache-mynewt-core_sys_mfg.a
|
||
30 5 @apache-mynewt-core_sys_sysinit.a
|
||
72 0 @apache-mynewt-core_util_mem.a
|
||
36 0 apps_blinky.a
|
||
44 12 hw_bsp_pinecone.a
|
||
3486 228 hw_mcu_bl_bl602.a
|
||
92 0 pinecone_app-sysinit-app.a
|
||
292 1064 libg.a</code></pre></div>
|
||
<p>Here are the components of our firmware. The BL602 IoT SDK (GPIO HAL and Standard Driver) occupies 3.4 KB of code and read-only data in <code>hw_mcu_bl_bl602.a</code>.</p>
|
||
<p>The Mynewt Kernel <code>apache-mynewt-core_kernel_os.a</code> occupies 4.3 KB of code and read-only data, plus another 8 KB of read-write data in RAM. (Mostly for the Kernel Stack)</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Loading compiler /home/runner/work/pinecone-rust-mynewt/pinecone-rust-mynewt/compiler/riscv-none-embed, buildProfile debug
|
||
objsize
|
||
text data bss dec hex filename
|
||
11318 28 9100 20446 4fde /home/runner/work/pinecone-rust-mynewt/pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div>
|
||
<p>The build creates a Firmware ELF File <code>blinky.elf</code> that contains 11 KB of code and read-only data.</p>
|
||
<h2 id="upload-mynewt-firmware"><a class="doc-anchor" href="#upload-mynewt-firmware">§</a>8.10 Upload Mynewt Firmware</h2>
|
||
<p>To save the firmware files generated by the Automated Build (and allow anyone to download), we call <code>actions/upload-artifact</code>…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Upload Application Firmware
|
||
uses: actions/upload-artifact@v2
|
||
with:
|
||
name: blinky.elf
|
||
path: bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div>
|
||
<p>Here we save the Mynewt Firmware ELF File <code>blinky.elf</code> as an Artifact, to make it accessible for everyone to download. <a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v2.0.0/blinky.elf">Download here</a></p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Upload Application Firmware Outputs
|
||
uses: actions/upload-artifact@v2
|
||
with:
|
||
name: blinky.zip
|
||
path: bin/targets/pinecone_app/app/apps/blinky/blinky.*</code></pre></div>
|
||
<p>Next we upload another Artifact named <code>blinky.zip</code> that contains some useful files from the Mynewt Automated Build…</p>
|
||
<ol>
|
||
<li>
|
||
<p><code>blinky.elf.bin</code>: Mynewt Firmware Binary.</p>
|
||
<p>Contains only the firmware code and read-only data, without the debugging symbols.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v2.0.0/blinky.elf.bin">Download here</a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><code>blinky.elf.map</code>: GCC Linker Map for our Mynewt Firmware.</p>
|
||
<p>Shows the addresses of every function and global variable in our firmware.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v2.0.0/blinky.elf.map">Download here</a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><code>blinky.elf.lst</code>: RISC-V Assembly Code for our Mynewt Firmware.</p>
|
||
<p>Disassembled from our firmware build.</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v2.0.0/blinky.elf.lst">Download here</a></li>
|
||
</ul>
|
||
</li>
|
||
</ol>
|
||
<h2 id="show-output"><a class="doc-anchor" href="#show-output">§</a>8.11 Show Output</h2>
|
||
<p>It’s good to keep a record of the files created from the build: pathname, timestamp, file size, …</p>
|
||
<p>Here’s how we capture the build output info with GitHub Actions…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Find output
|
||
run: |
|
||
find bin/targets/pinecone_app/app/apps/blinky -name "blinky.*" -ls</code></pre></div>
|
||
<p>And here’s the captured info…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>5439531 12 -rwxr-xr-x 1 runner docker 11348 Jan 10 02:26 bin/targets/pinecone_app/app/apps/blinky/blinky.elf.bin
|
||
5439528 348 -rw-r--r-- 1 runner docker 354281 Jan 10 02:26 bin/targets/pinecone_app/app/apps/blinky/blinky.elf.map
|
||
5439529 392 -rwxr-xr-x 1 runner docker 401104 Jan 10 02:26 bin/targets/pinecone_app/app/apps/blinky/blinky.elf
|
||
5439530 4 -rw-r--r-- 1 runner docker 3309 Jan 10 02:26 bin/targets/pinecone_app/app/apps/blinky/blinky.elf.cmd
|
||
5439532 300 -rw-r--r-- 1 runner docker 303790 Jan 10 02:26 bin/targets/pinecone_app/app/apps/blinky/blinky.elf.lst</code></pre></div><h2 id="caching-considerations"><a class="doc-anchor" href="#caching-considerations">§</a>8.12 Caching Considerations</h2>
|
||
<p>Remember how we cached <code>newt</code> and the GCC Compiler with GitHub Actions?</p>
|
||
<p>Note that the cache will be populated <strong>only when the build succeeds.</strong></p>
|
||
<p>When creating a new GitHub Actions Workflow, we should first comment out the build steps (to let the build succeed), let the caching happen, then uncomment the build steps.</p>
|
||
<p>With caching in effect, we save a lot of time testing and troubleshooting our Automated Build.</p>
|
||
<h1 id="run-mynewt-on-pinecone"><a class="doc-anchor" href="#run-mynewt-on-pinecone">§</a>9 Run Mynewt on PineCone</h1>
|
||
<p>To test and debug the updated Mynewt on PineCone with our Linux / macOS / Windows computer…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Download and install <code>newt</code>, GCC, OpenOCD, VSCode and <code>pinecone-rust-mynewt</code>…</p>
|
||
<p><a href="https://lupyuen.github.io/articles/mynewt#build-the-firmware">“Build the Firmware”</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Build the Mynewt firmware on our computer using the instructions above.</p>
|
||
<p>Alternatively, <a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v2.0.0/blinky.elf">download <code>blinky.elf</code> from here</a> and copy it to…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky</code></pre></div></li>
|
||
<li>
|
||
<p>Connect PineCone to our computer with a JTAG Debugger and start the VSCode Debugger…</p>
|
||
<p><a href="https://lupyuen.github.io/articles/mynewt#debug-firmware-with-vscode">“Debug Firmware with VSCode”</a></p>
|
||
</li>
|
||
</ol>
|
||
<p>In the GDB Debug Console we’ll see this…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Breakpoint 1 at 0x220092ba: file apps/blinky/src/main.c, line 30.
|
||
Breakpoint 2 at 0x22008242: file repos/apache-mynewt-core/kernel/os/src/arch/rv32imac/os_fault.c, line 30.
|
||
Remote debugging using | xpack-openocd/bin/openocd -c "gdb_port pipe; log_output openocd.log" -f openocd.cfg
|
||
Running executable
|
||
xPack OpenOCD, x86_64 Open On-Chip Debugger 0.10.0+dev-00378-ge5be992df (2020-06-26-12:31)</code></pre></div>
|
||
<p>This says that we have set two breakpoints. And that OpenOCD has been started, talking to PineCone.</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>0x21000000 in ?? ()
|
||
Not implemented stop reason (assuming exception): undefined</code></pre></div>
|
||
<p>OpenOCD has taken control of BL602 and has halted the execution at address <code>0x2100 0000</code></p>
|
||
<p>Which is really interesting because <code>0x2100 0000</code> is the address of <strong>BL602’s Boot ROM</strong>. Thus we have evidence that BL602 starts running the Boot ROM code at <code>0x2100 0000</code> whenever it reboots.</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Loading section .init, size 0xa2 lma 0x22008000
|
||
Loading section .text, size 0x1c1c lma 0x220080a4
|
||
Loading section .tcm_code, size 0xaa0 lma 0x22009cc0
|
||
Loading section .rodata, size 0x94 lma 0x2200a760
|
||
Loading section .sdata2.HFXOSC_PLL_256_MHZ, size 0x8 lma 0x2200a7f4
|
||
Loading section .sdata2._global_impure_ptr, size 0x4 lma 0x2200a7fc
|
||
Loading section .data, size 0x438 lma 0x2200a800
|
||
Loading section .sdata, size 0x1c lma 0x2200ac38
|
||
Start address 0x22008000, load size 11346
|
||
Transfer rate: 2 KB/sec, 1418 bytes/write.</code></pre></div>
|
||
<p>Our GDB Script (<a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/.vscode/launch.json#L15-L39">see this</a>) has loaded our firmware to BL602 at address <code>0x2200 8000</code>, which is in Cache Memory.</p>
|
||
<p>(BL602 doesn’t support flashing firmware to Flash Memory with OpenOCD. <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_Openocd%26GDB/en">More details</a>)</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Breakpoint 1, main (argc=0, argv=0x0) at apps/blinky/src/main.c:30
|
||
30 int main(int argc, char **argv) {</code></pre></div>
|
||
<p>When the debugger code hits the first breakpoint (in the <code>main</code> function), click the Continue button in the Debug Toolbar. (Or press F5)</p>
|
||
<h2 id="jtag-foiled-by-gpio"><a class="doc-anchor" href="#jtag-foiled-by-gpio">§</a>9.1 JTAG Foiled By GPIO</h2>
|
||
<p>Calamity strikes as our Mynewt GPIO Firmware runs.</p>
|
||
<p>Yes the Blue LED lights up, but we see this error in GDB…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Debugger is not authenticated to target Debug Module. (dmstatus=0x0).
|
||
Use `riscv authdata_read` and `riscv authdata_write` commands to authenticate.</code></pre></div>
|
||
<p>That’s because PineCone’s RGB LED is <strong>connected to the same pins as the JTAG port!</strong></p>
|
||
<div><table><thead><tr><th style="text-align: left">PineCone Pin</th><th style="text-align: left">LED Pin</th><th style="text-align: left">JTAG Pin</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left"><strong><code>GPIO 11</code></strong></td><td style="text-align: left"><code>Blue</code></td><td style="text-align: left"><code>TDO</code></td></tr>
|
||
<tr><td style="text-align: left"><strong><code>GPIO 14</code></strong></td><td style="text-align: left"><code>Green</code></td><td style="text-align: left"><code>TCK</code></td></tr>
|
||
<tr><td style="text-align: left"><strong><code>GPIO 17</code></strong></td><td style="text-align: left"><code>Red</code></td><td style="text-align: left"><code>TDI</code></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p>(See <a href="https://lupyuen.github.io/articles/openocd#if-you-love-the-led-set-it-free">“If you love the LED… Set it free!”</a>)</p>
|
||
<p>When we flip the LEDs on and off, the <strong>JTAG Debugger connection drops.</strong></p>
|
||
<p>But our firmware is indeed flipping the LEDs correctly, so we’re done with GPIO testing on Mynewt!</p>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-sensors.jpg" alt="Sensors and actuators to be tested with PineCone BL602" /></p>
|
||
<p><em>Sensors and actuators to be tested with PineCone BL602</em></p>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>10 What’s Next</h1>
|
||
<p>We’ll be testing Mynewt on PineCone BL602 with an interesting mix of Sensors and Actuators shown above. <a href="https://lupyuen.github.io/articles/gpio#appendix-inventory-of-sensors-and-actuators">Here’s the list</a></p>
|
||
<p>Most of the Sensors and Actuators will work fine with GPIO on Mynewt. But some require additional support from Mynewt: <strong>Pulse Width Modulation</strong> and <strong>Analog to Digital Converter</strong>.</p>
|
||
<p>We shall integrate with Mynewt the respective Hardware Abstraction Layers from the BL602 IoT SDK.</p>
|
||
<blockquote>
|
||
<p><em>What about DHT11, the Temperature and Humidity Sensor? (Lower right corner)</em></p>
|
||
</blockquote>
|
||
<p>DHT11 will be a problem because it transmits Serial Data in an unusual way <strong>(bidirectional single wire)</strong> that’s incompatible with UART, I2C and SPI. <a href="https://www.mouser.com/datasheet/2/758/DHT11-Technical-Data-Sheet-Translated-Version-1143054.pdf">See DHT11 Datasheet</a></p>
|
||
<p>We would have to read the data from DHT11 via <strong>Bit Banging</strong>. Which is hard to do reliably on a multitasking operating system like Mynewt. <a href="https://lupyuen.github.io/articles/openocd-on-raspberry-pi-better-with-swd-on-spi">More about the evils of Bit Banging</a></p>
|
||
<blockquote>
|
||
<p><em>Is there a better Temperature and Humidity Sensor that connects with standard interfaces… And works well with mutitasking?</em></p>
|
||
</blockquote>
|
||
<p>Yes BME280 senses Temperature, Humidity and Altitude (Air Pressure). BME280 supports <strong>both I2C and SPI</strong> interfaces. <a href="https://lupyuen.github.io/articles/create-your-iot-gadget-with-apache-mynewt-and-stm32-blue-pill">More about BME280</a></p>
|
||
<p>We shall we using BME280 for testing the implementation of I2C and SPI on Mynewt BL602.</p>
|
||
<blockquote>
|
||
<p><em>How do we find Software Drivers for BME280 and other Sensors and Actuators?</em></p>
|
||
</blockquote>
|
||
<p>This will be a problem for all operating systems running on BL602: Getting the <strong>Sensor / Actuator Drivers for Mynewt, FreeRTOS, Zephyr, RIOT, …</strong></p>
|
||
<p>Each operating system has its own Hardware Abstraction Layer (HAL) for talking to hardware interfaces (like I2C, SPI and Timers). Thus we’ll never find drivers that will work across all operaing system.</p>
|
||
<blockquote>
|
||
<p><em>What if we could standardise the HAL across all operating systems?</em></p>
|
||
</blockquote>
|
||
<p>There’s one possibility: <strong>Adopt the Rust Embedded HAL.</strong> I have previously ported the Rust Embedded HAL to Mynewt (for PineTime). <a href="https://lupyuen.github.io/articles/optimising-pinetimes-display-driver-with-rust-and-mynewt">More details</a></p>
|
||
<p>Once we have the Rust Embedded HAL ported to Mynewt (and other operating systems), we’ll be able to use the <strong>Rust Embedded Drivers</strong>. <a href="https://github.com/rust-embedded/awesome-embedded-rust/blob/master/README.md#driver-crates">List of Rust Embedded Drivers</a></p>
|
||
<p>(And we’ll code our firmware in Rust of course)</p>
|
||
<p>We shall experiment with the <a href="https://crates.io/crates/bme280">BME280 Rust Driver</a> on Mynewt BL602.</p>
|
||
<blockquote>
|
||
<p><em>Anything else we’ll be supporting in Mynewt BL602?</em></p>
|
||
</blockquote>
|
||
<p>Yes we shall be adding support for <strong>UART</strong> on Mynewt BL602, so that we can view debugging messages.</p>
|
||
<p>And <strong>Timers</strong> so that we can poll for GPIO Inputs.</p>
|
||
<p>Stay Tuned!</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/sponsor">Sponsor me a coffee</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://www.reddit.com/r/embedded_oc/comments/kxhlg0/mynewt_gpio_ported_to_pinecone_bl602_riscv_board/?utm_source=share&utm_medium=web2x&context=3">Discuss this article on Reddit</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/book">Read “The RISC-V BL602 Book”</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io">Check out my articles</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml">RSS Feed</a></p>
|
||
</li>
|
||
</ul>
|
||
<p><em>Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…</em></p>
|
||
<p><a href="https://github.com/lupyuen/lupyuen.github.io/blob/master/src/gpio.md"><code>lupyuen.github.io/src/gpio.md</code></a></p>
|
||
<h1 id="notes"><a class="doc-anchor" href="#notes">§</a>11 Notes</h1>
|
||
<ol>
|
||
<li>
|
||
<p>My thoughts on <strong>Teaching IoT and Embedded Programming</strong> with Sensors and Actuators?</p>
|
||
<p>Let’s move away from boring old GPIO-based Sensors and Actuators… And teach <strong>modern ones based on I2C and SPI!</strong></p>
|
||
<p>(<a href="https://lupyuen.github.io/articles/create-your-iot-gadget-with-apache-mynewt-and-stm32-blue-pill">Like BME280</a>)</p>
|
||
</li>
|
||
<li>
|
||
<p>To teach IoT with PineCone or Pinenut BL602, we need to add on…</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>SPI Display Controller with LED / OLED / EPaper display</strong> (like ST7789 on PineTime)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>I2C Touch Controller or Keypad</strong> (like on PineTime)</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Battery</strong></p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Will newbies find it difficult to code firmware for an SPI Display?</p>
|
||
<p>Not if we adopt a <strong>Common Graphics Library like LVGL</strong> that will work on all BL602 operating systems. <a href="https://docs.lvgl.io/latest/en/html/intro/index.html">More about LVGL</a></p>
|
||
<p>On PineTime we have proven that LVGL (and the ST7789 driver) works perfectly fine on <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/cloud">FreeRTOS</a>, <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/timesync">Mynewt</a>, <a href="https://lupyuen.github.io/pinetime-rust-riot/articles/watch_face">RIOT</a>, <a href="https://github.com/endian-albin/pinetime-hypnos">Zephyr</a>, …</p>
|
||
<p>We have even created Web Simulators for PineTime based on LVGL + WebAssembly. <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/simulator">See this</a></p>
|
||
<p>LVGL is a great way for newbies to <strong>create Graphical Embedded Apps in C and Rust</strong>, our PineTime experience has shown. <a href="https://lupyuen.github.io/pinetime-rust-mynewt/articles/watchface">LVGL on Rust</a></p>
|
||
<p>(Especially when BL602 has more RAM and Flash Memory than PineTime)</p>
|
||
</li>
|
||
<li>
|
||
<p>There is a GPIO feature that hasn’t been implemented on Mynewt BL602: Trigger an interrupt when a GPIO Input changes. <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/src/hal_gpio.c#L142-L283">See this</a></p>
|
||
<p>This requires CLNT Interrupts to be supported on Mynewt BL602.</p>
|
||
</li>
|
||
</ol>
|
||
<h1 id="appendix-inventory-of-sensors-and-actuators"><a class="doc-anchor" href="#appendix-inventory-of-sensors-and-actuators">§</a>12 Appendix: Inventory of Sensors and Actuators</h1>
|
||
<p><img src="https://lupyuen.github.io/images/gpio-sensors.jpg" alt="Sensors and actuators to be tested with PineCone BL602" /></p>
|
||
<p><em>Sensors and actuators to be tested with PineCone BL602</em></p>
|
||
<h2 id="sensors"><a class="doc-anchor" href="#sensors">§</a>12.1 Sensors</h2><div><table><thead><tr><th style="text-align: left">Sensor</th><th style="text-align: left">Outputs</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">Linear Hall</td><td style="text-align: left">Analog, Digital</td></tr>
|
||
<tr><td style="text-align: left">Shock Switch</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Knock Switch</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Mini Reed Switch</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Analog Temperature</td><td style="text-align: left">Analog</td></tr>
|
||
<tr><td style="text-align: left">Analog & Digital <br>Temperature</td><td style="text-align: left">Analog, Digital</td></tr>
|
||
<tr><td style="text-align: left">Button Switch</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Tilt Switch</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Photoresistor</td><td style="text-align: left">Analog</td></tr>
|
||
<tr><td style="text-align: left">Digital Temperature <br>& Humidity (DHT11)</td><td style="text-align: left">Digital (Serial)</td></tr>
|
||
<tr><td style="text-align: left">High Sensitivity Audio</td><td style="text-align: left">Analog, Digital</td></tr>
|
||
<tr><td style="text-align: left">Metal Touch</td><td style="text-align: left">Analog, Digital</td></tr>
|
||
<tr><td style="text-align: left">Flame</td><td style="text-align: left">Analog, Digital</td></tr>
|
||
</tbody></table>
|
||
</div><h2 id="actuators"><a class="doc-anchor" href="#actuators">§</a>12.2 Actuators</h2><div><table><thead><tr><th style="text-align: left">Actuator</th><th style="text-align: left">Input</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">Laser Transmitter</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Active Buzzer</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Passive Buzzer</td><td style="text-align: left">Digital</td></tr>
|
||
<tr><td style="text-align: left">Relay</td><td style="text-align: left">Digital</td></tr>
|
||
</tbody></table>
|
||
</div><h2 id="sensor--actuator"><a class="doc-anchor" href="#sensor--actuator">§</a>12.3 Sensor + Actuator</h2><div><table><thead><tr><th style="text-align: left">Sensor + Actuator</th><th style="text-align: left">Input / Output</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">Infrared Transmitter & Receiver</td><td style="text-align: left">Digital</td></tr>
|
||
</tbody></table>
|
||
</div><h1 id="appendix-github-actions-environment"><a class="doc-anchor" href="#appendix-github-actions-environment">§</a>13 Appendix: GitHub Actions Environment</h1>
|
||
<p>Here’s how we dump the GitHub Actions Environmment Variables and the File System…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> - name: Show files
|
||
run: set ; pwd ; ls -l</code></pre></div>
|
||
<p>And here’s the output…</p>
|
||
<h2 id="environment-variables"><a class="doc-anchor" href="#environment-variables">§</a>13.1 Environment Variables</h2><div class="example-wrap"><pre class="language-text"><code>AGENT_TOOLSDIRECTORY=/opt/hostedtoolcache
|
||
ANDROID_HOME=/usr/local/lib/android/sdk
|
||
ANDROID_SDK_ROOT=/usr/local/lib/android/sdk
|
||
ANT_HOME=/usr/share/ant
|
||
AZURE_EXTENSION_DIR=/opt/az/azcliextensions
|
||
BASH=/usr/bin/bash
|
||
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:extquote:force_fignore:globasciiranges:hostcomplete:interactive_comments:progcomp:promptvars:sourcepath
|
||
BASH_ALIASES=()
|
||
BASH_ARGC=()
|
||
BASH_ARGV=()
|
||
BASH_CMDS=()
|
||
BASH_LINENO=([0]="0")
|
||
BASH_SOURCE=([0]="/home/runner/work/_temp/e317ee99-ed5d-4e4d-bf6d-765dc458355d.sh")
|
||
BASH_VERSINFO=([0]="5" [1]="0" [2]="17" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
|
||
BASH_VERSION='5.0.17(1)-release'
|
||
CHROMEWEBDRIVER=/usr/local/share/chrome_driver
|
||
CHROME_BIN=/usr/bin/google-chrome
|
||
CI=true
|
||
CONDA=/usr/share/miniconda
|
||
DEBIAN_FRONTEND=noninteractive
|
||
DEPLOYMENT_BASEPATH=/opt/runner
|
||
DIRSTACK=()
|
||
DOTNET_MULTILEVEL_LOOKUP='"0"'
|
||
DOTNET_NOLOGO='"1"'
|
||
DOTNET_SKIP_FIRST_TIME_EXPERIENCE='"1"'
|
||
EUID=1001
|
||
GECKOWEBDRIVER=/usr/local/share/gecko_driver
|
||
GITHUB_ACTION=run2
|
||
GITHUB_ACTIONS=true
|
||
GITHUB_ACTION_REF=
|
||
GITHUB_ACTION_REPOSITORY=
|
||
GITHUB_ACTOR=lupyuen
|
||
GITHUB_API_URL=https://api.github.com
|
||
GITHUB_BASE_REF=
|
||
GITHUB_ENV=/home/runner/work/_temp/_runner_file_commands/set_env_64d8b762-fb69-4a06-8cda-f76ea66e06b5
|
||
GITHUB_EVENT_NAME=push
|
||
GITHUB_EVENT_PATH=/home/runner/work/_temp/_github_workflow/event.json
|
||
GITHUB_GRAPHQL_URL=https://api.github.com/graphql
|
||
GITHUB_HEAD_REF=
|
||
GITHUB_JOB=build
|
||
GITHUB_PATH=/home/runner/work/_temp/_runner_file_commands/add_path_64d8b762-fb69-4a06-8cda-f76ea66e06b5
|
||
GITHUB_REF=refs/heads/main
|
||
GITHUB_REPOSITORY=lupyuen/pinecone-rust-mynewt
|
||
GITHUB_REPOSITORY_OWNER=lupyuen
|
||
GITHUB_RETENTION_DAYS=90
|
||
GITHUB_RUN_ID=474939609
|
||
GITHUB_RUN_NUMBER=5
|
||
GITHUB_SERVER_URL=https://github.com
|
||
GITHUB_SHA=bafe061d1fa6e96cc014e4e9a3444a43a1c5144d
|
||
GITHUB_WORKFLOW='Build Firmware'
|
||
GITHUB_WORKSPACE=/home/runner/work/pinecone-rust-mynewt/pinecone-rust-mynewt
|
||
GOROOT=/opt/hostedtoolcache/go/1.14.13/x64
|
||
GOROOT_1_14_X64=/opt/hostedtoolcache/go/1.14.13/x64
|
||
GOROOT_1_15_X64=/opt/hostedtoolcache/go/1.15.6/x64
|
||
GRADLE_HOME=/usr/share/gradle
|
||
GROUPS=()
|
||
HOME=/home/runner
|
||
HOMEBREW_CELLAR='"/home/linuxbrew/.linuxbrew/Cellar"'
|
||
HOMEBREW_PREFIX='"/home/linuxbrew/.linuxbrew"'
|
||
HOMEBREW_REPOSITORY='"/home/linuxbrew/.linuxbrew/Homebrew"'
|
||
HOSTNAME=fv-az29-728
|
||
HOSTTYPE=x86_64
|
||
IFS=$' \t\n'
|
||
INVOCATION_ID=448992154cf94065a2a551779d186946
|
||
ImageOS=ubuntu20
|
||
ImageVersion=20201210.0
|
||
JAVA_HOME=/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
|
||
JAVA_HOME_11_X64=/usr/lib/jvm/adoptopenjdk-11-hotspot-amd64
|
||
JAVA_HOME_8_X64=/usr/lib/jvm/adoptopenjdk-8-hotspot-amd64
|
||
JOURNAL_STREAM=9:19739
|
||
LANG=C.UTF-8
|
||
LEIN_HOME=/usr/local/lib/lein
|
||
LEIN_JAR=/usr/local/lib/lein/self-installs/leiningen-2.9.5-standalone.jar
|
||
M2_HOME=/usr/share/apache-maven-3.6.3
|
||
MACHTYPE=x86_64-pc-linux-gnu
|
||
OPTERR=1
|
||
OPTIND=1
|
||
OSTYPE=linux-gnu
|
||
PATH=/home/linuxbrew/.linuxbrew/bin:/home/linuxbrew/.linuxbrew/sbin:/opt/pipx_bin:/usr/share/rust/.cargo/bin:/home/runner/.config/composer/vendor/bin:/home/runner/.dotnet/tools:/snap/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
|
||
PERFLOG_LOCATION_SETTING=RUNNER_PERFLOG
|
||
PIPX_BIN_DIR='"/opt/pipx_bin"'
|
||
PIPX_HOME='"/opt/pipx"'
|
||
POWERSHELL_DISTRIBUTION_CHANNEL=GitHub-Actions-ubuntu20
|
||
PPID=1419
|
||
PS4='+ '
|
||
***
|
||
RUNNER_OS=Linux
|
||
RUNNER_PERFLOG=/home/runner/perflog
|
||
RUNNER_TEMP=/home/runner/work/_temp
|
||
RUNNER_TOOL_CACHE=/opt/hostedtoolcache
|
||
RUNNER_TRACKING_ID=github_bd1e8ac9-ce6e-4066-bc5e-9e1017d2a08c
|
||
RUNNER_USER=runner
|
||
RUNNER_WORKSPACE=/home/runner/work/pinecone-rust-mynewt
|
||
SELENIUM_JAR_PATH=/usr/share/java/selenium-server-standalone.jar
|
||
SHELL=/bin/bash
|
||
SHELLOPTS=braceexpand:errexit:hashall:interactive-comments
|
||
SHLVL=1
|
||
SWIFT_PATH=/usr/share/swift/usr/bin
|
||
TERM=dumb
|
||
UID=1001
|
||
USER=runner
|
||
VCPKG_INSTALLATION_ROOT=/usr/local/share/vcpkg
|
||
_=/usr/bin/bash</code></pre></div><h2 id="file-system"><a class="doc-anchor" href="#file-system">§</a>13.2 File System</h2><div class="example-wrap"><pre class="language-text"><code>/home/runner/work/pinecone-rust-mynewt/pinecone-rust-mynewt
|
||
total 52
|
||
-rw-r--r-- 1 runner docker 11357 Jan 10 02:24 LICENSE
|
||
-rw-r--r-- 1 runner docker 241 Jan 10 02:24 NOTICE
|
||
-rw-r--r-- 1 runner docker 583 Jan 10 02:24 README.md
|
||
drwxr-xr-x 3 runner docker 4096 Jan 10 02:24 apps
|
||
drwxr-xr-x 3 runner docker 4096 Jan 10 02:24 compiler
|
||
drwxr-xr-x 4 runner docker 4096 Jan 10 02:24 hw
|
||
-rw-r--r-- 1 runner docker 1807 Jan 10 02:24 openocd.cfg
|
||
-rw-r--r-- 1 runner docker 1081 Jan 10 02:24 project.yml
|
||
drwxr-xr-x 7 runner docker 4096 Jan 10 02:24 repos
|
||
drwxr-xr-x 2 runner docker 4096 Jan 10 02:24 scripts
|
||
drwxr-xr-x 4 runner docker 4096 Jan 10 02:24 targets</code></pre></div>
|
||
|
||
<!-- Begin scripts/rustdoc-after.html: Post-HTML for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
|
||
<!-- Begin Theme Picker and Prism Theme -->
|
||
<script src="../theme.js"></script>
|
||
<script src="../prism.js"></script>
|
||
<!-- Theme Picker and Prism Theme -->
|
||
|
||
<!-- End scripts/rustdoc-after.html -->
|
||
|
||
|
||
</body>
|
||
</html> |