lupyuen.org/articles/pinedio.html

749 lines
No EOL
49 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>PineDio Stack BL604 RISC-V Board: Testing The Prototype</title>
<!-- Begin scripts/articles/*-header.html: Article Header for Custom Markdown files processed by rustdoc, like chip8.md -->
<meta property="og:title"
content="PineDio Stack BL604 RISC-V Board: Testing The Prototype"
data-rh="true">
<meta property="og:description"
content="What's it like to create Open Source Software for brand new prototype hardware? Read on to find out!"
data-rh="true">
<meta property="og:image"
content="https://lupyuen.github.io/images/pinedio-title.jpg">
<meta property="og:type"
content="article" data-rh="true">
<link rel="canonical" href="https://lupyuen.org/articles/pinedio.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">PineDio Stack BL604 RISC-V Board: Testing The Prototype</h1>
<nav id="rustdoc"><ul>
<li><a href="#connect-the-display" title="Connect The Display">1 Connect The Display</a><ul></ul></li>
<li><a href="#bl604-blinky" title="BL604 Blinky">2 BL604 Blinky</a><ul></ul></li>
<li><a href="#flash-firmware-to-bl604" title="Flash Firmware To BL604">3 Flash Firmware To BL604</a><ul></ul></li>
<li><a href="#bl604-spi" title="BL604 SPI">4 BL604 SPI</a><ul>
<li><a href="#initialise-spi-port" title="Initialise SPI Port">4.1 Initialise SPI Port</a><ul></ul></li>
<li><a href="#transfer-spi-data" title="Transfer SPI Data">4.2 Transfer SPI Data</a><ul></ul></li></ul></li>
<li><a href="#logic-analyser" title="Logic Analyser">5 Logic Analyser</a><ul></ul></li>
<li><a href="#spi-pins-are-swapped" title="SPI Pins Are Swapped">6 SPI Pins Are Swapped</a><ul></ul></li>
<li><a href="#st7789-display" title="ST7789 Display">7 ST7789 Display</a><ul></ul></li>
<li><a href="#9-bit-spi-for-st7789" title="9-Bit SPI for ST7789">8 9-Bit SPI for ST7789</a><ul>
<li><a href="#packing-9-bit-data" title="Packing 9-Bit Data">8.1 Packing 9-Bit Data</a><ul></ul></li>
<li><a href="#test-the-9-bit-packing" title="Test the 9-Bit Packing">8.2 Test the 9-Bit Packing</a><ul></ul></li>
<li><a href="#does-it-work" title="Does it work?">8.3 Does it work?</a><ul></ul></li></ul></li>
<li><a href="#arduino-gfx-ported-to-bl604" title="Arduino GFX Ported To BL604">9 Arduino GFX Ported To BL604</a><ul></ul></li>
<li><a href="#problem-with-st7789" title="Problem With ST7789?">10 Problem With ST7789?</a><ul></ul></li>
<li><a href="#seeking-volunteers" title="Seeking Volunteers!">11 Seeking Volunteers!</a><ul></ul></li>
<li><a href="#whats-next" title="Whats Next">12 Whats Next</a><ul></ul></li>
<li><a href="#notes" title="Notes">13 Notes</a><ul></ul></li>
<li><a href="#appendix-improvised-reset-button-for-pinedio-stack" title="Appendix: Improvised Reset Button for PineDio Stack">14 Appendix: Improvised Reset Button for PineDio Stack</a><ul></ul></li></ul></nav><p>📝 <em>29 Aug 2021</em></p>
<p><a href="https://lupyuen.github.io/articles/pinedio2"><strong>UPDATE: Theres a new version of PineDio Stack BL604, the GPIO Numbers have changed</strong></a></p>
<p><em>Whats it like to create <strong>Open Source Software</strong> (and firmware) for brand new <strong>Prototype Hardware</strong>?</em></p>
<p><em>What interesting challenges will we encounter?</em></p>
<p>Find out how we create new firmware to test (and improve) Pine64s newest and hottest prototype: <strong>PineDio Stack BL604 RISC-V Board!</strong></p>
<blockquote>
<p>⚠️ <em><strong>Obligatory Disclaimer:</strong> Features included in The Prototype are not complete, and will most certainly undergo changes before becoming available for public consumption. (Burp) They are described here for testing, exploration, education and entertainment purposes only. The Prototype shall NOT be used in production gadgets. (Like toasters, microwave ovens, and most definitely not, pressure cookers)</em></p>
</blockquote>
<p>The kind (and super cool) folks at Pine64 told me that I would be receiving a fun new gadget thats…</p>
<ol>
<li>
<p>Based on <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_DS/en"><strong>BL604 RISC-V + WiFi + Bluetooth LE SoC</strong></a>, which is the upsized sibling of <a href="https://lupyuen.github.io/articles/pinecone"><strong>Bouffalo Labs BL602 SoC</strong></a>.</p>
<p>(BL604 has 23 GPIOs vs BL602s 16 GPIOs. So its like comparing millipedes and centipedes, I guess)</p>
</li>
<li>
<p>And BL604 is supposed to be <strong>100% compatible with BL602</strong></p>
<p>(Is it really 100% compatible? Well find out in a while!)</p>
</li>
<li>
<p>Has an <strong>ST7789 SPI Display</strong></p>
<p>(Imagine the possibilities)</p>
</li>
<li>
<p>Has an onboard <strong>LoRa SX1262 Transceiver</strong> for low-power, long-range, low-bandwidth networking</p>
<p>(Wow!)</p>
</li>
<li>
<p>Plus <strong>SPI Flash, Battery Charging Chip, Accelerometer</strong> (optional) and <strong>Heart Rate Sensor</strong> (optional)!</p>
</li>
</ol>
<p>After some shipping delays at Shenzhen (due to flooding or pandemic?) I received something totally unexpected…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-solar.jpg" alt="Solar Panel?" /></p>
<p><strong>A Solar Panel!</strong></p>
<p>(Yeah Singapore is super sunny… Is this mockery? 🤔)</p>
<p>But a Solar Panel with a <strong>JTAG Cable</strong>? Thats highly unusual.</p>
<p>Opening the gadget reveals the hidden treasure inside: <a href="https://www.pine64.org/2021/08/15/introducing-the-pinenote/"><strong>PineDio Stack BL604 Board!</strong></a></p>
<p><img src="https://lupyuen.github.io/images/pinedio-inside.jpg" alt="Inside the Solar Panel: PineDio Stack BL604 Board" /></p>
<p>Thats typical of <strong>Prototype Hardware</strong> fresh from the factory: No docs, no fancy packaging, no branding either.</p>
<p>(Ground Plane is also missing, which well fix before FCC Certification)</p>
<p>We shall explore PineDio Stack ourselves… And <strong>document all our findings</strong> for the sake of the Open Source Community!</p>
<p><img src="https://lupyuen.github.io/images/pinedio-title.jpg" alt="PineDio Stack BL604 Board" /></p>
<h1 id="connect-the-display"><a class="doc-anchor" href="#connect-the-display">§</a>1 Connect The Display</h1>
<p><em>Whats on the underside of PineDio Stack?</em></p>
<p>Unscrewing the board (from the glue sticks?) reveals the <strong>LCD Display Connector</strong> on the underside of the board…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-back.jpg" alt="PineDio Stack Underside" /></p>
<p>The connector matches this familiar <strong>ST7789 SPI Display</strong> that was shipped with PineDio Stack…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-display3.jpg" alt="ST7789 SPI Display" /></p>
<p>So we snapped the ST7789 Display to the board…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-display4.jpg" alt="ST7789 Display connected to PineDio Stack" /></p>
<p>And we get an unusual contraption: A <strong>Solar Panel with LCD Display inside</strong>!</p>
<p><img src="https://lupyuen.github.io/images/pinedio-display5.jpg" alt="Solar Panel with an LCD Display inside" /></p>
<p>Were ready to test our firmware on PineDio Stack! Well follow this schematic…</p>
<ul>
<li><a href="https://wiki.pine64.org/wiki/Pinedio#PineDio_Stack"><strong>PineDio Stack Schematic (Prototype)</strong></a></li>
</ul>
<h1 id="bl604-blinky"><a class="doc-anchor" href="#bl604-blinky">§</a>2 BL604 Blinky</h1>
<p><em>Whats the first thing that we run on a brand new prototype board?</em></p>
<p><strong>Blinky Firmware</strong> of course! (Yep the firmware that blinks the LED)</p>
<div class="example-wrap"><pre class="language-c"><code>/// PineDio Stack LCD Backlight is connected on GPIO 21
#define LED_GPIO 21
/// Blink the LED
void blinky(char *buf, int len, int argc, char **argv) {
// Show a message on the serial console
puts(&quot;Hello from Blinky!&quot;);
// Configure the LED GPIO for output (instead of input)
int rc = bl_gpio_enable_output(
LED_GPIO, // GPIO pin number
0, // No GPIO pullup
0 // No GPIO pulldown
);
assert(rc == 0); // Halt on error
// Blink the LED 5 times
for (int i = 0; i &lt; 10; i++) {
// Toggle the LED GPIO between 0 (on) and 1 (off)
rc = bl_gpio_output_set( // Set the GPIO output (from BL602 GPIO HAL)
LED_GPIO, // GPIO pin number
i % 2 // 0 for low, 1 for high
);
assert(rc == 0); // Halt on error
// Sleep 1 second
time_delay( // Sleep by number of ticks (from NimBLE Porting Layer)
time_ms_to_ticks32(1000) // Convert 1,000 milliseconds to ticks (from NimBLE Porting Layer)
);
}
// Return to the command-line interface
}</code></pre></div>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_blinky/pinedio_blinky/demo.c">(Source)</a></p>
<p>This BL604 Blinky code is <strong>100% identical</strong> to the <a href="https://lupyuen.github.io/articles/rust#bl602-blinky-in-c">BL602 version of Blinky</a>. Except for the GPIO Pin Number…</p>
<div class="example-wrap"><pre class="language-c"><code>/// PineDio Stack LCD Backlight is connected on GPIO 21
#define LED_GPIO 21</code></pre></div>
<p>(Were blinking the Backlight of the ST7789 Display)</p>
<p>We <strong>build the BL604 Blinky Firmware</strong> the exact same way as BL602…</p>
<div class="example-wrap"><pre class="language-bash"><code>## Download the 3wire branch of lupyuen&#39;s bl_iot_sdk
git clone --recursive --branch 3wire https://github.com/lupyuen/bl_iot_sdk
cd customer_app/pinedio_blinky
## Build for BL602 (Should this be BL604?)
export CONFIG_CHIP_NAME=BL602
## Where BL602 / BL604 IoT SDK is located
export BL60X_SDK_PATH=$PWD/../..
## Build the firmware: build_out/pinedio_blinky.bin
make</code></pre></div>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_blinky/run.sh">(Source)</a></p>
<p>Lets flash the firmware to the board!</p>
<h1 id="flash-firmware-to-bl604"><a class="doc-anchor" href="#flash-firmware-to-bl604">§</a>3 Flash Firmware To BL604</h1>
<p>We <strong>flash the BL604 Blinky Firmware</strong> the exact same way as BL602…</p>
<ol>
<li>
<p><strong>Remove the battery</strong> from the Solar Panel</p>
<p>(Because well reboot the board during flashing)</p>
</li>
<li>
<p>Switch to <strong>Flashing Mode</strong></p>
<p>Flip the <strong>GPIO 8 Jumper</strong> to <strong>High</strong></p>
<p><a href="https://lupyuen.github.io/images/pinedio-high.jpg">(See this)</a></p>
</li>
<li>
<p><strong>Connect the board</strong> to our computers USB Port</p>
</li>
<li>
<p><strong>Run <code>blflash</code></strong> to flash this firmware file…</p>
<div class="example-wrap"><pre class="language-text"><code>build_out/pinedio_blinky.bin</code></pre></div>
<p><a href="https://lupyuen.github.io/articles/flash#flash-the-firmware">(More about <code>blflash</code>)</a></p>
</li>
</ol>
<p>To <strong>run the BL604 Blinky Firmware</strong></p>
<ol>
<li>
<p><strong>Disconnect the board</strong> from the USB Port</p>
</li>
<li>
<p>Switch to <strong>Normal Mode</strong></p>
<p>Flip the <strong>GPIO 8 Jumper</strong> to <strong>Low</strong></p>
<p><a href="https://lupyuen.github.io/images/pinedio-low.jpg">(See this)</a></p>
</li>
<li>
<p><strong>Connect the board</strong> to the USB Port</p>
</li>
<li>
<p><strong>Open a Serial Terminal</strong> and connect to the BL604 UART Port at <strong>2 Mbps</strong></p>
<p>Use <strong>screen</strong> (Linux), <strong>CoolTerm</strong> (macOS) or <strong>putty</strong> (Windows)</p>
<p>(Or use the Web Serial Terminal)</p>
<p><a href="https://lupyuen.github.io/articles/flash#watch-the-firmware-run">(Instructions here)</a></p>
</li>
<li>
<p>At the BL604 Command Prompt, enter…</p>
<div class="example-wrap"><pre class="language-text"><code>blinky</code></pre></div>
<p>And the Backlight blinks!</p>
<p><a href="https://youtu.be/vdRqhQ08uxU"><strong>Watch the Demo Video on YouTube</strong></a></p>
</li>
</ol>
<p><a href="https://lupyuen.github.io/articles/pinedio#appendix-improvised-reset-button-for-pinedio-stack">(PineDio Stack doesnt have a Reset Button, but we can make one)</a></p>
<p>Now that the Backlight GPIO is OK, lets test something more sophisticated: SPI!</p>
<p><img src="https://lupyuen.github.io/images/pinedio-zoom.jpg" alt="PineDio Stack BL604 with LoRa SX1262 Transceiver" /></p>
<h1 id="bl604-spi"><a class="doc-anchor" href="#bl604-spi">§</a>4 BL604 SPI</h1>
<p><em>Why test SPI on PineDio Stack?</em></p>
<p>Because SPI is the Data Bus that <strong>connects the key components</strong> of PineDio Stack…</p>
<ol>
<li>
<p><strong>SPI Flash</strong></p>
</li>
<li>
<p><strong>ST7789 Display</strong></p>
</li>
<li>
<p><strong>LoRa SX1262 Transceiver</strong></p>
</li>
</ol>
<p><img src="https://lupyuen.github.io/images/pinedio-spi.jpg" alt="SPI Bus on PineDio Stack" /></p>
<div><table><thead><tr><th style="text-align: center">GPIO Number</th><th style="text-align: left">SPI Pin</th></tr></thead><tbody>
<tr><td style="text-align: center"><strong><code>17</code></strong></td><td style="text-align: left">Common SDO <em>(MOSI)</em></td></tr>
<tr><td style="text-align: center"><strong><code>0</code></strong></td><td style="text-align: left">Common SDI <em>(MISO)</em></td></tr>
<tr><td style="text-align: center"><strong><code>11</code></strong></td><td style="text-align: left">Common SCK</td></tr>
<tr><td style="text-align: center"><strong><code>14</code></strong></td><td style="text-align: left">CS for SPI Flash</td></tr>
<tr><td style="text-align: center"><strong><code>20</code></strong></td><td style="text-align: left">CS for ST7789</td></tr>
<tr><td style="text-align: center"><strong><code>15</code></strong></td><td style="text-align: left">CS for SX1262</td></tr>
</tbody></table>
</div>
<p><a href="https://lupyuen.github.io/articles/pinedio2"><strong>UPDATE: Theres a new version of PineDio Stack BL604, the GPIO Numbers have changed</strong></a></p>
<p>SPI Flash, ST7789 and SX1262 are connected to the <strong>same GPIO Pins</strong> for SDO <em>(formerly MOSI)</em>, SDI <em>(formerly MISO)</em> and SCK.</p>
<p><a href="https://www.oshwa.org/a-resolution-to-redefine-spi-signal-names">(More about SDO and SDI)</a></p>
<p><em>But wont BL604 get confused by the SPI crosstalk?</em></p>
<p>Nope because SPI Flash, ST7789 and SX1262 are connected to <strong>different Chip Select Pins</strong>.</p>
<p>When our firmware talks to an SPI Peripheral (like ST7789), we shall set the peripherals <strong>Chip Select Pin</strong> to <strong>Low</strong>.</p>
<p>(Our firmware shall set the Chip Select Pins to High when idle)</p>
<p><em>How shall we code the firmware for testing SPI?</em></p>
<p>The same way as BL602… By calling the <strong>BL602 / BL604 IoT SDK</strong>!</p>
<p>We start by <strong>defining the Shared GPIOs</strong> for the SPI Peripherals: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/display.h#L45-L70"><code>pinedio_st7789/display.h</code></a></p>
<div class="example-wrap"><pre class="language-c"><code>/// GPIO for ST7789 / SX1262 / SPI Flash SDO (MOSI)
#define DISPLAY_MOSI_PIN 17
/// GPIO for ST7789 / SX1262 / SPI Flash SDI (MISO)
#define DISPLAY_MISO_PIN 0
/// GPIO for ST7789 / SX1262 / SPI Flash SCK
#define DISPLAY_SCK_PIN 11</code></pre></div>
<p>Followed by the <strong>Chip Select GPIOs</strong> for each SPI Peripheral…</p>
<div class="example-wrap"><pre class="language-c"><code>/// GPIO for SPI Flash Chip Select. We must set this to High to deselect SPI Flash.
#define FLASH_CS_PIN 14
/// GPIO for SX1262 SPI Chip Select. We must set this to High to deselect SX1262.
#define SX1262_CS_PIN 15
/// GPIO for ST7789 SPI Chip Select. We control Chip Select ourselves via GPIO, not SPI.
#define DISPLAY_CS_PIN 20</code></pre></div>
<p>The SPI Functions from the BL604 IoT SDK need us to specify a Chip Select GPIO.</p>
<p>Since were <strong>controlling Chip Select ourselves</strong>, well assign <strong>GPIO 8</strong> as the Unused Chip Select…</p>
<div class="example-wrap"><pre class="language-c"><code>/// GPIO for unused SPI Chip Select Pin. Unused because we control Chip Select ourselves via GPIO, not SPI.
#define DISPLAY_UNUSED_CS_PIN 8
/// For Debug Only: GPIO for SPI Chip Select Pin that is exposed on GPIO Connector and can be connected to Logic Analyser
#define DISPLAY_DEBUG_CS_PIN 5
/// GPIO for Backlight
#define DISPLAY_BLK_PIN 21</code></pre></div>
<p>(GPIO 8 selects the Flashing Mode when BL604 is booting, so GPIO 8 is normally unused)</p>
<p>We use <strong>GPIO 5</strong> to mirror the GPIO High / Low State of GPIO 20 (ST7789 Chip Select). More about this in a while.</p>
<h2 id="initialise-spi-port"><a class="doc-anchor" href="#initialise-spi-port">§</a>4.1 Initialise SPI Port</h2>
<p>Lets initialise the SPI Port before sending data: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/demo.c#L53-L117"><code>pinedio_st7789/demo.c</code></a></p>
<div class="example-wrap"><pre class="language-c"><code>/// Command to init the display
static void test_display_init(char *buf, int len, int argc, char **argv) {
// Configure Chip Select, Backlight pins as GPIO Output Pins (instead of GPIO Input)
int rc;
rc = bl_gpio_enable_output(DISPLAY_BLK_PIN, 0, 0); assert(rc == 0);
rc = bl_gpio_enable_output(DISPLAY_CS_PIN, 0, 0); assert(rc == 0);
rc = bl_gpio_enable_output(FLASH_CS_PIN, 0, 0); assert(rc == 0);
rc = bl_gpio_enable_output(SX1262_CS_PIN, 0, 0); assert(rc == 0);
rc = bl_gpio_enable_output(DISPLAY_DEBUG_CS_PIN, 0, 0); assert(rc == 0);</code></pre></div>
<p>First we configure the <strong>Chip Select GPIOs for GPIO Output</strong> (instead of GPIO Input).</p>
<p>Next we <strong>set the Chip Select GPIOs to High</strong> to deselect all SPI Peripherals…</p>
<div class="example-wrap"><pre class="language-c"><code> // Set Chip Select pins to High, to deactivate SPI Flash, SX1262 and ST7789
rc = bl_gpio_output_set(FLASH_CS_PIN, 1); assert(rc == 0);
rc = bl_gpio_output_set(SX1262_CS_PIN, 1); assert(rc == 0);
rc = bl_gpio_output_set(DISPLAY_CS_PIN, 1); assert(rc == 0);
rc = bl_gpio_output_set(DISPLAY_DEBUG_CS_PIN, 1); assert(rc == 0);
// Switch on the backlight
rc = bl_gpio_output_set(DISPLAY_BLK_PIN, 0); assert(rc == 0);
// Note: We must swap SDO (MOSI) and
// SDI (MISO) to comply with the
// SPI Pin Definitions in BL602 / BL604
// Reference Manual
rc = GLB_Swap_SPI_0_MOSI_With_MISO(ENABLE); assert(rc == 0);</code></pre></div>
<p>(Well cover <code>GLB_Swap_SPI</code> in a while)</p>
<p>Finally we <strong>configure the SPI Port</strong></p>
<div class="example-wrap"><pre class="language-c"><code> // Configure the SPI Port
rc = spi_init(
&amp;spi_device, // SPI Device
SPI_PORT, // SPI Port
0, // SPI Mode: 0 for Controller (formerly Master), 1 for Peripheral (formerly Slave)
0, // SPI Polar Phase. Valid values: 0 (CPOL=0, CPHA=0), 1 (CPOL=0, CPHA=1), 2 (CPOL=1, CPHA=0) or 3 (CPOL=1, CPHA=1)
1 * 1000 * 1000, // SPI Frequency (1 MHz, reduce this in case of problems)
2, // Transmit DMA Channel
3, // Receive DMA Channel
DISPLAY_SCK_PIN, // SPI Clock Pin
DISPLAY_UNUSED_CS_PIN, // Unused SPI Chip Select Pin (Unused because we control the GPIO ourselves as Chip Select Pin)
DISPLAY_MOSI_PIN, // SPI Serial Data Out Pin (formerly MOSI)
DISPLAY_MISO_PIN // SPI Serial Data In Pin (formerly MISO) (Unused for ST7789)
);
assert(rc == 0);
// Note: DISPLAY_UNUSED_CS_PIN must NOT be the same as DISPLAY_CS_PIN.
// Because the SPI Pin Function will override the GPIO Pin Function!</code></pre></div>
<p>Were ready to transfer data over SPI!</p>
<p><a href="https://lupyuen.github.io/articles/spi#spi_init-init-spi-port">(More about <code>spi_init</code>)</a></p>
<h2 id="transfer-spi-data"><a class="doc-anchor" href="#transfer-spi-data">§</a>4.2 Transfer SPI Data</h2>
<p>Heres how we transfer data (transmit + receive) over SPI: <a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/display.c#L465-L520"><code>pinedio_st7789/display.c</code></a></p>
<div class="example-wrap"><pre class="language-c"><code>/// Write packed data to the SPI port. `data` is the array of bytes to be written. `len` is the number of bytes.
static int transmit_packed(const uint8_t *data, uint16_t len) {
// Clear the receive buffer
memset(&amp;spi_rx_buf, 0, sizeof(spi_rx_buf));
// Prepare SPI Transfer
static spi_ioc_transfer_t transfer;
memset(&amp;transfer, 0, sizeof(transfer));
transfer.tx_buf = (uint32_t) data; // Transmit Buffer
transfer.rx_buf = (uint32_t) spi_rx_buf; // Receive Buffer
transfer.len = len; // How many bytes</code></pre></div>
<p>Here we specify the <strong>Transmit Buffer and Receive Buffer</strong> for the SPI transfer.</p>
<p>Next we <strong>set Chip Select GPIO to Low</strong> to select the SPI Peripheral (ST7789 Display)…</p>
<div class="example-wrap"><pre class="language-c"><code> // Select the SPI Peripheral
int rc;
rc = bl_gpio_output_set(DISPLAY_CS_PIN, 0); assert(rc == 0);
rc = bl_gpio_output_set(DISPLAY_DEBUG_CS_PIN, 0); assert(rc == 0);</code></pre></div>
<p>Then we <strong>start the SPI Transfer</strong> (transmit + receive) and wait for it to complete…</p>
<div class="example-wrap"><pre class="language-c"><code> // Execute the SPI Transfer with the DMA Controller
rc = hal_spi_transfer(
&amp;spi_device, // SPI Device
&amp;transfer, // SPI Transfers
1 // How many transfers (Number of requests, not bytes)
);
assert(rc == 0);
// DMA Controller will transmit and receive the SPI data in the background.
// hal_spi_transfer will wait for the SPI Transfer to complete before returning.</code></pre></div>
<p>Finally we <strong>set Chip Select GPIO to Low</strong> to deselect the SPI Peripheral (ST7789 Display)…</p>
<div class="example-wrap"><pre class="language-c"><code> // Now that we&#39;re done with the SPI Transfer...
// Deselect the SPI Peripheral
rc = bl_gpio_output_set(DISPLAY_CS_PIN, 1); assert(rc == 0);
rc = bl_gpio_output_set(DISPLAY_DEBUG_CS_PIN, 1); assert(rc == 0);
return 0;
}</code></pre></div>
<p>Thats how we transmit and receive data over SPI!</p>
<p><em>Why did we use BL604s Direct Memory Access (DMA) Controller for the SPI Transfer?</em></p>
<p>Because we want the SPI Transfer to be <strong>executed in the background</strong>, freeing up the CPU for other concurrent tasks.</p>
<p>BL604s <strong>DMA Controller executes the SPI Transfer</strong> on behalf of the CPU, shuffling data between the Transmit / Receive Buffers and the SPI Peripheral (ST7789).</p>
<p><a href="https://lupyuen.github.io/articles/spi#spi-with-direct-memory-access">(More about DMA)</a></p>
<p><em>What is <code>DISPLAY_DEBUG_CS_PIN</code>? Why is it mirroring <code>DISPLAY_CS_PIN</code>?</em></p>
<p>Yep everything we do to <code>DISPLAY_CS_PIN</code> (GPIO 20), we do the same to <code>DISPLAY_DEBUG_CS_PIN</code> (GPIO 5).</p>
<p>Well learn why in the next chapter.</p>
<p><img src="https://lupyuen.github.io/images/pinedio-logic.jpg" alt="PineDio Stack with Logic Analyser" /></p>
<h1 id="logic-analyser"><a class="doc-anchor" href="#logic-analyser">§</a>5 Logic Analyser</h1>
<p><em>When testing Prototype Hardware… Always have a Logic Analyser ready! (Pic above)</em></p>
<p>Why? Because well hit a baffling signalling problem when we test SPI on PineDio Stack.</p>
<p><em>How do we capture the data transferred over the SPI Port?</em></p>
<p>PineDio Stacks <strong>GPIO Connector</strong> (at right) exposes the SPI Pins: SDO <em>(formerly MOSI)</em>, SDI <em>(formerly MISO)</em> and SCK</p>
<p><img src="https://lupyuen.github.io/images/pinedio-gpio2.jpg" alt="PineDio Stack GPIO Connector" /></p>
<p>We <strong>connect our Logic Analyser</strong> to the GPIO Connector like so…</p>
<div><table><thead><tr><th style="text-align: center">GPIO Number</th><th style="text-align: left">SPI Pin</th><th style="text-align: center">Connector Pin</th></tr></thead><tbody>
<tr><td style="text-align: center"><strong><code>17</code></strong></td><td style="text-align: left">Common SDO <em>(MOSI)</em></td><td style="text-align: center"><code>7</code></td></tr>
<tr><td style="text-align: center"><strong><code>0</code></strong></td><td style="text-align: left">Common SDI <em>(MISO)</em></td><td style="text-align: center"><code>17</code></td></tr>
<tr><td style="text-align: center"><strong><code>11</code></strong></td><td style="text-align: left">Common SCK</td><td style="text-align: center"><code>4</code></td></tr>
<tr><td style="text-align: center"><strong><code>5</code></strong></td><td style="text-align: left">Debug CS</td><td style="text-align: center"><code>2</code></td></tr>
</tbody></table>
</div>
<p><a href="https://lupyuen.github.io/articles/pinedio2"><strong>UPDATE: Theres a new version of PineDio Stack BL604, the GPIO Numbers have changed</strong></a></p>
<p><img src="https://lupyuen.github.io/images/pinedio-logic2.jpg" alt="Logic Analyser connected to PineDio Stack" /></p>
<p><em>What about the ST7789 Chip Select Pin: GPIO 20?</em></p>
<p>Unfortunately <strong>GPIO 20 is not exposed</strong> on the GPIO Connector.</p>
<p>But remember: Everything we do to GPIO 20, we <strong>do the same to GPIO 5!</strong></p>
<p><strong>GPIO 5 is exposed</strong> on the GPIO Connector and it mirrors the GPIO High / Low state of GPIO 20.</p>
<p>Thus we simply connect our Logic Analyser to <strong>GPIO 5 as the Chip Select Pin!</strong> (Pic above)</p>
<p>Lets look at the data collected by our Logic Analyser…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-shadow.png" alt="GPIO 20 is mirrored to GPIO 5" /></p>
<h1 id="spi-pins-are-swapped"><a class="doc-anchor" href="#spi-pins-are-swapped">§</a>6 SPI Pins Are Swapped</h1>
<p><em>What appears in the Logic Analyser when BL604 transmits data over SPI?</em></p>
<p>Watch what happened the very first time that we transmitted SPI data from BL604 to ST7789 Display…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-mosi.png" alt="SDO (MOSI) is flat" /></p>
<p>The top line showed that <strong>SDO <em>(MOSI)</em> was flat</strong></p>
<p><strong>No data was flowing out</strong> from BL604 to ST7789 Display!</p>
<p>Though SDI <em>(MISO)</em> looked OK…</p>
<p><em>Maybe SDO and SDI were swapped?</em></p>
<p>Thankfully <a href="https://twitter.com/codingfield/status/1430605933714059273"><strong>JF found the fix</strong></a>!</p>
<div class="example-wrap"><pre class="language-c"><code>// Note: We must swap SDO (MOSI) and
// SDI (MISO) to comply with the
// SPI Pin Definitions in BL602 / BL604
// Reference Manual
int rc = GLB_Swap_SPI_0_MOSI_With_MISO(ENABLE); assert(rc == 0);</code></pre></div>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/demo.c#L53-L117">(Source)</a></p>
<p>After applying the fix, BL604 swaps the SDO and SDI pins… And <strong>BL604 transmits SPI data correctly to ST7789</strong>!</p>
<p><img src="https://lupyuen.github.io/images/pinedio-swap3.png" alt="SDO (MOSI) is OK!" /></p>
<p><em>But the <a href="https://github.com/bouffalolab/bl_docs/tree/main/BL602_RM/en">BL604 Reference Manual</a> says that GPIO 17 is SDO (MOSI)… Not SDI (MISO) right?</em></p>
<p><img src="https://lupyuen.github.io/images/pinedio-swap4.png" alt="GPIO 17 is SDO (MOSI)" /></p>
<p>Yeah the BL604 Reference Manual says that GPIO 17 is SDO <em>(MOSI)</em>… So we shouldnt need to call <strong>GLB_Swap_SPI_0_MOSI_With_MISO</strong> to swap the pins.</p>
<p>But since PineDio Stack was designed for GPIO 17 as SDO <em>(MOSI)</em>, well have to <strong>call GLB_Swap_SPI_0_MOSI_With_MISO in our firmware</strong> to make SPI work.</p>
<p><em>This SPI Pin Swap Problem sounds familiar…?</em></p>
<p>Yep if youve been following my BL602 Adventures, weve seen this <strong>SPI Pin Swap Problem on BL602</strong></p>
<ul>
<li><a href="https://lupyuen.github.io/articles/spi#spi-data-pins-are-flipped"><strong>“SPI Data Pins are flipped”</strong></a></li>
</ul>
<p>Hence Im happy to confirm: <strong>BL604 is 100% compatible with BL602</strong>… Right down to the SPI Quirks!</p>
<p><em>How does this SPI Pin Swap Problem affect PineDio Stack Developers?</em></p>
<p>To work around the SPI Pin Swap Problem…</p>
<p>All PineDio Stack Developers should ensure that <strong>GLB_Swap_SPI_0_MOSI_With_MISO is always called</strong> before initialising the SPI Port.</p>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/demo.c#L53-L117">(Heres an example)</a></p>
<p><img src="https://lupyuen.github.io/images/pinedio-display2.jpg" alt="PineDio Stack ST7789 Display" /></p>
<h1 id="st7789-display"><a class="doc-anchor" href="#st7789-display">§</a>7 ST7789 Display</h1>
<p>Now that PineDio Stack SPI is OK, lets <strong>draw something on the ST7789 Display</strong>!</p>
<p>According to the PineDio Stack Schematic…</p>
<ul>
<li><a href="https://wiki.pine64.org/wiki/Pinedio#PineDio_Stack"><strong>PineDio Stack Schematic (Prototype)</strong></a></li>
</ul>
<p>The ST7789 SPI Display is connected on these pins…</p>
<ul>
<li>
<p><strong>GPIO 20:</strong> SPI Chip Select</p>
</li>
<li>
<p><strong>GPIO 0:</strong> SPI SDI <em>(MISO)</em></p>
</li>
<li>
<p><strong>GPIO 11:</strong> SPI SCK</p>
</li>
<li>
<p><strong>GPIO 17:</strong> SPI SDO <em>(MOSI)</em></p>
</li>
</ul>
<p><a href="https://lupyuen.github.io/articles/pinedio2"><strong>UPDATE: Theres a new version of PineDio Stack BL604, the GPIO Numbers have changed</strong></a></p>
<p><em>Wait are we missing a pin?</em></p>
<p>Yep we usually connect the <strong>ST7789 Data / Command (DC) Pin</strong>. (Like on PineTime)</p>
<p>We flip this pin to Low to indicate that were sending Command Bytes, and flip it to High for Data Bytes.</p>
<p>We call this the <strong>4-Wire Interface</strong> for ST7789: SDO, SDI, SCK and DC.</p>
<p><em>Data / Command (DC) Pin is missing on PineDio Stack. So were using the 3-Wire Interface?</em></p>
<p>Yep ST7789 supports a <strong>3-Wire Interface</strong>: SDO, SDI and SCK. (Without DC)</p>
<p><img src="https://lupyuen.github.io/images/pinedio-3wire.png" alt="ST7789 3-Wire Interface" /></p>
<p><a href="https://www.rhydolabz.com/documents/33/ST7789.pdf">(Source)</a></p>
<p>Instead of transmitting the Data / Command Indicator on a separate pin, the 3-Wire Interface inserts a <strong>Data / Command (DC) Bit</strong> to specify whether the <strong>upcoming byte is a Command or Data Byte</strong>.</p>
<p>(DC Bit is 1 for Command Byte, 0 for Data Byte)</p>
<p><em>Whoa that means we transmit 9 bits for every Data and Command Byte?</em></p>
<p>Yep we need to find some way to <strong>transmit 9-bit data over our 8-bit SPI Port</strong>.</p>
<p>The 3-Wire (9-bit) Interface might actually be <strong>more efficient</strong> than the 4-Wire (8-bit) Interface… Because it lets us blast out multiple Command and Data Bytes in a <strong>single SPI DMA Transfer</strong>.</p>
<p>(Without having to flip the Data / Command Pin)</p>
<p>More about this in the next chapter.</p>
<p><em>Why cant we stick with the familiar 4-Wire Interface for ST7789?</em></p>
<p>I guess the PineDio Stack hardware designers wanted to <strong>free up a precious GPIO Pin</strong> for use by other components.</p>
<p>(And maybe the designers also thought that the 3-Wire Interface is more efficient than the 4-Wire one!)</p>
<h1 id="9-bit-spi-for-st7789"><a class="doc-anchor" href="#9-bit-spi-for-st7789">§</a>8 9-Bit SPI for ST7789</h1>
<p><em>How on earth do we send 9-bit data over 8-bit SPI to ST7789 Display?</em></p>
<p>OK hear me out… We could pack the 9-bit data into <strong>chunks of 9 bytes.</strong> Then send the chunks over 8-bit SPI.</p>
<p>(Why 9 bytes? Because 9 bytes = 9 bits x 8)</p>
<p><em>What if the 9-bit data doesnt fill up a 9-byte chunk?</em></p>
<p>We fill up the rest of the chunk with the <strong>ST7789 NOP Command Byte</strong> (0x00).</p>
<p><em>Show me how?</em></p>
<p>Previously we did this for the <strong>4-Wire (8-bit) ST7789 Interface</strong></p>
<p><img src="https://lupyuen.github.io/images/st7789-4wire.jpg" alt="4-Wire ST7789 Interface" /></p>
<p>Now we do this for the <strong>3-Wire (9-bit) ST7789 Interface</strong></p>
<p><img src="https://lupyuen.github.io/images/st7789-3wire.jpg" alt="3-Wire ST7789 Interface" /></p>
<p>Thus were sending <strong>8-bit data over SPI</strong>… But it magically appears as <strong>9-bit data to ST7789!</strong></p>
<h2 id="packing-9-bit-data"><a class="doc-anchor" href="#packing-9-bit-data">§</a>8.1 Packing 9-Bit Data</h2>
<p><em>How exactly do we pack 9-bit data into chunks of 9 bytes?</em></p>
<p>Heres the <strong>9-Bit Packing Logic</strong> (please pardon my peculiar pseudocode)…</p>
<p>To pack 9-bit data into bytes, we do this for every 8 bytes of unpacked data (Most Significant Bit first)…</p>
<blockquote>
<p>If <em>Unpacked Length mod 8</em> is…</p>
</blockquote>
<blockquote>
<p><em>0:</em> <br>
<strong>DC</strong><strong>P0</strong> bit 7 <br>
<strong>U</strong> bits 1 to 7 → <strong>P0</strong> bits 0 to 6 <br>
<strong>U</strong> bits 0 to 0 → <strong>P1</strong> bits 7 to 7 <br></p>
</blockquote>
<blockquote>
<p><em>1:</em> <br>
<strong>DC</strong><strong>P0</strong> bit 6 <br>
<strong>U</strong> bits 2 to 7 → <strong>P0</strong> bits 0 to 5 <br>
<strong>U</strong> bits 0 to 1 → <strong>P1</strong> bits 6 to 7 <br></p>
</blockquote>
<blockquote>
<p><em>2:</em> <br>
<strong>DC</strong><strong>P0</strong> bit 5 <br>
<strong>U</strong> bits 3 to 7 → <strong>P0</strong> bits 0 to 4 <br>
<strong>U</strong> bits 0 to 2 → <strong>P1</strong> bits 5 to 7 <br></p>
</blockquote>
<blockquote>
<p></p>
</blockquote>
<blockquote>
<p><em>6:</em> <br>
<strong>DC</strong><strong>P0</strong> bit 1 <br>
<strong>U</strong> bits 7 to 7 → <strong>P0</strong> bits 0 to 0 <br>
<strong>U</strong> bits 0 to 6 → <strong>P1</strong> bits 1 to 7 <br></p>
</blockquote>
<blockquote>
<p><em>7:</em> <br>
<strong>DC</strong><strong>P0</strong> bit 0 <br>
<strong>U</strong> bits 0 to 7 → <strong>P1</strong> bits 0 to 7 <br></p>
</blockquote>
<p>Where…</p>
<ul>
<li><strong>DC</strong> is the Data / Command bit (0 = command, 1 = data)</li>
<li><strong>U</strong> is the unpacked 8-bit data byte</li>
<li><strong>P0</strong> is the current byte of the packed data</li>
<li><strong>P1</strong> is the next byte of the packed data</li>
</ul>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/display.c#L290-L395">(Source)</a></p>
<p>The implementation looks like this…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-pack2.png" alt="Packing 9-bit data" /></p>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789/pinedio_st7789/display.c#L290-L395">(Source)</a></p>
<h2 id="test-the-9-bit-packing"><a class="doc-anchor" href="#test-the-9-bit-packing">§</a>8.2 Test the 9-Bit Packing</h2>
<p>Since the 9-Bit Packing is implemented in C, lets <strong>test it on Linux!</strong></p>
<p><img src="https://lupyuen.github.io/images/pinedio-linux.png" alt="Test the 9-Bit Packing on Linux" /></p>
<p>We <strong>verify the packed data</strong> with this spreadsheet…</p>
<ul>
<li><a href="https://docs.google.com/spreadsheets/d/1Qy0MjU79s__wzTAFwpTYUUIzLWcrFnKCrvvo_rHamiE/edit?usp=sharing&amp;authuser=0"><strong>Google Sheets Spreadsheet</strong></a></li>
</ul>
<p><img src="https://lupyuen.github.io/images/pinedio-spreadsheet.png" alt="Verify the packed data with a spreadsheet" /></p>
<h2 id="does-it-work"><a class="doc-anchor" href="#does-it-work">§</a>8.3 Does it work?</h2>
<p>Sadly nope.</p>
<p><img src="https://lupyuen.github.io/images/pinedio-pack3.jpg" alt="Sending packed data to ST7789 on PineDio Stack" /></p>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789">(Source Code is here)</a></p>
<p>Our <strong>9-bit data is correctly packed</strong> into 9-byte chunks and sent to ST7789 over SPI…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-pad.png" alt="Sending packed data to ST7789 on PineDio Stack" /></p>
<p>Yet <strong>nothing appears on the ST7789 Display</strong>.</p>
<p>We also verified the SPI Data with our Logic Analyser and its <strong>9-bit SPI Decoder</strong></p>
<p><img src="https://lupyuen.github.io/images/pinedio-3wire2.png" alt="Logic Analyser with 9-bit SPI Decoder" /></p>
<h1 id="arduino-gfx-ported-to-bl604"><a class="doc-anchor" href="#arduino-gfx-ported-to-bl604">§</a>9 Arduino GFX Ported To BL604</h1>
<p><em>Are we being too smarty-pants with 9-bit SPI? Like <a href="https://en.wiktionary.org/wiki/%E7%95%AB%E8%9B%87%E6%B7%BB%E8%B6%B3">adding feet to a drawing of a snake</a>?</em></p>
<p>Lets talk to ST7789 the simpler way… With <a href="https://en.wikipedia.org/wiki/Bit_banging"><strong>Bit-Banging</strong></a>! (Instead of SPI)</p>
<p><a href="https://github.com/moononournation"><strong>moononournation</strong></a> has built an awesome <strong>Arduino GFX Library that supports 9-Bit-Banging</strong> to ST7789 Display…</p>
<ul>
<li><a href="https://github.com/moononournation/Arduino_GFX"><strong>moononournation / Arduino_GFX</strong></a></li>
</ul>
<p>Lets <strong>port this Arduino Library to BL604!</strong></p>
<p><img src="https://lupyuen.github.io/images/pinedio-gfx4.jpg" alt="moononournation / Arduino_GFX" /></p>
<p>We ported only <strong>two source files</strong> from Arduino GFX Library to BL604…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-gfx3.png" alt="Arduino GFX Library ported to BL604" /></p>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_bitbang/pinedio_st7789_bitbang">(Source)</a></p>
<p>…By mapping the <strong>Arduino API to BL604 IoT SDK</strong>.</p>
<p>(And we flattened the C++ Classes into plain C Functions)</p>
<p>Our Logic Analyser shows that the <strong>9-bit ST7789 data is correctly Bit-Banged</strong> to ST7789…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-gfx2.png" alt="Arduino GFX with Logic Analyser" /></p>
<p>(Were using the 9-Bit SPI Decoder with our Logic Analyser)</p>
<p>Guess what? <strong>Nothing appears on PineDio Stacks ST7789 Display!</strong> 😭</p>
<p>To be super sure, we <strong>tested Arduino GFX on Linux</strong> and verified the data…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-gfx5.jpg" alt="Testing Arduino GFX on Linux" /></p>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_bitbang/test">(Source)</a></p>
<p>Now were super stuck with our ST7789 testing!</p>
<h1 id="problem-with-st7789"><a class="doc-anchor" href="#problem-with-st7789">§</a>10 Problem With ST7789?</h1>
<p><em>Wait a minute… Is there a switch that configures ST7789 Display for 3-Wire or 4-Wire Interface?</em></p>
<p><strong>Pins IM0 to IM3</strong> on ST7789 will select the <strong>3-Wire or 4-Wire Interface</strong></p>
<p><img src="https://lupyuen.github.io/images/pinedio-im.png" alt="Configuring ST7789 Display for 3-Wire Interface" /></p>
<p><a href="https://www.rhydolabz.com/documents/33/ST7789.pdf">(Source)</a></p>
<p>So for <strong>3-Wire (9-Bit) Interface</strong>, we should hardwire the pins as…</p>
<div><table><thead><tr><th style="text-align: center">IM3</th><th style="text-align: center">IM2</th><th style="text-align: center">IM1</th><th style="text-align: center">IM0</th></tr></thead><tbody>
<tr><td style="text-align: center"><code>1</code></td><td style="text-align: center"><code>1</code></td><td style="text-align: center"><code>0</code></td><td style="text-align: center"><code>1</code></td></tr>
</tbody></table>
</div>
<p><em>Maybe Pins IM0 to IM3 are not hard-wired as such?</em></p>
<p>Thats a possibility… Which were checking with the Display Makers now.</p>
<p>Also were <strong>probing the tiny ST7789 Connector</strong> (with a sharp Pogo Pin) to understand how the pins are connected.</p>
<p><img src="https://lupyuen.github.io/images/pinedio-probe.jpg" alt="Probing the tiny ST7789 Connector with a sharp Pogo Pin" /></p>
<p>Heres what we discovered from the <strong>Pogo Pin Probing</strong></p>
<div><table><thead><tr><th style="text-align: center">ST7789 Pin</th><th style="text-align: center">BL604 GPIO</th></tr></thead><tbody>
<tr><td style="text-align: center"><strong>SDA</strong></td><td style="text-align: center">GPIO 0</td></tr>
<tr><td style="text-align: center"><strong>DC</strong></td><td style="text-align: center">GPIO 17</td></tr>
<tr><td style="text-align: center"><strong>SCK</strong></td><td style="text-align: center">GPIO 11</td></tr>
</tbody></table>
</div>
<p><a href="https://lupyuen.github.io/articles/pinedio2"><strong>UPDATE: Theres a new version of PineDio Stack BL604, the GPIO Numbers have changed</strong></a></p>
<p><img src="https://lupyuen.github.io/images/pinedio-probe2.jpg" alt="Probe Results" /></p>
<p>Not quite what we expected. We tried both <strong>SPI and Bit-Banging</strong> with the discovered settings…</p>
<ul>
<li>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_spi"><strong><code>pinedio_st7789_spi</code></strong></a></p>
</li>
<li>
<p><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_bitbang2"><strong><code>pinedio_st7789_bitbang2</code></strong></a></p>
</li>
</ul>
<p>But both dont show anything on the ST7789 Display.</p>
<p>We also tried to <a href="https://github.com/lupyuen/bl_iot_sdk/blob/3wire/customer_app/pinedio_st7789_bitbang3/pinedio_st7789_bitbang3/demo.c#L62-L97"><strong>read the display ID</strong></a> (RDDID) by flipping GPIO 0 between output and input modes…</p>
<ul>
<li><a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_bitbang3"><strong><code>pinedio_st7789_bitbang3</code></strong></a></li>
</ul>
<p>But the GPIO 0 signal looks glitchy. See the top line, centre part…</p>
<p><img src="https://lupyuen.github.io/images/pinedio-readid.png" alt="Reading display ID looks glitchy" /></p>
<p>Any ideas? 🤔</p>
<p>UPDATE: JF commented…</p>
<blockquote>
<p>About the serial modes of the ST7789, my understanding is that it supports 4 modes :</p>
</blockquote>
<blockquote>
<ul>
<li>2 “interface” (I and II) : “I “ means that the same pin (SDA in the datasheet) is used as data INPUT and OUTPUT. “II” means it uses 1 pin as INPUT (SDA) and one as OUTPUT (SDO)</li>
</ul>
</blockquote>
<blockquote>
<ul>
<li>3/4 lines : 3 lines means that the driver must output 9 bits for each “byte” sent to the driver (the 9th bit being the data/command bit). In 4 lines, the 4th lines is used to output the data/command bit, allowing the driver to send 8-bits “bytes” on the SPI bus.</li>
</ul>
</blockquote>
<blockquote>
<p>The mode implemented on the PineTime and on this LCD board is the “4-lines interface I” : data/command pin + single MOSI -&gt; SDA pin as data pin. I think we could use the 4-lines interface II mode if we wanted to read data from the display (MOSI -&gt; SDA, MISO -&gt; SDO), but that is not necessary.</p>
</blockquote>
<blockquote>
<p>The naming of the pins in the datasheet are really confusing : the controller is advertised (and works) as a SPI device, but the pins are labelled as I²C pins. However, I do confirm that Im driving the controller using the SPI bus, not the I²C!</p>
</blockquote>
<p><a href="https://twitter.com/codingfield/status/1436609097344995334">See JFs experiment with PineDio Stack and an external ST7789 display</a></p>
<h1 id="seeking-volunteers"><a class="doc-anchor" href="#seeking-volunteers">§</a>11 Seeking Volunteers!</h1>
<p>Im really excited that PineDio Stack BL604 will be available soon!</p>
<p>But in the meantime, JF and I have <strong>plenty to test on PineDio Stack</strong></p>
<ol>
<li>ST7789 Display <em>(SPI)</em></li>
<li>LoRa SX1262 <em>(SPI)</em></li>
<li>SPI Flash <em>(SPI)</em></li>
<li>Accelerometer <em>(I2C)</em></li>
<li>Heart Rate Sensor <em>(I2C)</em></li>
<li>Touch Panel <em>(I2C)</em></li>
<li>Vibrator <em>(GPIO)</em></li>
<li>Push Button <em>(GPIO)</em></li>
<li>WiFi</li>
<li>Bluetooth LE</li>
<li>JTAG Debugging</li>
<li>Battery Charging</li>
<li>Solar Power</li>
</ol>
<p><a href="https://twitter.com/MisterTechBlog"><strong>Please let us know</strong></a> if youre keen to help! 🙏</p>
<p><strong>UPDATE</strong>: LoRa SX1262 on PineDio Stack has been tested OK! See this article…</p>
<ul>
<li><a href="https://lupyuen.github.io/articles/lorawan2"><strong>“LoRaWAN on PineDio Stack BL604 RISC-V Board”</strong></a></li>
</ul>
<p><img src="https://lupyuen.github.io/images/pinedio-box.jpg" alt="PineDio Stack BL604 In A Box" /></p>
<h1 id="whats-next"><a class="doc-anchor" href="#whats-next">§</a>12 Whats Next</h1>
<p>Many Thanks to <a href="https://github.com/moononournation"><strong>@moononournation</strong></a> and <a href="https://twitter.com/AndreasDyhrberg"><strong>@AndreasDyhrberg</strong></a> for the valuable tips on testing PineDio Stack BL604!</p>
<p>This has been a super exciting <strong>first week of testing</strong> the Prototype Hardware for PineDio Stack BL604…</p>
<p>I hope you will join JF and me as we continue our testing of PineDio Stack.</p>
<p>(Maybe real soon well create toasters, microwave ovens and pressure cookers with PineDio Stack!)</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/pdrepw/pinedio_stack_bl604_riscv_board_testing_the/">Discuss this article on Reddit</a></p>
</li>
<li>
<p><a href="https://lupyuen.github.io/articles/book">Read “The RISC-V BL602 / BL604 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/pinedio.md"><code>lupyuen.github.io/src/pinedio.md</code></a></p>
<h1 id="notes"><a class="doc-anchor" href="#notes">§</a>13 Notes</h1>
<ol>
<li>
<p>This article is the expanded version of <a href="https://twitter.com/MisterTechBlog/status/1429273222780887041">this Twitter Thread</a></p>
</li>
<li>
<p>JF has <a href="https://twitter.com/codingfield/status/1431541455210913792"><strong>successfully tested PineDio Stacks SPI Port</strong></a> with an external eInk Display</p>
</li>
<li>
<p>We have created new firmware to <a href="https://github.com/lupyuen/bl_iot_sdk/tree/3wire/customer_app/pinedio_st7789_bitbang2"><strong>Bit-Bang ST7789s 4-Wire (8-Bit) Interface: <code>pinedio_st7789_bitbang2</code></strong></a></p>
</li>
</ol>
<p><img src="https://lupyuen.github.io/images/pinedio-reset.jpg" alt="Improvised Reset Button" /></p>
<h1 id="appendix-improvised-reset-button-for-pinedio-stack"><a class="doc-anchor" href="#appendix-improvised-reset-button-for-pinedio-stack">§</a>14 Appendix: Improvised Reset Button for PineDio Stack</h1>
<p>Sometimes we need to <strong>restart PineDio Stack</strong> to see the Boot Messages, without disconnecting the USB port. Heres how…</p>
<ol>
<li>
<p>We assume that PineDio Stack is already powered on by our computer (via USB)</p>
</li>
<li>
<p>Connect a Jumper Cable between <strong>Pin 5 (GND)</strong> and <strong>Pin 6 (RESET)</strong> of the JTAG Port (Pic above)</p>
</li>
<li>
<p>Disconnect the Jumper Cable</p>
</li>
<li>
<p>PineDio Stack will restart. The <strong>Boot Messages</strong> will appear in the Serial Terminal.</p>
</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>