mirror of
https://github.com/lupyuen/lupyuen.github.io.git
synced 2025-01-13 10:18:33 +08:00
619 lines
No EOL
37 KiB
HTML
619 lines
No EOL
37 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>Control PineCone BL602 RGB LED with GPIO and PWM</title>
|
||
|
||
|
||
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
|
||
<meta property="og:title"
|
||
content="Control PineCone BL602 RGB LED with GPIO and PWM"
|
||
data-rh="true">
|
||
<meta property="og:description"
|
||
content="Explore the BL602 GPIO and PWM Demo Firmware... And how they call the GPIO and PWM Hardware Abstraction Layer"
|
||
data-rh="true">
|
||
<meta property="og:image"
|
||
content="https://lupyuen.github.io/images/led-title.jpg">
|
||
<meta property="og:type"
|
||
content="article" data-rh="true">
|
||
<link rel="canonical" href="https://lupyuen.org/articles/led.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">Control PineCone BL602 RGB LED with GPIO and PWM</h1>
|
||
<nav id="rustdoc"><ul>
|
||
<li><a href="#control-rgb-led-with-gpio" title="Control RGB LED with GPIO">1 Control RGB LED with GPIO</a><ul></ul></li>
|
||
<li><a href="#gpio-exercise-for-the-reader" title="GPIO Exercise for The Reader">2 GPIO Exercise for The Reader</a><ul></ul></li>
|
||
<li><a href="#how-it-works-bl602-gpio" title="How It Works: BL602 GPIO">3 How It Works: BL602 GPIO</a><ul>
|
||
<li><a href="#enable-gpio" title="Enable GPIO">3.1 Enable GPIO</a><ul></ul></li>
|
||
<li><a href="#read-and-write-gpio" title="Read and Write GPIO">3.2 Read and Write GPIO</a><ul></ul></li>
|
||
<li><a href="#gpio-interrupts" title="GPIO Interrupts">3.3 GPIO Interrupts</a><ul></ul></li>
|
||
<li><a href="#gpio-device-tree" title="GPIO Device Tree">3.4 GPIO Device Tree</a><ul></ul></li></ul></li>
|
||
<li><a href="#from-gpio-to-pulse-width-modulation-pwm" title="From GPIO to Pulse Width Modulation (PWM)">4 From GPIO to Pulse Width Modulation (PWM)</a><ul></ul></li>
|
||
<li><a href="#control-rgb-led-with-pwm" title="Control RGB LED with PWM">5 Control RGB LED with PWM</a><ul></ul></li>
|
||
<li><a href="#how-it-works-bl602-pwm" title="How It Works: BL602 PWM">6 How It Works: BL602 PWM</a><ul>
|
||
<li><a href="#initialise-pwm" title="Initialise PWM">6.1 Initialise PWM</a><ul></ul></li>
|
||
<li><a href="#pwm-frequency-and-duty-cycle" title="PWM Frequency and Duty Cycle">6.2 PWM Frequency and Duty Cycle</a><ul></ul></li>
|
||
<li><a href="#pwm-operation" title="PWM Operation">6.3 PWM Operation</a><ul></ul></li>
|
||
<li><a href="#pwm-device-tree" title="PWM Device Tree">6.4 PWM Device Tree</a><ul></ul></li></ul></li>
|
||
<li><a href="#bl602-pwm-internals" title="BL602 PWM Internals">7 BL602 PWM Internals</a><ul></ul></li>
|
||
<li><a href="#whats-next" title="What’s Next">8 What’s Next</a><ul></ul></li>
|
||
<li><a href="#appendix-fix-bl602-demo-firmware-for-macos" title="Appendix: Fix BL602 Demo Firmware for macOS">9 Appendix: Fix BL602 Demo Firmware for macOS</a><ul></ul></li></ul></nav><p><img src="https://lupyuen.github.io/images/led-title.jpg" alt="PineCone BL602 RISC-V Evaluation Board connected to Pinebook Pro" /></p>
|
||
<p><em>PineCone BL602 RISC-V Evaluation Board connected to Pinebook Pro</em></p>
|
||
<p>📝 <em>6 Jan 2021</em></p>
|
||
<p>Today we shall take control of <strong>PineCone’s Onboard RGB LED</strong> in two ways…</p>
|
||
<ol>
|
||
<li>
|
||
<p><strong>GPIO</strong></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Pulse Width Modulation (PWM)</strong></p>
|
||
</li>
|
||
</ol>
|
||
<p>We’ll do this with the <strong>GPIO and PWM Demo Firmware</strong> from the <a href="https://github.com/lupyuen/bl_iot_sdk"><strong>BL602 IoT SDK</strong></a>.</p>
|
||
<p>Through the Demo Firmware we shall learn to call <strong>BL602’s Hardware Abstraction Layer</strong> in C to perform GPIO and PWM Functions.</p>
|
||
<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/led-rgb.png" alt="PineCone RGB LED Schematic" /></p>
|
||
<p><em>PineCone RGB LED Schematic</em></p>
|
||
<h1 id="control-rgb-led-with-gpio"><a class="doc-anchor" href="#control-rgb-led-with-gpio">§</a>1 Control RGB LED with GPIO</h1>
|
||
<p>According to the <a href="https://github.com/pine64/bl602-docs/blob/main/mirrored/Pine64%20BL602%20EVB%20Schematic%20ver%201.1.pdf">PineCone Schematics</a>, the onboard RGB LED is connected to these GPIO Pins…</p>
|
||
<div><table><thead><tr><th style="text-align: left">LED</th><th style="text-align: left">GPIO Pin</th></tr></thead><tbody>
|
||
<tr><td style="text-align: left">Blue</td><td style="text-align: left">GPIO 11</td></tr>
|
||
<tr><td style="text-align: left">Red</td><td style="text-align: left">GPIO 17</td></tr>
|
||
<tr><td style="text-align: left">Green</td><td style="text-align: left">GPIO 14</td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p>Let’s flash the <strong>GPIO Demo</strong> from the BL602 IoT SDK and interact with the above GPIO Pins…</p>
|
||
<ol>
|
||
<li>
|
||
<p>Download the <strong>BL602 Demo Firmware Binaries</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/releases/download/v1.0.0/customer_app.zip"><strong>BL602 Demo Firmware Binaries</strong>: <code>customer_app.zip</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Unzip <code>customer_app.zip</code>. Look for the file…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>sdk_app_gpio/build_out/sdk_app_gpio.bin</code></pre></div></li>
|
||
<li>
|
||
<p>Flash <code>sdk_app_gpio.bin</code> to PineCone. Follow the instructions in the article…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/flash"><strong>“Flashing Firmware to PineCone BL602”</strong></a></li>
|
||
</ul>
|
||
<p>After flashing, flip the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>L</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperl.jpg">(Like this)</a></p>
|
||
<p>Press the Reset Button.</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect to PineCone…</p>
|
||
<p><strong>For Linux:</strong></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>screen /dev/ttyUSB0 2000000</code></pre></div>
|
||
<p><strong>For macOS:</strong> Use CoolTerm (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>For Windows:</strong> Use <code>putty</code> (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>Alternatively:</strong> Use the Web Serial Terminal (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">More details on connecting to BL602</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the <strong>RST Button</strong> on PineCone to restart the firmware.</p>
|
||
<p>We should see this…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-gpio1.png" alt="BL602 GPIO Demo" /></p>
|
||
</li>
|
||
<li>
|
||
<p>Press <code>Enter</code> to reveal the command prompt.</p>
|
||
<p>Enter <code>help</code> to see the commands…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-gpio2.png" alt="BL602 GPIO Demo Commands" /></p>
|
||
</li>
|
||
<li>
|
||
<p>Enter these commands to set GPIO 11 (Blue), 14 (Green), 17 (Red) to output (no pullup, no pulldown)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>gpio-func 11 0 0 0
|
||
gpio-func 14 0 0 0
|
||
gpio-func 17 0 0 0</code></pre></div></li>
|
||
<li>
|
||
<p>Switch off the 3 LEDs (1 = Off)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>gpio-set 11 1
|
||
gpio-set 14 1
|
||
gpio-set 17 1</code></pre></div></li>
|
||
<li>
|
||
<p>Switch on and off each of the 3 LEDs: Blue, Green, Red (0 = On, 1 = Off)…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>gpio-set 11 0
|
||
gpio-set 11 1
|
||
|
||
gpio-set 14 0
|
||
gpio-set 14 1
|
||
|
||
gpio-set 17 0
|
||
gpio-set 17 1</code></pre></div></li>
|
||
<li>
|
||
<p>To exit <code>screen</code>, press <code>Ctrl-A</code> then <code>k</code> then <code>y</code></p>
|
||
</li>
|
||
</ol>
|
||
<p><a href="https://youtu.be/yaXsfM1ne4w">Watch the GPIO Demo Video on YouTube</a></p>
|
||
<p><img src="https://lupyuen.github.io/images/led-jumper.png" alt="PineCone Jumper Schematic" /></p>
|
||
<p><em>PineCone Jumper Schematic</em></p>
|
||
<h1 id="gpio-exercise-for-the-reader"><a class="doc-anchor" href="#gpio-exercise-for-the-reader">§</a>2 GPIO Exercise for The Reader</h1>
|
||
<p>According to the <a href="https://github.com/pine64/bl602-docs/blob/main/mirrored/Pine64%20BL602%20EVB%20Schematic%20ver%201.1.pdf">PineCone Schematics</a>, the onboard jumper is connected to GPIO 8.</p>
|
||
<p>Can we use this command to read the jumper?</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>gpio-get 8</code></pre></div>
|
||
<p>Flip the jumper and check whether the value changes.</p>
|
||
<p>Remember to use this command to configure GPIO 8…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>gpio-func 8 1 PULLUP PULLDOWN</code></pre></div>
|
||
<ul>
|
||
<li><code>8</code> is the GPIO Number</li>
|
||
<li><code>1</code> to configure the GPIO for Input (instead of output)</li>
|
||
<li><code>PULLUP</code> is <code>0</code> for No Pullup, <code>1</code> for Pullup</li>
|
||
<li><code>PULLDOWN</code> is <code>0</code> for No Pulldown, <code>1</code> for Pulldown</li>
|
||
</ul>
|
||
<p>Please lemme know!</p>
|
||
<h1 id="how-it-works-bl602-gpio"><a class="doc-anchor" href="#how-it-works-bl602-gpio">§</a>3 How It Works: BL602 GPIO</h1>
|
||
<p>The GPIO Demo Firmware calls the GPIO Functions provided by the <strong>BL602 Hardware Abstraction Layer (HAL)</strong>.</p>
|
||
<p>Let’s look at the BL602 GPIO Functions called by the GPIO Demo Firmware: <a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/sdk_app_gpio"><code>sdk_app_gpio.bin</code></a></p>
|
||
<h2 id="enable-gpio"><a class="doc-anchor" href="#enable-gpio">§</a>3.1 Enable GPIO</h2>
|
||
<p>To designate a GPIO Pin for input or output, we call these GPIO HAL Functions: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_gpio.h"><code>bl_gpio.h</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);
|
||
int bl_gpio_enable_input( uint8_t pin, uint8_t pullup, uint8_t pulldown);</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>pin</code> is the GPIO Pin Number, so <code>pin=0</code> refers to GPIO 0.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>pullup</code> is set to 1 if the pin should be pulled up electrically, 0 otherwise.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>pulldown</code> is set to 1 if the pin should be pulled down electrically, 0 otherwise.</p>
|
||
</li>
|
||
</ul>
|
||
<p>Check out this sample code for GPIO Output…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/rust#bl602-blinky-in-c"><strong>“BL602 Blinky in C”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/spi#configure-chip-select-pin-as-gpio-output-pin"><strong>“Configure GPIO Output Pin”</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="read-and-write-gpio"><a class="doc-anchor" href="#read-and-write-gpio">§</a>3.2 Read and Write GPIO</h2>
|
||
<p>To read or write a GPIO Pin, we call these GPIO HAL Functions: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_gpio.h"><code>bl_gpio.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int bl_gpio_output_set(uint8_t pin, uint8_t value);
|
||
int bl_gpio_input_get( uint8_t pin, uint8_t *value);
|
||
int bl_gpio_input_get_value(uint8_t pin);</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>pin</code> is the GPIO Pin Number.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>value</code> is the value to be read or written (0=Low, 1=High).</p>
|
||
</li>
|
||
<li>
|
||
<p><code>bl_gpio_input_get</code> stores the value read at the pointer passed in.</p>
|
||
</li>
|
||
</ul>
|
||
<p>Check out this sample code for writing to GPIO…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/spi#set-chip-select-to-low"><strong>“Set GPIO To Low”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/spi#set-chip-select-to-high"><strong>“Set GPIO To High”</strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<h2 id="gpio-interrupts"><a class="doc-anchor" href="#gpio-interrupts">§</a>3.3 GPIO Interrupts</h2>
|
||
<p>To allow a GPIO Pin to trigger interrupts (like when a button is pressed), we call these GPIO HAL Functions: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_gpio.h"><code>bl_gpio.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int bl_gpio_int_clear( uint8_t gpioPin, uint8_t intClear);
|
||
void bl_gpio_intmask( uint8_t gpiopin, uint8_t mask);
|
||
void bl_set_gpio_intmod(uint8_t gpioPin, uint8_t intCtrlMod, uint8_t intTrgMod);
|
||
void bl_gpio_register(gpio_ctx_t *pstnode);</code></pre></div>
|
||
<p>Check the following for details on GPIO Interrupts…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://lupyuen.github.io/articles/lora2#bl602-gpio-interrupts"><strong>“BL602 GPIO Interrupts”</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_gpio.c"><strong>GPIO HAL Source Code: <code>bl_gpio.c</code></strong></a></p>
|
||
</li>
|
||
</ul>
|
||
<p>To see the above GPIO HAL Functions in action, check out the GPIO Demo Source Code…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_gpio/sdk_app_gpio/demo.c"><strong>GPIO Demo Source Code: <code>demo.c</code></strong></a></li>
|
||
</ul>
|
||
<h2 id="gpio-device-tree"><a class="doc-anchor" href="#gpio-device-tree">§</a>3.4 GPIO Device Tree</h2>
|
||
<p>There is an alternative set of functions for controlling GPIO…</p>
|
||
<ul>
|
||
<li><strong>GPIO Device Tree</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/hal_gpio.h"><strong><code>hal_gpio.h</code></strong></a>, <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/hal_gpio.c"><strong><code>hal_gpio.c</code></strong></a></li>
|
||
</ul>
|
||
<p>These functions are meant to be used with the <strong>BL602 Device Tree</strong>.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#device-tree">More about BL602 Device Tree</a></p>
|
||
<h1 id="from-gpio-to-pulse-width-modulation-pwm"><a class="doc-anchor" href="#from-gpio-to-pulse-width-modulation-pwm">§</a>4 From GPIO to Pulse Width Modulation (PWM)</h1>
|
||
<p><em>How many colours can we show on the RGB LED through GPIO?</em></p>
|
||
<p>Each GPIO Pin is binary… Either On or Off. Let’s flip each LED and count the colours…</p>
|
||
<div><table><thead><tr><th style="text-align: center">Red</th><th style="text-align: center">Green</th><th style="text-align: center">Blue</th><th style="text-align: left">Colour</th></tr></thead><tbody>
|
||
<tr><td style="text-align: center">Off</td><td style="text-align: center">Off</td><td style="text-align: center">Off</td><td style="text-align: left"><strong>Black</strong></td></tr>
|
||
<tr><td style="text-align: center">ON</td><td style="text-align: center">Off</td><td style="text-align: center">Off</td><td style="text-align: left"><strong>Red</strong></td></tr>
|
||
<tr><td style="text-align: center">Off</td><td style="text-align: center">ON</td><td style="text-align: center">Off</td><td style="text-align: left"><strong>Green</strong></td></tr>
|
||
<tr><td style="text-align: center">ON</td><td style="text-align: center">ON</td><td style="text-align: center">Off</td><td style="text-align: left"><strong>Yellow</strong></td></tr>
|
||
<tr><td style="text-align: center">Off</td><td style="text-align: center">Off</td><td style="text-align: center">ON</td><td style="text-align: left"><strong>Blue</strong></td></tr>
|
||
<tr><td style="text-align: center">ON</td><td style="text-align: center">Off</td><td style="text-align: center">ON</td><td style="text-align: left"><strong>Magenta</strong></td></tr>
|
||
<tr><td style="text-align: center">Off</td><td style="text-align: center">ON</td><td style="text-align: center">ON</td><td style="text-align: left"><strong>Cyan</strong></td></tr>
|
||
<tr><td style="text-align: center">ON</td><td style="text-align: center">ON</td><td style="text-align: center">ON</td><td style="text-align: left"><strong>White</strong></td></tr>
|
||
</tbody></table>
|
||
</div>
|
||
<p><em>Only 8 colours?! That’s not a Full Colour RGB LED!</em></p>
|
||
<p>GPIO Pins are binary (not analogue)… So are LEDs. This will let us switch each LED On and Off, nothing in between (no 50 shades of grey)…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-off-on.jpg" alt="Switching LED on and off with GPIO" /></p>
|
||
<p>But what if we strobe or <strong>blink the LEDs very quickly</strong> (a thousand times a second)…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-wave1.jpg" alt="Blink the LED very quickly" /></p>
|
||
<p>Aha! We’ll see something that’s neither On nor Off… It’s <strong>halfway between Light and Dark</strong>!</p>
|
||
<p>Now what if we <strong>tweak the spacing</strong> between the On and Off parts (keeping the same blinking frequency)…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-wave2.jpg" alt="Blink the LED with spacing" /></p>
|
||
<p>We’ll get <strong>many, many shades of grey</strong>! (>50 yes!)</p>
|
||
<p>And if we apply this nifty trick to each of the RGB LEDs, we’ll get our Full Colour RGB LED!</p>
|
||
<p><em>How shall we program the rapid blinking? Call the GPIO Functions in a loop?</em></p>
|
||
<p>Not a good idea, because our microcontroller will become very busy blinking the LEDs. No time for reading sensors or transmitting data!</p>
|
||
<p>Thankfully we have <strong>Pulse Width Modulation (PWM)</strong>… Our BL602 Microcontroller (and many others) will happily strobe the LED pins for us, without coding any loops.</p>
|
||
<p>Here’s the schematic for PineCone’s RGB LED…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-rgb.png" alt="PineCone RGB LED Schematic" /></p>
|
||
<p><em>What are CH1, CH2 and CH4?</em></p>
|
||
<p>CH1, CH2 and CH4 are <strong>PWM Channels</strong>. Each PWM Channel will let us strobe the output on one pin. (Hence we need 3 PWM Channels)</p>
|
||
<p>Let’s match the 3 GPIO Pins and 3 PWM Channels to the Pin Mapping Table: <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_RM/en">BL602 Reference Manual</a> (Page 27)</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-pins.png" alt="BL602 Pin Mapping" /></p>
|
||
<p>The table says that <strong>GPIO 11, 17 and 14</strong> may be mapped to <strong>PWM Channels 1, 2 and 4</strong> (by calling the PWM HAL Functions). Perfect!</p>
|
||
<p>Remember that we tweaked the spacing of the blinking to get many levels of brightness?</p>
|
||
<p>We call this the <strong>Duty Cycle</strong> in PWM.</p>
|
||
<p>Let’s experiment with the RGB LED on PWM…</p>
|
||
<h1 id="control-rgb-led-with-pwm"><a class="doc-anchor" href="#control-rgb-led-with-pwm">§</a>5 Control RGB LED with PWM</h1>
|
||
<p>Now we’ll switch PineCone to the <strong>Modified PWM Demo</strong> from the BL602 IoT SDK.</p>
|
||
<p>(The firmware was modified to run without a Device Tree. <a href="https://github.com/lupyuen/bl_iot_sdk/pull/1">More details</a>)</p>
|
||
<ol>
|
||
<li>
|
||
<p>Download the <strong>BL602 Demo Firmware Binaries</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/releases/download/v1.0.0/customer_app.zip"><strong>BL602 Demo Firmware Binaries</strong>: <code>customer_app.zip</code></a></li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Unzip <code>customer_app.zip</code>. Look for the file…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>sdk_app_pwm/build_out/sdk_app_pwm.bin</code></pre></div></li>
|
||
<li>
|
||
<p>Flash <code>sdk_app_pwm.bin</code> to PineCone. Follow the instructions in the article…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/flash"><strong>“Flashing Firmware to PineCone BL602”</strong></a></li>
|
||
</ul>
|
||
<p>After flashing, flip the <strong>PineCone Jumper (IO 8)</strong> to the <strong><code>L</code> Position</strong> <a href="https://lupyuen.github.io/images/pinecone-jumperl.jpg">(Like this)</a></p>
|
||
<p>Press the Reset Button.</p>
|
||
</li>
|
||
<li>
|
||
<p>Connect to PineCone…</p>
|
||
<p><strong>For Linux:</strong></p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>screen /dev/ttyUSB0 2000000</code></pre></div>
|
||
<p><strong>For macOS:</strong> Use CoolTerm (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>For Windows:</strong> Use <code>putty</code> (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><strong>Alternatively:</strong> Use the Web Serial Terminal (<a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">See this</a>)</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">More details on connecting to BL602</a></p>
|
||
</li>
|
||
<li>
|
||
<p>Press the <strong>RST Button</strong> on PineCone to restart the firmware. Ignore the errors.</p>
|
||
</li>
|
||
<li>
|
||
<p>Press <code>Enter</code> to reveal the command prompt.</p>
|
||
</li>
|
||
<li>
|
||
<p>Assign GPIO 11 (Blue), 17 (Red), 14 (Green) to <strong>PWM Channels</strong> 1, 2 and 4.</p>
|
||
<p>Set the <strong>PWM Frequency</strong> to 2 kHz. (Each LED will blink at 2,000 cycles per second)</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>pwm_init 1 11 2000
|
||
pwm_init 2 17 2000
|
||
pwm_init 4 14 2000</code></pre></div></li>
|
||
<li>
|
||
<p>Set <strong>PWM Duty Cycle</strong> for all 3 PWM Channels to 100%.</p>
|
||
<p>Which means that 100% of the time, the 3 PWM Channels will be set to 1 (High).</p>
|
||
<p>Which means total darkness: All 3 LEDs will be switched off 100% of the time.</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>pwm_duty_set 1 100
|
||
pwm_duty_set 2 100
|
||
pwm_duty_set 4 100</code></pre></div></li>
|
||
<li>
|
||
<p>Start the PWM Output for all 3 PWM Channels…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>pwm_start 1
|
||
pwm_start 2
|
||
pwm_start 4</code></pre></div></li>
|
||
<li>
|
||
<p>Gradually decrease the PWM Duty Cycle for PWM Channel 1 (Blue) from 100% to 0%.</p>
|
||
<p>This means the Blue LED will gradually get brighter.</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>pwm_duty_set 1 75
|
||
pwm_duty_set 1 50
|
||
pwm_duty_set 1 25
|
||
pwm_duty_set 1 0</code></pre></div></li>
|
||
<li>
|
||
<p>To exit <code>screen</code>, press <code>Ctrl-A</code> then <code>k</code> then <code>y</code></p>
|
||
</li>
|
||
</ol>
|
||
<p><a href="https://youtu.be/66h2rXXc6Tk">Watch the PWM Demo Video on YouTube</a></p>
|
||
<h1 id="how-it-works-bl602-pwm"><a class="doc-anchor" href="#how-it-works-bl602-pwm">§</a>6 How It Works: BL602 PWM</h1>
|
||
<p>Now we look at the BL602 PWM HAL Functions called by the PWM Demo Firmware: <a href="https://github.com/lupyuen/bl_iot_sdk/tree/master/customer_app/sdk_app_pwm"><code>sdk_app_pwm.bin</code></a></p>
|
||
<h2 id="initialise-pwm"><a class="doc-anchor" href="#initialise-pwm">§</a>6.1 Initialise PWM</h2>
|
||
<p>To designate a GPIO PIN as a PWM Channel, we call this PWM HAL Function: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.h"><code>bl_pwm.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int32_t bl_pwm_init(uint8_t id, uint8_t pin, uint32_t freq);</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>id</code> is the PWM Channel ID (0 to 4). BL602 supports 5 PWM Channels: PWM 0 to PWM 4.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>pin</code> is the GPIO Pin Number, so <code>pin=0</code> refers to GPIO 0.</p>
|
||
</li>
|
||
<li>
|
||
<p><code>freq</code> is the PWM Frequency (in Hz / Cycles Per Second). So <code>freq=2000</code> means that the PWM Channel will be blinked 2,000 cycles every second. <code>freq</code> must be between 2,000 and 800,000 (inclusive).</p>
|
||
</li>
|
||
<li>
|
||
<p><strong>UPDATE:</strong> To set the effective PWM Frequency below 2,000 Hz, we may use the <strong>PWM Channel Clock Divider</strong> (which defaults to 1).</p>
|
||
<p>For instance, to achieve a clock frequency of 50 Hz on the PWM, we may set an initial frequency of 6,400 Hz on channel 1, then use…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>PWM_Channel_Set_Div(1, 128)</code></pre></div>
|
||
<p>Which sets channel 1’s clock divider to 128, making the effective PWM Frequency 50 Hz. <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/bl602/bl602_std/bl602_std/StdDriver/Src/bl602_pwm.c#L223-L241">(PWM_Channel_Set_Div comes from the PWM Standard Driver)</a></p>
|
||
<p>(Many thanks to Chandler Jearls for the tip!)</p>
|
||
</li>
|
||
</ul>
|
||
<p>Not all GPIO Pins may be assigned to a PWM Channel. Check “Table 3.1: Pin description” (Page 27) in <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_RM/en">BL602 Reference Manual</a>.</p>
|
||
<h2 id="pwm-frequency-and-duty-cycle"><a class="doc-anchor" href="#pwm-frequency-and-duty-cycle">§</a>6.2 PWM Frequency and Duty Cycle</h2>
|
||
<p>We set the Frequency and Duty Cycle on a PWM Channel by calling these PWM HAL Functions: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.h"><code>bl_pwm.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int32_t bl_pwm_set_freq(uint8_t id, uint32_t freq);
|
||
int32_t bl_pwm_set_duty(uint8_t id, float duty);</code></pre></div>
|
||
<ul>
|
||
<li>
|
||
<p><code>id</code> is the PWM Channel ID (0 to 4).</p>
|
||
</li>
|
||
<li>
|
||
<p><code>freq</code> is the PWM Frequency (in Hz / Cycles Per Second). <code>freq</code> must be between 2,000 and 800,000 (inclusive).</p>
|
||
</li>
|
||
<li>
|
||
<p><code>duty</code> is the PWM Duty Cycle (0 to 100). When <code>duty=25</code>, it means that in every PWM Cycle…</p>
|
||
<ul>
|
||
<li>PWM Ouput is 1 (High) for the initial 25% of the PWM Cycle</li>
|
||
<li>Followed by PWM Output 0 (Low) for the remaining 75% of the PWM Cycle</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
<p>To get the Duty Cycle for a PWM Channel, we call this function…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int32_t bl_pwm_get_duty(uint8_t id, float *p_duty);</code></pre></div>
|
||
<ul>
|
||
<li><code>bl_pwm_get_duty</code> stores the Duty Cycle at the pointer passed in <code>p_duty</code>.</li>
|
||
</ul>
|
||
<h2 id="pwm-operation"><a class="doc-anchor" href="#pwm-operation">§</a>6.3 PWM Operation</h2>
|
||
<p>We start and stop a PWM Channel by calling these PWM HAL Functions: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.h"><code>bl_pwm.h</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>int32_t bl_pwm_start(uint8_t id);
|
||
int32_t bl_pwm_stop( uint8_t id);</code></pre></div>
|
||
<ul>
|
||
<li><code>id</code> is the PWM Channel ID (0 to 4).</li>
|
||
</ul>
|
||
<p>The above PWM HAL Functions are defined here…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.c"><strong>PWM HAL Source Code: <code>bl_pwm.c</code></strong></a></li>
|
||
</ul>
|
||
<p>To see the above PWM HAL Functions in action, check out the PWM Demo Source Code…</p>
|
||
<ul>
|
||
<li><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_pwm/sdk_app_pwm/main.c"><strong>PWM Demo Source Code: <code>main.c</code></strong></a></li>
|
||
</ul>
|
||
<h2 id="pwm-device-tree"><a class="doc-anchor" href="#pwm-device-tree">§</a>6.4 PWM Device Tree</h2>
|
||
<p>There is an alternative set of functions for controlling PWM…</p>
|
||
<ul>
|
||
<li><strong>PWM Device Tree</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/hal_pwm.h"><strong><code>hal_pwm.h</code></strong></a>, <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/hal_pwm.c"><strong><code>hal_pwm.c</code></strong></a></li>
|
||
</ul>
|
||
<p>These functions are meant to be used with the <strong>BL602 Device Tree</strong>.</p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#device-tree">More about BL602 Device Tree</a></p>
|
||
<h1 id="bl602-pwm-internals"><a class="doc-anchor" href="#bl602-pwm-internals">§</a>7 BL602 PWM Internals</h1>
|
||
<p>This helpful diagram from the <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_RM/en">BL602 Reference Manual</a> (Page 158) explains the internals of BL602’s PWM…</p>
|
||
<p><img src="https://lupyuen.github.io/images/led-pwm.png" alt="BL602 Pulse Width Modulation" /></p>
|
||
<p><em>BL602 Pulse Width Modulation</em></p>
|
||
<ol>
|
||
<li>
|
||
<p>BL602’s PWM uses an <strong>Internal Counter</strong> to generate a Sawtooth Wave</p>
|
||
</li>
|
||
<li>
|
||
<p>Each cycle of the Sawtooth Wave has a duration (<strong>PWM Period</strong>) that’s determined by the <strong>PWM Frequency</strong> (PWM Period = 1 / PWM Frequency)</p>
|
||
</li>
|
||
<li>
|
||
<p>The PWM Channel outputs 0 or 1 by comparing the Internal Counter with two values: <strong>PWM Threshold1</strong> (the lower limit) and <strong>PWM Threshold2</strong> (the upper limit)</p>
|
||
</li>
|
||
<li>
|
||
<p>We assume that <strong>PWM Threshold1 (the lower limit) is always 0</strong>. That’s because the BL602 PWM HAL Function <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.c#L126-L140"><code>bl_pwm_set_duty</code></a> always sets Threshold1 to 0.</p>
|
||
</li>
|
||
<li>
|
||
<p>What’s the value of PWM Threshold2 (the upper limit)? That’s computed based on the PWM Period and <strong>PWM Duty Cycle</strong>: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/components/hal_drv/bl602_hal/bl_pwm.c#L126-L140"><code>bl_pwm_set_duty</code></a></p>
|
||
<div class="example-wrap"><pre class="language-c"><code>// The Duty Cycle `duty` is between 0 to 100
|
||
threshold2 = ( period / 100 ) * duty;</code></pre></div>
|
||
<p>So when we increase the Duty Cycle, Threshold2 gets higher.</p>
|
||
</li>
|
||
<li>
|
||
<p>Here’s the PWM Output logic…</p>
|
||
<ul>
|
||
<li>
|
||
<p>When the <strong>Internal Counter is below Threshold2</strong>, the PWM Channel outputs <strong>1</strong>.</p>
|
||
</li>
|
||
<li>
|
||
<p>And when the <strong>Internal Counter is above Threshold2</strong>, the PWM Channel outputs <strong>0</strong>.</p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>What happens when we <strong>increase the Duty Cycle</strong>?</p>
|
||
<p>Threshold2 gets higher, hence the PWM Channel <strong>outputs 1 more often</strong>.</p>
|
||
</li>
|
||
<li>
|
||
<p>That’s precisely the definition of Duty Cycle…</p>
|
||
<p><strong>Duty Cycle</strong> is the percentage of time (0 to 100) within a Cycle that’s spent Working. (“Working” means Output=1)</p>
|
||
<p>Outside of the Duty Cycle, our PWM Channel is Idle. (Output=0)</p>
|
||
</li>
|
||
<li>
|
||
<p>Note that the Working vs Idle definition is <strong>flipped for our LED</strong>…</p>
|
||
<ul>
|
||
<li>
|
||
<p><strong>Working</strong> (Output=1) switches the <strong>LED OFF</strong></p>
|
||
</li>
|
||
<li>
|
||
<p><strong>Idle</strong> (Output=0) switches the <strong>LED ON</strong></p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Which explains this odd behaviour we’ve seen earlier…</p>
|
||
<ul>
|
||
<li>
|
||
<p>Higher Duty Cycle decreases our LED Brightness</p>
|
||
</li>
|
||
<li>
|
||
<p>Lower Duty Cycle increases our LED Brightness</p>
|
||
</li>
|
||
</ul>
|
||
<p>(Yep the Duty Cycle is Inversely Proportional to the LED Brightness)</p>
|
||
</li>
|
||
</ol>
|
||
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>8 What’s Next</h1>
|
||
<p>Today we have we have explored the GPIO and PWM HAL Functions through the BL602 IoT SDK.</p>
|
||
<p>Alternatively we may access BL602 GPIO Functions through another embedded operating system: <strong>Apache NuttX</strong>…</p>
|
||
<ul>
|
||
<li><a href="https://lupyuen.github.io/articles/nuttx#gpio-demo"><strong>“GPIO on NuttX”</strong></a></li>
|
||
</ul>
|
||
<p>Stay tuned for more NuttX!</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/RISCV/comments/krkm6g/control_pinecone_bl602_rgb_led_with_gpio_and_pwm/?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/led.md"><code>lupyuen.github.io/src/led.md</code></a></p>
|
||
<h1 id="appendix-fix-bl602-demo-firmware-for-macos"><a class="doc-anchor" href="#appendix-fix-bl602-demo-firmware-for-macos">§</a>9 Appendix: Fix BL602 Demo Firmware for macOS</h1>
|
||
<p><em>On macOS, why doesn’t <code>screen</code> work for accessing the BL602 Demo Firmware?</em></p>
|
||
<p>BL602 Demo Firmware configures the UART Port for 2 Mbps. (Which is not a standard POSIX baud rate)</p>
|
||
<p>This causes problems for POSIX serial apps (like <code>screen</code>) that don’t call macOS IOKit. <a href="https://twitter.com/madushan1000/status/1345352779502669824">See this</a></p>
|
||
<p>To fix this, use a newer serial app like <strong>CoolTerm</strong>…</p>
|
||
<ol>
|
||
<li>
|
||
<p><a href="https://freeware.the-meiers.org/"><strong>Download CoolTerm</strong></a></p>
|
||
</li>
|
||
<li>
|
||
<p>Click <strong><code>Options</code></strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Set <strong><code>Port</code></strong> to <strong><code>usbserial-1420</code></strong></p>
|
||
</li>
|
||
<li>
|
||
<p>Set <strong><code>Baudrate</code></strong> to <strong><code>2000000</code></strong> (2 Mbps)</p>
|
||
</li>
|
||
<li>
|
||
<p>Click <strong><code>Connect</code></strong></p>
|
||
</li>
|
||
</ol>
|
||
<p><img src="https://lupyuen.github.io/images/led-coolterm.png" alt="CoolTerm Options" /></p>
|
||
<p><a href="https://twitter.com/Kongduino/status/1358557946670551040">(Many thanks to @Kongduino)</a></p>
|
||
<p><em>What if we really really want to use POSIX serial apps like <code>screen</code>?</em></p>
|
||
<p>This is NOT recommended… But to support POSIX serial apps with macOS, we need to lower the UART baud rate from 2 Mbps to 230.4 kbps. (Which is a POSIX baud rate)</p>
|
||
<ol>
|
||
<li>
|
||
<p>In the BL602 Demo Firmware, edit the <code>main.c</code> source file, like…</p>
|
||
<ul>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_gpio/sdk_app_gpio/main.c#L266"><code>sdk_app_gpio/main.c</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_pwm/sdk_app_pwm/main.c#L599"><code>sdk_app_pwm/main.c</code></a></p>
|
||
</li>
|
||
<li>
|
||
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/master/customer_app/sdk_app_helloworld/sdk_app_helloworld/main.c#L80"><code>sdk_app_helloworld/main.c</code></a></p>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
<li>
|
||
<p>Look for this line that configures the UART port for 2 Mbps…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>bl_uart_init(0, 16, 7, 255, 255, 2 * 1000 * 1000);</code></pre></div>
|
||
<p>Change it to 230.4 kbps…</p>
|
||
<div class="example-wrap"><pre class="language-c"><code>bl_uart_init(0, 16, 7, 255, 255, 230400);</code></pre></div></li>
|
||
<li>
|
||
<p>Rebuild the firmware.</p>
|
||
</li>
|
||
<li>
|
||
<p>Edit the BL602 Device Tree: <a href="https://github.com/bouffalolab/BLOpenFlasher/blob/main/bl602/device_tree/bl_factory_params_IoTKitA_40M.dts"><code>bl_factory_params_IoTKitA_40M.dts</code></a></p>
|
||
<p>Look for…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code>uart {
|
||
#address-cells = <1>;
|
||
#size-cells = <1>;
|
||
uart@4000A000 {
|
||
status = "okay";
|
||
id = <0>;
|
||
compatible = "bl602_uart";
|
||
path = "/dev/ttyS0";
|
||
baudrate = <2000000>;</code></pre></div>
|
||
<p>Change <code>baudrate</code> to…</p>
|
||
<div class="example-wrap"><pre class="language-text"><code> baudrate = <230400>;</code></pre></div></li>
|
||
<li>
|
||
<p>Compile the Device Tree with BLOpenFlasher.</p>
|
||
<p>Copy the compiled Device Tree <code>ro_params.dtb</code> to <code>blflash</code></p>
|
||
<p>Flash the firmware to PineCone with <code>blflash</code></p>
|
||
<p><a href="https://lupyuen.github.io/articles/flash#blflash-vs-blopenflasher">More details</a></p>
|
||
</li>
|
||
<li>
|
||
<p>After flashing, set the PineCone Jumper IO8 to <code>L</code> Position. Press the Reset Button.</p>
|
||
<p>We should be able to access the Demo Firmware at 230.4 kbps…</p>
|
||
<div class="example-wrap"><pre class="language-bash"><code>screen /dev/tty.usbserial-1420 230400 </code></pre></div></li>
|
||
</ol>
|
||
|
||
|
||
<!-- 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> |