mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 10:18:33 +08:00
1000 lines
No EOL
65 KiB
HTML
1000 lines
No EOL
65 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>Porting Mynewt to PineCone BL602</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="Porting Mynewt to PineCone BL602"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="How we port Apache Mynewt embedded operating system to the PineCone BL602 RISC-V Board"
|
||
data-rh="true">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/mynewt-title.png">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical" href="https://lupyuen.org/articles/mynewt.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">Porting Mynewt to PineCone BL602</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#adapt-from-existing-risc-v-port" title="Adapt from Existing RISC-V Port">1 Adapt from Existing RISC-V Port</a><ul></ul></li>
|
||
<li><a href="#set-gcc-compiler-for-risc-v" title="Set GCC Compiler for RISC-V">2 Set GCC Compiler for RISC-V</a><ul>
|
||
<li><a href="#mynewt-project-and-firmware" title="Mynewt Project and Firmware">2.1 Mynewt Project and Firmware</a><ul></ul></li></ul></li>
|
||
<li><a href="#add-microcontroller-definition" title="Add Microcontroller Definition">3 Add Microcontroller Definition</a><ul></ul></li>
|
||
<li><a href="#add-board-support-package" title="Add Board Support Package">4 Add Board Support Package</a><ul></ul></li>
|
||
<li><a href="#define-linker-script" title="Define Linker Script">5 Define Linker Script</a><ul>
|
||
<li><a href="#bootloader-image-header" title="Bootloader Image Header">5.1 Bootloader Image Header</a><ul></ul></li></ul></li>
|
||
<li><a href="#define-flash-map" title="Define Flash Map">6 Define Flash Map</a><ul>
|
||
<li><a href="#future-flash-map" title="Future Flash Map">6.1 Future Flash Map</a><ul></ul></li></ul></li>
|
||
<li><a href="#set-firmware-target" title="Set Firmware Target">7 Set Firmware Target</a><ul></ul></li>
|
||
<li><a href="#build-the-firmware" title="Build the Firmware">8 Build the Firmware</a><ul></ul></li>
|
||
<li><a href="#implement-hardware-abstraction-layer" title="Implement Hardware Abstraction Layer">9 Implement Hardware Abstraction Layer</a><ul></ul></li>
|
||
<li><a href="#implement-start-code" title="Implement Start Code">10 Implement Start Code</a><ul></ul></li>
|
||
<li><a href="#risc-v-rv32imfc-vs-rv32imac" title="RISC-V rv32imfc vs rv32imac">11 RISC-V rv32imfc vs rv32imac</a><ul></ul></li>
|
||
<li><a href="#decouple-sifive-fe310-from-rv32imac" title="Decouple SiFive FE310 from rv32imac">12 Decouple SiFive FE310 from rv32imac</a><ul></ul></li>
|
||
<li><a href="#inspect-the-firmware" title="Inspect the Firmware">13 Inspect the Firmware</a><ul></ul></li>
|
||
<li><a href="#debug-firmware-with-vscode" title="Debug Firmware with VSCode">14 Debug Firmware with VSCode</a><ul>
|
||
<li><a href="#debugging-features" title="Debugging Features">14.1 Debugging Features</a><ul></ul></li>
|
||
<li><a href="#terminating-openocd" title="Terminating OpenOCD">14.2 Terminating OpenOCD</a><ul></ul></li></ul></li>
|
||
<li><a href="#how-to-test" title="How To Test">15 How To Test</a><ul>
|
||
<li><a href="#testing-the-led" title="Testing the LED">15.1 Testing the LED</a><ul></ul></li>
|
||
<li><a href="#testing-the-jumper" title="Testing the Jumper">15.2 Testing the Jumper</a><ul></ul></li>
|
||
<li><a href="#testing-the-uart-port" title="Testing the UART Port">15.3 Testing the UART Port</a><ul></ul></li></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">16 What’s Next</a><ul></ul></li>
|
||
<li><a href="#appendix-load-firmware-to-cache-memory-not-flash-memory" title="Appendix: Load Firmware to Cache Memory, not Flash Memory">17 Appendix: Load Firmware to Cache Memory, not Flash Memory</a><ul></ul></li>
|
||
<li><a href="#appendix-install-newt" title="Appendix: Install newt">18 Appendix: Install newt</a><ul>
|
||
<li><a href="#linux-and-macos" title="Linux and macOS">18.1 Linux and macOS</a><ul></ul></li>
|
||
<li><a href="#windows" title="Windows">18.2 Windows</a><ul></ul></li></ul></li>
|
||
<li><a href="#appendix-create-the-mynewt-firmware" title="Appendix: Create the Mynewt Firmware">19 Appendix: Create the Mynewt Firmware</a><ul></ul></li>
|
||
<li><a href="#appendix-vscode-settings" title="Appendix: VSCode Settings">20 Appendix: VSCode Settings</a><ul>
|
||
<li><a href="#debugger-settings" title="Debugger Settings">20.1 Debugger Settings</a><ul></ul></li>
|
||
<li><a href="#task-settings" title="Task Settings">20.2 Task Settings</a><ul></ul></li></ul></li></ul></nav><p><img src="https://lupyuen.github.io/images/mynewt-title.png" alt="Debugging Mynewt Firmware with VSCode" /></p>
|
||
<p><em>Debugging Mynewt Firmware with VSCode</em></p>
|
||
<p>📝 <em>21 Dec 2020</em></p>
|
||
<p>Our journey so far…</p>
|
||
<ol>
|
||
<li>
|
||
<p>We took a quick peek at <a href="https://lupyuen.github.io/articles/pinecone"><strong>PineCone BL602 RISC-V Evaluation Board</strong></a>…</p>
|
||
</li>
|
||
<li>
|
||
<p>Then we <a href="https://lupyuen.github.io/articles/openocd"><strong>connected PineCone to OpenOCD</strong></a> with a JTAG Debugger…</p>
|
||
</li>
|
||
<li>
|
||
<p>And we <a href="https://lupyuen.github.io/articles/debug"><strong>debugged Rust on PineCone</strong></a> with VSCode and GDB</p>
|
||
</li>
|
||
</ol>
|
||
<p>Today we’ll learn about our port of <a href="https://mynewt.apache.org/"><strong>Apache Mynewt</strong></a> embedded operating system to PineCone.</p>
|
||
<p><a href="https://youtu.be/iDS8CBplSw8">Watch the Sneak Peek on YouTube</a></p>
|
||
<p><em>Why port Mynewt to BL602?</em></p>
|
||
<p>Since FreeRTOS is already supported on BL602 (for multitasking Bluetooth LE and WiFi in the background), let’s port a modern embedded operating system like Mynewt.</p>
|
||
<p>It’s a great way to learn the internals of BL602. And this article will be a valuable resource for porting to BL602 other embedded operating systems, like Zephyr and RIOT.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/nuttx"><strong>UPDATE: Check out Apache NuttX operating system for BL602</strong></a></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>
|
||
<h1 id="adapt-from-existing-risc-v-port"><a class="doc-anchor" href="#adapt-from-existing-risc-v-port">§</a>1 Adapt from Existing RISC-V Port</h1>
|
||
<p><em>What’s the quickest way to port Mynewt to PineCone BL602?</em></p>
|
||
<p>There’s one (and only one) RISC-V Board supported today on Mynewt: <strong>SiFive’s HiFive1 Board</strong>, based on the <strong>SiFive FE310 Microcontroller</strong>.</p>
|
||
<p>We shall copy and adapt the necessary files from the HiFive1 FE310 port to our PineCone BL602 port.</p>
|
||
<p><em>How different is BL602 from SiFive FE310?</em></p>
|
||
<p>The Memory Maps for BL602 and SiFive FE310 look totally different…</p>
|
||
<p><img src="https://lupyuen.github.io/images/pinecone-compare.jpg" alt="BL602 Memory Map vs SiFive FE310: Totally different" /></p>
|
||
<p><em>BL602 Memory Map (left) vs SiFive FE310 (right): Totally different</em></p>
|
||
<p>But <strong>BL602’s RISC-V Core is highly similar to SiFive FE310</strong>. Compare these two files…</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="https://github.com/pine64/bl_iot_sdk/blob/master/components/bl602/freertos_riscv/config/platform.h"><code>platform.h</code> from <strong>BL602 IoT SDK</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/apache/mynewt-core/blob/master/hw/mcu/sifive/src/ext/freedom-e-sdk_3235929/bsp/env/freedom-e300-hifive1/platform.h"><code>platform.h</code> from <strong>Mynewt’s FE310 Port</strong></a></p>
|
||
</li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-platform.png" alt="platform.h: BL602 (left) vs SiFive FE310 (right)" /></p>
|
||
<p><em>platform.h: BL602 (left) vs SiFive FE310 (right)</em></p>
|
||
<p>Since BL602’s RISC-V Core is so similar to FE310, it makes porting simpler.</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-e21.png" alt="BL602 is based on SiFive E21 RISC-V Core" /></p>
|
||
<p><em>BL602 is based on which SiFive RISC-V Core?</em></p>
|
||
<p>From the screenshot above, the name “E21” appears (over a hundred times) in the BL602 IoT SDK. <a href="https://github.com/pine64/bl_iot_sdk/blob/master/components/bl602/bl602_std/bl602_std/Device/Bouffalo/BL602/Peripherals/l1c_reg.h#L178-L194">(See this)</a></p>
|
||
<p>Thus we assume that BL602 is based on the <strong>SiFive E21 RISC-V Core</strong> (and not E24)…</p>
|
||
<ul>
|
||
<li><a href="https://sifive.cdn.prismic.io/sifive/39d336f7-7dba-43f2-a453-8d55227976cc_sifive_E21_rtl_full_20G1.03.00_manual.pdf">SiFive E21 Manual</a></li>
|
||
</ul>
|
||
<p>While doing the porting, we shall compare the above E21 doc with the FE310 doc so that we can identify the differences (e.g. FE310 supports PLIC, E21 doesn’t)</p>
|
||
<ul>
|
||
<li><a href="https://sifive.cdn.prismic.io/sifive/4d063bf8-3ae6-4db6-9843-ee9076ebadf7_fe310-g000.pdf">SiFive FE310 Manual</a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-gcc.png" alt="Mynewt’s default GCC Compiler is riscv64-unknown-elf-gcc" /></p>
|
||
<p><em>Mynewt’s default GCC Compiler is <code>riscv64-unknown-elf-gcc</code></em></p>
|
||
<h1 id="set-gcc-compiler-for-risc-v"><a class="doc-anchor" href="#set-gcc-compiler-for-risc-v">§</a>2 Set GCC Compiler for RISC-V</h1>
|
||
<p>When building RISC-V Firmware, Mynewt uses the RISC-V GCC Compiler <code>riscv64-unknown-elf-gcc</code> <a href="https://github.com/apache/mynewt-core/blob/master/compiler/riscv64/compiler.yml">(See this)</a></p>
|
||
<p>But that’s not the same as our compiler from xPack RISC-V GCC: <code>riscv-none-embed-gcc</code></p>
|
||
<p><em>(See <a href="https://lupyuen.github.io/articles/debug">“Debug Rust on PineCone BL602 with VSCode and GDB”</a>, Section 1.3, <a href="https://lupyuen.github.io/articles/debug#install-gdb">“Install GDB”</a>)</em></p>
|
||
<p>Hence we copy and modify the GCC settings like so: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/compiler/riscv-none-embed/compiler.yml"><code>compiler/riscv-none-embed/compiler.yml</code></a></p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>compiler.path.cc: "riscv-none-embed-gcc"
|
||
compiler.path.as: "riscv-none-embed-gcc"
|
||
compiler.path.archive: "riscv-none-embed-ar"
|
||
compiler.path.objdump: "riscv-none-embed-objdump"
|
||
compiler.path.objsize: "riscv-none-embed-size"
|
||
compiler.path.objcopy: "riscv-none-embed-objcopy"</code></pre></div>
|
||
<p>Mynewt will now compile our firmware with <code>riscv-none-embed-gcc</code></p>
|
||
<h2 id="mynewt-project-and-firmware"><a class="doc-anchor" href="#mynewt-project-and-firmware">§</a>2.1 Mynewt Project and Firmware</h2>
|
||
<p><em>In the screen above, how did we create the Mynewt Project <code>pinecone-rust-mynewt</code> and the Mynewt Firmware <code>pinecone_app</code>?</em></p>
|
||
<p>I created <code>pinecone-rust-mynewt</code> and <code>pinecone_app</code> using Mynewt’s <code>newt</code> tool.</p>
|
||
<p>We’ll download them in a while, so you don’t need to create them.</p>
|
||
<p><em>(FYI: I created <code>pinecone-rust-mynewt</code> and <code>pinecone_app</code> using the steps explained in the sections “Appendix: Install newt” and “Appendix: Create the Mynewt Firmware” below)</em></p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-mcu.png" alt="Mynewt Microcontroller Definition for BL602" /></p>
|
||
<p><em>Mynewt Microcontroller Definition for BL602</em></p>
|
||
<h1 id="add-microcontroller-definition"><a class="doc-anchor" href="#add-microcontroller-definition">§</a>3 Add Microcontroller Definition</h1>
|
||
<p>We create a <strong>Microcontroller Definition</strong> to tell Mynewt all about BL602…</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>BL602 Microcontroller Definition</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602"><code>hw/mcu/bl/bl602</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>BL602 Package</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/pkg.yml"><code>pkg.yml</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>BL602 Configuration</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/syscfg.yml"><code>syscfg.yml</code></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>This contains the code for the <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/src"><strong>Hardware Adaptaion Layer</strong></a> that’s specific to BL602 and its built-in Periperal Functions (like Flash Memory, GPIO, I2C, SPI, …)</p>
|
||
<p>The code here was derived from SiFive FE310: <a href="https://github.com/apache/mynewt-core/tree/master/hw/mcu/sifive/fe310"><code>hw/mcu/sifive/fe310</code></a></p>
|
||
<h1 id="add-board-support-package"><a class="doc-anchor" href="#add-board-support-package">§</a>4 Add Board Support Package</h1>
|
||
<p>BL602 is present on various boards, PineCone is one of them. The BL602 boards have different features: LEDs, buttons, JTAG debugger, …</p>
|
||
<p>In Mynewt we handle the board differences by creating a <strong>Board Support Package</strong> for PineCone…</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>PineCone Board Support Package</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/bsp/pinecone"><code>hw/bsp/pinecone</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>PineCone Definition</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/bsp.yml"><code>bsp.yml</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>PineCone Package</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/pkg.yml"><code>pkg.yml</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>PineCone Configuration</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/syscfg.yml"><code>syscfg.yml</code></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>The Board Support Package for PineCone contains code that’s specific to PineCone. <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/bsp/pinecone/src">More details</a></p>
|
||
<p>The code here was derived from SiFive HiFive1 Board: <a href="https://github.com/apache/mynewt-core/tree/master/hw/bsp/hifive1"><code>hw/bsp/hifive1</code></a></p>
|
||
<h1 id="define-linker-script"><a class="doc-anchor" href="#define-linker-script">§</a>5 Define Linker Script</h1>
|
||
<p>The Linker Script tells GCC Compiler about the Memory Layout for executing our firmware…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Flash Memory Area</strong>: For firmware code and read-only data</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>RAM Memory Area</strong>: For read/write data</p>
|
||
</li>
|
||
</ol>
|
||
<p>Here’s our Linker Script for PineCone…</p>
|
||
<ul>
|
||
<li><strong>PineCone Linker Script</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/bsp_app.ld"><code>hw/bsp/pinecone/bsp_app.ld</code></a></li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-text"><code>MEMORY
|
||
{
|
||
/* Use this memory layout when firmware is loaded into cache memory.
|
||
Based on https://github.com/lupyuen/pinecone-rust/blob/main/memory.x */
|
||
flash (rxai!w) : ORIGIN = 0x22008000, LENGTH = 48K /* Instruction Cache Memory */
|
||
ram (wxa!ri) : ORIGIN = 0x22014000, LENGTH = 48K /* Data Cache Memory */
|
||
}</code></pre></div>
|
||
<p>Note that we’re loading the firmware code and read-only data into BL602’s Instruction Cache Memory (similar to RAM), not into Flash Memory. (We’ll learn why in a while)</p>
|
||
<p>In future when we’re ready to load our firmware into Flash Memory, we’ll use this memory layout instead…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code> /* TODO: Use this memory layout when firmware is loaded into Flash Memory
|
||
Based on Based on https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602/evb/ld/flash_rom.ld */
|
||
flash (rxai!w) : ORIGIN = 0x23000000, LENGTH = 4M /* Flash Memory */
|
||
ram (wxa!ri) : ORIGIN = 0x4200c000, LENGTH = 216K /* RAM */</code></pre></div>
|
||
<p>(This is commented out in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/bsp_app.ld"><code>bsp_app.ld</code></a>)</p>
|
||
<h2 id="bootloader-image-header"><a class="doc-anchor" href="#bootloader-image-header">§</a>5.1 Bootloader Image Header</h2>
|
||
<p>We’re presently not using a Bootloader on PineCone…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>/* Bootloader not in use. */
|
||
_imghdr_size = 0x0;</code></pre></div>
|
||
<p>In future when we use the Mynewt Bootloader, we need to reserve some space for the Bootloader Image Header, which is located at the start of the firmware code…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>/* This linker script is used for images and thus contains an image header */
|
||
/* TODO: Uncomment the next line when Bootloader is in use */
|
||
_imghdr_size = 0x20;</code></pre></div><h1 id="define-flash-map"><a class="doc-anchor" href="#define-flash-map">§</a>6 Define Flash Map</h1>
|
||
<p>Mynewt’s MCUBoot Bootloader will roll back the Active Firmware to the Standby Firmware in case the Active Firmware can’t be started.</p>
|
||
<p>We define the <strong>Flash Map</strong> to tell Mynewt where in Flash Memory the Bootloader, Active Firmware Image and Standby Firmware Image will be located…</p>
|
||
<ul>
|
||
<li><strong>PineCone Flash Map</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/bsp.yml"><code>hw/bsp/pinecone/bsp.yml</code></a></li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>## BL602 Instruction Cache Memory starts at 0x2200 8000, size 48 KB
|
||
## Based on https://github.com/lupyuen/pinecone-rust/blob/main/memory.x
|
||
bsp.flash_map:
|
||
areas:
|
||
## System areas.
|
||
## (Not Used) Bootloader
|
||
FLASH_AREA_BOOTLOADER:
|
||
device: 0
|
||
offset: 0x22013c00
|
||
size: 1kB # 0x400
|
||
## Active Firmware Image
|
||
FLASH_AREA_IMAGE_0:
|
||
device: 0
|
||
offset: 0x22008000
|
||
size: 43kB # 0xac00
|
||
## (Not Used) Standby Firmware Image, in case Active Firmware can't start
|
||
FLASH_AREA_IMAGE_1:
|
||
device: 0
|
||
offset: 0x22012c00
|
||
size: 1kB # 0x400
|
||
## (Not used) Scratch Area for swapping Active Firmware and Standby Firmware
|
||
FLASH_AREA_IMAGE_SCRATCH:
|
||
device: 0
|
||
offset: 0x22013000
|
||
size: 1kB # 0x400</code></pre></div>
|
||
<p>Remember that we’re loading our firmware into Cache Memory (instead of Flash Memory) and we’re not using the Bootloader.</p>
|
||
<p>That’s why we allocate most of the Cache Memory to the Active Firmware Image (located at the start of Cache Memory).</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> ## User areas.
|
||
## (Not Used) Reboot Log
|
||
FLASH_AREA_REBOOT_LOG:
|
||
user_id: 0
|
||
device: 0
|
||
offset: 0x22013400
|
||
size: 1kB # 0x400
|
||
## (Not Used) User File System, like LittleFS
|
||
FLASH_AREA_NFFS:
|
||
user_id: 1
|
||
device: 0
|
||
offset: 0x22013800
|
||
size: 1kB # 0x400</code></pre></div>
|
||
<p>Since we have very little Cache Memory, we’ll cut down on the Reboot Log and User File Systems.</p>
|
||
<h2 id="future-flash-map"><a class="doc-anchor" href="#future-flash-map">§</a>6.1 Future Flash Map</h2>
|
||
<p>The Flash Map looks more meaningful when we’re ready to load our firmware into Flash Memory and turn on the Bootloader.</p>
|
||
<p>Here is our Flash Map for the future…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>## TODO: Use this memory layout when firmware is loaded into Flash Memory
|
||
## BL602 Flash starts at 0x2300 0000, size 4 MB
|
||
## Based on https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602/evb/ld/flash_rom.ld
|
||
bsp.flash_map:
|
||
areas:
|
||
## System areas.
|
||
## TODO: Bootloader not in use. When used, move Bootloader to 0x2300 0000 and shift the other areas accordingly
|
||
FLASH_AREA_BOOTLOADER:
|
||
device: 0
|
||
offset: 0x2330d000
|
||
size: 32kB # 0x8000
|
||
## Active Firmware Image
|
||
FLASH_AREA_IMAGE_0:
|
||
device: 0
|
||
offset: 0x23000000
|
||
size: 1024kB # 0x100 000
|
||
## Standby Firmware Image, in case Active Firmware can't start
|
||
FLASH_AREA_IMAGE_1:
|
||
device: 0
|
||
offset: 0x23100000
|
||
size: 1024kB # 0x100 000
|
||
## Scratch Area for swapping Active Firmware and Standby Firmware
|
||
FLASH_AREA_IMAGE_SCRATCH:
|
||
device: 0
|
||
offset: 0x23300000
|
||
size: 4kB # 0x1000</code></pre></div>
|
||
<p>(This is commented out in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/bsp/pinecone/bsp.yml"><code>bsp.yml</code></a>)</p>
|
||
<p>In future we’ll have a proper Reboot Log and a User File System for saving files and data that will be retained across reboots…</p>
|
||
<div class="example-wrap"><pre class="language-yaml"><code> ## User areas.
|
||
## Reboot Log
|
||
FLASH_AREA_REBOOT_LOG:
|
||
user_id: 0
|
||
device: 0
|
||
offset: 0x23301000
|
||
size: 48kB # 0xc000
|
||
## User File System, like LittleFS
|
||
FLASH_AREA_NFFS:
|
||
user_id: 1
|
||
device: 0
|
||
offset: 0x23200000
|
||
size: 1024kB # 0x100 000</code></pre></div><h1 id="set-firmware-target"><a class="doc-anchor" href="#set-firmware-target">§</a>7 Set Firmware Target</h1>
|
||
<p>We select the Mynewt Firmware to be built by creating a Firmware Target…</p>
|
||
<ul>
|
||
<li><strong>PineCone Firmware Target</strong>: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/targets/pinecone_app/target.yml"><code>targets/pinecone_app/target.yml</code></a></li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-yaml"><code>target.app: apps/blinky
|
||
target.bsp: "hw/bsp/pinecone"
|
||
target.build_profile: debug</code></pre></div>
|
||
<p>Here we specify that our firmware code comes from the <a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/apps/blinky">Blinky Sample App</a>. And our firmware will be compiled for the PineCone BL602 Board.</p>
|
||
<p>Also check out the <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/targets/pinecone_app/pkg.yml"><strong>Target Package</strong></a> and the <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/targets/pinecone_app/syscfg.yml"><strong>Target Configuration</strong></a>.</p>
|
||
<h1 id="build-the-firmware"><a class="doc-anchor" href="#build-the-firmware">§</a>8 Build the Firmware</h1>
|
||
<p>We have created a minimal port of Mynewt to PineCone. Here’s how we build the firmware on Linux, macOS and Windows (plain old CMD, without WSL and MSYS2)…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Install Mynewt’s <code>newt</code> tool according to the instructions here…</p>
|
||
<ul>
|
||
<li><a href="https://mynewt.apache.org/latest/newt/install/index.html">Installing <code>newt</code></a></li>
|
||
</ul>
|
||
<p>To build <code>newt</code> from the source code, check the section “Appendix: Install newt” below</p>
|
||
</li>
|
||
<li>
|
||
<p>At the command prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Download source files
|
||
git clone --recursive https://github.com/lupyuen/pinecone-rust-mynewt
|
||
cd pinecone-rust-mynewt</code></pre></div></li>
|
||
<li>
|
||
<p>Download GCC from the <a href="https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/tag/v8.3.0-2.3">xPack GCC for RISC-V site</a>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="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">xPack GCC RISC-V for Linux x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="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-arm64.tar.gz">xPack GCC RISC-V for Linux Arm64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="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-darwin-x64.tar.gz">xPack GCC RISC-V for macOS x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="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-win32-x64.zip">xPack GCC RISC-V for Windows x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/riscv-none-embed-gcc-xpack/releases/tag/v8.3.0-2.3">Other builds of xPack GCC RISC-V</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>Extract the downloaded archive.</p>
|
||
</li>
|
||
<li>
|
||
<p>Copy the extracted xPack GCC RISC-V folder to the <code>pinecone-rust-mynewt</code> folder.</p>
|
||
<p>Rename the copied folder as…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/xpack-riscv-none-embed-gcc</code></pre></div>
|
||
<p><strong>For Windows:</strong> Add the full path of <code>xpack-riscv-none-embed-gcc/bin</code> to the PATH. For example…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>c:\pinecone-rust-mynewt\xpack-riscv-none-embed-gcc\bin</code></pre></div></li>
|
||
<li>
|
||
<p>Download OpenOCD from the <a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/tag/v0.10.0-15/">xPack OpenOCD site</a>… (Other variants of OpenOCD may not work with PineCone)</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.10.0-15/xpack-openocd-0.10.0-15-linux-x64.tar.gz">xPack OpenOCD for Linux x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.10.0-15/xpack-openocd-0.10.0-15-linux-arm64.tar.gz">xPack OpenOCD for Linux Arm64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.10.0-15/xpack-openocd-0.10.0-15-darwin-x64.tar.gz">xPack OpenOCD for macOS x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/download/v0.10.0-15/xpack-openocd-0.10.0-15-win32-x64.zip">xPack OpenOCD for Windows x64</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/xpack-dev-tools/openocd-xpack/releases/tag/v0.10.0-15/">Other builds of xPack OpenOCD</a></p>
|
||
</li>
|
||
</ul>
|
||
<p>Extract the downloaded archive.</p>
|
||
</li>
|
||
<li>
|
||
<p>Copy the extracted xPack OpenOCD folder to the <code>pinecone-rust-mynewt</code> folder.</p>
|
||
<p>Rename the copied folder as…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/xpack-openocd</code></pre></div>
|
||
<p><strong>For Windows:</strong> Add the full path of <code>xpack-openocd/bin</code> to the PATH. For example…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>c:\pinecone-rust-mynewt\pinecone-rust-mynewt\xpack-openocd\bin</code></pre></div></li>
|
||
<li>
|
||
<p><strong>For Linux and macOS:</strong> Enter at the command prompt…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build the firmware
|
||
export PATH="$PWD/xpack-riscv-none-embed-gcc/bin:$PATH"
|
||
newt build pinecone_app
|
||
|
||
## Display the firmware size
|
||
newt size -v pinecone_app</code></pre></div>
|
||
<p><strong>For Windows:</strong> Enter at the command prompt…</p>
|
||
<div class="example-wrap"><pre class="language-cmd"><code>:: Build the firmware
|
||
newt\newt.exe build pinecone_app
|
||
|
||
:: Display the firmware size
|
||
newt\newt.exe size -v pinecone_app</code></pre></div></li>
|
||
</ol>
|
||
<p>We should see this…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Linking /Users/Luppy/pinecone/pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf
|
||
Target successfully built: targets/pinecone_app</code></pre></div>
|
||
<p>Followed by the size of the firmware (8,488 bytes) and its library components…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>+ newt size -v pinecone_app
|
||
Size of Application Image: app
|
||
Mem flash: 0x22008000-0x22014000
|
||
Mem ram: 0x22014000-0x22020000
|
||
flash ram
|
||
6 525 *fill*
|
||
172 0 @apache-mynewt-core_hw_hal.a
|
||
4494 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
|
||
60 8 apps_blinky.a
|
||
44 12 hw_bsp_pinecone.a
|
||
580 228 hw_mcu_bl_bl602.a
|
||
92 0 pinecone_app-sysinit-app.a
|
||
292 1064 libg.a
|
||
Loading compiler pinecone-rust-mynewt/compiler/riscv-none-embed, buildProfile debug
|
||
|
||
objsize
|
||
text data bss dec hex filename
|
||
8488 28 9104 17620 44d4 pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div>
|
||
<p>The compiled ELF firmware is located at…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div><h1 id="implement-hardware-abstraction-layer"><a class="doc-anchor" href="#implement-hardware-abstraction-layer">§</a>9 Implement Hardware Abstraction Layer</h1>
|
||
<p>The above steps will build successfully a minimal port of Mynewt for PineCone.</p>
|
||
<p>That’s because I have fixed many missing functions in Mynewt’s Hardware Abstraction Layer (HAL), like these…</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-hal.png" alt="Missing Functions in Mynewt HAL" /></p>
|
||
<p><em>Missing Functions in Mynewt HAL</em></p>
|
||
<p>We can see that Mynewt’s HAL consists of low-level functions that control BL602’s hardware functions: Flash Memory, Interrupts, Watchdog, GPIO, …</p>
|
||
<p>We’ll be filling in these missing HAL functions someday… But for now I have inserted Stub Functions.</p>
|
||
<p>Which means that the firmware will build OK… Just that GPIO and other features won’t actually work when we run the firmware.</p>
|
||
<p><em>How shall we fill in the HAL Functions for PineCone?</em></p>
|
||
<p>The BL602 HAL functions (GPIO, I2C, SPI, …) are already implemented here…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/components"><strong>BL602 IoT SDK Firmware Components</strong></a></li>
|
||
</ul>
|
||
<p>We shall copy the source files from above and embed them here…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/ext"><strong>Mynewt External Source Files for BL602</strong></a></li>
|
||
</ul>
|
||
<p>The BL602 SDK Functions look different from the Mynewt HAL API. Thus we’ll have to create some adapter code in C to make the BL602 Functions look like the Mynewt HAL.</p>
|
||
<p>The code that adapts the BL602 SDK to Mynewt HAL shall be placed here…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/tree/main/hw/mcu/bl/bl602/src"><strong>Mynewt HAL for BL602</strong></a></li>
|
||
</ul>
|
||
<p>As we can see from the GPIO pic below, our job now is to <strong>adapt the BL602 SDK</strong> (left) <strong>to the Mynewt HAL</strong> (right).</p>
|
||
<p>(For reference: Here’s how the <a href="https://github.com/apache/mynewt-core/tree/master/hw/mcu/sifive/fe310/src">Mynewt HAL for SiFive FE310</a> is adapted from the <a href="https://github.com/apache/mynewt-core/tree/master/hw/mcu/sifive/src/ext/freedom-e-sdk_3235929">FE310 SDK</a>)</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-hal2.png" alt="BL602 GPIO SDK (left) vs Mynewt GPIO HAL (right)" /></p>
|
||
<p><em>BL602 GPIO SDK (left) vs Mynewt GPIO HAL (right)</em></p>
|
||
<h1 id="implement-start-code"><a class="doc-anchor" href="#implement-start-code">§</a>10 Implement Start Code</h1>
|
||
<p>Most firmware will have some Start Code (written in Assembly Code) that will be executed when the firmware starts.</p>
|
||
<p>For the BL602 IoT SDK, this is the Start Code (in RISC-V Assembly)…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602/evb/src/boot/gcc/start.S"><strong>Start Code from BL602 IoT SDK: <code>start.S</code></strong></a></li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-start.png" alt="Start Code from BL602 IoT SDK: start.S" /></p>
|
||
<p><em>Start Code from BL602 IoT SDK: start.S</em></p>
|
||
<p>For Mynewt we’re using this Start Code instead…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/src/arch/rv32imac/start.s"><strong>Start Code for Mynewt BL602: <code>start.s</code></strong></a></li>
|
||
</ul>
|
||
<p>(Adapted from <a href="https://github.com/apache/mynewt-core/blob/master/hw/mcu/sifive/fe310/src/arch/rv32imac/start.s">FE310 Start Code</a>)</p>
|
||
<p>Mynewt’s Start Code initialises the RAM before calling the <code>main</code> function.</p>
|
||
<p><em>Is Mynewt’s Start Code any different from the BL602 SDK?</em></p>
|
||
<p>When we compare Mynewt’s Start Code with the BL602 SDK, we see that the BL602 SDK Start Code uses the Boot Partition and Flash Configuration. <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602/evb/src/boot/gcc/start.S#L27-L54">More details</a></p>
|
||
<p>This code will have to be inserted into Mynewt’s Start Code, when our firmware is ready to be loaded into Flash Memory.</p>
|
||
<h1 id="risc-v-rv32imfc-vs-rv32imac"><a class="doc-anchor" href="#risc-v-rv32imfc-vs-rv32imac">§</a>11 RISC-V rv32imfc vs rv32imac</h1>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/make_scripts_riscv/project.mk#L223">According to the SDK</a>, BL602 uses a RISC-V Core (SiFive E21) that’s designated <strong><code>rv32imfc</code></strong> based on its capabilities…</p>
|
||
<div><table><thead><tr><th style="text-align: center">Designation</th><th style="text-align: left">Meaning</th></tr></thead><tbody>
|
||
<tr><td style="text-align: center"><strong><code>rv32i</code></strong></td><td style="text-align: left">32-bit RISC-V with Base Integer Instructions</td></tr>
|
||
<tr><td style="text-align: center"><strong><code>m</code></strong></td><td style="text-align: left">Integer Multiplication + Division</td></tr>
|
||
<tr><td style="text-align: center"><strong><code>f</code></strong></td><td style="text-align: left"><strong>Single-Precision Hardware Floating Point</strong></td></tr>
|
||
<tr><td style="text-align: center"><strong><code>c</code></strong></td><td style="text-align: left">Compressed Instructions</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><a href="https://en.wikipedia.org/wiki/RISC-V#ISA_base_and_extensions">(Here’s the whole list)</a></p>
|
||
<p><strong>UPDATE:</strong> BL602 actually supports <strong><code>rv32acfimx</code></strong> <a href="https://lupyuen.github.io/articles/uart#enter-the-commands">(See this)</a></p>
|
||
<p>However Mynewt today supports only <strong><code>rv32imac</code></strong>…</p>
|
||
<div><table><thead><tr><th style="text-align: center">Designation</th><th style="text-align: left">Meaning</th></tr></thead><tbody>
|
||
<tr><td style="text-align: center"><strong><code>rv32i</code></strong></td><td style="text-align: left">32-bit RISC-V with Base Integer Instructions</td></tr>
|
||
<tr><td style="text-align: center"><strong><code>m</code></strong></td><td style="text-align: left">Integer Multiplication + Division</td></tr>
|
||
<tr><td style="text-align: center"><strong><code>a</code></strong></td><td style="text-align: left"><strong>Atomic Instructions</strong></td></tr>
|
||
<tr><td style="text-align: center"><strong><code>c</code></strong></td><td style="text-align: left">Compressed Instructions</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><em>What’s the difference?</em></p>
|
||
<p>Mynewt doesn’t support RISC-V <strong>Hardware Floating Point</strong> yet… But it supports <strong>Atomic Instructions</strong> (for data synchronisation).</p>
|
||
<p>Thus for now we’ll compile our Mynewt Firmware for <code>rv32imac</code> (without Hardware Floating Point)…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/apache/mynewt-core/tree/master/kernel/os/src/arch/rv32imac"><strong>Mynewt Support for <code>rv32imac</code></strong></a></li>
|
||
</ul>
|
||
<p>In future we’ll have to implement <code>rv32imfc</code> (with Hardware Floating Point) in Mynewt.</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-fe310.png" alt="SiFive FE310 Reference in Mynewt rv32imac" /></p>
|
||
<p><em>SiFive FE310 Reference in Mynewt rv32imac</em></p>
|
||
<h1 id="decouple-sifive-fe310-from-rv32imac"><a class="doc-anchor" href="#decouple-sifive-fe310-from-rv32imac">§</a>12 Decouple SiFive FE310 from rv32imac</h1>
|
||
<p>There’s a peculiar problem compiling RISC-V Firmware on Mynewt…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Error: In file included from ...
|
||
repos/apache-mynewt-core/kernel/os/include/os/arch/rv32imac/os/os_arch.h:24:10:
|
||
fatal error: mcu/fe310.h: No such file or directory
|
||
#include "mcu/fe310.h"</code></pre></div>
|
||
<p>This error shows that <code>rv32imac</code>, the RISC-V support in Mynewt, is dependent on SiFive FE310. Which looks really odd.</p>
|
||
<p>(Probably done that way because FE310 is the only RISC-V Microcontroller supported by Mynewt)</p>
|
||
<p>We work around this problem by creating Stub Files like these…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/include/mcu/fe310.h"><code>mcu/fe310.h</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/include/env/freedom-e300-hifive1/platform.h"><code>env/freedom-e300-hifive1/platform.h</code></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>These Stub Files point to the correct Header Files for BL602, so that our BL602 Firmware can be compiled successfully.</p>
|
||
<h1 id="inspect-the-firmware"><a class="doc-anchor" href="#inspect-the-firmware">§</a>13 Inspect the Firmware</h1>
|
||
<p>We’re almost ready to run Mynewt on PineCone! Let’s do one final check before running our firmware…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>## Build the firmware
|
||
export PATH="$PWD/xpack-riscv-none-embed-gcc/bin:$PATH"
|
||
newt build pinecone_app
|
||
|
||
## Display the firmware size
|
||
newt size -v pinecone_app</code></pre></div>
|
||
<p>We should see…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Linking 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>Yep this matches our Instruction Cache Memory (<code>0x2200 8000</code>) and Data Cache Memory (<code>0x2201 4000</code>).</p>
|
||
<div class="example-wrap"><pre class="language-text"><code> flash ram
|
||
6 525 *fill*
|
||
172 0 @apache-mynewt-core_hw_hal.a
|
||
4494 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
|
||
60 8 apps_blinky.a
|
||
44 12 hw_bsp_pinecone.a
|
||
580 228 hw_mcu_bl_bl602.a
|
||
92 0 pinecone_app-sysinit-app.a
|
||
292 1064 libg.a</code></pre></div>
|
||
<p>Here are all the code modules linked into our Mynewt Firmware. Note that…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Mynewt Kernel takes the most memory</p>
|
||
</li>
|
||
<li>
|
||
<p>Our BL602 HAL <code>hw_mcu_bl_bl602</code> is tiny because it’s mostly Stub Functions</p>
|
||
</li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-text"><code>Loading compiler pinecone-rust-mynewt/compiler/riscv-none-embed, buildProfile debug
|
||
objsize
|
||
text data bss dec hex filename
|
||
8488 28 9104 17620 44d4 pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div>
|
||
<p>Our Mynewt Firmware contains 8,488 bytes of code and data. It runs with 9,104 bytes of RAM (BSS).</p>
|
||
<p>The firmware build produces the following files in…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf"><strong><code>blinky.elf</code></strong></a>: Our Mynewt Firmware in ELF Format (<a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf">See this</a>)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf.map"><strong><code>blinky.elf.map</code></strong></a>: Memory Map of our Mynewt Firmware (<a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf.map">See this</a>)</p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf.lst"><strong><code>blinky.elf.lst</code></strong></a>: RISC-V Disassembly of our Mynewt Firmware (<a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf.lst">See this</a>)</p>
|
||
</li>
|
||
</ul>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-disassembly.png" alt="RISC-V Disassembly of Mynewt Firmware" /></p>
|
||
<p><em>RISC-V Disassembly of Mynewt Firmware</em></p>
|
||
<p>Inspect the RISC-V Disassembly: <a href="https://github.com/lupyuen/pinecone-rust-mynewt/releases/download/v1.0.0/blinky.elf.lst"><code>blinky.elf.lst</code></a></p>
|
||
<p>It should look similar to our <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/hw/mcu/bl/bl602/src/arch/rv32imac/start.s">Start Code</a>. And it should be located at the Start Address of our firmware: <code>0x2200 8000</code>.</p>
|
||
<p>We’re ready to run our Mynewt Firmware on PineCone!</p>
|
||
<h1 id="debug-firmware-with-vscode"><a class="doc-anchor" href="#debug-firmware-with-vscode">§</a>14 Debug Firmware with VSCode</h1>
|
||
<p>Now we run and debug our Mynewt Firmware with <a href="https://code.visualstudio.com/"><strong>VSCode</strong></a> on Linux, macOS and Windows…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Connect PineCone and the JTAG Debugger to our computer. See the article…</p>
|
||
<p><a href="https://lupyuen.github.io/articles/openocd">“Connect PineCone BL602 to OpenOCD”</a>, Section 4, <a href="https://lupyuen.github.io/articles/openocd#connect-jtag-debugger-to-pinecone">“Connect JTAG Debugger to PineCone”</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Launch VSCode</p>
|
||
</li>
|
||
<li>
|
||
<p>Click <strong><code>File → Open</code></strong></p>
|
||
<p>Select the folder <strong><code>pinecone-rust-mynewt</code></strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Click <strong><code>Terminal → Run Build Task</code></strong></p>
|
||
<p>This builds the Mynewt Firmware. The RISC-V ELF Firmware image is generated here…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/bin/targets/pinecone_app/app/apps/blinky/blinky.elf</code></pre></div>
|
||
<p>This step also terminates any OpenOCD processes that are running. (Linux and macOS only)</p>
|
||
</li>
|
||
<li>
|
||
<p>Click <strong><code>Run → Start Debugging</code></strong></p>
|
||
<p>The debugger loads our Mynewt Firmware to PineCone’s Cache Memory and begins execution.</p>
|
||
<p>Click <strong><code>View → Debug Console</code></strong> to view the Debug Console. GDB messages will be shown here.</p>
|
||
</li>
|
||
<li>
|
||
<p>The debugger pauses execution at the first line of the <code>main</code> function</p>
|
||
<p>We should see the screen below…</p>
|
||
<p><a href="https://youtu.be/iDS8CBplSw8">Watch on YouTube</a></p>
|
||
</li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-debug.png" alt="Debug Firmware with VSCode" /></p>
|
||
<p><em>Debug Firmware with VSCode</em></p>
|
||
<h2 id="debugging-features"><a class="doc-anchor" href="#debugging-features">§</a>14.1 Debugging Features</h2>
|
||
<p>We may use these features for debugging our Mynewt Firmware…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Variables</strong> (Left Top Pane): Inspect global and local variables</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Watch</strong> (Left Centre): Show the value of expressions</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Call Stack</strong> (Left Bottom): Navigate the stack trace and its variables</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Debug Console</strong> (Centre): Enter GDB commands here</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Debug Toolbar</strong> (Top Right): Continue / Pause, Step Over, Step Into, Step Out, Restart, Stop</p>
|
||
</li>
|
||
<li>
|
||
<p>To set a <strong>Breakpoint</strong>, click the Gutter Column at the left of the source code</p>
|
||
</li>
|
||
<li>
|
||
<p>When we’re done with debugging, click the Stop button in the Debug Toolbar at top right</p>
|
||
</li>
|
||
</ol>
|
||
<p><a href="https://youtu.be/iDS8CBplSw8">Watch on YouTube</a></p>
|
||
<p><a href="https://code.visualstudio.com/docs/editor/debugging">More about VSCode Debugger</a></p>
|
||
<h2 id="terminating-openocd"><a class="doc-anchor" href="#terminating-openocd">§</a>14.2 Terminating OpenOCD</h2>
|
||
<p>Before we start a new debugging session with <strong><code>Run → Start Debugging</code></strong>…</p>
|
||
<p><em>We must always click <strong><code>Terminal → Run Build Task</code></strong> first!</em></p>
|
||
<p>That’s because stopping the debugger will leave OpenOCD running (and locking up the connection to PineCone).</p>
|
||
<p>Clicking <strong><code>Run Build Task</code></strong> will terminate the OpenOCD task, so that the next debugging session can restart OpenOCD successfully.</p>
|
||
<p>For Windows: Sorry we need to terminate the OpenOCD task manually with the Task Manager.</p>
|
||
<p>In case of OpenOCD problems, check the OpenOCD log file…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt/openocd.log</code></pre></div>
|
||
<p>For details on the VSCode settings, check the section “Appendix: VSCode Settings” below.</p>
|
||
<h1 id="how-to-test"><a class="doc-anchor" href="#how-to-test">§</a>15 How To Test</h1>
|
||
<p><em>How shall we test Mynewt on PineCone? Or any other RTOS ported to PineCone?</em></p>
|
||
<p>We have an interesting problem here… PineCone is a barebones board that doesn’t have any sensors or actuators connected on interfaces like I2C and SPI.</p>
|
||
<p>It will be challenging to test the various interfaces ported to Mynewt. (I might test with the <a href="http://dangerousprototypes.com/docs/Bus_Pirate"><strong>Bus Pirate Probe</strong></a>)</p>
|
||
<p>For now I’ll do <strong>“Opportunistic Porting and Testing”</strong>… I’ll port to Mynewt only those PineCone Interfaces that I can test.</p>
|
||
<p><strong>Do you have ideas for testing an RTOS on PineCone? Let us know!</strong></p>
|
||
<h2 id="testing-the-led"><a class="doc-anchor" href="#testing-the-led">§</a>15.1 Testing the LED</h2>
|
||
<p>Testing PineCone’s onboard RGB LED over GPIO seems easy… Except that the LED is connected to the JTAG Port. So the debugger will fail.</p>
|
||
<p>In the earlier articles we learnt about remapping the JTAG port. This could be a (complicated) solution to test and debug the GPIO Port.</p>
|
||
<p>Meanwhile I’ll proceed to port the GPIO HAL from the BL602 IoT SDK to Mynewt, as discussed earlier.</p>
|
||
<h2 id="testing-the-jumper"><a class="doc-anchor" href="#testing-the-jumper">§</a>15.2 Testing the Jumper</h2>
|
||
<p>We could test GPIO Input with PineCone’s onboard jumper.</p>
|
||
<p>This should be straightforward, right after we port over the GPIO HAL to Mynewt.</p>
|
||
<h2 id="testing-the-uart-port"><a class="doc-anchor" href="#testing-the-uart-port">§</a>15.3 Testing the UART Port</h2>
|
||
<p>PineCone’s UART Port is wired to the USB Connector. We could test PineCone’s UART Port over USB.</p>
|
||
<p>We’ll need to port the UART HAL from the BL602 IoT SDK to Mynewt.</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-furry.jpg" alt="Furry PineCone" /></p>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>16 What’s Next</h1>
|
||
<p>There’s more work to be done porting Mynewt to PineCone…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>Port the Hardware Abstraction Layer</strong> from BL602 IoT SDK to Mynewt: GPIO, UART, PWM, I2C, SPI…</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Bluetooth LE</strong>: We shall reverse engineer the Bluetooth LE Stack on PineCone. Then replace it by the open source <a href="https://github.com/apache/mynewt-nimble"><strong>NimBLE Stack</strong></a>.</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>WiFi</strong>: Also needs to be reverse engineered. We might be able to port this Mynewt WiFi Driver to PineCone…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/runtimeco/mynewt_arduino_zero/tree/master/libs/winc1500"><code>mynewt_arduino_zero/ libs/winc1500</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/runtimeco/mynewt_arduino_zero/tree/master/apps/winc1500_wifi"><code>mynewt_arduino_zero/ apps/winc1500_wifi</code></a></p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p><strong>Rust</strong> will be supported so that we may build complex firmware without falling into traps with C Pointers.</p>
|
||
</li>
|
||
</ol>
|
||
<p>Then we shall have a fully <strong>Open Source Operating System for PineCone!</strong></p>
|
||
<p><em>How confident are we of porting Mynewt to PineCone BL602?</em></p>
|
||
<p>One year ago I <a href="https://lupyuen.github.io/articles/hey-gd32-vf103-on-risc-v-i-surrender-for-now">failed to port Mynewt</a> to an earlier RISC-V Microcontroller (GD32 VF103)</p>
|
||
<p><em>But Second Time’s The Charm!</em></p>
|
||
<p>PineCone’s BL602 Microcontroller runs on a RISC-V Core that’s similar to SiFive FE310. And porting Mynewt from FE310 to BL602 seems quick and easy. <a href="https://twitter.com/MisterTechBlog/status/1338759961526951937?s=19">(As seen on Twitter)</a></p>
|
||
<p>The port of Mynewt to PineCone BL602 continues here…</p>
|
||
<ul>
|
||
<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/articles/sponsor">Sponsor me a coffee</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io">Check out my articles</a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/rss.xml">RSS Feed</a></p>
|
||
</li>
|
||
</ul>
|
||
<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/mynewt.md"><code>lupyuen.github.io/src/mynewt.md</code></a></p>
|
||
<h1 id="appendix-load-firmware-to-cache-memory-not-flash-memory"><a class="doc-anchor" href="#appendix-load-firmware-to-cache-memory-not-flash-memory">§</a>17 Appendix: Load Firmware to Cache Memory, not Flash Memory</h1>
|
||
<p><a href="https://lupyuen.github.io/articles/rust"><strong>UPDATE:</strong> We have a new way to create Rust Firmware with BL602 IoT SDK and flash to BL602 Flash Memory over UART, check this out</a></p>
|
||
<p><a href="https://github.com/9names/bl602-rust-example"><strong>UPDATE:</strong> Check out this Rust Firmware that runs in Flash Memory instead of Cache Memory</a></p>
|
||
<p><em>Why did we load our Mynewt Firmware (and Rust Firmware) to Cache Memory instead of Flash Memory?</em></p>
|
||
<p>Because OpenOCD couldn’t load our Mynewt Firmware (and Rust Firmware) into Flash Memory.</p>
|
||
<p>(Probably because of Flash Protection. Or because writing to BL602 Flash Memory hasn’t been implemented in OpenOCD.)</p>
|
||
<p><a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_Openocd&GDB/en">BL602 OpenOCD with JTAG doesn’t support loading firmware into Flash Memory. See the BL602 OpenOCD Docs</a></p>
|
||
<p><em>What happens when we use <code>blflash</code> to load our firmware to Flash Memory?</em></p>
|
||
<p>We’re not sure if the Mynewt (or Rust) Firmware will run… But it’s worth trying!</p>
|
||
<p>Make sure that we update the Memory Map to load our code into the XIP Flash Memory at <code>0x2300 0000</code>.</p>
|
||
<p>Note that the <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602/evb/src/boot/gcc/start.S">Start Code from BL602 IoT SDK <code>start.S</code></a> references the Boot2 Bootloader.</p>
|
||
<p>We’re not sure why. Our Start Code from Mynewt (and Rust) doesn’t use the Boot2 Bootloader.</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-flash.png" alt="Loading Mynewt Firmware to Flash Memory" /></p>
|
||
<p><em>What happens when we use OpenOCD + JTAG to load our firmware to Flash Memory?</em></p>
|
||
<p>The screen above shows the first version of the Mynewt Firmware, that loads into Flash Memory.</p>
|
||
<p>We used this GDB command to dump out the first 10 words of PineCone’s Flash Memory…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>x/10x _reset_handler</code></pre></div>
|
||
<p>(<code>_reset_handler</code> is the function name of Mynewt’s Start Code, located at the start of our firmware)</p>
|
||
<p>When we compare the dumped data with our Firmware Disassembly, we see that the bytes don’t match.</p>
|
||
<p>Hence we deduce that our Mynewt Firmware wasn’t loaded correctly into Flash Memory.</p>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-ram.png" alt="Loading Mynewt Firmware to Cache Memory" /></p>
|
||
<p><em>What happens when we use OpenOCD + JTAG to load our firmware to Cache Memory?</em></p>
|
||
<p>Here’s the second try, loading our Mynewt Firmware to Cache Memory. (The same way that we loaded Rust Firmware in our previous article)</p>
|
||
<p>Entering the same GDB Command…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>x/10x _reset_handler</code></pre></div>
|
||
<p>We see that the data is identical. Our Mynewt Firmware is loaded correctly to Cache Memory indeed!</p>
|
||
<p><em>But we can’t run Mynewt Firmware in Cache Memory forever right?</em></p>
|
||
<p>The solution is to load our firmware to PineCone over USB (UART). (And flipping the jumper)</p>
|
||
<p>We may integrate with VSCode the command-line scripts for loading our firmware to PineCone.</p>
|
||
<p>Check out the article…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/flash">“Flashing Firmware to PineCone BL602”</a></li>
|
||
</ul>
|
||
<h1 id="appendix-install-newt"><a class="doc-anchor" href="#appendix-install-newt">§</a>18 Appendix: Install newt</h1>
|
||
<p>We may install Mynewt’s <code>newt</code> tool according to the instructions here…</p>
|
||
<ul>
|
||
<li><a href="https://mynewt.apache.org/latest/newt/install/index.html">Installing <code>newt</code></a></li>
|
||
</ul>
|
||
<p>Or we may build from the source code…</p>
|
||
<h2 id="linux-and-macos"><a class="doc-anchor" href="#linux-and-macos">§</a>18.1 Linux and macOS</h2>
|
||
<ol>
|
||
<li>
|
||
<p>Install the <a href="https://golang.org/dl/">latest version of Go</a></p>
|
||
</li>
|
||
<li>
|
||
<p>At a command prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>cd /tmp
|
||
export mynewt_version=mynewt_1_8_0_tag
|
||
git clone --branch $mynewt_version https://github.com/apache/mynewt-newt/
|
||
cd mynewt-newt
|
||
./build.sh
|
||
sudo mv newt/newt /usr/local/bin
|
||
newt version</code></pre></div></li>
|
||
<li>
|
||
<p>We should see…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Apache Newt 1.8.0</code></pre></div></li>
|
||
</ol>
|
||
<h2 id="windows"><a class="doc-anchor" href="#windows">§</a>18.2 Windows</h2>
|
||
<p>The Windows version of <code>newt</code> is already bundled at…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt\newt\newt.exe</code></pre></div>
|
||
<p>The build script <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/scripts/build-app.cmd"><code>build-app.cmd</code></a> uses the above <code>newt</code> executable.</p>
|
||
<p>However, the <code>newt</code> executable triggers a Windows Defender warning (because it wasn’t built as a certified executable). We need to <strong>update the Windows Security settings</strong> to allow the <code>newt</code> executable to run.</p>
|
||
<p>To build <code>newt</code> from the source code, follow these steps…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Install the <a href="https://golang.org/dl/">latest version of Go</a></p>
|
||
</li>
|
||
<li>
|
||
<p>At a command prompt, enter…</p>
|
||
<div class="example-wrap"><pre class="language-cmd"><code>git clone --branch mynewt_1_8_0_tag https://github.com/apache/mynewt-newt/
|
||
cd mynewt-newt\newt
|
||
go build
|
||
newt.exe version</code></pre></div></li>
|
||
<li>
|
||
<p>We should see…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>Apache Newt 1.8.0</code></pre></div></li>
|
||
<li>
|
||
<p>Copy the <code>newt</code> executable from…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>mynewt-newt\newt\newt.exe</code></pre></div>
|
||
<p>To…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>pinecone-rust-mynewt\newt\newt.exe</code></pre></div></li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/mynewt-windows.png" alt="Mynewt BL602 built with Windows CMD" /></p>
|
||
<p><em>Mynewt BL602 built with Windows CMD</em></p>
|
||
<h1 id="appendix-create-the-mynewt-firmware"><a class="doc-anchor" href="#appendix-create-the-mynewt-firmware">§</a>19 Appendix: Create the Mynewt Firmware</h1>
|
||
<p>Mynewt Project <code>pinecone-rust-mynewt</code> and Mynewt Firmware <code>pinecone_app</code> were originally created using these steps…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>newt new pinecone-rust-mynewt
|
||
cd pinecone-rust-mynewt
|
||
newt upgrade
|
||
newt target create pinecone_app
|
||
newt target set pinecone_app app=apps/blinky
|
||
## This will be changed to pinecone later
|
||
newt target set pinecone_app bsp=@apache-mynewt-core/hw/bsp/hifive1
|
||
newt target set pinecone_app build_profile=debug</code></pre></div>
|
||
<p>We don’t need to create them again, just download from…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt"><code>github.com/lupyuen/pinecone-rust-mynewt</code></a></li>
|
||
</ul>
|
||
<p>The steps above were based on the <a href="https://mynewt.apache.org/latest/tutorials/blinky/blinky_stm32f4disc.html">Blinky Tutorial for STM32F4-Discovery</a>.</p>
|
||
<p>I added this Git Modules file so that the Mynewt source files will be downloaded together with the repo…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/.gitmodules"><code>.gitmodules</code></a></li>
|
||
</ul>
|
||
<h1 id="appendix-vscode-settings"><a class="doc-anchor" href="#appendix-vscode-settings">§</a>20 Appendix: VSCode Settings</h1><h2 id="debugger-settings"><a class="doc-anchor" href="#debugger-settings">§</a>20.1 Debugger Settings</h2>
|
||
<p>The VSCode Debugger Settings may be found in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/.vscode/launch.json"><code>.vscode/launch.json</code></a></p>
|
||
<p>This file defines…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Firmware Path (<code>target</code>)</p>
|
||
</li>
|
||
<li>
|
||
<p>GDB Path (<code>gdbpath</code>)</p>
|
||
</li>
|
||
<li>
|
||
<p>OpenOCD Path (in <code>autorun</code>, after <code>target remote</code>)</p>
|
||
</li>
|
||
<li>
|
||
<p>GDB Commands to be executed upon starting the debugger (<code>autorun</code>)</p>
|
||
</li>
|
||
</ul>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
// VSCode Debugger Config for PineCone BL602
|
||
"version": "0.2.0",
|
||
"configurations": [
|
||
{
|
||
"name": "BL602",
|
||
"type": "gdb",
|
||
"request": "launch",
|
||
// Application Executable to be flashed before debugging
|
||
"target": "${workspaceRoot}/bin/targets/pinecone_app/app/apps/blinky/blinky.elf",
|
||
"cwd": "${workspaceRoot}",
|
||
"gdbpath": "${workspaceRoot}/xpack-riscv-none-embed-gcc/bin/riscv-none-embed-gdb",
|
||
"valuesFormatting": "parseText",
|
||
"autorun": [
|
||
// Before loading the Application, run these gdb commands.
|
||
// Set timeout for executing openocd commands.
|
||
"set remotetimeout 600",
|
||
|
||
// This indicates that an unrecognized breakpoint location should automatically result in a pending breakpoint being created.
|
||
"set breakpoint pending on",
|
||
|
||
// Set breakpoints
|
||
"break main", // Break at main()
|
||
"break __assert_func", // Break for any C assert failures
|
||
// "break os_default_irq", // Break for any Mynewt unhandled interrupts
|
||
// "break core::panicking::panic", // Break for any Rust assert failures and panics
|
||
// "break core::result::unwrap_failed", // Break for any Rust unwrap and expect failures
|
||
|
||
// Launch OpenOCD. Based on https://www.justinmklam.com/posts/2017/10/vscode-debugger-setup/
|
||
"target remote | xpack-openocd/bin/openocd -c \"gdb_port pipe; log_output openocd.log\" -f openocd.cfg ",
|
||
|
||
// Load the program into board memory
|
||
"load",
|
||
|
||
// Execute one RISC-V instruction and stop
|
||
// "stepi",
|
||
|
||
// Run the program until we hit the main() breakpoint
|
||
// "continue",
|
||
]
|
||
}
|
||
]
|
||
}</code></pre></div><h2 id="task-settings"><a class="doc-anchor" href="#task-settings">§</a>20.2 Task Settings</h2>
|
||
<p>The VSCode Task Settings may be found in <a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/.vscode/tasks.json"><code>.vscode/tasks.json</code></a></p>
|
||
<p>This file defines the VSCode Task for building the Mynewt Firmware…</p>
|
||
<div class="example-wrap"><pre class="language-json"><code>{
|
||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||
// for the documentation about the tasks.json format
|
||
"version": "2.0.0",
|
||
"tasks": [
|
||
{
|
||
// Build firmware
|
||
"label": "Build Firmware",
|
||
"type": "shell",
|
||
"windows": {
|
||
"command": "cmd",
|
||
"args": [
|
||
"/c",
|
||
" newt build pinecone_app && newt size -v pinecone_app && echo ✅ ◾ ️Done! "
|
||
]
|
||
},
|
||
"osx": {
|
||
"command": "bash",
|
||
"args": [
|
||
"-c", "-l",
|
||
" scripts/build-app.sh && echo ✅ ◾ ️Done! "
|
||
]
|
||
},
|
||
"linux": {
|
||
"command": "bash",
|
||
"args": [
|
||
"-c", "-l",
|
||
" scripts/build-app.sh && echo ✅ ◾ ️Done! "
|
||
]
|
||
},
|
||
"group": {
|
||
"kind": "build",
|
||
"isDefault": true
|
||
},
|
||
"problemMatcher": [
|
||
{
|
||
// Problem matcher for GNU Linker, e.g. /Users/Luppy/mynewt/stm32bluepill-mynewt-sensor/apps/my_sensor_app/src/ATParser.h:82: undefined reference to `operator delete[](void*)'
|
||
"fileLocation": [ "absolute" ],
|
||
"pattern": {
|
||
"regexp": "^(/.*):(\\d+):\\s+(.*)$",
|
||
"file": 1,
|
||
"line": 2,
|
||
"message": 3,
|
||
// "code": 3,
|
||
// "severity": 4,
|
||
}
|
||
}
|
||
],
|
||
"presentation": {
|
||
"clear": true
|
||
}
|
||
},
|
||
...</code></pre></div>
|
||
<p><a href="https://github.com/lupyuen/pinecone-rust-mynewt/blob/main/scripts/build-app.sh"><code>scripts/build-app.sh</code></a> does the following…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Terminate the OpenOCD process</p>
|
||
</li>
|
||
<li>
|
||
<p>Build the Mynewt Firmware</p>
|
||
</li>
|
||
<li>
|
||
<p>Display the firmware size</p>
|
||
</li>
|
||
</ol>
|
||
<div class="example-wrap"><pre class="language-bash"><code>#!/usr/bin/env bash
|
||
## macOS and Linux Bash script to build Mynewt Firmware
|
||
|
||
set -e # Exit when any command fails
|
||
set -x # Echo commands
|
||
|
||
## Terminate any OpenOCD processes from the debug session
|
||
set +e # Ignore errors
|
||
pkill openocd
|
||
set -e # Stop on errors
|
||
|
||
## Add GCC to the PATH
|
||
set +x # Stop echo
|
||
export PATH="$PWD/xpack-riscv-none-embed-gcc/bin:$PATH"
|
||
set -x # Echo commands
|
||
|
||
## Build the Mynewt Firmware
|
||
newt build pinecone_app
|
||
|
||
## Display the firmware size
|
||
newt size -v pinecone_app</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> |