<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.pine64.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JF</id>
	<title>PINE64 - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.pine64.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JF"/>
	<link rel="alternate" type="text/html" href="https://wiki.pine64.org/wiki/Special:Contributions/JF"/>
	<updated>2026-04-08T19:16:03Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.37.1</generator>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinebook_Pro&amp;diff=12033</id>
		<title>Pinebook Pro</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinebook_Pro&amp;diff=12033"/>
		<updated>2021-12-12T13:33:28Z</updated>

		<summary type="html">&lt;p&gt;JF: Add pictures to illustrate the replacement procedure of the keyboard&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= User Guide =&lt;br /&gt;
== Introducing PineBook Pro == &lt;br /&gt;
[[File:PBP.jpg|400px|thumb|right|Pinebook Pro running Debian with MATE]]&lt;br /&gt;
&lt;br /&gt;
The Pinebook Pro is a Linux and *BSD ARM laptop from [https://www.pine64.org/ PINE64]&lt;br /&gt;
&lt;br /&gt;
It is built to be a compelling alternative to mid-ranged Chromebooks that people convert into Linux laptops. It features an IPS 1080p 14″ LCD panel, a premium magnesium alloy shell, high capacity eMMC storage, a 10,000 mAh capacity battery, and the modularity that only an open source project can deliver. &lt;br /&gt;
&lt;br /&gt;
It's compact and slim dimensions are 329mm x 220mm x 12mm (WxDxH).&lt;br /&gt;
&lt;br /&gt;
Key features include: the RK3399 SOC; USB-C for data, video-out and power-in (3A 5V); privacy switches for the microphone, BT/WiFi module, and camera; and expandable storage via NVMe (PCIe x4) with an optional adapter. &lt;br /&gt;
&lt;br /&gt;
The Pinebook Pro is equipped with 4GB LPDDR4 system memory, high capacity eMMC flash storage, and 128Mb SPI boot Flash. The I/O includes: 1 x micro SD card reader (bootable), 1 x USB 2.0, 1 x USB 3.0, 1 x USB type C Host with DP 1.2 and power-in, PCIe x4 for an NVMe SSD drive (requires an optional adapter), and UART (via the headphone jack by setting an internal switch). &lt;br /&gt;
&lt;br /&gt;
The keyboard and touchpad both use the USB 2.0 protocol.  The LCD panel uses eDP MiPi display protocol.&lt;br /&gt;
&lt;br /&gt;
Many different Operating Systems (OS) are freely available from the open source community and partner projects.  These include various flavors of Linux (Ubuntu, Debian, Manjaro, etc.) and *BSD.&lt;br /&gt;
&lt;br /&gt;
== Software and OS Image Downloads ==&lt;br /&gt;
&lt;br /&gt;
=== Default Manjaro KDE Desktop Quick Start ===&lt;br /&gt;
&lt;br /&gt;
When you first get your Pinebook Pro and boot it up for the first time, it'll come with Manjaro using the KDE desktop. The Pinebook Pro is officially supported by the Manjaro ARM project, and support can be found on the [https://forum.manjaro.org/c/manjaro-arm/78 Manjaro ARM forums.]&lt;br /&gt;
&lt;br /&gt;
On first boot, it will ask for certain information such as your timezone location, keyboard layout, username, password, and hostname. Most of these should be self-explanatory. Note that the hostname it asks for should be thought of as the &amp;quot;codename&amp;quot; of your machine, and if you don't know what it's about, you can make something up (use a single word, all lower case, no punctuation; e.g. &amp;quot;pbpro&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
After you're on the desktop, be sure to update it as soon as possible and reboot after updates are finished installing. If nothing appears when you click on the Networking icon in your system tray to connect to your Wi-Fi, ensure the Wi-Fi [https://wiki.pine64.org/index.php/Pinebook_Pro#ANSI_Fn_.2B_F_keys_wrong_for_F9.2C_F10.2C_F11_and_F12  privacy switch] is not disabled.&lt;br /&gt;
&lt;br /&gt;
=== Pinebook Pro images ===&lt;br /&gt;
Under [[Pinebook Pro Software Release]] you will find a complete list of currently supported Operating System images that work with the Pinebook as well as other related software. &lt;br /&gt;
&lt;br /&gt;
The list includes OS images and descriptions of:&lt;br /&gt;
&lt;br /&gt;
* [[PinebookPro_Software_Release#Manjaro ARM|Manjaro ARM]] (microSD and eMMC Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Armbian|Armbian]] (microSD and eMMC Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Twister OS|Twister OS]] (microSD Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Fedora|Fedora]] (microSD and eMMC Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Arch_Linux_ARM|Arch Linux]] (microSD and USB boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#postmarketOS|Postmarket OS]] (microSD and USB boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Kali Linux|Kali Linux]] (microSD and USB boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#DietPi|DietPi]] (microSD and eMMC Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#Q4OS|Q4OS]] (microSD and eMMC Boot)&lt;br /&gt;
* [[PinebookPro_Software_Release#NetBSD|NetBSD]] (microSD and eMMC Boot)&lt;br /&gt;
* [[Pinebook_Pro_Software_Release#OpenBSD|OpenBSD release for ARM64]]&lt;br /&gt;
* [[Pinebook_Pro_Software_Release#Gentoo|Gentoo]]&lt;br /&gt;
&lt;br /&gt;
== Keyboard ==&lt;br /&gt;
The Pinebook Pro is available in two keyboard configurations: ISO and ANSI. Both the keyboard and touchpad in the Pinebook Pro use the USB 2.0 protocol and show up as such in xinput. The keyboard features function (Fn) keys in the F-key row, which include display brightness controls, sound volume, touchpad lock, and other functionality. There is also a custom PINE64 logo key that functions as Menu/Super key. It has also a secondary functionality for setting the privacy switches.   &lt;br /&gt;
&lt;br /&gt;
The keyboard firmware binary can be flashed from userspace using the provided open source utility.&lt;br /&gt;
&lt;br /&gt;
{{warning|DO NOT update the keyboard firmware before checking which keyboard IC your Pinebook Pro has.&amp;lt;/b&amp;gt; Some Pinebook Pro were delivered with a '''SH61F83''' instead of a '''SH68F83'''. The SH61F83 can only be written 8 times, this will render the keyboard and touchpad unusable if this limit is reached when &amp;lt;code&amp;gt;step-1&amp;lt;/code&amp;gt; is flashed, see the [https://reddit.com/r/PINE64official/comments/loq4db/very_disappointed/ Reddit SH61F83 thread]. The keyboard IC corresponds to &amp;lt;code&amp;gt;U23&amp;lt;/code&amp;gt; on the [[#Pinebook_Pro_Schematics_and_Certifications|top layer silkscreen of the main board]]. It is located under the keyboard flat flexible cable.}}&lt;br /&gt;
&lt;br /&gt;
Documentation for the keyboard can be found in [[#Datasheets for Components and Peripherals|Datasheets for Components and Peripherals]]. &lt;br /&gt;
&lt;br /&gt;
=== Typing special characters ===&lt;br /&gt;
The [[Wikipedia:British_and_American_keyboards#Other_keyboard_layouts|UK ISO Layout]] does not have dedicated keys for characters like the German umlauts (Ä,Ö,Ü, etc). Certain characters can still be generated by means of either key combinations or key sequences. &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!Character&lt;br /&gt;
!Key combination/sequence&lt;br /&gt;
|-&lt;br /&gt;
|Ä, Ö, Ü, ä, ö, ü&lt;br /&gt;
|[[Wikipedia:AltGr_key|[AltGr]]]+'[' followed by [A], [O], [U], [a], [o] or [u]&lt;br /&gt;
|-&lt;br /&gt;
|µ&lt;br /&gt;
|[AltGr]+[m]&lt;br /&gt;
|-&lt;br /&gt;
|Ø, ø&lt;br /&gt;
|[AltGr]+[O], [AltGr]+[o]&lt;br /&gt;
|-&lt;br /&gt;
|@&lt;br /&gt;
|[AltGr]+[q] (as on the German layout)&lt;br /&gt;
|-&lt;br /&gt;
|ß&lt;br /&gt;
|[AltGr]+[s]&lt;br /&gt;
|-&lt;br /&gt;
|§&lt;br /&gt;
|[AltGr]+[S]&lt;br /&gt;
|-&lt;br /&gt;
|°&lt;br /&gt;
|[AltGr]+[)]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Privacy Switches ===&lt;br /&gt;
There are three privacy switches mapped to the F10, F11 and F12 keys on the Pinebook Pro keyboard. They de/activate the following:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Privacy switch function and description&lt;br /&gt;
! Combination&lt;br /&gt;
! Effect&lt;br /&gt;
! Description&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | PINE64 logo key+F10&lt;br /&gt;
| Microphone Privacy switch&lt;br /&gt;
| CAPs lock LED blinks. 2 blinks = enabled, 3 blinks = disabled&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | PINE64 logo key+F11&lt;br /&gt;
| WiFi Privacy switch&lt;br /&gt;
| NUM lock LED blinks. 2 blinks = WiFi enabled / privacy switch disabled, 3 blinks = WiFi disabled / privacy switch enabled.&lt;br /&gt;
| '''Re-enabling requires reboot''' (or a [//forum.pine64.org/showthread.php?tid=8313&amp;amp;pid=52645#pid52645 command line hack to bind/unbind]).&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | PINE64 logo key+F12&lt;br /&gt;
| Camera privacy switch&lt;br /&gt;
| CAPs lock and NUM lock LEDs blink together. 2 blinks = enabled, 3 blinks = disabled&lt;br /&gt;
| Can use tools like '''&amp;lt;code&amp;gt;lsusb&amp;lt;/code&amp;gt;''' to detect camera's presence. If not detected, check privacy switch.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
'''(Press the PINE64 logo key plus F10/F11/F12) for 3 seconds)'''&lt;br /&gt;
&lt;br /&gt;
The keyboard operates on firmware independent of the operating system.  It detects if one of the F10, F11 or F12 keys is pressed in combination with the Pine key for 3 seconds. Doing so disables power to the appropriate peripheral, thereby disabling it.  This has the same effect as cutting off the power to each peripheral with a physical switch. This implementation is very secure, since the firmware that determines whether a peripheral gets power is not part of the Pinebook Pro’s operating system. So the power state value for each peripheral cannot be overridden or accessed from the operating system. The power state setting for each peripheral is stored across reboots inside the keyboard's firmware flash memory.&lt;br /&gt;
&lt;br /&gt;
=== Basic summary of replacing keyboard ===&lt;br /&gt;
&lt;br /&gt;
This guide is very basic and should be fleshed out with (better) pictures.  There just isn't a list of steps anywhere else yet.&lt;br /&gt;
&lt;br /&gt;
Here's what the replacement keyboard looks like:&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-front.jpg|300px|Replacement keyboard (front)]]&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-front.jpg|300px|Replacement keyboard (back)]]&lt;br /&gt;
&lt;br /&gt;
''Step 0'': If changing from ISO keyboard to ANSI keyboard, or vice versa, be sure to have a system capable of running the firmware updater that you can access either remotely or with a USB keyboard beyond the internal keyboard, as the firmware for each is very different and keys won't work correctly.  See https://forum.pine64.org/showthread.php?tid=8407 (and for NetBSD, https://forum.pine64.org/showthread.php?tid=8716).&lt;br /&gt;
&lt;br /&gt;
''Step 1'': The remove back back panel.&lt;br /&gt;
&lt;br /&gt;
There are 10 screws on the back that must be removed, and the back panel detached.  The speakers may remain attached via glue to the case and should be carefully pried off.  When this is done, taking photos of how everything looks now can help put it all back together later.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_keyboard-replacement-screws.jpg|300px|Remove the back panel]]&lt;br /&gt;
&lt;br /&gt;
''Step 2'': Places to unscrew.&lt;br /&gt;
&lt;br /&gt;
There are 3 items screwed into the keyboard frame that must be removed.  There are 2 large screws for daughter board, 3 large screws and 1 small screw for mainboard, and 4 screws for battery.  Be sure to not lose them.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-back-removed.jpg|300px|Remove the back panel]]&lt;br /&gt;
&lt;br /&gt;
''Step 3'': Remove the battery.&lt;br /&gt;
&lt;br /&gt;
Once the battery screws are removed, it should be unplugged from the mainboard and removed.  Note that there are two unconnected cables lying around, that should remain unconnected.  They are used when the battery is disconnected entirely.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-zoom-mainboard.jpg.jpg|300px|Zoom on the mainboard]]&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-zoom-daughterboard.jpg|300px|Zoom on the daughterboard]]&lt;br /&gt;
&lt;br /&gt;
''Step 4'': Unplug the ribbon cables.&lt;br /&gt;
&lt;br /&gt;
There are several ribbon cables.  To remove, flip up the tab and gentle pull the ribbon out.&lt;br /&gt;
&lt;br /&gt;
* One cable runs from the mainboard to the daughterboard underneath the battery.  Detach from both ends.  With the battery removed, detach from keyboard shell, and set aside for the new keyboard shell.&lt;br /&gt;
* One cable runs between the touchpad and the mainboard.  Detach from both ends, and also set aside.&lt;br /&gt;
* One cable runs between the keyboard and the mainboard.  This one remains attached to the keyboard and only needs to be detached from the mainboard.&lt;br /&gt;
* One cable from the LCD attaches near the lid hinge.  It should be just unplugged.&lt;br /&gt;
&lt;br /&gt;
''Step 5'': Detach microphone and speakers.  &lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_microphone_removed.jpg|300px|thumb|right|One of the Pinebook Pro microphones after removal]]&lt;br /&gt;
&lt;br /&gt;
The speakers and microphone don't have to be detached from the mainboard, but they need to be detached from the keyboard shell.  The microphones are held in place by tape, and the speakers have sticky sides.  The speakers are found obviously, but the microphones (two of) can be found between the battery and the hinge area. Each microphone can be carefully pulled/wedged out of its position by a small screwdriver or pick.&lt;br /&gt;
&lt;br /&gt;
''Step 6'': Remove mainboard and daughterboard.&lt;br /&gt;
&lt;br /&gt;
At this point, the mainboard and daughterboards should be removed.  When unscrewed (see Step 2) they should pull out fairly easily.  Put them aside (including microphones and speakers if left attached.)&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-all-boards-removed.jpg|300px|All boards removed]]&lt;br /&gt;
&lt;br /&gt;
''Step 7'': Detach the LCD panel.&lt;br /&gt;
&lt;br /&gt;
Step 2 didn't tell you, there are 6 more screws to remove here, 3 for each of the hinges.  Unscrew these and the LCD panel will be able to be removed.  You may have to jiggle or move the hinges for this.  When detached, be sure to place the LCD panel such that the display is protected.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-detached-display.jpg|300px|Display detached]]&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-detached-display2.jpg|300px|Display detached (front)]]&lt;br /&gt;
&lt;br /&gt;
''Step 8'': Try Not To Break Your Touchpad, or, How I Learned To Love Things That Bend&lt;br /&gt;
&lt;br /&gt;
'''NOTE This section really feels like you're going to break something.'''&lt;br /&gt;
&lt;br /&gt;
The touchpad is glued to the keyboard shell and it's glued well.  There are two places it is glued to.  If you can, only the middle must be force-detached.  You will think you're going to break it.  Gently apply increasing force until the glue begins to detach (you will hear a crackle as it comes off), and continue very slowly until the whole thing is detached.  This may take minutes due to that feeling you're going to break it.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-touchpad1.jpg|300px|Unmouting the touchpad]]&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-touchpad2.jpg|300px|Unmouting the touchpad]]&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-touchpad3.jpg|300px|Unmouting the touchpad]]&lt;br /&gt;
&lt;br /&gt;
''Step 9'': Over the hill, touchpad goes into new shell.&lt;br /&gt;
&lt;br /&gt;
In the new keyboard shell put the touchpad back where it was, hopefully the glue will remain sufficiently attached.  If there is a glue issue, this guide unfortunately has no advice currently.&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_Pro_new_keyboard-install-touchpad.jpg|300px|Install the touchpad]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
''Step 10'': Reattach the LCD panel.&lt;br /&gt;
&lt;br /&gt;
The LCD panel should slot back into the keyboard frame, the same way it came out.  If the hinges were moved, they should be *very* *gently* closed such that the LCD panel and keyboard closed like normal for the remaining steps.&lt;br /&gt;
&lt;br /&gt;
''Step 11'': Tape it out.&lt;br /&gt;
&lt;br /&gt;
Move any tape from the old keyboard shell to the new one.  These items protect the mainboard and daughterboard, and keep various wires in their right place.  Some are grey and some are black.  For tape that holds the speakers, microhones, or their cables in place, do not reattach yet.&lt;br /&gt;
&lt;br /&gt;
''Step 12'': Board install.&lt;br /&gt;
&lt;br /&gt;
Install the mainboard, the daughtboard, and their connecting ribbon cable.  Be sure to put the boards in place, 2 large flat screws for the daughterboard, 3 large flat screws and one small screw for the mainboard, before attempting to place the ribbon.&lt;br /&gt;
&lt;br /&gt;
''Step 13'': Microphone and speaker install.&lt;br /&gt;
&lt;br /&gt;
Reattached the microphones and speakers to their respective areas, making sure that both are properly oriented - the speaker &amp;quot;out&amp;quot; faces up, and the microphone cables as connected must face up (these are opposite directions.)&lt;br /&gt;
&lt;br /&gt;
''Step 14'': Reattach other ribbon cables.&lt;br /&gt;
 &lt;br /&gt;
The LCD panel, keyboard and touchpad ribbon cables should be reattached.  Make sure the flap is open, insert the ribbon into the slot (a portion of the cable will disappear), and push the flap down.  The cable should not be easy to pull out.&lt;br /&gt;
 &lt;br /&gt;
''Step 15'': Reattach the battery, and final re-tape.&lt;br /&gt;
  &lt;br /&gt;
The battery should be installed with the 4 screws holding it in place, and the connector attached to the mainboard.  Be sure to keep the two other cables remain unconnected.  Ensure all wires and other tapes are held in place.&lt;br /&gt;
&lt;br /&gt;
''Step 16'': Reattach the back panel.&lt;br /&gt;
 &lt;br /&gt;
Put the back panel back on, and reattach the 10 screws.&lt;br /&gt;
&lt;br /&gt;
''Step 17'': If you changed from ISO to ANSI or from ANSI to ISO, you'll need to update your firmware now.  See the links in Step 0 above.&lt;br /&gt;
&lt;br /&gt;
== Touchpad (trackpad) ==&lt;br /&gt;
Documentation for the touchpad can be found in [[#Datasheets for Components and Peripherals|Datasheets for Components and Peripherals]]. It is the only component of the Pinebook Pro held in place with strong adhesive tape. Here are some of its features:&lt;br /&gt;
&lt;br /&gt;
* 2 actuating buttons.&lt;br /&gt;
&lt;br /&gt;
* multi-touch functionality. &lt;br /&gt;
&lt;br /&gt;
* A matte finish that your finger can slide along easily.&lt;br /&gt;
&lt;br /&gt;
* A reasonable size (96mm &amp;amp;times; 64mm; diagonal: 115.378mm or 4.542&amp;amp;rdquo;).&lt;br /&gt;
&lt;br /&gt;
=== Troubleshooting ===&lt;br /&gt;
&lt;br /&gt;
If you are having trouble using 2 fingers to scroll or emulate the click of a mouse's right-button, then try these solutions:&lt;br /&gt;
&lt;br /&gt;
* Update the firmware.&lt;br /&gt;
&lt;br /&gt;
* Keep your 2 fingers spread apart rather than close together.&lt;br /&gt;
&lt;br /&gt;
* Individual programs might need to be configured specially.&lt;br /&gt;
&lt;br /&gt;
:* For smooth scrolling and gestures under X-Windows, ''Firefox'' should be launched with with the following environment variable assignment:&lt;br /&gt;
&lt;br /&gt;
::: &amp;lt;code&amp;gt;MOZ_USE_XINPUT2=1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Experiment with other settings, via [[#X-Windows Configuration|X-Windows Configuration]] or some other system preferences; for example, you could disable double-finger scrolling, and instead enable scrolling by sliding one finger along the edge of the touchpad.&lt;br /&gt;
&lt;br /&gt;
=== Firmware ===&lt;br /&gt;
The touchpad controller is connected to the keyboard controller. All touchpad events go through the keyboard controller and it's software, then to the keyboard controller's USB port. Note that the touchpad does have separate firmware, (which has to be written through the keyboard controller). The touchpad vendor&amp;amp;rsquo;s firmware binary can be flashed from userspace using the following open source command-line utility:&lt;br /&gt;
&lt;br /&gt;
* Kamil Trzciński&amp;amp;rsquo;s [https://github.com/ayufan-rock64/pinebook-pro-keyboard-updater pinebook-pro-keyboard-updater].&lt;br /&gt;
&lt;br /&gt;
Naturally, forks have begun to appear:&lt;br /&gt;
&lt;br /&gt;
* Jack Humbert&amp;amp;rsquo;s [https://github.com/jackhumbert/pinebook-pro-keyboard-updater fork]&lt;br /&gt;
&lt;br /&gt;
* Dragan Simic&amp;amp;rsquo;s [https://github.com/dragan-simic/pinebook-pro-keyboard-updater fork]. This one has recently delivered a much improved firmware from the vendor, which greatly improves the control of the cursor (see this [https://forum.pine64.org/showthread.php?tid=14531 thread] for discussion); before installing this update, consider resetting to the defaults any configuration of your touchpad.&lt;br /&gt;
&lt;br /&gt;
'''Every Pinebook Pro produced before September 2021 should have its keyboard and touchpad firmware updated.'''&lt;br /&gt;
&lt;br /&gt;
{{warning| DO NOT update the touchpad firmware before checking which keyboard IC your Pinebook Pro has.&amp;lt;/b&amp;gt; Some Pinebook Pro were delivered with a '''SH61F83''' instead of a '''SH68F83'''. The SH61F83 can only be written 8 times, this will render the keyboard and touchpad unusable if this limit is reached when &amp;lt;code&amp;gt;step-1&amp;lt;/code&amp;gt; is flashed. See [//old.reddit.com/r/PINE64official/comments/loq4db/very_disappointed/ Reddit SH61F83 thread]. The keyboard IC corresponds to &amp;lt;code&amp;gt;U23&amp;lt;/code&amp;gt; on the [[#Pinebook_Pro_Schematics_and_Certifications|top layer silkscreen of the main board]]. It is located under the keyboard flat flexible cable.}}&lt;br /&gt;
&lt;br /&gt;
Before updating ''any'' firmware, your Pinebook Pro should be either fully charged or, preferably, running from mains. This utility will be writing data to chips on the keyboard and touchpad, so a loss of power during any stage of the update can result in irrecoverable damage to your touchpad or keyboard.&lt;br /&gt;
&lt;br /&gt;
The scripts ought to work on all OSs available for the Pinebook Pro. Some OSs may, however, require installation of relevant dependencies. The instructions below assume a Debian desktop. To install these dependencies, newer Pinebook Pro models that come with Manjaro will require a different command.&lt;br /&gt;
&lt;br /&gt;
There are two keyboard versions of the Pinebook Pro: ISO and ANSI. You need to know which model you have prior to running the updater. &lt;br /&gt;
Firmware update steps for both models are listed below.  &lt;br /&gt;
&lt;br /&gt;
What you will need:&lt;br /&gt;
&lt;br /&gt;
* Connection to WiFi (for getting dependencies).&lt;br /&gt;
&lt;br /&gt;
* Your Pinebook Pro fully charged or running from mains power.&lt;br /&gt;
&lt;br /&gt;
* An external USB keyboard &amp;amp;amp; mouse (or access to the Pinebook Pro via SSH. Please note that for some configurations, the SSH service might not be available without first having logged in once; in this case, you will definitely want at least an external keyboard).&lt;br /&gt;
&lt;br /&gt;
==== ISO Model ====&lt;br /&gt;
&lt;br /&gt;
From the terminal command line: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/ayufan-rock64/pinebook-pro-keyboard-updater&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo apt-get install build-essential libusb-1.0-0-dev xxd&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step 1&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo ./updater step-1 iso&lt;br /&gt;
sudo poweroff # do not use 'reboot'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step 2 (after booting)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo ./updater step-2 iso&lt;br /&gt;
sudo poweroff # do not use 'reboot'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== ANSI Model ====&lt;br /&gt;
&lt;br /&gt;
{{Hint| Note: Running step 1 on the ANSI keyboard model will make the keyboard and touchpad inaccessible until step 2 is ran, so an external keyboard must be connected to complete the update on this model!}}&lt;br /&gt;
&lt;br /&gt;
From the terminal command line: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/ayufan-rock64/pinebook-pro-keyboard-updater&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo apt-get install build-essential libusb-1.0-0-dev xxd&lt;br /&gt;
make&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step 1&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo ./updater step-1 ansi&lt;br /&gt;
sudo poweroff # do not use 'reboot'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step 2 (after booting)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
cd pinebook-pro-keyboard-updater&lt;br /&gt;
sudo ./updater step-2 ansi&lt;br /&gt;
sudo poweroff # do not use 'reboot'&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When done, if some of the keys produce incorrect characters, please check your OS’s language settings. For ANSI users, the default OS may have shipped with English UK as the default language; you can change it to English US if desired.&lt;br /&gt;
&lt;br /&gt;
==== Revised Firmware ====&lt;br /&gt;
&lt;br /&gt;
In addition, you might consider using revised firmware data; this is one final step that should not require a reboot:&lt;br /&gt;
&lt;br /&gt;
Step 3: '''ISO''' (after booting)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./updater flash-kb firmware/default_iso.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Step 3: '''ANSI''' (after booting)&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
sudo ./updater flash-kb firmware/default_ansi.hex&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== X-Windows Configuration ===&lt;br /&gt;
''Before making adjustments, consider updating the firmware; reset your adjustments before updating the firmware, so that your adjustments do not interfere with new functionality.''&lt;br /&gt;
&lt;br /&gt;
Some forum members have found that an adjustment to X-Windows will allow finer motion in the touchpad. If you use the '''Synaptic''' mouse/touchpad driver, use this command to make the change live:&lt;br /&gt;
&amp;lt;pre&amp;gt;synclient MinSpeed=0.25&amp;lt;/pre&amp;gt;&lt;br /&gt;
You may experiment with different settings, but 0.25 was tested as helping noticeably.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
To make the change persist across reboots, change the file &amp;lt;code&amp;gt;/etc/X11/xorg.conf&amp;lt;/code&amp;gt; similar to below:&lt;br /&gt;
&amp;lt;pre&amp;gt;    Section &amp;quot;InputClass&amp;quot;&lt;br /&gt;
        Identifier &amp;quot;touchpad catchall&amp;quot;&lt;br /&gt;
        Driver &amp;quot;synaptics&amp;quot;&lt;br /&gt;
        MatchIsTouchpad &amp;quot;on&amp;quot;&lt;br /&gt;
        MatchDevicePath &amp;quot;/dev/input/event*&amp;quot;&lt;br /&gt;
        Option &amp;quot;MinSpeed&amp;quot; &amp;quot;0.25&amp;quot;&lt;br /&gt;
    EndSection&amp;lt;/pre&amp;gt;&lt;br /&gt;
The line &amp;lt;code&amp;gt;Option &amp;quot;MinSpeed&amp;quot; &amp;quot;0.25&amp;quot;&amp;lt;/code&amp;gt; is the change.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Another forum user built on the above settings a little, and have found these to be very good:&lt;br /&gt;
&amp;lt;pre&amp;gt;synclient MinSpeed=0.25&lt;br /&gt;
synclient TapButton1=1&lt;br /&gt;
synclient TapButton2=3&lt;br /&gt;
synclient TapButton3=2&lt;br /&gt;
synclient FingerLow=30&lt;br /&gt;
synclient PalmDetect=1&lt;br /&gt;
synclient VertScrollDelta=64&lt;br /&gt;
synclient HorizScrollDelta=64&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;FingerLow&amp;lt;/code&amp;gt; has the same value as 'FingerHigh' in one config (30). It is believed to help reduce mouse movement as you lift your finger, but it's unknown whether synaptic works like this.&lt;br /&gt;
You may find this config to be comfortable for daily use.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;TabButton&amp;lt;/code&amp;gt; allows to just tab the touchpad instead of physically pressing it down (to get this click noise).&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;right mouse click&amp;lt;/code&amp;gt; is emulated by tapping with two fingers on the touchpad. If you feel that this is not very responsive you can try this value:&lt;br /&gt;
&amp;lt;pre&amp;gt; synclient MaxTapTime=250 &amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Some users may encounter an issue with the mouse jumping when typing when using libinput driver (has not been test with synaptic) due to their hand hitting the touchpad which can be fixed by updating the xorg settings to disable it while typing. One can disable the touchpad while typing by setting the below option in the xorg config simliar to the previou example. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        Option &amp;quot;DisableWhileTyping&amp;quot; &amp;quot;on&amp;quot; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The setting can be verified by using the xinput command to first list the devices and then listing the properties for the Touchpad device. Exact commands to check this have been omitted for save of brevity. If DisableWhileTyping is shown enabled but does not appear to be working the issue may be due to the fact that the keyboard is connected to a USB bus which causes it to be seen as a external keyboard. To resolve this one can add the config below which sets the keyboard to internal to ensure the DisableWhileTyping works properly. &lt;br /&gt;
&lt;br /&gt;
You will need to edit &amp;lt;code&amp;gt;/etc/libinput/local-overrides.quirks&amp;lt;/code&amp;gt; and add the following lines:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
[Serial Keyboards]&lt;br /&gt;
MatchUdevType=keyboard&lt;br /&gt;
MatchBus=usb&lt;br /&gt;
AttrKeyboardIntegration=internal&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once X11 is restarted the new setting should now take effect and you will no longer be able to use the touchpad while typing which will mostly eliminate the mouse jumping issue.&lt;br /&gt;
&lt;br /&gt;
== Power Supply ==&lt;br /&gt;
* Input Power: 5V DC @ 3A&lt;br /&gt;
* Mechanical: 3.5mm OD / 1.35mm ID, Barrel jack&lt;br /&gt;
* USB-C 5V, 15W PD quickcharge&lt;br /&gt;
* Only use one power input at a time, barrel jack OR USB-C&lt;br /&gt;
&lt;br /&gt;
== LEDs ==&lt;br /&gt;
In total, there are four LEDs on the Pinebook Pro, three of which are placed in the top-left side of the keyboard, and one near the barrel port: &lt;br /&gt;
&lt;br /&gt;
# The red LED next to the barrel port indicates charging, in three ways.  First, it will illuminate steadily when either the factory power supply or a USB Type-C charger is connected to the Pinebook Pro, and the battery is getting charged.  Second, if the battery is at 100%, the LED will remain turned off regardless of the connected power input; however, this is [https://forum.pine64.org/showthread.php?tid=10899 rather rarely achieved].  Third, this LED will flash at 0.5&amp;amp;nbsp;Hz if there are any problems that prevent charging, such as the battery becoming too hot.&lt;br /&gt;
# The power indicator LED, above the keyboard, supports three different colors: green, amber and red. It is also capable of flashing to indicate eMMC activity. In the default Debian with MATE build, green LED means power and red means suspend (amber is unused). &lt;br /&gt;
# The green NumLock LED, above the keyboard.&lt;br /&gt;
# The green CapsLock LED, above the keyboard.&lt;br /&gt;
&lt;br /&gt;
The NumLock and CapsLock LEDs serve their usual purposes on a keyboard, but they also have a secondary function. When the privacy switches get activated they blink to confirm that the switch has been activated.&lt;br /&gt;
&lt;br /&gt;
== Webcam ==&lt;br /&gt;
{{Hint| You can use Cheese to test the Camera functionality}}&lt;br /&gt;
* Streaming video resolutions supported, (uncompressed):&lt;br /&gt;
** 320 x 240 &lt;br /&gt;
** 640 x 480&lt;br /&gt;
** 800 x 600&lt;br /&gt;
** 1280 x 720&lt;br /&gt;
** 1600 x 1200&lt;br /&gt;
* Still frame resolutions supported:&lt;br /&gt;
** 160 x 120&lt;br /&gt;
** 176 x 144&lt;br /&gt;
** 320 x 240&lt;br /&gt;
** 352 x 288 &lt;br /&gt;
** 640 x 480&lt;br /&gt;
** 800 x 600&lt;br /&gt;
** 1280 x 720&lt;br /&gt;
** 1600 x 1200&lt;br /&gt;
&lt;br /&gt;
== Microphones ==&lt;br /&gt;
While it has been said that some Pinebook Pro units contain only one microphone despite having two labeled microphone holes on the outer casing, other units do indeed contain two microphones. It is presently unclear which batches have either configuration; units from the initial community batch of 1000 units (following the initial 100) are believed to contain two, populating both labeled holes.&lt;br /&gt;
&lt;br /&gt;
The wires leading to both microphones connect to the mainboard with a small white plastic connector, located directly adjacent to the ribbon cable attachment point for the keyboard interface.&lt;br /&gt;
&lt;br /&gt;
'''Microphones not working?'''&lt;br /&gt;
&lt;br /&gt;
If pavucontrol input doesn't show microphone activity try changing the [[Pinebook_Pro#Privacy_Switches|privacy switches]]. If the switches are in the correct place and microphone input isn't working you can run &amp;lt;code&amp;gt;alsamixer&amp;lt;/code&amp;gt; from the command line, hit &amp;lt;i&amp;gt;F6&amp;lt;/i&amp;gt; and select the &amp;lt;i&amp;gt;es8316&amp;lt;/i&amp;gt;, hit F4 to get to the capture screen, select the bar labeled ADC, increase the gain to 0dB, change the audio profile in pavucontrol to another one with input. Additionally you may want to modify ADC PGA to get the levels to where you want them. If that still hasn't fixed it you may want to check that the microphone connector is plugged in (see the section [[#Technical Reference|Technical Reference]]).&lt;br /&gt;
&lt;br /&gt;
== Bluetooth and WiFi ==&lt;br /&gt;
[[File:PinebookPro_WirelessIC_Location.jpg|400px|thumb|right|The Pinebook Pro's AP6256 wireless module]]&lt;br /&gt;
===Hardware Overview===&lt;br /&gt;
The Pinebook Pro contains an AMPAK AP6256 wireless module to provide Wi-Fi (compliant to IEEE 802.11ac) and Bluetooth (compliant to Bluetooth SIG revision 5.0). The module contains a Broadcom transceiver IC, believed to be the BCM43456, as well as the support electronics needed to allow the Wi-Fi and Bluetooth modes to share a single antenna. &lt;br /&gt;
&lt;br /&gt;
The wireless module interfaces with the Pinebook Pro’s system-on-chip using a combination of three interfaces: Bluetooth functionality is operated by serial UART and PCM, while the Wi-Fi component uses SDIO. It is unknown if the module’s Bluetooth capabilities are usable under operating systems that do not support SDIO.&lt;br /&gt;
&lt;br /&gt;
The module’s RF antenna pin is exposed on the mainboard via a standard Hirose U.FL connector, where a coaxial feedline links it to a flexible adhesive antenna situated near the upper right corner of the Pinebook Pro’s battery. As the RF connector is fragile and easily damaged, it should be handled carefully during connection and disconnection, and should not be reconnected frequently.&lt;br /&gt;
&lt;br /&gt;
===Issues===&lt;br /&gt;
Problems have been reported with the Wi-Fi transceiver’s reliability during extended periods of high throughput, especially on the 2.4 GHz band. While the cause of this has yet to be determined, switching to the 5 GHz band may improve stability.&lt;br /&gt;
&lt;br /&gt;
Since the Bluetooth transceiver shares both its spectrum and antenna with 2.4 GHz Wi-Fi, simultaneous use of these modes may cause interference, especially when listening to audio over Bluetooth. If Bluetooth audio cuts out frequently, switching to the 5 GHz band – or deactivating Wi-Fi – may help.&lt;br /&gt;
&lt;br /&gt;
===Wi-Fi Capabilities===&lt;br /&gt;
Wi-Fi on the Pinebook Pro is capable of reaching a maximum data transfer rate of approximately 433 megabits per second, using one spatial stream. The transceiver does not support multiple spatial streams or 160-MHz channel bandwidths.&lt;br /&gt;
&lt;br /&gt;
The Wi-Fi transceiver supports the lower thirteen standard channels on the 2.4 GHz band, using a bandwidth of 20 MHz. At least twenty-four channels are supported on the 5 GHz band, spanning frequencies from 5180 to 5320 MHz, 5500 to 5720 MHz, and 5745 to 5825 MHz, with bandwidths of 20, 40, or 80 MHz.&lt;br /&gt;
&lt;br /&gt;
Maximum reception sensitivity for both bands is approximately -92 dBm. The receiver can tolerate input intensities of no more than -20 dBm on the 2.4 GHz band, and no more than -30 dBm on the 5 GHz band. Maximum transmission power is approximately +15 dBm for either band, falling further to approximately +10 dBm at higher data transfer rates on the 5 GHz band.&lt;br /&gt;
&lt;br /&gt;
With current available drivers and firmware, the Wi-Fi interface supports infrastructure, ad-hoc, and access-point modes with satisfactory reliability. Monitor mode is not presently supported. Wi-Fi Direct features may be available, but it is unclear how to make use of them under Linux.&lt;br /&gt;
&lt;br /&gt;
Be aware that Linux userspace utilities, such as &amp;lt;code&amp;gt;iw&amp;lt;/code&amp;gt;, may report inaccurate information about the capabilities of wireless devices. Parameter values derived from vendor datasheets, or direct testing, should be preferred to the outputs of hardware-querying tools.&lt;br /&gt;
&lt;br /&gt;
===Bluetooth Capabilities===&lt;br /&gt;
Bluetooth data transfer speeds have an indicated maximum of 3 megabits per second, but it is unclear what practical data rates can be expected. Audio streaming over Bluetooth is functioning normally, as is networking. Bluetooth Low-Energy functions, such as interacting with Bluetooth beacons, have not yet been tested conclusively.&lt;br /&gt;
&lt;br /&gt;
The Bluetooth transceiver supports all 79 channel allocations, spanning frequencies from 2402 MHz to 2480 MHz. Reception sensitivity is approximately -85 dBm, with a maximum tolerable reception intensity of -20 dBm. Bluetooth transmission power is limited to +10 dBm.&lt;br /&gt;
&lt;br /&gt;
===Disabling Bluetooth===&lt;br /&gt;
&lt;br /&gt;
To disable Bluetooth under Linux once:&lt;br /&gt;
&lt;br /&gt;
 sudo rfkill block bluetooth&lt;br /&gt;
&lt;br /&gt;
To confirm if Bluetooth under Linux is disabled:&lt;br /&gt;
&lt;br /&gt;
 rfkill&lt;br /&gt;
&lt;br /&gt;
To disable Bluetooth on boot (note: for distributions such as Manjaro XFCE see the step below):&lt;br /&gt;
&lt;br /&gt;
 sudo systemctl enable rfkill-block@bluetooth&lt;br /&gt;
&lt;br /&gt;
To disable Bluetooth on certain distributions, such as Manjaro XFCE, right click on the Bluetooth panel icon, select &amp;lt;i&amp;gt;plugins&amp;lt;/i&amp;gt;, then &amp;lt;i&amp;gt;PowerManager&amp;lt;/i&amp;gt;, then &amp;lt;i&amp;gt;configuration&amp;lt;/i&amp;gt; and then deselect the &amp;lt;i&amp;gt;auto power on&amp;lt;/i&amp;gt; option&lt;br /&gt;
&lt;br /&gt;
== LCD Panel ==&lt;br /&gt;
* Model: BOE NV140FHM-N49&lt;br /&gt;
* 14.0&amp;quot; (35.56&amp;amp;nbsp;cm) diagonal size&lt;br /&gt;
* 1920x1080 resolution&lt;br /&gt;
* 60&amp;amp;nbsp;Hz refresh rate&lt;br /&gt;
* IPS technology&lt;br /&gt;
* 1000:1 contrast&lt;br /&gt;
* 250&amp;amp;nbsp;nit brightness&lt;br /&gt;
* 63% sRGB coverage&lt;br /&gt;
* 6-bit color&lt;br /&gt;
* 30-pin eDP connection&lt;br /&gt;
&lt;br /&gt;
Some people have tested hardware video decode using the following;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;ffmpeg -benchmark -c:v h264_rkmpp -i file.mp4 -f null -&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== External ports list ==&lt;br /&gt;
Here are a list of the external ports. See [[Pinebook_Pro#Expansion_Ports|Technical Reference - Expansion Ports]] for port specifications.&lt;br /&gt;
* Left side&lt;br /&gt;
** Barrel jack for power, (with LED)&lt;br /&gt;
** USB 3, Type A&lt;br /&gt;
** USB 3, Type C&lt;br /&gt;
* Right side&lt;br /&gt;
** USB 2, Type A&lt;br /&gt;
** Standard headset jack&lt;br /&gt;
** MicroSD card slot&lt;br /&gt;
&lt;br /&gt;
== Using the UART ==&lt;br /&gt;
[[File:PinePhone_Serial_Cable.png|400px|thumb|right|Pinout of the serial adapter. Swapping the tx and rx around from this also works and is more traditional. See the official [https://files.pine64.org/doc/pinebook/guide/Pinebook_Earphone_Serial_Console_Developer_Guide.pdf Pine64 document].]]&lt;br /&gt;
&lt;br /&gt;
UART output is enabled by flipping the UART switch to the ON position (item 9). To do so you need to remove the Pinebook Pro's bottom cover - please follow [[Pinebook_Pro#Disassembly_and_Reassembly|proper disassembly and reassembly protocol]]. The OFF position is towards the touchpad, the ON position is towards the display hinges.&lt;br /&gt;
&lt;br /&gt;
With the UART switch in the ON position, console is relayed via the audiojack and the laptop's sound is turned OFF. Please ensure that you are using a 3.3&amp;amp;nbsp;V interface (such as the CH340, FTDI-232R, or PL2303, which are sold in both 3.3&amp;amp;nbsp;V and 5&amp;amp;nbsp;V variants) to avoid damage to the CPU.  Older version of the serial console cable sold by Pine64 uses wrong voltage level and should not be used; see [https://forum.pine64.org/showthread.php?tid=9367 this forum thread] for further information.  Recent version of the same cable uses the right voltage level.&lt;br /&gt;
&lt;br /&gt;
Insert the USB plug of the cable into an open USB port on the machine which will monitor, ensuring that the audio jack of the serial cable is be fully inserted into the Pinebook Pro audio port. Run the following in a terminal:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
$ lsusb&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
you should find a line similar to this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
Bus 001 Device 058: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Serial output should now be accessible using screen, picocom or minicom (and others).&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
screen /dev/ttyUSB0 1500000&lt;br /&gt;
&lt;br /&gt;
picocom /dev/ttyUSB0 -b 1500000&lt;br /&gt;
&lt;br /&gt;
minicom -D /dev/ttyUSB0 -b 1500000&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Old versions of U-Boot do not use the UART for console output. &amp;lt;strike&amp;gt;The console function is activated by the Linux kernel. Thus, if you use a non-Pinebook Pro Linux distro and want the UART as a console, you have to manually enable it.&amp;lt;/strike&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Using the optional NVMe adapter ==&lt;br /&gt;
The optional NVMe adapter allows the use of M.2 cards that support the NVMe standard, (but not SATA standard). The optional NVMe M.2 adapter supports '''M''' &amp;amp; '''M'''+'''B''' keyed devices, in both 2242 &amp;amp; 2280 physical sizes, the most common ones available. In addition, 2230 &amp;amp; 2260 are also supported, though NVMe devices that use those sizes are rare.&lt;br /&gt;
&lt;br /&gt;
Once you have fitted and tested your NVMe drive, please add a note to this page [[Pinebook Pro Hardware Accessory Compatibility]] to help build a list of tried and tested devices.&lt;br /&gt;
&lt;br /&gt;
Please see [[Pinebook Pro Troubleshooting Guide#NVMe SSD issues|a separate section]] that describes reported issues with the NVMe drives in PineBook Pro.&lt;br /&gt;
&lt;br /&gt;
=== Installing the adapter ===&lt;br /&gt;
The V2.1-2019-0809 SSD adapter that shipped with the initial Pinebook Pro batches had significant issues. A repair kit will be shipped to address those issues.&lt;br /&gt;
(If necessary, it can be modified to work. There is [https://forum.pine64.org/showthread.php?tid=8322&amp;amp;pid=52700#pid52700 an unofficial tutorial on the forums] describing these modifications.)&lt;br /&gt;
&lt;br /&gt;
The updated SSD adapter, labeled V2-2019-1107, takes into account the prior problems with touchpad interference. New orders as of Feb. 22nd, 2020 will be the updated adapter.&lt;br /&gt;
&lt;br /&gt;
This is the link to the Pinebook Pro accessories in the store: [[https://pine64.com/?v=0446c16e2e66]]&lt;br /&gt;
&lt;br /&gt;
Actual installation instructions are a work in progress. Unofficial instructions for installing V2-2019-1107 can be found [https://eli.gladman.cc/blog/2020/06/23/pine-book-pro-nvme.html here].&lt;br /&gt;
&lt;br /&gt;
=== Post NVMe install power limiting ===&lt;br /&gt;
Some NVMe SSDs allow reducing the maximum amount of power. Doing so may reduce the speed, but it may be needed in the Pinebook Pro to both improve reliability at lower battery levels. And to reduce power used, to maintain battery life.&lt;br /&gt;
Here are the commands to obtain and change the power settings. The package 'nvme-cli' is required to run these commands. The example shows how to find the available power states, and then sets it to the lowest, non-standby setting, (which is 3.8 watts for the device shown);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo nvme id-ctrl /dev/nvme0&lt;br /&gt;
NVME Identify Controller:&lt;br /&gt;
...&lt;br /&gt;
ps    0 : mp:9.00W operational enlat:0 exlat:0 rrt:0 rrl:0&lt;br /&gt;
         rwt:0 rwl:0 idle_power:- active_power:-&lt;br /&gt;
ps    1 : mp:4.60W operational enlat:0 exlat:0 rrt:1 rrl:1&lt;br /&gt;
         rwt:1 rwl:1 idle_power:- active_power:-&lt;br /&gt;
ps    2 : mp:3.80W operational enlat:0 exlat:0 rrt:2 rrl:2&lt;br /&gt;
         rwt:2 rwl:2 idle_power:- active_power:-&lt;br /&gt;
ps    3 : mp:0.0450W non-operational enlat:2000 exlat:2000 rrt:3 rrl:3&lt;br /&gt;
         rwt:3 rwl:3 idle_power:- active_power:-&lt;br /&gt;
ps    4 : mp:0.0040W non-operational enlat:6000 exlat:8000 rrt:4 rrl:4&lt;br /&gt;
         rwt:4 rwl:4 idle_power:- active_power:-&lt;br /&gt;
&lt;br /&gt;
$ sudo nvme get-feature /dev/nvme0 -f 2&lt;br /&gt;
get-feature:0x2 (Power Management), Current value:00000000&lt;br /&gt;
$ sudo nvme set-feature /dev/nvme0 -f 2 -v 2 -s&lt;br /&gt;
set-feature:02 (Power Management), value:0x000002&amp;lt;/pre&amp;gt;&lt;br /&gt;
Some NVMe SSDs don't appear to allow saving the setting with &amp;quot;-s&amp;quot; option. In those cases, leave off the &amp;quot;-s&amp;quot; and use a startup script to set the non-default power state at boot.&amp;lt;br&amp;gt;&lt;br /&gt;
If you want to test performance without saving the new power setting semi-permanantly, then leave off the &amp;quot;-s&amp;quot; option.&amp;lt;br/&amp;gt;&lt;br /&gt;
&amp;lt;br/&amp;gt;&lt;br /&gt;
There is another power saving feature for NVMes, APST, (Autonomous Power State Transitions). This performs the power saving &amp;amp; transitions based on usage. To check if you have a NVMe SSD with this feature;&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo nvme get-feature -f 0x0c -H /dev/nvme0&amp;lt;/pre&amp;gt;&lt;br /&gt;
Information for this feature, (on a Pinebook Pro), is a work in progress.&lt;br /&gt;
&lt;br /&gt;
=== Using as data drive ===&lt;br /&gt;
As long as the kernel in use has both the PCIe and NVMe drivers, you should be able to use a NVMe drive as a data drive. It can automatically mount when booting from either the eMMC or an SD card. This applies to Linux, FreeBSD, and Chromium, using the normal partitioning and file system creation tools. Android requires testing.&lt;br /&gt;
&lt;br /&gt;
=== Using as OS root drive ===&lt;br /&gt;
The SoC does not include the NVMe boot code, so the NVMe is not in the SoC's boot order. However, using the [https://github.com/mrfixit2001/updates_repo/blob/v1.1/pinebook/filesystem/mrfixit_update.sh U-Boot update script] from the mrfixit2001 Debian or [https://pastebin.com/raw/EeK074XB Arglebargle's modified script], and [https://github.com/pcm720/rockchip-u-boot/releases the modified u-boot images] provided by forum user pcm720, you can now add support to boot from an NVMe drive. Binary images are useable with SD, eMMC, and [[Pinebook_Pro_SPI|SPI flash]]. For OS images using the mainline kernel, there are a few variants of U-Boot available that also support NVMe as the OS drive. Though these may require writing the U-Boot to the SPI flash for proper use of the NVMe as the OS drive.&lt;br /&gt;
&lt;br /&gt;
The current boot order, per last testing, for this modified U-Boot is:&lt;br /&gt;
*MicroSD&lt;br /&gt;
*eMMC&lt;br /&gt;
*NVMe&lt;br /&gt;
&lt;br /&gt;
For more information, please refer to [https://forum.pine64.org/showthread.php?tid=8439&amp;amp;pid=53764#pid53764 the forum post.]&lt;br /&gt;
&lt;br /&gt;
It is also possible to initially boot off an eMMC or SD card, then transfer to a root file system on the NVMe. Currently, it is necessary to have the U-Boot code on an eMMC or SD card.  (A forum member [https://forum.pine64.org/showthread.php?tid=8439 posted here] about using a modified version of U-Boot with NVMe drivers, that uses &amp;lt;code&amp;gt;/boot&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;/&amp;lt;/code&amp;gt; off the NVMe drive. So this may change in the future.)&lt;br /&gt;
&lt;br /&gt;
Please see [[Pinebook_Pro#Bootable Storage|Bootable Storage]].&lt;br /&gt;
&lt;br /&gt;
== Caring for the PineBook Pro ==&lt;br /&gt;
=== Bypass Cables ===&lt;br /&gt;
The mainboard features two (disconnected by default) bypass cables that are only to be used with the battery disconnected. The female (10) male (6) ends of the bypass cables can be connected to provide power to the mainboard if you need to run the laptop without a battery. Please refer to this [https://files.pine64.org/doc/PinebookPro/PinebookPro_Engineering_Notice.pdf engineering notice].  &lt;br /&gt;
&lt;br /&gt;
'''Note that despite the bypass cable being a two conductor cable, it is only used as one. Both wires being soldered together on either side is normal!'''&lt;br /&gt;
&lt;br /&gt;
{{warning|Do not connect the bypass cables with the battery connected.  Using the bypass cables with the battery connected can permanently damage the computer.}}&lt;br /&gt;
&lt;br /&gt;
=== Pinebook Service Step-by-Step Guides ===&lt;br /&gt;
&lt;br /&gt;
Under [[Pinebook_Service_Step_by_Step_Guides|Service Guides for Pinebook]] you can find instructions guides concerning disassembly of:&lt;br /&gt;
&lt;br /&gt;
* The installation process on Pinebook Pro similar to 14&amp;quot; Pinebook&lt;br /&gt;
* The installation process is the reverse order of removal guide:&lt;br /&gt;
** 14″ Pinebook Lithium Battery Pack Removal Guide&lt;br /&gt;
** 14″ Pinebook LCD Panel Screen Removal Guide&lt;br /&gt;
** 14″ Pinebook eMMC Module Removal Guide&lt;br /&gt;
&lt;br /&gt;
== Using the SPI flash device ==&lt;br /&gt;
&lt;br /&gt;
See [[Pinebook Pro SPI]] for details.&lt;br /&gt;
&lt;br /&gt;
The Pinebook Pro comes with a 128Mbit, (16MByte), flash device suitable for initial boot target, to store the bootloader. The SoC used on the Pinebook Pro boots from this SPI flash device first, before eMMC or SD card. At present, April 19, 2020, the Pinebook Pros ship without anything programmed in the SPI flash device. So the SoC moves on to the next potential boot device, the eMMC. ARM/ARM64 computers do not have a standardized BIOS, yet.&lt;br /&gt;
&lt;br /&gt;
Here is some information on using the SPI flash device:&lt;br /&gt;
&lt;br /&gt;
* You need the kernel built with SPI flash device support, which will supply a device similar to: code&amp;gt;/dev/mtd0&amp;lt;/code&amp;gt;&lt;br /&gt;
* The Linux package below, will need to be available: &amp;lt;code&amp;gt;mtd-utils&amp;lt;/code&amp;gt;&lt;br /&gt;
* You can then use this program from the package to write the SPI device: &amp;lt;code&amp;gt;flashcp &amp;amp;lt;filename&amp;amp;gt; /dev/mtd0&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Even if you need to recover from a defective bootloader written to the SPI flash, you can simply short pin 6 of the SPI flash to GND and boot. This will render the SoC bootrom unable to read from the SPI flash and have it fall back to reading the bootloader from other boot media like the eMMC or Micro SD card.&lt;br /&gt;
&lt;br /&gt;
The procedures described above are a lot less risky than attaching an external SPI flasher and do not require any additional hardware. At present, April 19th, 2020, there is no good bootloader image to flash into the SPI flash device. This is expected to change, as there are people working on issue.&lt;br /&gt;
&lt;br /&gt;
= Software tuning guide =&lt;br /&gt;
Details on how to get the most out of a Pinebook Pro &amp;amp; its RK3399 SoC.&lt;br /&gt;
&lt;br /&gt;
== Customizing the Pinebook Pro's default Manjaro KDE system ==&lt;br /&gt;
=== Watching DRM content (Netflix, etc.) ===&lt;br /&gt;
Most paid online streaming services use Widevine DRM to make their content more difficult to pirate. Widevine is not directly supported on Manjaro KDE, however it is still possible to watch DRM content via the &amp;quot;chromium-docker&amp;quot; package which downloads a 32-bit ARM container and installs Chromium with Widevine inside of that. While not space-efficient, or efficient in general, it's the recommended solution for watching this content on your Pinebook Pro. You can install this package with:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo pacman -Sy chromium-docker&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Checking GPU capabilities ===&lt;br /&gt;
To see what versions of OpenGL and OpenGL ES are supported by the Pinebook Pro, what driver is in use, and what version of the driver is loaded, install the &amp;quot;mesa-demos&amp;quot; package with:&lt;br /&gt;
&amp;lt;pre&amp;gt;sudo pacman -Sy mesa-demos&amp;lt;/pre&amp;gt;&lt;br /&gt;
And then run:&lt;br /&gt;
&amp;lt;pre&amp;gt;glxinfo | grep OpenGL&amp;lt;/pre&amp;gt;&lt;br /&gt;
This will give detailed information about your graphics card and driver, useful for debugging.&lt;br /&gt;
&lt;br /&gt;
=== Better GPU compatibility and performance ===&lt;br /&gt;
For better graphics performance, you may install the &amp;quot;mesa-git&amp;quot; package, built and supplied in the Manjaro ARM repos. This lets you bring in the latest features, optimizations, and bugfixes for the graphics driver used by the Pinebook Pro. Installation is as simple as:&lt;br /&gt;
&amp;lt;pre&amp;gt;pacman -Sy mesa-git&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then you may reboot to load the newer driver.&lt;br /&gt;
&lt;br /&gt;
With Mesa 20.2 there is no longer much reason to use this over the standard mesa package, and applications may occasionally break with mesa-git.&lt;br /&gt;
&lt;br /&gt;
[https://docs.mesa3d.org/bugs.html Reporting bugs] to the Mesa project will help make sure any problems are quickly fixed.&lt;br /&gt;
&lt;br /&gt;
=== OpenGL 3.3 support ===&lt;br /&gt;
By default, with the current state of the Panfrost GPU driver, the Pinebook Pro supports OpenGL 2.1 and OpenGL ES 3.0. If you want to use OpenGL 3.3, you need to set the system-wide environment variable, open the '''/etc/environment''' file with:&lt;br /&gt;
&amp;lt;pre&amp;gt;kate /etc/environment&amp;lt;/pre&amp;gt;&lt;br /&gt;
And then at the bottom of the file, on a new line, add:&lt;br /&gt;
&amp;lt;pre&amp;gt;PAN_MESA_DEBUG=&amp;quot;gl3&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
Then save the file, entering your password when prompted, and reboot the system. When you check your GPU capabilities, it should report OpenGL 3.3 and applications that rely on it should function properly. Note that GL 3.3 support is incomplete and some rendering features do not work yet, notably geometry shaders.&lt;br /&gt;
&lt;br /&gt;
=== Install Anbox on Pinebook Pro Manjaro 20.10 ===&lt;br /&gt;
[https://www.youtube.com/watch?v=EU8_Q11dATs Youtube video on installing Anbox on Pienbook Pro Manjaro Build 20.10 by LivingLinux]&lt;br /&gt;
&lt;br /&gt;
== Customizing the Pinebook Pro's previously-default Debian system ==&lt;br /&gt;
Here are some hints on what you can do to customize the Pinebook Pro's previous factory image (aka [https://github.com/mrfixit2001/debian_desktop mrfixit2001 debian build])&lt;br /&gt;
&lt;br /&gt;
=== Initial user changes, password, name, etc ===&lt;br /&gt;
When you first get your Pinebook Pro, you should consider setting strong passwords and making the default account your own.&lt;br /&gt;
&lt;br /&gt;
* Reboot (this is just to ensure all background processes belong to the user are not running... there are other ways to achieve this but this way is easy)&lt;br /&gt;
* Once the machine reboots press Alt-Ctrl-F1 to bring up a text terminal&lt;br /&gt;
* Login as root (login: root, password: root)&lt;br /&gt;
* Set a strong password for the root user using the following command and it's prompts:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd (and follow prompts)&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Rename the rock user to your prefered username (replace myself with whatever you like):&lt;br /&gt;
&amp;lt;pre&amp;gt;# usermod -l myself -d /home/myself -m rock&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Rename the rock group to match your preferred username:&lt;br /&gt;
&amp;lt;pre&amp;gt;# groupmod -n myself rock&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Put your name in the account, (replace &amp;quot;John A Doe&amp;quot; with your name):&lt;br /&gt;
&amp;lt;pre&amp;gt;# chfn -f &amp;quot;John A Doe&amp;quot; myself&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Set a strong password for the normal user:&lt;br /&gt;
&amp;lt;pre&amp;gt;# passwd myself&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Log out of the text terminal:&lt;br /&gt;
&amp;lt;pre&amp;gt;# logout&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Press Alt-Ctrl-F7 to go back to the login screen and then login as the normal user&lt;br /&gt;
* Open text terminal to fix login error: &amp;quot;Configured directory for incoming files does not exist&amp;quot;;&lt;br /&gt;
&amp;lt;pre&amp;gt;$ blueman-services&amp;lt;/pre&amp;gt;&lt;br /&gt;
Select &amp;quot;Transfer&amp;quot; tab and set &amp;quot;Incoming Folder&amp;quot; to myself&lt;br /&gt;
OR&lt;br /&gt;
If adduser is in distro, this is MUCH easier&lt;br /&gt;
sudo adduser $USER ,, fill out requested data&lt;br /&gt;
Then,, sudo adduser $USER $GROUP,,, 1 group at a time&lt;br /&gt;
To see which groups to add,,, id $USER,  id rock&lt;br /&gt;
&lt;br /&gt;
=== Changing the default hostname ===&lt;br /&gt;
Debian 9 has a command to allow you to change the hostname. You can see the current settings using;&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo hostnamectl&lt;br /&gt;
   Static hostname: Debian-Desktop&lt;br /&gt;
         Icon name: computer&lt;br /&gt;
        Machine ID: dccbddccbdccbdccbdccbdccbdccbccb&lt;br /&gt;
           Boot ID: ea99ea99ea99ea99ea99ea99ea99ea99&lt;br /&gt;
  Operating System: Debian GNU/Linux 9 (stretch)&lt;br /&gt;
            Kernel: Linux 4.4.210&lt;br /&gt;
      Architecture: arm64&amp;lt;/pre&amp;gt;&lt;br /&gt;
To change, use this, (with &amp;quot;My_Hostname&amp;quot; used as the example);&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo hostnamectl set-hostname My_Hostname&amp;lt;/pre&amp;gt;&lt;br /&gt;
Whence done, you can re-verify using the first example.&lt;br /&gt;
&lt;br /&gt;
Then you should backup and edit your &amp;lt;code&amp;gt;/etc/hosts&amp;lt;/code&amp;gt; entry's name;&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo cp -p /etc/hosts /etc/hosts.`date +%Y%m%d`&lt;br /&gt;
$ sudo vi /etc/hosts&lt;br /&gt;
127.0.0.1	localhost&lt;br /&gt;
127.0.0.1	My_Hostname&lt;br /&gt;
::1		localhost ip6-localhost ip6-loopback&lt;br /&gt;
fe00::0		ip6-localnet&lt;br /&gt;
ff00::0		ip6-mcastprefix&lt;br /&gt;
ff02::1		ip6-allnodes&lt;br /&gt;
ff02::2		ip6-allrouters&lt;br /&gt;
127.0.1.1       linaro-alip&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Disable Chromium browser's prompt for passphrase &amp;amp; password storage ===&lt;br /&gt;
&lt;br /&gt;
Perform the following steps:&lt;br /&gt;
&lt;br /&gt;
* On the tool bar, hover over the Chromium icon&lt;br /&gt;
* Using the right mouse button, select '''Properties'''&lt;br /&gt;
* In the '''Command:''' line section, add &amp;lt;code&amp;gt;--password-store=basic&amp;lt;/code&amp;gt; before the &amp;lt;code&amp;gt;%U&amp;lt;/code&amp;gt;&lt;br /&gt;
* Use the '''x Close''' button to save the change&lt;br /&gt;
This will of course, use basic password storage, meaning any saved passwords are not encrypted. Perfectly fine if you never use password storage.&lt;br /&gt;
&lt;br /&gt;
=== Changing the boot splash picture ===&lt;br /&gt;
&lt;br /&gt;
The default boot splash picture can be replaced using the following instructions:&lt;br /&gt;
&lt;br /&gt;
* Install '''ImageMagick''' which will do the conversion&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo apt-get install imagemagick&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Create a 1920 x 1080 picture. For the best results, use a PNG image (It supports lossless compression).&lt;br /&gt;
* From the directory in which your new image is stored run the following commands&lt;br /&gt;
* Convert your image to the bootsplash raw format using imagemagick convert.&lt;br /&gt;
&amp;lt;pre&amp;gt;$ convert yoursplashimage.png -separate +channel -swap 0,2 -combine -colorspace sRGB RGBO:splash.fb&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Create a backup copy of your current splash screen&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo cp /usr/share/backgrounds/splash.fb /usr/share/backgrounds/splash_original.fb&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Copy your new splash screen into place&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo cp splash.fb /usr/share/backgrounds/splash.fb&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Set the correct permissions on the splash.fb file&lt;br /&gt;
&amp;lt;pre&amp;gt;$ sudo chmod 644 /usr/share/backgrounds/splash.fb&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you do not want to see kernel console text messages, make sure you don't have '''Plymouth''' installed&lt;br /&gt;
&lt;br /&gt;
=== Watching Amazon Prime videos with Chromium ===&lt;br /&gt;
When you create a new user, it will be necessary to launch the Chromium browswer with a specific user agent like below;&lt;br /&gt;
&amp;lt;pre&amp;gt;chromium-browser --user-agent=&amp;quot;Mozilla/5.0 (X11; CrOS armv7l 6946.63.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36&amp;quot;&amp;lt;/pre&amp;gt;&lt;br /&gt;
There may be more tweaks needed.&lt;br /&gt;
&lt;br /&gt;
=== Enabling text boot time messages ===&lt;br /&gt;
&lt;br /&gt;
By default, most Linux distros have a boot screen with a picture. To see all the boot time messages, use one of the following;&lt;br /&gt;
&lt;br /&gt;
==== Debian ====&lt;br /&gt;
* Backup and edit the U-Boot configuration file:&lt;br /&gt;
&lt;br /&gt;
 cp -p /etc/default/u-boot /etc/default/u-boot.`date +%Y%m%d`&lt;br /&gt;
 chmod a-w /etc/default/u-boot.`date +%Y%m%d`&lt;br /&gt;
 vi /etc/default/u-boot&lt;br /&gt;
&lt;br /&gt;
Remove the '''quiet''' and '''splash''' parameters. Leave everything else alone.&lt;br /&gt;
&lt;br /&gt;
* Update the U-Boot configuration:&lt;br /&gt;
&lt;br /&gt;
 u-boot-update&lt;br /&gt;
&lt;br /&gt;
* Test and verify you get what you think you should be seeing.&lt;br /&gt;
&lt;br /&gt;
==== Manjaro ====&lt;br /&gt;
* Backup and edit the U-Boot configuration file:&lt;br /&gt;
&lt;br /&gt;
 cp -p /boot/extlinux/extlinux.conf /boot/extlinux/extlinux.conf.`date +%Y%m%d`&lt;br /&gt;
 chmod a-w /boot/extlinux/extlinux.conf.`date +%Y%m%d`&lt;br /&gt;
 vi /boot/extlinux/extlinux.conf&lt;br /&gt;
&lt;br /&gt;
* Change '''console=ttyS2,1500000''' to '''console=tty1'''&lt;br /&gt;
* Remove the '''bootsplash.bootfile''' option and it's parameter.&lt;br /&gt;
* You can add verbose logging by appending '''ignore_loglevel''' to the line where boot splash was.&lt;br /&gt;
* Leave everything else alone.&lt;br /&gt;
* Test and verify you get what you think you should be seeing.&lt;br /&gt;
&lt;br /&gt;
== Improving readability ==&lt;br /&gt;
&lt;br /&gt;
Some people find that a 14&amp;quot; LCD screen with 1080p, (1920 x 1080), has text and icons a bit too small. There are things you can do to make the screen easier to use and read.&amp;lt;br&amp;gt;&lt;br /&gt;
* Increase the font size&lt;br /&gt;
* Use a font with more pronounced features&lt;br /&gt;
* Increase the various window manager sizes (e.g. increase the height of the tool bar)&lt;br /&gt;
* Change the color scheme to be easier on the eyes. Higher contrast can help usability.&lt;br /&gt;
* Change the window manager's decorations (e.g. use larger icons)&lt;br /&gt;
* Use a workspace manager, with one application per workspace&lt;br /&gt;
* When at home or office, use an external monitor&lt;br /&gt;
* Change the X-Windows DPI. One such method that someone used successfully, is:&amp;lt;br&amp;gt;&amp;lt;blockquote&amp;gt;&amp;lt;code&amp;gt;echo &amp;quot;Xft.dpi: 150&amp;quot; &amp;gt;&amp;gt; ~/.Xresources&amp;lt;/code&amp;gt;&amp;lt;/blockquote&amp;gt;Change the 150 as desired to get the size adjustment you want.&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
However, do not change the resolution of the LCD screen, otherwise you may end up with a blank / black screen. If that happens, see this troubleshooting section for the fix:&amp;lt;br&amp;gt;&lt;br /&gt;
[[Pinebook_Pro#After_changing_builtin_LCD_resolution.2C_blank_screen|Blank screen after changing builtin LCD resolution]]&lt;br /&gt;
&lt;br /&gt;
== Chromium tweaks ==&lt;br /&gt;
&lt;br /&gt;
=== Flags ===&lt;br /&gt;
&lt;br /&gt;
From the [https://github.com/mrfixit2001/updates_repo/blob/v1.8/pinebook/filesystem/default official Debian image]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
--disable-low-res-tiling \&lt;br /&gt;
--num-raster-threads=6 \&lt;br /&gt;
--profiler-timing=0 \&lt;br /&gt;
--disable-composited-antialiasing \&lt;br /&gt;
--test-type \&lt;br /&gt;
--show-component-extension-options \&lt;br /&gt;
--ignore-gpu-blacklist \&lt;br /&gt;
--use-gl=egl \&lt;br /&gt;
--ppapi-flash-path=/usr/lib/chromium-browser/pepper/libpepflashplayer.so \&lt;br /&gt;
--ppapi-flash-version=32.0.0.255 \&lt;br /&gt;
--enable-pinch \&lt;br /&gt;
--flag-switches-begin \&lt;br /&gt;
--enable-gpu-rasterization \&lt;br /&gt;
--enable-oop-rasterization \&lt;br /&gt;
--flag-switches-end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that in some cases, this may also decrease performance substantially, as observed when using these flags on the Manjaro KDE desktop. Feel free to experiment to find what is smoothest for you personally.&lt;br /&gt;
&lt;br /&gt;
== gVim has performance issue ==&lt;br /&gt;
It appears that using GTK3 can cause very slow scrolling, while Vim in a terminal window works fine.&amp;lt;br/&amp;gt;&lt;br /&gt;
Simply revert back to using GTK2, (how to do so is somewhat Linux distro-specific).&lt;br /&gt;
&lt;br /&gt;
Another solution may be to run gVim with &lt;br /&gt;
&lt;br /&gt;
 GDK_RENDERING=image&lt;br /&gt;
&lt;br /&gt;
environment variable set. It seems that this improves the performance by reverting back to software-only rendering.&lt;br /&gt;
&lt;br /&gt;
== Kernel options ==&lt;br /&gt;
Here are some Pinebook Pro &amp;amp; its RK3399 SoC Linux specific options. If kernel version, (or version range specific), it should list that information in the description.&lt;br /&gt;
&lt;br /&gt;
To see if a specific feature is enabled in the current kernel, you can use something like this;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ zgrep -i rockchip_pcie /proc/config.gz&lt;br /&gt;
# CONFIG_ROCKCHIP_PCIE_DMA_OBJ is not set&lt;br /&gt;
CONFIG_PHY_ROCKCHIP_PCIE=m&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If it's listed as &amp;lt;code&amp;gt;=m&amp;lt;/code&amp;gt;, then it's a module. You can see if the module is loaded with;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ lsmod | grep -i rockchip_pcie&lt;br /&gt;
phy_rockchip_pcie      16384  0&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note modules are not loaded until needed. Thus, we sometimes check the kernel configuration instead to see if a feature is configured first, then see if it's a module.&lt;br /&gt;
&lt;br /&gt;
=== Hardware video decoding ===&lt;br /&gt;
Here is a method to check for hardware video decoding by the VPU. There are special Linux kernel modules that perform this function.&amp;lt;br&amp;gt;&lt;br /&gt;
Older systems, such as the previously-default Debian desktop, use the Rockchip-supplied kernel module &amp;lt;code&amp;gt;rk-vcodec&amp;lt;/code&amp;gt;. To check, something like this can be used:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ lsmod | grep rk-vcodec&lt;br /&gt;
    or&lt;br /&gt;
$ zgrep RK_VCODEC /proc/config.gz&lt;br /&gt;
CONFIG_RK_VCODEC=y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that in the above example, the Rockchip video CODEC is not built as a module, but included into the kernel. Thus, it does not show up in the list modules check.&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Newer systems may use a different option as in the configuration below:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ zgrep HANTRO /proc/config.gz&lt;br /&gt;
CONFIG_VIDEO_HANTRO=m&lt;br /&gt;
CONFIG_VIDEO_HANTRO_ROCKCHIP=y&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting guide =&lt;br /&gt;
&lt;br /&gt;
Do not to panic if something goes wrong or in an unexpected way.  Instead, stop and consider carefully how to undo something, or how to redo it.  This particularly applies when flashing a new operating system, or flashing new firmware to the keyboard or touchpad.  If everything fails, consider reporting the issue on the forums, with as many relevant details as available.&lt;br /&gt;
&lt;br /&gt;
Please, have a look at the [[Pinebook Pro Troubleshooting Guide]], which details a number of issues you may encounter.&lt;br /&gt;
&lt;br /&gt;
= Hardware/Accessory Compatibility =&lt;br /&gt;
Please contribute to the [[Pinebook Pro Hardware Accessory Compatibility|hardware/accessory compatibility page]], which lists the status of hardware tested with the Pinebook Pro.  Available hardware categories include the following:&lt;br /&gt;
&lt;br /&gt;
* [[Pinebook Pro Hardware Accessory Compatibility#NVMe SSD drives|NVMe SSD drives]]&lt;br /&gt;
* [[Pinebook Pro Hardware Accessory Compatibility#USB hardware|USB hardware]]&lt;br /&gt;
* [[Pinebook Pro Hardware Accessory Compatibility#USB C alternate mode DP|USB-C alternate mode DP]]&lt;br /&gt;
* [[Pinebook Pro Hardware Accessory Compatibility#Other hardware|Other hardware]]&lt;br /&gt;
&lt;br /&gt;
= Technical Reference =&lt;br /&gt;
== Disassembly and Reassembly  == &lt;br /&gt;
[[File:Standoffs.png|400px|thumb|right|Pinebook Screw stand-offs correct placement and location]]&lt;br /&gt;
&lt;br /&gt;
[[File:Hinges_cover_removed_1.jpeg|300px|thumb|right|Hinge area of the Pinebook Pro lid with the cover removed]]&lt;br /&gt;
[[File:Hinges_cover_removed_2.jpeg|300px|thumb|right|Close-up of a Pinebook Pro lid hinge]]&lt;br /&gt;
&lt;br /&gt;
There are a few '''mandatory''' precautions to be taken:&lt;br /&gt;
&lt;br /&gt;
* Do not open the laptop by lifting the lid while the Pinebook Pro bottom cover is removed - this can cause structural damage to the hinges and/or other plastic components of the chassis such as the IO port cut-outs.&lt;br /&gt;
* When removing the back cover plate, *do not, under any circumstances, slide your fingertips between the metal shell and the plastic frame!* The back cover plate edges are sharp, and when combined with the pressure and movement generated from, specifically, attempting to slide the tips of your fingers along the bottom edge of the plate along the lid-hinge, they *will* slice open the tips of your fingers like a knife.&lt;br /&gt;
* When removing the back cover plate, use care to avoid damaging the speakers. They can be stuck to the back cover with double-sided tape, and the thin wires are very delicate. Newer Pinebook Pro laptops (as of the May 2021 batch, and perhaps earlier) seem to lack the double-sided tape to the rear cover, instead opting for tape or glue that makes them stick to the front cover. Nevertheless, be gentle when removing the back cover.&lt;br /&gt;
&lt;br /&gt;
[[File:PinebookProScrewGuide.png|400px|thumb|right|Pinebook Pro external screws (this particular unit has suffered damage on screw (4)L)]]&lt;br /&gt;
&lt;br /&gt;
When disassembling the laptop make sure that it is powered off and folded closed. To remove the bottom cover of the Pinebook Pro, first remove the ten (10) Phillips head screws that hold the bottom section of the laptop in place. There are four (4) short screws along the front edge, and six (6) long screws along the 3 remaining sides. Remove the cover from the back where the hinges are situated by lifting it up and away from the rest of the chassis. The aluminum case is held on only by screws. There are no plastic snaps, and the shell should pull away without any effort. If you experience any resistance at all stop and ensure all ten (10) screws are accounted for.&lt;br /&gt;
&lt;br /&gt;
During reassembly, make sure that the back-screw standoffs are in place and seated correctly. Before replacing the aluminum back-plate, ensure that the speakers are properly seated by pressing gently on the hard plastic edge of the speaker module. Slide the bottom section into place so it meets the front lip of the keyboard section. Secure the front section (where the touchpad is located) in place using the short screws in the front left and right corners. Then proceed to pop in the bottom panel into place. Secure the bottom section (where hinges are located) by screwing in the left and right corners. Then screw in the remaining screws and run your finger though the rim on the chassis to make sure its fitted correctly. Note that the front uses the remaining 4 short screws.&lt;br /&gt;
&lt;br /&gt;
The screws are small and should only be finger tight. Too much force will strip the threads. If after installing screws the back cover plate has not seated properly on one side (which may be caused by the aforementioned misseating of the speakers), open the display and hold the base on either side of the keyboard and gently flex the base with both hands in opposing directions. Once the side pops further in, then recheck the screws on that side. If it does not pop back in, re-open the machine and check for misseated components.&lt;br /&gt;
&lt;br /&gt;
A basic 3D model to print replacement standoffs for the back cover screws is [https://www.thingiverse.com/thing:4226648 available on Thingiverse], until the official drawings or 3D models are made available.&lt;br /&gt;
&lt;br /&gt;
====Display Disassembly====&lt;br /&gt;
It is not recommended to adjust the position of the lid when the bottom cover is removed, because the bottom cover provides structural strength, so the lid should be open fully as the first step, before starting any disassembly of the laptop.  After opening the lid, remove the bottom cover by following the instruction found in the section above.  Alternatively, you can keep the lid closed and remove the screws that hold the hinges to the main laptop body, as described in [[Pinebook Service Step by Step Guides]].&lt;br /&gt;
&lt;br /&gt;
Parts of the hinge mechanism, as well as the screws that hold the hinges to the lid, are hidden behind an elongated plactic U-shaped cover that snaps in place using latches.  Use a dedicated plastic prying tool or a guitar pick to gently pry the cover and remove it, starting from the outer edge.  Once you pry the cover to a certain extent, it should be possible to remove it fully using only your hands.  The U-shaped cover is rather sturdy, but still be careful not to break or bend it.&lt;br /&gt;
&lt;br /&gt;
There are two small screws hidden underneath the two small rubber nubs on the upper part of the screen bezel, so first gently remove the nubs and then remove the screws.  The screen bezel is held in place with a combination of latches and some adhesive tape, which is there to prevent dust ingress.  The adhesive isn't very strong, and the bezel is capable of flexing back into shape after being twisted to a certain extent.  There is more adhesive on the bottom part of the screen bezel, so be more careful while prying that section apart.  Use the same prying tool that you used for the U-shaped cover, and work it around the outer edges of the screen bezel.&lt;br /&gt;
&lt;br /&gt;
== Internal Layout ==&lt;br /&gt;
&lt;br /&gt;
=== Main chips ===&lt;br /&gt;
* RK3399 system-on-chip (1)&lt;br /&gt;
* LPDDR4 SDRAM (21)&lt;br /&gt;
* SPI NOR flash memory (29)&lt;br /&gt;
* eMMC flash memory (26)&lt;br /&gt;
* WiFi/BT module (27)&lt;br /&gt;
&lt;br /&gt;
=== Mainboard Switches and Buttons ===&lt;br /&gt;
There are two switches on the main board: disabling the eMMC (24), and enabling UART (9) via headphone jack. &lt;br /&gt;
&lt;br /&gt;
The Reset and Recovery buttons (28): the reset button performs an immediate reset of the laptop. The Recovery button is used to place the device in maskrom mode; this mode allows flashing eMMC using Rockchip tools (e.g. rkflashtools). &lt;br /&gt;
&lt;br /&gt;
[[File:PBPL_S.jpg]]&lt;br /&gt;
&lt;br /&gt;
=== Key Internal Parts ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Numbered parts classification and description&lt;br /&gt;
! Number&lt;br /&gt;
! Type&lt;br /&gt;
! Descriptor&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 1&lt;br /&gt;
| Component || RK3399 System-On-Chip&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 2&lt;br /&gt;
| Socket || PCIe x4 slot for optional NVMe adapter&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 3&lt;br /&gt;
| Socket || Speakers socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 4&lt;br /&gt;
| Socket || Touchpad socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 5&lt;br /&gt;
| Component || Left speaker &lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 6&lt;br /&gt;
| Connector || Power bridge connector &lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 7&lt;br /&gt;
| Socket || Keyboard Socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 8&lt;br /&gt;
| Component || Optional NVMe SSD adapter&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 9&lt;br /&gt;
| Switch || UART/Audio switch - outputs UART via headphone jack&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 10&lt;br /&gt;
| Socket || Power bridge socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 11&lt;br /&gt;
| Socket || Battery socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 12&lt;br /&gt;
| Component || Touchpad&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 13&lt;br /&gt;
| Component || Battery&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 14&lt;br /&gt;
| Component || Right speaker&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 15&lt;br /&gt;
| Socket || MicroSD card slot&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 16&lt;br /&gt;
| Socket || Headphone / UART jack&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 17&lt;br /&gt;
| Socket || USB 2.0 Type A&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 18&lt;br /&gt;
| Socket || Daughterboard-to-mainboard ribbon cable socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 19&lt;br /&gt;
| Cable || Daughterboard-to-mainboard ribbon cable&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 20&lt;br /&gt;
| Component || microphone&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 21&lt;br /&gt;
| Component || LPDDR4 RAM&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 22&lt;br /&gt;
| Socket || Mainboard-to-daughterboard ribbon cable socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 23&lt;br /&gt;
| Socket || Microphone socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 24&lt;br /&gt;
| Switch || Switch to hardware disable eMMC&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 25&lt;br /&gt;
| Antenna || BT/WiFI antenna&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 26&lt;br /&gt;
| Component || eMMC flash memory module &lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 27&lt;br /&gt;
| Component ||BT/WiFi module chip&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 28&lt;br /&gt;
| Buttons || Reset and recovery buttons&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 29&lt;br /&gt;
| Component || SPI flash storage&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 30&lt;br /&gt;
| Socket || eDP LCD socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 31&lt;br /&gt;
| Socket || Power in barrel socket&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 32&lt;br /&gt;
| Socket || USB 3.0 Type A&lt;br /&gt;
|-&lt;br /&gt;
! scope=row | 33&lt;br /&gt;
| Socket || USB 3.0 Type C &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Smallboard detailed picture ===&lt;br /&gt;
&lt;br /&gt;
[[File:Pinebook_pro_smallboard.jpg]]&lt;br /&gt;
&lt;br /&gt;
== Bootable Storage ==&lt;br /&gt;
&lt;br /&gt;
=== Boot sequence details ===&lt;br /&gt;
The RK3399's mask 32KB ROM boot code looks for the next stage of code at byte off-set 32768, (sector 64 if using 512 byte sectors). This is where U-Boot code would reside on any media that is bootable.&amp;lt;br&amp;gt;&lt;br /&gt;
[[RK3399_boot_sequence|RK3399 boot sequence]]&lt;br /&gt;
&lt;br /&gt;
=== Boot devices ===&lt;br /&gt;
&lt;br /&gt;
The Pinebook Pro is capable of booting from eMMC, USB 2.0, USB 3.0, or an SD card. It cannot boot from USB-C.  The boot order of the hard-coded ROM of its RK3399 SoC is: SPI NOR, eMMC, SD, USB OTG. &lt;br /&gt;
&lt;br /&gt;
At this time, the Pinebook Pro ships with a Manjaro + KDE build with [https://www.denx.de/wiki/U-Boot/ u-boot] on the eMMC.  Its boot order is: SD, USB, then eMMC.&lt;br /&gt;
&lt;br /&gt;
(An update has been pushed for the older Debian + MATE build that improves compatibility with booting other OSes from an SD card. In order to update, fully charge the battery, establish an internet connection, click the update icon in the toolbar, and then reboot your Pinebook Pro.  Please see [https://forum.pine64.org/showthread.php?tid=7830 this log] for details.)&lt;br /&gt;
&lt;br /&gt;
Please note that PCIe, the interface used for NVMe SSD on the Pinebook Pro, is not bootable on the RK3399 and therefore is not a part of the boot hierarchy. It is possible to run the desired OS from NVMe by pointing extlinux on the eMMC to rootfs on the SSD. This requires uboot, the Kernel image, DTB, and extlinux.conf&lt;br /&gt;
in a /boot partition on the eMMC.&lt;br /&gt;
&lt;br /&gt;
=== eMMC information ===&lt;br /&gt;
The eMMC appears to be hot-pluggable. This can be useful if trying to recover data or a broken install. Best practice is probably to turn the eMMC switch to off position before changing modules. Note that the enable/disable label on the silkscreen is incorrect on some board revisions (known bad on v2.1).&lt;br /&gt;
&lt;br /&gt;
The eMMC storage will show up as multiple block devices:&lt;br /&gt;
*mmcblk1boot0 - eMMC standard boot0 partition, may be 4MB&lt;br /&gt;
*mmcblk1boot1 - eMMC standard boot1 partition, may be 4MB&lt;br /&gt;
*mmcblk1rpmb - eMMC standard secure data partition, may be 16MB&lt;br /&gt;
*mmcblk1 - This block contains the user areas&lt;br /&gt;
&lt;br /&gt;
Only the last is usable as regular storage device in the Pinebook Pro.&lt;br /&gt;
The device number of &amp;quot;1&amp;quot; shown above may vary, depending on kernel.&lt;br /&gt;
&lt;br /&gt;
If the eMMC module is enabled after boot from an SD card, you can detect this change with the following commands as user &amp;quot;root&amp;quot;;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
echo fe330000.sdhci &amp;gt;/sys/bus/platform/drivers/sdhci-arasan/unbind&lt;br /&gt;
echo fe330000.sdhci &amp;gt;/sys/bus/platform/drivers/sdhci-arasan/bind&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Case Dimensions and Data ==&lt;br /&gt;
* Dimensions: 329mm x 220mm x 12mm (WxDxH)&lt;br /&gt;
* Weight: 1.26Kg&lt;br /&gt;
* Screws&lt;br /&gt;
** Philips head type screws&lt;br /&gt;
** M2 flat head machine screws (measurements in mm)&lt;br /&gt;
** 4 x Small screws (used along the front edge): Head - 3.44, Thread Diameter - 1.97, Thread Length - 2.1,  Overall length - 3.05&lt;br /&gt;
** 6 x Large screws: Head - 3.44, Thread Diameter - 1.97, Thread Length - 4.41, Overall Length - 5.85&lt;br /&gt;
* Rubber Feet&lt;br /&gt;
** 18mm diameter&lt;br /&gt;
** 3mm height&lt;br /&gt;
** Dome shaped&lt;br /&gt;
&lt;br /&gt;
== SoC and Memory Specification ==&lt;br /&gt;
[[File:Rockchip_RK3399.png|right]]&lt;br /&gt;
* Based on Rockchip RK3399&lt;br /&gt;
&lt;br /&gt;
=== CPU Architecture ===&lt;br /&gt;
* big.LITTLE architecture: Dual Cortex-A72 + Quad Cortex-A53, 64-bit CPU&lt;br /&gt;
** Full implementation of the ARM architecture v8-A instruction set (both AArch64 and AArch32)&lt;br /&gt;
** ARM Neon Advanced SIMD (single instruction, multiple data) support for accelerated media and signal processing computation&lt;br /&gt;
** ARMv8 Cryptography Extensions&lt;br /&gt;
** VFPv4 floating point unit supporting single and double-precision operations&lt;br /&gt;
** Hardware virtualization support&lt;br /&gt;
** TrustZone technology support&lt;br /&gt;
** Full CoreSight debug solution&lt;br /&gt;
** One isolated voltage domain to support DVFS&lt;br /&gt;
* Cortex-A72 (big cluster):&lt;br /&gt;
** [https://developer.arm.com/products/processors/cortex-a/cortex-a72 Dual-core Cortex-A72 up to 2.0GHz CPU]&lt;br /&gt;
** Superscalar, variable-length, out-of-order pipeline&lt;br /&gt;
** L1 cache 48KB Icache and 32KB Dcache for each A72 &lt;br /&gt;
** L2 cache 1024KB for big cluster &lt;br /&gt;
* Cortex-A53 (little cluster):&lt;br /&gt;
** [https://developer.arm.com/products/processors/cortex-a/cortex-a53 Quad-core Cortex-A53 up to 1.5GHz CPU]&lt;br /&gt;
** In-order pipeline with symmetric dual-issue of most instructions &lt;br /&gt;
** L1 cache 32KB Icache and 32KB Dcache for each A53&lt;br /&gt;
** L2 cache 512KB for little cluster&lt;br /&gt;
* Cortex-M0 (control processors):&lt;br /&gt;
** [https://developer.arm.com/ip-products/processors/cortex-m/cortex-m0 Cortex-M0 CPU]&lt;br /&gt;
** Two Cortex-M0 cooperate with the central processors&lt;br /&gt;
** Architecture: Armv6-M&lt;br /&gt;
** Thumb/Thumb2 instruction set&lt;br /&gt;
** 32 bit only&lt;br /&gt;
&lt;br /&gt;
=== GPU Architecture ===&lt;br /&gt;
* [https://developer.arm.com/products/graphics-and-multimedia/mali-gpus/mali-t860-and-mali-t880-gpus ARM Mali-T860MP4 Quad-core GPU]&lt;br /&gt;
* The highest performance GPUs built on Arm Mali’s famous Midgard architecture, the Mali-T860 GPU is designed for complex graphics use cases and provide stunning visuals for UHD content.&lt;br /&gt;
* Frequency 	650MHz &lt;br /&gt;
* Throughput 	1300Mtri/s, 10.4Gpix/s&lt;br /&gt;
* Graphic interface standards:&lt;br /&gt;
** OpenGL® ES 1.1, 1.2, 2.0, 3.0, 3.1, 3.2. (Panfrost has initial support of 3.0 beginning 2020/02/27)&lt;br /&gt;
** Vulkan 1.0, using the Mali binary blob. (Panfrost does not support Vulkan as of 2020/06/24)&lt;br /&gt;
** OpenCL™ 1.1, 1.2&lt;br /&gt;
** DirectX® 11 FL11_1&lt;br /&gt;
** RenderScript™&lt;br /&gt;
&lt;br /&gt;
=== System Memory ===&lt;br /&gt;
* RAM Memory:&lt;br /&gt;
** LPDDR4&lt;br /&gt;
** 800MHz, (limited by RK3399)&lt;br /&gt;
** Dual memory channels on the CPU, each 32 bits wide&lt;br /&gt;
** Quad memory channels on the RAM chip, each 16 bits wide, 2 bonded together for each CPU channel&lt;br /&gt;
** 4GB as a single 366 pin mobile RAM chip&lt;br /&gt;
* Storage Memory: &lt;br /&gt;
** 64GB eMMC module, can be upgraded to an 128GB eMMC module. (The initial PINE64 community build version shipped with a 128GB eMMC.)&lt;br /&gt;
** eMMC version 5.1, HS400, 8 bit on RK3399 side&lt;br /&gt;
** Bootable&lt;br /&gt;
* SPI flash:&lt;br /&gt;
** [[Pinebook Pro SPI]]&lt;br /&gt;
** 128Mbit / 16MByte&lt;br /&gt;
** 1 bit interface&lt;br /&gt;
** Bootable, (first boot device, ahead of eMMC &amp;amp; SD card)&lt;br /&gt;
** U-Boot images can be made to work, but as of 2020/06/24 there is no standardized image available.&lt;br /&gt;
&lt;br /&gt;
=== Video out ===&lt;br /&gt;
* USB-C Alt mode DP&lt;br /&gt;
* Up to 3840x2160 p60, dependant on adapter, (2 lanes verses 4 lanes)&lt;br /&gt;
&lt;br /&gt;
=== Expansion Ports ===&lt;br /&gt;
* MicroSD card:&lt;br /&gt;
** Bootable&lt;br /&gt;
** Supports SD, SDHC and SDXC cards, up to 512GB tested. SDXC standard says 2TB is the maximum.&lt;br /&gt;
** Version SD3.0, (MMC 4.5), up to 50MB/s&lt;br /&gt;
** SD card Application Performance Class 1 (A1), (or better), recommended by some users, for better IOPS&lt;br /&gt;
* USB ports:&lt;br /&gt;
** 1 x USB 2.0 Type-A Host Port, bootable&lt;br /&gt;
** 1 x USB 3.0 Type-A Host Port, 5Gbps, is not bootable&lt;br /&gt;
** 1 x USB 3.0 Type-C OTG Port, 5Gbps, (includes laptop charging function), is not bootable&lt;br /&gt;
** Note that high power USB devices may not work reliably on a PBP. Or they may draw enough power to drain the battery even when the PBP is plugged into A.C. One alternative is externally powered USB devices.&lt;br /&gt;
* Headphone jack switchable to UART console mux circuit&lt;br /&gt;
&lt;br /&gt;
== Additional hardware ==&lt;br /&gt;
Hardware that is not part of the SoC.&lt;br /&gt;
&lt;br /&gt;
=== Battery ===&lt;br /&gt;
* Lithium Polymer Battery (10,000 mAH)&lt;br /&gt;
&lt;br /&gt;
=== Display ===&lt;br /&gt;
* 14.0&amp;quot; 1920x1080 IPS LCD panel&lt;br /&gt;
=== Lid closed magnet ===&lt;br /&gt;
There is a magnet to detect when the laptop lid is closed, so action can be taken like sleep. This meets up with the Hall sensor on the daughter / small board to detect lid closed.&lt;br /&gt;
* The magnet is located on the LCD panel right side, around 1.5 inches up measure from bottom edge.&lt;br /&gt;
&lt;br /&gt;
=== Webcam ===&lt;br /&gt;
* Internal USB attached Webcam&lt;br /&gt;
&lt;br /&gt;
=== Audio ===&lt;br /&gt;
* 3.5mm stereo earphone/microphone plug&lt;br /&gt;
* Built-in microphone&lt;br /&gt;
* Built-in stereo speakers:&lt;br /&gt;
** Oval in design&lt;br /&gt;
** 3 mm high x 20 mm x 30 mm&lt;br /&gt;
&lt;br /&gt;
=== Network ===&lt;br /&gt;
* WiFi:&lt;br /&gt;
** 802.11 b/g/n/ac&lt;br /&gt;
** Dual band: 2.4Ghz &amp;amp; 5Ghz&lt;br /&gt;
** Single antenna&lt;br /&gt;
* Bluetooth 5.0&lt;br /&gt;
&lt;br /&gt;
=== Optional NVMe adapter ===&lt;br /&gt;
* PCIe 2.0, 5&amp;amp;nbsp;GT/s per lane&lt;br /&gt;
* Four PCIe lanes, which can not be bifurcated, but can be used with one- or two-lane NVMe cards&lt;br /&gt;
* '''M''' keyed, though '''M'''+'''B''' keyed devices will work too&lt;br /&gt;
* Maximum length for M.2 card is 80mm (M.2 2280). The following sizes will also work: 2230, 2242, 2260&lt;br /&gt;
* Power: 2.5&amp;amp;nbsp;W continuous, 8.25&amp;amp;nbsp;W peak momentary&lt;br /&gt;
* Does not support SATA M.2 cards&lt;br /&gt;
* Does not support USB M.2 cards&lt;br /&gt;
&lt;br /&gt;
== Pinebook Pro Schematics and Certifications ==&lt;br /&gt;
* Pinebook Pro Main Board Schematic And Silkscreen:&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/pinebookpro_v2.1_mainboard_schematic.pdf Pinebook Pro Main Board ver 2.1 Schematic]&lt;br /&gt;
** [https://wiki.pine64.org/images/3/30/Pinebookpro-v2.1-top-ref.pdf Pinebook Pro ver 2.1 Top Layer Silkscreen]&lt;br /&gt;
** [https://wiki.pine64.org/images/b/b7/Pinebookpro-v2.1-bottom-ref.pdf Pinebook Pro ver 2.1 Bottom Layer Silkscreen]&lt;br /&gt;
* Pinebook Pro Daughter Board Schematic:&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/pinebookpro_v2.1_daughterboard_schematic.pdf Pinebook Pro Daughter Board ver 2.1 Schematic]&lt;br /&gt;
* Optional Pinebook Pro NVMe Adapter Schematic:&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/pinebookpro_v2.1_NVMe-adapter_schematic.pdf Pinebook Pro NVMe Adapter Board ver 2.1 Schematic]&lt;br /&gt;
* Serial Console Earphone Jack Pinout:&lt;br /&gt;
** [https://files.pine64.org/doc/pinebook/guide/Pinebook_Earphone_Serial_Console_Developer_Guide.pdf Pinkbook Serial Console Earphone Jack Pinout]&lt;br /&gt;
* Pinebook Pro Case:&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/drawings/Pinebook%20Pro%20Principle%20Views.pdf AutoCAD PDF File ]&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/drawings/Pinebook%20Pro%20Principle%20Views.ai AutoCAD AI File ]&lt;br /&gt;
** [https://files.pine64.org/doc/PinebookPro/drawings/Pinebook%20Pro%20Principle%20Views.dwg AutoCAD DWG File ]&lt;br /&gt;
* Pinebook Pro Certifications:&lt;br /&gt;
** [https://files.pine64.org/doc/cert/Pinebook%20Pro%20FCC%20Certificate-S19071103501001.pdf Pinebook Pro FCC Certificate]&lt;br /&gt;
** [https://files.pine64.org/doc/cert/Pinebook%20Pro%20CE%20RED%20Certificate-S19051404304.pdf Pinebook Pro CE Certificate]&lt;br /&gt;
** [https://files.pine64.org/doc/cert/Pinebook%20Pro%20ROHS%20Compliance%20Certificate.pdf Pinebook Pro RoHS Certificate]&lt;br /&gt;
&lt;br /&gt;
== Datasheets for Components and Peripherals ==&lt;br /&gt;
* Rockchip RK3399 SoC information:&lt;br /&gt;
** [https://www.rock-chips.com/a/en/products/RK33_Series/2016/0419/758.html Rockchip RK3399 SoC Brief]&lt;br /&gt;
** [https://opensource.rock-chips.com/images/d/d7/Rockchip_RK3399_Datasheet_V2.1-20200323.pdf Rockchip RK3399 Datasheet v2.1]&lt;br /&gt;
** [https://www.rockchip.fr/Rockchip%20RK3399%20TRM%20V1.4%20Part1.pdf Rockchip RK3399 Technical Reference Manual v1.4, part 1]&lt;br /&gt;
** [https://www.rockchip.fr/Rockchip%20RK3399%20TRM%20V1.3%20Part1.pdf Rockchip RK3399 Technical Reference Manual v1.3, part 1] and [https://www.rockchip.fr/Rockchip%20RK3399%20TRM%20V1.3%20Part2.pdf part 2]&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/rockpro64/RK808%20datasheet%20V0.8.pdf Rockchip RK808 Datasheet v0.8]&lt;br /&gt;
* LPDDR4 SDRAM (366-pin BGA):&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/micron%20SM512M64Z01MD4BNK-053FT%20LPDDR4%20(366Ball).pdf Micron 366 balls Mobile LPDDR4 Datasheet]&lt;br /&gt;
* eMMC information:&lt;br /&gt;
** [https://files.pine64.org/doc/rock64/PINE64_eMMC_Module_20170719.pdf PINE64 eMMC module schematic]&lt;br /&gt;
** [https://files.pine64.org/doc/rock64/usb%20emmc%20module%20adapter%20v2.pdf PINE64 USB adapter for eMMC module V2 schematic]&lt;br /&gt;
** [https://files.pine64.org/doc/rock64/USB%20adapter%20for%20eMMC%20module%20PCB.tar PINE64 USB adapter for eMMC module PCB in JPEG]&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/pine64/SDINADF4-16-128GB-H%20data%20sheet%20v1.13.pdf 64GB/128GB SanDisk eMMC Datasheet]&lt;br /&gt;
* SPI NOR Flash information:&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/pine64/w25q128jv%20spi%20revc%2011162016.pdf WinBond 128Mb SPI Flash Datasheet]&lt;br /&gt;
** [https://wiki.pine64.org/images/b/b9/Ds-00220-gd25q127c-rev1-df2f4.pdf GigaDevice 128Mb SPI Flash Datasheet (updated)]&lt;br /&gt;
* Wireless and Bluetooth information:&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/AP6256%20datasheet_V1.7_12282018.pdf AMPAK AP6256 11AC Wi-Fi + Bluetooth5 Datasheet]&lt;br /&gt;
* Audio codec:&lt;br /&gt;
** [http://www.everest-semi.com/pdf/ES8316%20PB.pdf Everest ES8316 Audio Codec Datasheet]&lt;br /&gt;
* LCD panel:&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/NV140FHM-N49_Rev.P0_20160804_201710235838.pdf 14&amp;quot; 1920x1080 IPS LCD Panel datasheet]&lt;br /&gt;
* USB-related information:&lt;br /&gt;
** Internal USB 2.0 hub: [https://wiki.pine64.org/images/3/39/GL850G_USB_Hub_1.07.pdf GL850G USB Hub Datasheet]&lt;br /&gt;
** USB Type-C Controller: [https://www.onsemi.com/pub/Collateral/FUSB302-D.PDF ON Semiconductor FUSB302 Datasheet]&lt;br /&gt;
* Touchpad information:&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/YX%20HK-9562%20HID%20I2C%20Specification.pdf PineBook Pro Touchpad Specification]&lt;br /&gt;
* Keyboard information:&lt;br /&gt;
** [https://wiki.pine64.org/images/b/b0/SH68F83V2.0.pdf Sinowealth SH68F83 Datasheet]&lt;br /&gt;
** US ANSI: XK-HS002 MB27716023&lt;br /&gt;
* Full HD camera sensor:&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/HK-2145-263.pdf Full HD Camera module specification (in Chinese)]&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/PinebookPro/GC2145%20CSP%20DataSheet%20release%20V1.0_20131201.pdf GalaxyCore GC2145 Full HD Camera Sensor Datasheet]&lt;br /&gt;
* Battery-related information:&lt;br /&gt;
** Battery charging IC: [https://www.ti.com/lit/ds/symlink/bq24171.pdf?ts=1607068456825&amp;amp;ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FBQ24171 Texas Instruments BQ24171 Datasheet]&lt;br /&gt;
** Battery monitoring IC: [https://cdn.datasheetspdf.com/pdf-down/C/W/2/CW2015-Cellwise.pdf Cellwise CW2015 Datasheet]&lt;br /&gt;
** [https://files.pine64.org/doc/datasheet/pinebook/40110175P%203.8V%2010000mAh规格书-14.pdf 10000mAH Lithium Battery Specification]&lt;br /&gt;
* Power path device:&lt;br /&gt;
** [https://wiki.pine64.org/images/9/99/Sis412dn.pdf N-MOS / MOSFET]&lt;br /&gt;
* NVMe adapter:&lt;br /&gt;
** [https://wiki.pine64.org/images/d/d0/Hirose-FH26W-35S-0.3SHW%2860%29-datasheet.pdf FH26-35S-0.3SHW flat flex connector (compatible, not OEM)]&lt;br /&gt;
&lt;br /&gt;
== Versions ==&lt;br /&gt;
Pinebook Pro v1 and v2 were prototype models that did not make it to the public. The &amp;quot;first batch&amp;quot; (First 100 forum preorders) onward are v2.1. [https://forum.pine64.org/showthread.php?tid=8111]&lt;br /&gt;
&lt;br /&gt;
=Skinning and Case Customization=&lt;br /&gt;
* Template files for creating custom skins. Each includes template layers for art placement, and CUT lines.&lt;br /&gt;
**[https://drive.google.com/open?id=1UKFlC53DO0GJm3Hz1E_669n_HhI45e4n Case Lid Template]&lt;br /&gt;
**[https://drive.google.com/open?id=1Q6bKGarMDhvWz3HdGvhL5qDhyHb546ve Case Bottom Template]&lt;br /&gt;
**[https://drive.google.com/open?id=1ugI74ygNJ3EN5jXks5jKvdpEAoxIzHo4 Case Palmrest Template]&lt;br /&gt;
&lt;br /&gt;
= Other Resources =&lt;br /&gt;
* [https://forum.pine64.org/forumdisplay.php?fid=111 Pinebook Pro Forum]&lt;br /&gt;
* [https://forum.pine64.org/forumdisplay.php?fid=98 ROCKPro64 Forum]&lt;br /&gt;
* [https://riot.im/app/#/room/#pinebook:matrix.org Matrix Channel] (no login required to read)&lt;br /&gt;
* IRC Server: irc.pine64.org Channel: PineBook&lt;br /&gt;
* [https://discordapp.com/channels/463237927984693259/622348681538043924 Discord Channel]&lt;br /&gt;
* [https://github.com/rockchip-linux Rockchip Linux GitHub Repo]&lt;br /&gt;
* [https://opensource.rock-chips.com/ Rockchip Open Source Wiki]&lt;br /&gt;
* [[Pinebook Pro/Freepascal and Lazarus IDE on Manjaro|Freepascal and Lazarus IDE on Pinebook Pro]]&lt;br /&gt;
&lt;br /&gt;
[[Category:PineBook Pro]]&lt;br /&gt;
[[Category:Rockchip RK3399]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-install-touchpad.jpg&amp;diff=12032</id>
		<title>File:Pinebook Pro new keyboard-install-touchpad.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-install-touchpad.jpg&amp;diff=12032"/>
		<updated>2021-12-12T13:32:10Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad3.jpg&amp;diff=12031</id>
		<title>File:Pinebook Pro new keyboard-touchpad3.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad3.jpg&amp;diff=12031"/>
		<updated>2021-12-12T13:30:33Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad2.jpg&amp;diff=12030</id>
		<title>File:Pinebook Pro new keyboard-touchpad2.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad2.jpg&amp;diff=12030"/>
		<updated>2021-12-12T13:30:17Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad1.jpg&amp;diff=12029</id>
		<title>File:Pinebook Pro new keyboard-touchpad1.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-touchpad1.jpg&amp;diff=12029"/>
		<updated>2021-12-12T13:29:56Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-detached-display2.jpg&amp;diff=12028</id>
		<title>File:Pinebook Pro new keyboard-detached-display2.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-detached-display2.jpg&amp;diff=12028"/>
		<updated>2021-12-12T13:28:48Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-detached-display.jpg&amp;diff=12027</id>
		<title>File:Pinebook Pro new keyboard-detached-display.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-detached-display.jpg&amp;diff=12027"/>
		<updated>2021-12-12T13:27:44Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-all-boards-removed.jpg&amp;diff=12026</id>
		<title>File:Pinebook Pro new keyboard-all-boards-removed.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-all-boards-removed.jpg&amp;diff=12026"/>
		<updated>2021-12-12T13:26:09Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-zoom-daughterboard.jpg&amp;diff=12025</id>
		<title>File:Pinebook Pro new keyboard-zoom-daughterboard.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-zoom-daughterboard.jpg&amp;diff=12025"/>
		<updated>2021-12-12T13:24:31Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-zoom-mainboard.jpg.jpg&amp;diff=12024</id>
		<title>File:Pinebook Pro new keyboard-zoom-mainboard.jpg.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-zoom-mainboard.jpg.jpg&amp;diff=12024"/>
		<updated>2021-12-12T13:23:53Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-back-removed.jpg&amp;diff=12023</id>
		<title>File:Pinebook Pro new keyboard-back-removed.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-back-removed.jpg&amp;diff=12023"/>
		<updated>2021-12-12T13:22:35Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_keyboard-replacement-screws.jpg&amp;diff=12022</id>
		<title>File:Pinebook Pro keyboard-replacement-screws.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_keyboard-replacement-screws.jpg&amp;diff=12022"/>
		<updated>2021-12-12T13:20:41Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-back.jpg&amp;diff=12021</id>
		<title>File:Pinebook Pro new keyboard-back.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-back.jpg&amp;diff=12021"/>
		<updated>2021-12-12T13:17:30Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-front.jpg&amp;diff=12020</id>
		<title>File:Pinebook Pro new keyboard-front.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pinebook_Pro_new_keyboard-front.jpg&amp;diff=12020"/>
		<updated>2021-12-12T13:17:16Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11687</id>
		<title>User:JF/JF's note on PineDio devices</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11687"/>
		<updated>2021-10-21T17:44:10Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Test setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== USB LoRa adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Documents ===&lt;br /&gt;
* Schematics : [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;br /&gt;
&lt;br /&gt;
== RAW LoRa communication between USB LoRa adapter and PineDio STACK ==&lt;br /&gt;
&lt;br /&gt;
=== Test setup ===&lt;br /&gt;
&lt;br /&gt;
[[File:Lora-raw-setup.jpg]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* One Pine64 USB LoRa adapter (SX1262 + CH341)&lt;br /&gt;
* One PineDio STACK (BL604 + SX1262)&lt;br /&gt;
* One PyCom Lopy board (dev board based on ESP32 + LoRa module, MicroPython)&lt;br /&gt;
* One NooElec SDR adapter and GQRX running on my PC&lt;br /&gt;
&lt;br /&gt;
The goal is to implement RAW LoRa communication between Pine64 LoRa devices (USB adapter + PineDio STACK at first, pinephone adapter later on).&lt;br /&gt;
The Lopy board allows me to debug my setup easily, as I know it's working correctly in both RX and TX.&lt;br /&gt;
&lt;br /&gt;
I'm writing this section to share my experiments with RAW LoRa on those devices and maybe get some help on some issues. I'm a noob in RF and LoRa technologies !&lt;br /&gt;
&lt;br /&gt;
=== RX on Pine64 devices ===&lt;br /&gt;
Setup : The Lopy board emits 16 Bytes every 5s&lt;br /&gt;
&lt;br /&gt;
Using default TX settings on the Lopy (868Mhz, BW 125Khz, SF7, 8 preamble symbols, CR 4/5, IQ not inverted), the reception on both Pine64 devices was really poor : they would detect the preamble most of the time, but fail to check the CRC of the header or of the payload.&lt;br /&gt;
&lt;br /&gt;
Then I change those settings : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted. Magically, the reception on both device was perfect!&lt;br /&gt;
&lt;br /&gt;
Question : why the RX was not working with original settings and would work with the new ones?&lt;br /&gt;
&lt;br /&gt;
=== TX from Pine64 devices ===&lt;br /&gt;
Using the same TX parameters as the previous test : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted&lt;br /&gt;
&lt;br /&gt;
==== TX from the USB LoRa Adapter ====&lt;br /&gt;
On the SDR acquisition, the TX power seems lower than the Lopy board, even with TX power set to +22dB&lt;br /&gt;
&lt;br /&gt;
[[File:USB-tx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy does not receive anything.&lt;br /&gt;
The STACK detects the message but detects a bad CRC. Indeed, the messages is scrambled...&lt;br /&gt;
&lt;br /&gt;
[[File:Stack-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The RSSI and SNR are displayed. I notice that the RSSI is much lower for messages coming from the USB adapter than for messages coming from the Lopy&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Is it normal that the power of the TX from the USB adapter looks much lower than the power from the lopy?&lt;br /&gt;
 - What about the RSSI that is much lower on messages comng from the USB adapter?&lt;br /&gt;
 - Why are the messages and CRC corrupted ?&lt;br /&gt;
&lt;br /&gt;
==== TX from the PineDio STACK ==== &lt;br /&gt;
On the SDR acquisition, the signal power looks similar than the Lopy.&lt;br /&gt;
&lt;br /&gt;
[[File:Tx-stack.png]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB adapter receives the message but detects a bad CRC. &lt;br /&gt;
&lt;br /&gt;
[[File:USB-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy board does not receive anything (probably because of messages with bad CRC that are dropped in lower level layers).&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Why are the messages corrupted?&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
==== PineDio STACK ====&lt;br /&gt;
Based on this driver: https://github.com/lupyuen/bl_iot_sdk/blob/pinedio/components/3rdparty/lora-sx1262/src/radio.c&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  RadioEvents_t RadioEvents;&lt;br /&gt;
&lt;br /&gt;
  RadioEvents.RxDone = OnRadioRxDone;&lt;br /&gt;
  RadioEvents.RxError = OnRadioRxError;&lt;br /&gt;
  RadioEvents.TxDone = OnRadioTxDone;&lt;br /&gt;
&lt;br /&gt;
  Radio.Init(&amp;amp;RadioEvents);&lt;br /&gt;
  Radio.SetPublicNetwork(false);&lt;br /&gt;
  Radio.SetChannel(868000000);&lt;br /&gt;
  Radio.SetRxConfig(&lt;br /&gt;
          MODEM_LORA,&lt;br /&gt;
          2, //500khz&lt;br /&gt;
          12, //SF12&lt;br /&gt;
          1, // CR 4/5&lt;br /&gt;
          0, // N/A&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          7, // symbol timeout&lt;br /&gt;
          0, // dynamic length&lt;br /&gt;
          0, // payload length&lt;br /&gt;
          1, // crc enabled&lt;br /&gt;
          0, // freq hoping disabled&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          1, // no iq inversion&lt;br /&gt;
          1// continous receive&lt;br /&gt;
          );&lt;br /&gt;
  Radio.SetTxConfig(&lt;br /&gt;
          RadioModems_t::MODEM_LORA,&lt;br /&gt;
          0, // power&lt;br /&gt;
          0, //N/A&lt;br /&gt;
          2, // 500 khz&lt;br /&gt;
          12, // SF12&lt;br /&gt;
          1, // CR4/5&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          false, // dynamic length&lt;br /&gt;
          true, // CRC ON&lt;br /&gt;
          false, // hop&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          true, // invert iq&lt;br /&gt;
          0xffffffff // timeout&lt;br /&gt;
          );&lt;br /&gt;
  // RX&lt;br /&gt;
  Radio.Rx(0);&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // OR TX&lt;br /&gt;
  const char msg[] = {&amp;quot;Hello, I'm a PineDio STACK!&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  int i = 0;&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
    if((i % 30) ==0){&lt;br /&gt;
      printf(&amp;quot;send...\r\n&amp;quot;);&lt;br /&gt;
      Radio.Send((uint8_t *) msg, strlen(msg));&lt;br /&gt;
    }&lt;br /&gt;
    i++;&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== USB adapter ====&lt;br /&gt;
Based on this driver: https://github.com/YukiWorkshop/sx126x_driver&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  radio.Init();&lt;br /&gt;
&lt;br /&gt;
  radio.SetRfFrequency(868000000);&lt;br /&gt;
  radio.SetBufferBaseAddresses(0, 0);&lt;br /&gt;
&lt;br /&gt;
  SX126x::ModulationParams_t modulationParams;&lt;br /&gt;
  modulationParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  modulationParams.Params.LoRa.SpreadingFactor = SX126x::RadioLoRaSpreadingFactors_t::LORA_SF12;&lt;br /&gt;
  modulationParams.Params.LoRa.CodingRate = SX126x::RadioLoRaCodingRates_t::LORA_CR_4_5;&lt;br /&gt;
  modulationParams.Params.LoRa.Bandwidth = SX126x::RadioLoRaBandwidths_t::LORA_BW_500;&lt;br /&gt;
  modulationParams.Params.LoRa.LowDatarateOptimize = false;&lt;br /&gt;
  radio.SetModulationParams(modulationParams);&lt;br /&gt;
&lt;br /&gt;
  SX126x::PacketParams_t packetParams;&lt;br /&gt;
  packetParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  packetParams.Params.LoRa.PreambleLength = 8;&lt;br /&gt;
  packetParams.Params.LoRa.HeaderType = SX126x::RadioLoRaPacketLengthsMode_t::LORA_PACKET_VARIABLE_LENGTH;&lt;br /&gt;
  packetParams.Params.LoRa.PayloadLength = 27;&lt;br /&gt;
  packetParams.Params.LoRa.CrcMode = SX126x::RadioLoRaCrcModes_t::LORA_CRC_ON;&lt;br /&gt;
  packetParams.Params.LoRa.InvertIQ = SX126x::RadioLoRaIQModes_t::LORA_IQ_INVERTED;&lt;br /&gt;
  radio.SetPacketParams(packetParams);&lt;br /&gt;
&lt;br /&gt;
  radio.SetTxParams(22, SX126x::RADIO_RAMP_3400_US);&lt;br /&gt;
  radio.SetRegulatorMode(SX126x::RadioRegulatorMode_t::USE_DCDC);&lt;br /&gt;
&lt;br /&gt;
  radio.SetDioIrqParams(0xffff, 0x0001, 0, 0);&lt;br /&gt;
  &lt;br /&gt;
// RX&lt;br /&gt;
  radio.SetRx(0xffffffff);&lt;br /&gt;
&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// OR TX&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.SetPayload(data, 27);&lt;br /&gt;
    radio.SetTx(0xffffffff);&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11686</id>
		<title>User:JF/JF's note on PineDio devices</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11686"/>
		<updated>2021-10-21T17:43:58Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Test setup */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== USB LoRa adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Documents ===&lt;br /&gt;
* Schematics : [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;br /&gt;
&lt;br /&gt;
== RAW LoRa communication between USB LoRa adapter and PineDio STACK ==&lt;br /&gt;
&lt;br /&gt;
=== Test setup ===&lt;br /&gt;
&lt;br /&gt;
File:Lora-raw-setup.jpg&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* One Pine64 USB LoRa adapter (SX1262 + CH341)&lt;br /&gt;
* One PineDio STACK (BL604 + SX1262)&lt;br /&gt;
* One PyCom Lopy board (dev board based on ESP32 + LoRa module, MicroPython)&lt;br /&gt;
* One NooElec SDR adapter and GQRX running on my PC&lt;br /&gt;
&lt;br /&gt;
The goal is to implement RAW LoRa communication between Pine64 LoRa devices (USB adapter + PineDio STACK at first, pinephone adapter later on).&lt;br /&gt;
The Lopy board allows me to debug my setup easily, as I know it's working correctly in both RX and TX.&lt;br /&gt;
&lt;br /&gt;
I'm writing this section to share my experiments with RAW LoRa on those devices and maybe get some help on some issues. I'm a noob in RF and LoRa technologies !&lt;br /&gt;
&lt;br /&gt;
=== RX on Pine64 devices ===&lt;br /&gt;
Setup : The Lopy board emits 16 Bytes every 5s&lt;br /&gt;
&lt;br /&gt;
Using default TX settings on the Lopy (868Mhz, BW 125Khz, SF7, 8 preamble symbols, CR 4/5, IQ not inverted), the reception on both Pine64 devices was really poor : they would detect the preamble most of the time, but fail to check the CRC of the header or of the payload.&lt;br /&gt;
&lt;br /&gt;
Then I change those settings : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted. Magically, the reception on both device was perfect!&lt;br /&gt;
&lt;br /&gt;
Question : why the RX was not working with original settings and would work with the new ones?&lt;br /&gt;
&lt;br /&gt;
=== TX from Pine64 devices ===&lt;br /&gt;
Using the same TX parameters as the previous test : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted&lt;br /&gt;
&lt;br /&gt;
==== TX from the USB LoRa Adapter ====&lt;br /&gt;
On the SDR acquisition, the TX power seems lower than the Lopy board, even with TX power set to +22dB&lt;br /&gt;
&lt;br /&gt;
[[File:USB-tx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy does not receive anything.&lt;br /&gt;
The STACK detects the message but detects a bad CRC. Indeed, the messages is scrambled...&lt;br /&gt;
&lt;br /&gt;
[[File:Stack-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The RSSI and SNR are displayed. I notice that the RSSI is much lower for messages coming from the USB adapter than for messages coming from the Lopy&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Is it normal that the power of the TX from the USB adapter looks much lower than the power from the lopy?&lt;br /&gt;
 - What about the RSSI that is much lower on messages comng from the USB adapter?&lt;br /&gt;
 - Why are the messages and CRC corrupted ?&lt;br /&gt;
&lt;br /&gt;
==== TX from the PineDio STACK ==== &lt;br /&gt;
On the SDR acquisition, the signal power looks similar than the Lopy.&lt;br /&gt;
&lt;br /&gt;
[[File:Tx-stack.png]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB adapter receives the message but detects a bad CRC. &lt;br /&gt;
&lt;br /&gt;
[[File:USB-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy board does not receive anything (probably because of messages with bad CRC that are dropped in lower level layers).&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Why are the messages corrupted?&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
==== PineDio STACK ====&lt;br /&gt;
Based on this driver: https://github.com/lupyuen/bl_iot_sdk/blob/pinedio/components/3rdparty/lora-sx1262/src/radio.c&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  RadioEvents_t RadioEvents;&lt;br /&gt;
&lt;br /&gt;
  RadioEvents.RxDone = OnRadioRxDone;&lt;br /&gt;
  RadioEvents.RxError = OnRadioRxError;&lt;br /&gt;
  RadioEvents.TxDone = OnRadioTxDone;&lt;br /&gt;
&lt;br /&gt;
  Radio.Init(&amp;amp;RadioEvents);&lt;br /&gt;
  Radio.SetPublicNetwork(false);&lt;br /&gt;
  Radio.SetChannel(868000000);&lt;br /&gt;
  Radio.SetRxConfig(&lt;br /&gt;
          MODEM_LORA,&lt;br /&gt;
          2, //500khz&lt;br /&gt;
          12, //SF12&lt;br /&gt;
          1, // CR 4/5&lt;br /&gt;
          0, // N/A&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          7, // symbol timeout&lt;br /&gt;
          0, // dynamic length&lt;br /&gt;
          0, // payload length&lt;br /&gt;
          1, // crc enabled&lt;br /&gt;
          0, // freq hoping disabled&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          1, // no iq inversion&lt;br /&gt;
          1// continous receive&lt;br /&gt;
          );&lt;br /&gt;
  Radio.SetTxConfig(&lt;br /&gt;
          RadioModems_t::MODEM_LORA,&lt;br /&gt;
          0, // power&lt;br /&gt;
          0, //N/A&lt;br /&gt;
          2, // 500 khz&lt;br /&gt;
          12, // SF12&lt;br /&gt;
          1, // CR4/5&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          false, // dynamic length&lt;br /&gt;
          true, // CRC ON&lt;br /&gt;
          false, // hop&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          true, // invert iq&lt;br /&gt;
          0xffffffff // timeout&lt;br /&gt;
          );&lt;br /&gt;
  // RX&lt;br /&gt;
  Radio.Rx(0);&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // OR TX&lt;br /&gt;
  const char msg[] = {&amp;quot;Hello, I'm a PineDio STACK!&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  int i = 0;&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
    if((i % 30) ==0){&lt;br /&gt;
      printf(&amp;quot;send...\r\n&amp;quot;);&lt;br /&gt;
      Radio.Send((uint8_t *) msg, strlen(msg));&lt;br /&gt;
    }&lt;br /&gt;
    i++;&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== USB adapter ====&lt;br /&gt;
Based on this driver: https://github.com/YukiWorkshop/sx126x_driver&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  radio.Init();&lt;br /&gt;
&lt;br /&gt;
  radio.SetRfFrequency(868000000);&lt;br /&gt;
  radio.SetBufferBaseAddresses(0, 0);&lt;br /&gt;
&lt;br /&gt;
  SX126x::ModulationParams_t modulationParams;&lt;br /&gt;
  modulationParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  modulationParams.Params.LoRa.SpreadingFactor = SX126x::RadioLoRaSpreadingFactors_t::LORA_SF12;&lt;br /&gt;
  modulationParams.Params.LoRa.CodingRate = SX126x::RadioLoRaCodingRates_t::LORA_CR_4_5;&lt;br /&gt;
  modulationParams.Params.LoRa.Bandwidth = SX126x::RadioLoRaBandwidths_t::LORA_BW_500;&lt;br /&gt;
  modulationParams.Params.LoRa.LowDatarateOptimize = false;&lt;br /&gt;
  radio.SetModulationParams(modulationParams);&lt;br /&gt;
&lt;br /&gt;
  SX126x::PacketParams_t packetParams;&lt;br /&gt;
  packetParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  packetParams.Params.LoRa.PreambleLength = 8;&lt;br /&gt;
  packetParams.Params.LoRa.HeaderType = SX126x::RadioLoRaPacketLengthsMode_t::LORA_PACKET_VARIABLE_LENGTH;&lt;br /&gt;
  packetParams.Params.LoRa.PayloadLength = 27;&lt;br /&gt;
  packetParams.Params.LoRa.CrcMode = SX126x::RadioLoRaCrcModes_t::LORA_CRC_ON;&lt;br /&gt;
  packetParams.Params.LoRa.InvertIQ = SX126x::RadioLoRaIQModes_t::LORA_IQ_INVERTED;&lt;br /&gt;
  radio.SetPacketParams(packetParams);&lt;br /&gt;
&lt;br /&gt;
  radio.SetTxParams(22, SX126x::RADIO_RAMP_3400_US);&lt;br /&gt;
  radio.SetRegulatorMode(SX126x::RadioRegulatorMode_t::USE_DCDC);&lt;br /&gt;
&lt;br /&gt;
  radio.SetDioIrqParams(0xffff, 0x0001, 0, 0);&lt;br /&gt;
  &lt;br /&gt;
// RX&lt;br /&gt;
  radio.SetRx(0xffffffff);&lt;br /&gt;
&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// OR TX&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.SetPayload(data, 27);&lt;br /&gt;
    radio.SetTx(0xffffffff);&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Lora-raw-setup.jpg&amp;diff=11685</id>
		<title>File:Lora-raw-setup.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Lora-raw-setup.jpg&amp;diff=11685"/>
		<updated>2021-10-21T17:43:40Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11684</id>
		<title>User:JF/JF's note on PineDio devices</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11684"/>
		<updated>2021-10-21T17:38:13Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== USB LoRa adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Documents ===&lt;br /&gt;
* Schematics : [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;br /&gt;
&lt;br /&gt;
== RAW LoRa communication between USB LoRa adapter and PineDio STACK ==&lt;br /&gt;
&lt;br /&gt;
=== Test setup ===&lt;br /&gt;
* One Pine64 USB LoRa adapter (SX1262 + CH341)&lt;br /&gt;
* One PineDio STACK (BL604 + SX1262)&lt;br /&gt;
* One PyCom Lopy board (dev board based on ESP32 + LoRa module, MicroPython)&lt;br /&gt;
* One NooElec SDR adapter and GQRX running on my PC&lt;br /&gt;
&lt;br /&gt;
The goal is to implement RAW LoRa communication between Pine64 LoRa devices (USB adapter + PineDio STACK at first, pinephone adapter later on).&lt;br /&gt;
The Lopy board allows me to debug my setup easily, as I know it's working correctly in both RX and TX.&lt;br /&gt;
&lt;br /&gt;
I'm writing this section to share my experiments with RAW LoRa on those devices and maybe get some help on some issues. I'm a noob in RF and LoRa technologies !&lt;br /&gt;
&lt;br /&gt;
=== RX on Pine64 devices ===&lt;br /&gt;
Setup : The Lopy board emits 16 Bytes every 5s&lt;br /&gt;
&lt;br /&gt;
Using default TX settings on the Lopy (868Mhz, BW 125Khz, SF7, 8 preamble symbols, CR 4/5, IQ not inverted), the reception on both Pine64 devices was really poor : they would detect the preamble most of the time, but fail to check the CRC of the header or of the payload.&lt;br /&gt;
&lt;br /&gt;
Then I change those settings : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted. Magically, the reception on both device was perfect!&lt;br /&gt;
&lt;br /&gt;
Question : why the RX was not working with original settings and would work with the new ones?&lt;br /&gt;
&lt;br /&gt;
=== TX from Pine64 devices ===&lt;br /&gt;
Using the same TX parameters as the previous test : 868Mhz, BW 500Khz, SF12, 8 preamble symbols, CR 4/5, IQ inverted&lt;br /&gt;
&lt;br /&gt;
==== TX from the USB LoRa Adapter ====&lt;br /&gt;
On the SDR acquisition, the TX power seems lower than the Lopy board, even with TX power set to +22dB&lt;br /&gt;
&lt;br /&gt;
[[File:USB-tx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy does not receive anything.&lt;br /&gt;
The STACK detects the message but detects a bad CRC. Indeed, the messages is scrambled...&lt;br /&gt;
&lt;br /&gt;
[[File:Stack-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The RSSI and SNR are displayed. I notice that the RSSI is much lower for messages coming from the USB adapter than for messages coming from the Lopy&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Is it normal that the power of the TX from the USB adapter looks much lower than the power from the lopy?&lt;br /&gt;
 - What about the RSSI that is much lower on messages comng from the USB adapter?&lt;br /&gt;
 - Why are the messages and CRC corrupted ?&lt;br /&gt;
&lt;br /&gt;
==== TX from the PineDio STACK ==== &lt;br /&gt;
On the SDR acquisition, the signal power looks similar than the Lopy.&lt;br /&gt;
&lt;br /&gt;
[[File:Tx-stack.png]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB adapter receives the message but detects a bad CRC. &lt;br /&gt;
&lt;br /&gt;
[[File:USB-rx.png]]&lt;br /&gt;
&lt;br /&gt;
The Lopy board does not receive anything (probably because of messages with bad CRC that are dropped in lower level layers).&lt;br /&gt;
&lt;br /&gt;
Questions : &lt;br /&gt;
 - Why are the messages corrupted?&lt;br /&gt;
&lt;br /&gt;
=== Code ===&lt;br /&gt;
==== PineDio STACK ====&lt;br /&gt;
Based on this driver: https://github.com/lupyuen/bl_iot_sdk/blob/pinedio/components/3rdparty/lora-sx1262/src/radio.c&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  RadioEvents_t RadioEvents;&lt;br /&gt;
&lt;br /&gt;
  RadioEvents.RxDone = OnRadioRxDone;&lt;br /&gt;
  RadioEvents.RxError = OnRadioRxError;&lt;br /&gt;
  RadioEvents.TxDone = OnRadioTxDone;&lt;br /&gt;
&lt;br /&gt;
  Radio.Init(&amp;amp;RadioEvents);&lt;br /&gt;
  Radio.SetPublicNetwork(false);&lt;br /&gt;
  Radio.SetChannel(868000000);&lt;br /&gt;
  Radio.SetRxConfig(&lt;br /&gt;
          MODEM_LORA,&lt;br /&gt;
          2, //500khz&lt;br /&gt;
          12, //SF12&lt;br /&gt;
          1, // CR 4/5&lt;br /&gt;
          0, // N/A&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          7, // symbol timeout&lt;br /&gt;
          0, // dynamic length&lt;br /&gt;
          0, // payload length&lt;br /&gt;
          1, // crc enabled&lt;br /&gt;
          0, // freq hoping disabled&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          1, // no iq inversion&lt;br /&gt;
          1// continous receive&lt;br /&gt;
          );&lt;br /&gt;
  Radio.SetTxConfig(&lt;br /&gt;
          RadioModems_t::MODEM_LORA,&lt;br /&gt;
          0, // power&lt;br /&gt;
          0, //N/A&lt;br /&gt;
          2, // 500 khz&lt;br /&gt;
          12, // SF12&lt;br /&gt;
          1, // CR4/5&lt;br /&gt;
          8, // preamble&lt;br /&gt;
          false, // dynamic length&lt;br /&gt;
          true, // CRC ON&lt;br /&gt;
          false, // hop&lt;br /&gt;
          0, // hop period&lt;br /&gt;
          true, // invert iq&lt;br /&gt;
          0xffffffff // timeout&lt;br /&gt;
          );&lt;br /&gt;
  // RX&lt;br /&gt;
  Radio.Rx(0);&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // OR TX&lt;br /&gt;
  const char msg[] = {&amp;quot;Hello, I'm a PineDio STACK!&amp;quot;};&lt;br /&gt;
&lt;br /&gt;
  int i = 0;&lt;br /&gt;
  while(1) {&lt;br /&gt;
    Radio.IrqProcess();&lt;br /&gt;
    vTaskDelay(100);&lt;br /&gt;
    if((i % 30) ==0){&lt;br /&gt;
      printf(&amp;quot;send...\r\n&amp;quot;);&lt;br /&gt;
      Radio.Send((uint8_t *) msg, strlen(msg));&lt;br /&gt;
    }&lt;br /&gt;
    i++;&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== USB adapter ====&lt;br /&gt;
Based on this driver: https://github.com/YukiWorkshop/sx126x_driver&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&lt;br /&gt;
  radio.Init();&lt;br /&gt;
&lt;br /&gt;
  radio.SetRfFrequency(868000000);&lt;br /&gt;
  radio.SetBufferBaseAddresses(0, 0);&lt;br /&gt;
&lt;br /&gt;
  SX126x::ModulationParams_t modulationParams;&lt;br /&gt;
  modulationParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  modulationParams.Params.LoRa.SpreadingFactor = SX126x::RadioLoRaSpreadingFactors_t::LORA_SF12;&lt;br /&gt;
  modulationParams.Params.LoRa.CodingRate = SX126x::RadioLoRaCodingRates_t::LORA_CR_4_5;&lt;br /&gt;
  modulationParams.Params.LoRa.Bandwidth = SX126x::RadioLoRaBandwidths_t::LORA_BW_500;&lt;br /&gt;
  modulationParams.Params.LoRa.LowDatarateOptimize = false;&lt;br /&gt;
  radio.SetModulationParams(modulationParams);&lt;br /&gt;
&lt;br /&gt;
  SX126x::PacketParams_t packetParams;&lt;br /&gt;
  packetParams.PacketType = SX126x::RadioPacketTypes_t::PACKET_TYPE_LORA;&lt;br /&gt;
  packetParams.Params.LoRa.PreambleLength = 8;&lt;br /&gt;
  packetParams.Params.LoRa.HeaderType = SX126x::RadioLoRaPacketLengthsMode_t::LORA_PACKET_VARIABLE_LENGTH;&lt;br /&gt;
  packetParams.Params.LoRa.PayloadLength = 27;&lt;br /&gt;
  packetParams.Params.LoRa.CrcMode = SX126x::RadioLoRaCrcModes_t::LORA_CRC_ON;&lt;br /&gt;
  packetParams.Params.LoRa.InvertIQ = SX126x::RadioLoRaIQModes_t::LORA_IQ_INVERTED;&lt;br /&gt;
  radio.SetPacketParams(packetParams);&lt;br /&gt;
&lt;br /&gt;
  radio.SetTxParams(22, SX126x::RADIO_RAMP_3400_US);&lt;br /&gt;
  radio.SetRegulatorMode(SX126x::RadioRegulatorMode_t::USE_DCDC);&lt;br /&gt;
&lt;br /&gt;
  radio.SetDioIrqParams(0xffff, 0x0001, 0, 0);&lt;br /&gt;
  &lt;br /&gt;
// RX&lt;br /&gt;
  radio.SetRx(0xffffffff);&lt;br /&gt;
&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// OR TX&lt;br /&gt;
  while (1) {&lt;br /&gt;
    radio.SetPayload(data, 27);&lt;br /&gt;
    radio.SetTx(0xffffffff);&lt;br /&gt;
    radio.ProcessIrqs();&lt;br /&gt;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));&lt;br /&gt;
  }&lt;br /&gt;
 &amp;lt;/nowiki&amp;gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Stack-rx.png&amp;diff=11683</id>
		<title>File:Stack-rx.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Stack-rx.png&amp;diff=11683"/>
		<updated>2021-10-21T17:27:39Z</updated>

		<summary type="html">&lt;p&gt;JF: JF uploaded a new version of File:Stack-rx.png&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Stack-rx.png&amp;diff=11682</id>
		<title>File:Stack-rx.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Stack-rx.png&amp;diff=11682"/>
		<updated>2021-10-21T17:25:31Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:USB-tx.png&amp;diff=11681</id>
		<title>File:USB-tx.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:USB-tx.png&amp;diff=11681"/>
		<updated>2021-10-21T17:20:46Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:USB-rx.png&amp;diff=11680</id>
		<title>File:USB-rx.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:USB-rx.png&amp;diff=11680"/>
		<updated>2021-10-21T17:11:10Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Tx-stack.png&amp;diff=11679</id>
		<title>File:Tx-stack.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Tx-stack.png&amp;diff=11679"/>
		<updated>2021-10-21T17:06:49Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=11175</id>
		<title>Pinedio</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=11175"/>
		<updated>2021-08-24T18:25:18Z</updated>

		<summary type="html">&lt;p&gt;JF: Add PineDio Stack schematic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to change. Project is in early development phase.}}&lt;br /&gt;
&lt;br /&gt;
LoRa is a long range, low power wireless platform that is being used by a lot of Internet of Things (IoT) products. Using LoRa and LoRaWAN, devices can communicate across the world using the internet, using various decentralised networks such as [https://www.thethingsnetwork.org/ The Things Network] or [https://www.helium.com/ Helium]. Since, PINE64 believes in openness, the LoRa gateway can connect to any network, per the developer implementation. If Helium Spots open up for PINE64 gateway and developers have implemented the hook for Helium, then this is good thing. The PINE64 LoRa gateway also open connect to The Things Network if developers implement support. The choice is yours!&lt;br /&gt;
&lt;br /&gt;
== Gateway ==&lt;br /&gt;
&lt;br /&gt;
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have &amp;quot;an aluminum, rugged and water resistant case&amp;quot;. &lt;br /&gt;
The indoor unit consists of a PINE A64-LTS, fitted with a purpose built hat (adapter) which uses a LoRa module by RakWireless. The chipset used is the SX1302, and the module via the SPI interface. There are two external connections on the enclosure for the GPS and loRa antenna. &lt;br /&gt;
&lt;br /&gt;
=== Connections ===&lt;br /&gt;
* GPS is connected to UART2 on the A64 board&lt;br /&gt;
* SX1302 on SPI0&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|RAK2287 module&lt;br /&gt;
|PI-2 connector&lt;br /&gt;
|PINE A64-LTS&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 SPI&lt;br /&gt;
|Pin 19 = MOSI / PC0&amp;lt;br/&amp;gt;Pin 21 = MISO/PC1&amp;lt;br/&amp;gt;Pin23 = CLK/PC2&amp;lt;br/&amp;gt;Pin24 = CS/PC3&lt;br /&gt;
|SPI0 (/dev/spidev0.0)&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 RESET&lt;br /&gt;
|Pin 11 = GPIO17/PC7&lt;br /&gt;
|GPIO71 (/sys/class/gpio/gpio71)&lt;br /&gt;
|-&lt;br /&gt;
|GPS UART&lt;br /&gt;
|Pin 8 = TX/&amp;lt;br&amp;gt;Pin 10 = RX&lt;br /&gt;
|UART2 (/dev/ttyS2)&lt;br /&gt;
|-&lt;br /&gt;
|GPS RESET&lt;br /&gt;
|Pin 33 = GPIO13/PC5&lt;br /&gt;
|GPIO69 (/sys/class/gpio/gpio69)&lt;br /&gt;
|-&lt;br /&gt;
|GPS Standby&lt;br /&gt;
|Pin 35 = GPIO19/PC9&lt;br /&gt;
|GPIO73 (/sys/class/gpio/gpio73)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-InsideLoRaGateway.jpg&lt;br /&gt;
File:Blog-april-InsideLoRaGateway2.jpeg&lt;br /&gt;
File:Discord-lora-gateway-20210413_143615.jpg&lt;br /&gt;
File:Discord-lora-gateway-20210413_1435271.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Operating System Options===&lt;br /&gt;
&lt;br /&gt;
Pinedio Gateway carries the A64-LTS board. Based on ram specifications SOPINE images are also compatible.&lt;br /&gt;
&lt;br /&gt;
====Armbian====&lt;br /&gt;
&lt;br /&gt;
Gateway is based on the pine64 A64-LTS, and the current Armbian_sopine image download options can be found here: &lt;br /&gt;
https://www.armbian.com/sopine-a64/&lt;br /&gt;
&lt;br /&gt;
(Previous issues in DTS have been fixed by Armbian developers and Armbian_sopine_21.05.1 is confirmed to boot).&lt;br /&gt;
&lt;br /&gt;
Armbian Official Website: https://www.armbian.com&lt;br /&gt;
&lt;br /&gt;
'''Default Credentials'''&lt;br /&gt;
&lt;br /&gt;
 Login: root&lt;br /&gt;
 password: 1234&lt;br /&gt;
&lt;br /&gt;
After your first login you will be guided through creating your user account (create a strong password).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):'''&lt;br /&gt;
&lt;br /&gt;
Inside armbian-config -&amp;gt; system -&amp;gt; Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):&lt;br /&gt;
&lt;br /&gt;
 overlays=spi-spidev uart2 i2c0&lt;br /&gt;
 param_spidev_spi_bus=0&lt;br /&gt;
&lt;br /&gt;
Or you may hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.&lt;br /&gt;
&lt;br /&gt;
Save. Reboot. &lt;br /&gt;
&lt;br /&gt;
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.&lt;br /&gt;
&lt;br /&gt;
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot). &lt;br /&gt;
Make sure to offer GPS antenna a strong signal, preferably by a window (if indoors).&lt;br /&gt;
&lt;br /&gt;
====Dietpi====&lt;br /&gt;
&lt;br /&gt;
NOTE: IMAGE CURRENTLY EXPERIMENTAL. FOR TESTING. NOT CONSIDERED STABLE.&lt;br /&gt;
&lt;br /&gt;
HIGHLY SUGGESTED TO USE ARMBIAN (AT THIS TIME).&lt;br /&gt;
THIS SECTION WILL BE UPDATED.&lt;br /&gt;
&lt;br /&gt;
Download current Dietpi image (for Pinedio/SOPINE/LTS): &lt;br /&gt;
https://mega.nz/file/7VpmAQ6S#CxOpSHBHgFkynXIOKVQEQk8864-DLsNnFtbpCH6PU6o&lt;br /&gt;
&lt;br /&gt;
 Login: dietpi&lt;br /&gt;
 Password: SoPinePass!&lt;br /&gt;
&lt;br /&gt;
Dietpi is a lightweight SOPINE/A64-LTS image using Armbian as pre-image (Debian based). Carrying a large array of options, Dietpi includes SBC hardware configurations available inside ncurses menu interface (ssh/terminal accessible). In addition to it being a full on Debian based Linux system, a variety of servers and services can be added on demand.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Dietpi Commands:'''&lt;br /&gt;
&lt;br /&gt;
dietpi-launcher: access all dietpi tools/menus&lt;br /&gt;
&lt;br /&gt;
dietpi-software: select from numerous optimized servers/services to install&lt;br /&gt;
&lt;br /&gt;
dietpi-config: feature rich configuration tool&lt;br /&gt;
&lt;br /&gt;
dietpi-autostart: choose software to run after boot&lt;br /&gt;
&lt;br /&gt;
dietpi-update: update/upgrade system&lt;br /&gt;
&lt;br /&gt;
The entire list of software available for installation (inside dietpi-software) can be found here: https://dietpi.com/docs/software/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):'''&lt;br /&gt;
&lt;br /&gt;
As Dietpi strips down the system to a minimum level (deleting original Armbian commands), we can either install armbian-config command by issuing:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install armbian-config&lt;br /&gt;
&lt;br /&gt;
Inside armbian-config -&amp;gt; system -&amp;gt; Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):&lt;br /&gt;
&lt;br /&gt;
 overlays=spi-spidev uart2 i2c0&lt;br /&gt;
 param_spidev_spi_bus=0&lt;br /&gt;
&lt;br /&gt;
Or, instead of installing the above armbian-config, hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.&lt;br /&gt;
&lt;br /&gt;
Save. Reboot. &lt;br /&gt;
&lt;br /&gt;
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.&lt;br /&gt;
&lt;br /&gt;
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot).&lt;br /&gt;
&lt;br /&gt;
Dietpi Official Website: https://www.dietpi.com&lt;br /&gt;
&lt;br /&gt;
== USB adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
== Other end nodes ==&lt;br /&gt;
&lt;br /&gt;
There are several end-node units planned:&lt;br /&gt;
* loRa back case for the PinePhone&lt;br /&gt;
* standalone USB dongle-type end-node adapter&lt;br /&gt;
* PineTab adapter&lt;br /&gt;
* as well as a SPI module (which can also be configured as a USB LoRa dongle)&lt;br /&gt;
* a LoRa stick powered by a single 18650 battery (using the [https://wiki.pine64.org/wiki/Nutcracker BL602], and can be fitted with GPS, an low-power OLED panel and additional sensors)&lt;br /&gt;
&lt;br /&gt;
All the end-nodes use the SX1262 chip. &lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-USB-LoRa-1024x655.jpg&lt;br /&gt;
File:Blog-april-LoRa-something-839x1024.jpg&lt;br /&gt;
File:Discord_20210421_lora_usb_closeup.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Datasheets and schematics ==&lt;br /&gt;
=== Gateway ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302 SX1302 datasheets and resources]&lt;br /&gt;
* [https://docs.rakwireless.com/Product-Categories/WisLink/RAK2247/Overview/ RAK2287 datasheets and resources]&lt;br /&gt;
* [https://wiki.pine64.org/images/5/54/PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf Pine64 LoRa Gateway module adapter schematic]&lt;br /&gt;
&lt;br /&gt;
=== End nodes ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1262 SX1262 datasheets and resources]&lt;br /&gt;
&lt;br /&gt;
=== Pinephone backplate ===&lt;br /&gt;
* [[File:Pinephone_LoRa_BackPanel_Schematic-v1.0-20210402.pdf]]&lt;br /&gt;
* [[File:CA-S01_LoRa_Chip_Antenna_in_Chinese.pdf]]&lt;br /&gt;
* [https://github.com/zschroeder6212/tiny-i2c-spi I2C SPI Bridge code running on ATtiny84]&lt;br /&gt;
&lt;br /&gt;
=== USB LoRa adapter ===&lt;br /&gt;
* [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;br /&gt;
&lt;br /&gt;
=== PineDio Stack ===&lt;br /&gt;
* Schematic : [[File:PINEDIO_STACK_V1_0-2021_05_24C.pdf]]&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules]&lt;br /&gt;
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:PINEDIO_STACK_V1_0-2021_05_24C.pdf&amp;diff=11174</id>
		<title>File:PINEDIO STACK V1 0-2021 05 24C.pdf</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:PINEDIO_STACK_V1_0-2021_05_24C.pdf&amp;diff=11174"/>
		<updated>2021-08-24T18:23:00Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=11134</id>
		<title>Pinedio</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=11134"/>
		<updated>2021-08-20T18:06:01Z</updated>

		<summary type="html">&lt;p&gt;JF: Add new section about the USB LoRa adapter&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to change. Project is in early development phase.}}&lt;br /&gt;
&lt;br /&gt;
LoRa is a long range, low power wireless platform that is being used by a lot of Internet of Things (IoT) products. Using LoRa and LoRaWAN, devices can communicate across the world using the internet, using various decentralised networks such as [https://www.thethingsnetwork.org/ The Things Network] or [https://www.helium.com/ Helium]. Since, PINE64 believes in openness, the LoRa gateway can connect to any network, per the developer implementation. If Helium Spots open up for PINE64 gateway and developers have implemented the hook for Helium, then this is good thing. The PINE64 LoRa gateway also open connect to The Things Network if developers implement support. The choice is yours!&lt;br /&gt;
&lt;br /&gt;
== Gateway ==&lt;br /&gt;
&lt;br /&gt;
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have &amp;quot;an aluminum, rugged and water resistant case&amp;quot;. &lt;br /&gt;
The indoor unit consists of a PINE A64-LTS, fitted with a purpose built hat (adapter) which uses a LoRa module by RakWireless. The chipset used is the SX1302, and the module via the SPI interface. There are two external connections on the enclosure for the GPS and loRa antenna. &lt;br /&gt;
&lt;br /&gt;
=== Connections ===&lt;br /&gt;
* GPS is connected to UART2 on the A64 board&lt;br /&gt;
* SX1302 on SPI0&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|RAK2287 module&lt;br /&gt;
|PI-2 connector&lt;br /&gt;
|PINE A64-LTS&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 SPI&lt;br /&gt;
|Pin 19 = MOSI / PC0&amp;lt;br/&amp;gt;Pin 21 = MISO/PC1&amp;lt;br/&amp;gt;Pin23 = CLK/PC2&amp;lt;br/&amp;gt;Pin24 = CS/PC3&lt;br /&gt;
|SPI0 (/dev/spidev0.0)&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 RESET&lt;br /&gt;
|Pin 11 = GPIO17/PC7&lt;br /&gt;
|GPIO71 (/sys/class/gpio/gpio71)&lt;br /&gt;
|-&lt;br /&gt;
|GPS UART&lt;br /&gt;
|Pin 8 = TX/&amp;lt;br&amp;gt;Pin 10 = RX&lt;br /&gt;
|UART2 (/dev/ttyS2)&lt;br /&gt;
|-&lt;br /&gt;
|GPS RESET&lt;br /&gt;
|Pin 33 = GPIO13/PC5&lt;br /&gt;
|GPIO69 (/sys/class/gpio/gpio69)&lt;br /&gt;
|-&lt;br /&gt;
|GPS Standby&lt;br /&gt;
|Pin 35 = GPIO19/PC9&lt;br /&gt;
|GPIO73 (/sys/class/gpio/gpio73)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-InsideLoRaGateway.jpg&lt;br /&gt;
File:Blog-april-InsideLoRaGateway2.jpeg&lt;br /&gt;
File:Discord-lora-gateway-20210413_143615.jpg&lt;br /&gt;
File:Discord-lora-gateway-20210413_1435271.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Operating System Options===&lt;br /&gt;
&lt;br /&gt;
Pinedio Gateway carries the A64-LTS board. Based on ram specifications SOPINE images are also compatible.&lt;br /&gt;
&lt;br /&gt;
====Armbian====&lt;br /&gt;
&lt;br /&gt;
Gateway is based on the pine64 A64-LTS, and the current Armbian_sopine image download options can be found here: &lt;br /&gt;
https://www.armbian.com/sopine-a64/&lt;br /&gt;
&lt;br /&gt;
(Previous issues in DTS have been fixed by Armbian developers and Armbian_sopine_21.05.1 is confirmed to boot).&lt;br /&gt;
&lt;br /&gt;
Armbian Official Website: https://www.armbian.com&lt;br /&gt;
&lt;br /&gt;
'''Default Credentials'''&lt;br /&gt;
&lt;br /&gt;
 Login: root&lt;br /&gt;
 password: 1234&lt;br /&gt;
&lt;br /&gt;
After your first login you will be guided through creating your user account (create a strong password).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):'''&lt;br /&gt;
&lt;br /&gt;
Inside armbian-config -&amp;gt; system -&amp;gt; Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):&lt;br /&gt;
&lt;br /&gt;
 overlays=spi-spidev uart2 i2c0&lt;br /&gt;
 param_spidev_spi_bus=0&lt;br /&gt;
&lt;br /&gt;
Or you may hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.&lt;br /&gt;
&lt;br /&gt;
Save. Reboot. &lt;br /&gt;
&lt;br /&gt;
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.&lt;br /&gt;
&lt;br /&gt;
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot). &lt;br /&gt;
Make sure to offer GPS antenna a strong signal, preferably by a window (if indoors).&lt;br /&gt;
&lt;br /&gt;
====Dietpi====&lt;br /&gt;
&lt;br /&gt;
NOTE: IMAGE CURRENTLY EXPERIMENTAL. FOR TESTING. NOT CONSIDERED STABLE.&lt;br /&gt;
&lt;br /&gt;
HIGHLY SUGGESTED TO USE ARMBIAN (AT THIS TIME).&lt;br /&gt;
THIS SECTION WILL BE UPDATED.&lt;br /&gt;
&lt;br /&gt;
Download current Dietpi image (for Pinedio/SOPINE/LTS): &lt;br /&gt;
https://mega.nz/file/7VpmAQ6S#CxOpSHBHgFkynXIOKVQEQk8864-DLsNnFtbpCH6PU6o&lt;br /&gt;
&lt;br /&gt;
 Login: dietpi&lt;br /&gt;
 Password: SoPinePass!&lt;br /&gt;
&lt;br /&gt;
Dietpi is a lightweight SOPINE/A64-LTS image using Armbian as pre-image (Debian based). Carrying a large array of options, Dietpi includes SBC hardware configurations available inside ncurses menu interface (ssh/terminal accessible). In addition to it being a full on Debian based Linux system, a variety of servers and services can be added on demand.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Dietpi Commands:'''&lt;br /&gt;
&lt;br /&gt;
dietpi-launcher: access all dietpi tools/menus&lt;br /&gt;
&lt;br /&gt;
dietpi-software: select from numerous optimized servers/services to install&lt;br /&gt;
&lt;br /&gt;
dietpi-config: feature rich configuration tool&lt;br /&gt;
&lt;br /&gt;
dietpi-autostart: choose software to run after boot&lt;br /&gt;
&lt;br /&gt;
dietpi-update: update/upgrade system&lt;br /&gt;
&lt;br /&gt;
The entire list of software available for installation (inside dietpi-software) can be found here: https://dietpi.com/docs/software/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):'''&lt;br /&gt;
&lt;br /&gt;
As Dietpi strips down the system to a minimum level (deleting original Armbian commands), we can either install armbian-config command by issuing:&lt;br /&gt;
&lt;br /&gt;
 sudo apt install armbian-config&lt;br /&gt;
&lt;br /&gt;
Inside armbian-config -&amp;gt; system -&amp;gt; Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):&lt;br /&gt;
&lt;br /&gt;
 overlays=spi-spidev uart2 i2c0&lt;br /&gt;
 param_spidev_spi_bus=0&lt;br /&gt;
&lt;br /&gt;
Or, instead of installing the above armbian-config, hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.&lt;br /&gt;
&lt;br /&gt;
Save. Reboot. &lt;br /&gt;
&lt;br /&gt;
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.&lt;br /&gt;
&lt;br /&gt;
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot).&lt;br /&gt;
&lt;br /&gt;
Dietpi Official Website: https://www.dietpi.com&lt;br /&gt;
&lt;br /&gt;
== USB adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
== Other end nodes ==&lt;br /&gt;
&lt;br /&gt;
There are several end-node units planned:&lt;br /&gt;
* loRa back case for the PinePhone&lt;br /&gt;
* standalone USB dongle-type end-node adapter&lt;br /&gt;
* PineTab adapter&lt;br /&gt;
* as well as a SPI module (which can also be configured as a USB LoRa dongle)&lt;br /&gt;
* a LoRa stick powered by a single 18650 battery (using the [https://wiki.pine64.org/wiki/Nutcracker BL602], and can be fitted with GPS, an low-power OLED panel and additional sensors)&lt;br /&gt;
&lt;br /&gt;
All the end-nodes use the SX1262 chip. &lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-USB-LoRa-1024x655.jpg&lt;br /&gt;
File:Blog-april-LoRa-something-839x1024.jpg&lt;br /&gt;
File:Discord_20210421_lora_usb_closeup.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Datasheets and schematics ==&lt;br /&gt;
=== Gateway ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302 SX1302 datasheets and resources]&lt;br /&gt;
* [https://docs.rakwireless.com/Product-Categories/WisLink/RAK2247/Overview/ RAK2287 datasheets and resources]&lt;br /&gt;
* [https://wiki.pine64.org/images/5/54/PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf Pine64 LoRa Gateway module adapter schematic]&lt;br /&gt;
&lt;br /&gt;
=== End nodes ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1262 SX1262 datasheets and resources]&lt;br /&gt;
&lt;br /&gt;
=== Pinephone backplate ===&lt;br /&gt;
* [[File:Pinephone_LoRa_BackPanel_Schematic-v1.0-20210402.pdf]]&lt;br /&gt;
* [[File:CA-S01_LoRa_Chip_Antenna_in_Chinese.pdf]]&lt;br /&gt;
* [https://github.com/zschroeder6212/tiny-i2c-spi I2C SPI Bridge code running on ATtiny84]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== USB LoRa adapter ===&lt;br /&gt;
* [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules]&lt;br /&gt;
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11023</id>
		<title>User:JF/JF's note on PineDio devices</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF/JF%27s_note_on_PineDio_devices&amp;diff=11023"/>
		<updated>2021-08-15T15:24:35Z</updated>

		<summary type="html">&lt;p&gt;JF: Created page with &amp;quot;== USB LoRa adapter == 500px  The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip....&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== USB LoRa adapter ==&lt;br /&gt;
[[File:Pine64-lora-usb-adapter.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
The Pine64 USB LoRa adapter is based on the Semtech SX1262 LoRa module and the CH341 USB bus converter chip. The '''CH341''' chip can be configured in multiple mode to convert USB to various serial and parallel ports. In this case, it's configured in '''synchronous serial mode''', which allows this chip to convert from USB to the SPI bus needed to talk to the SX1262 LoRa module:&lt;br /&gt;
&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
 |      |            |   USB LoRa Adapter     |&lt;br /&gt;
 | PC   |  &amp;lt;--USB--&amp;gt; | CH341 &amp;lt;--SPI--&amp;gt; SX1262 |&lt;br /&gt;
 |      |            |       &amp;lt;--I/O--&amp;gt;        |&lt;br /&gt;
 --------            --------------------------&lt;br /&gt;
&lt;br /&gt;
=== Pins ===&lt;br /&gt;
[[File:Lora-usb-pins.jpg|500px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
&lt;br /&gt;
!SX1262 Pin&lt;br /&gt;
!Name&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|1&lt;br /&gt;
|ANT&lt;br /&gt;
|Antenna&lt;br /&gt;
|-&lt;br /&gt;
|2&lt;br /&gt;
|GND2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|3&lt;br /&gt;
|VREG&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|4&lt;br /&gt;
|DCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|5&lt;br /&gt;
|VCC&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|6&lt;br /&gt;
|DIO1&lt;br /&gt;
|Connected on CH341 Pin 7&lt;br /&gt;
|-&lt;br /&gt;
|7&lt;br /&gt;
|DIO2&lt;br /&gt;
|Connected on CH341 Pin6&lt;br /&gt;
|-&lt;br /&gt;
|8&lt;br /&gt;
|DIO3&lt;br /&gt;
|Connected on CH341 Pin 5&lt;br /&gt;
|-&lt;br /&gt;
|9&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|10&lt;br /&gt;
|MISO&lt;br /&gt;
|SPI MISO&lt;br /&gt;
|-&lt;br /&gt;
|11&lt;br /&gt;
|MOSI&lt;br /&gt;
|SPI MOSI&lt;br /&gt;
|-&lt;br /&gt;
|12&lt;br /&gt;
|SCK&lt;br /&gt;
|SPI clock&lt;br /&gt;
|- &lt;br /&gt;
|13&lt;br /&gt;
|NSS&lt;br /&gt;
|SPI Chip select&lt;br /&gt;
|-&lt;br /&gt;
|14&lt;br /&gt;
|POR&lt;br /&gt;
|Reset pin&lt;br /&gt;
|-&lt;br /&gt;
|15&lt;br /&gt;
|Busy&lt;br /&gt;
|Busy pin&lt;br /&gt;
|-&lt;br /&gt;
|16&lt;br /&gt;
|GND&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel module for CH341 === &lt;br /&gt;
We need a driver for the CH341 USB bus converter chip. This driver will allow us to send command to the CH341 (SPI messages and access to the GPIOs). I've succesfuly build and run [https://github.com/rogerjames99/spi-ch341-usb this driver from '''rogerjames99'''] on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).&lt;br /&gt;
&lt;br /&gt;
 $ git clone https://github.com/rogerjames99/spi-ch341-usb.git&lt;br /&gt;
 $ cd spi-ch341-usb&lt;br /&gt;
 $ make&lt;br /&gt;
 $ sudo make install&lt;br /&gt;
&lt;br /&gt;
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded:&lt;br /&gt;
&lt;br /&gt;
 $ lsmod |grep ch341&lt;br /&gt;
 $ sudo rmmod ch341&lt;br /&gt;
&lt;br /&gt;
On my setup, ''ch341'' would be automatically loaded once I connected my USB adapter. This module drives the CH341 is asynchronous serial mode, which will not work for a SPI bus. &lt;br /&gt;
&lt;br /&gt;
Then load the new module:&lt;br /&gt;
&lt;br /&gt;
 $ sudo modprobe spi-ch341-usb&lt;br /&gt;
&lt;br /&gt;
Plug your USB adapter and check that the module is correctly loaded : &lt;br /&gt;
&lt;br /&gt;
 $ dmesg&lt;br /&gt;
 [20141.872107] usb 1-1.1: USB disconnect, device number 4&lt;br /&gt;
 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform&lt;br /&gt;
 [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04&lt;br /&gt;
 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0&lt;br /&gt;
 [20143.973434] usb 1-1.1: Product: USB UART-LPT&lt;br /&gt;
 [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device&lt;br /&gt;
 [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3&lt;br /&gt;
 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=0 type=2 dir=1 addr=2&lt;br /&gt;
 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=1 type=2 dir=0 addr=2&lt;br /&gt;
 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe:   endpoint=2 type=3 dir=1 addr=1&lt;br /&gt;
 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0&lt;br /&gt;
 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 &lt;br /&gt;
 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1&lt;br /&gt;
 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 &lt;br /&gt;
 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2&lt;br /&gt;
 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 &lt;br /&gt;
 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio4 gpio=3 irq=3 &lt;br /&gt;
 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  gpio6 gpio=4 irq=4 &lt;br /&gt;
 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  err gpio=5 irq=5 &lt;br /&gt;
 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  pemp gpio=6 irq=6 &lt;br /&gt;
 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  int gpio=7 irq=7 (hwirq)&lt;br /&gt;
 [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  slct gpio=8 irq=8 &lt;br /&gt;
 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  wait gpio=9 irq=9 &lt;br /&gt;
 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  autofd gpio=10 irq=10 &lt;br /&gt;
 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input  addr gpio=11 irq=11 &lt;br /&gt;
 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 &lt;br /&gt;
 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 &lt;br /&gt;
 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 &lt;br /&gt;
 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 &lt;br /&gt;
 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start&lt;br /&gt;
 [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1&lt;br /&gt;
 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created&lt;br /&gt;
 [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created&lt;br /&gt;
 [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created&lt;br /&gt;
 [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done&lt;br /&gt;
 [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start&lt;br /&gt;
 [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103&lt;br /&gt;
 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done&lt;br /&gt;
 [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start&lt;br /&gt;
 [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0&lt;br /&gt;
 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0&lt;br /&gt;
 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0&lt;br /&gt;
 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1&lt;br /&gt;
 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1&lt;br /&gt;
 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1&lt;br /&gt;
 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1&lt;br /&gt;
 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1&lt;br /&gt;
 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1&lt;br /&gt;
 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1&lt;br /&gt;
 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1&lt;br /&gt;
 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1&lt;br /&gt;
 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0&lt;br /&gt;
 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0&lt;br /&gt;
 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0&lt;br /&gt;
 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0&lt;br /&gt;
 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511&lt;br /&gt;
 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done&lt;br /&gt;
 [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start&lt;br /&gt;
 [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected&lt;br /&gt;
 [20144.756250] usbcore: registered new interface driver ch341&lt;br /&gt;
 [20144.756334] usbserial: USB Serial support registered for ch341-uart  &lt;br /&gt;
&lt;br /&gt;
=== Driver development === &lt;br /&gt;
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C):&lt;br /&gt;
&lt;br /&gt;
 /* Open the SPI bus */&lt;br /&gt;
 int spi = open(&amp;quot;/dev/spidev1.0&amp;quot;, O_RDWR);&lt;br /&gt;
 uint8_t mmode = SPI_MODE_0;&lt;br /&gt;
 uint8_t lsb = 0;&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_MODE, &amp;amp;mmode);&lt;br /&gt;
 ioctl(spi, SPI_IOC_WR_LSB_FIRST, &amp;amp;lsb);&lt;br /&gt;
 &lt;br /&gt;
 /* Transfer data */&lt;br /&gt;
 /* TODO: Init buffer_out, buffer_in and size */&lt;br /&gt;
 const uint8_t *mosi = buffer_out; // output data&lt;br /&gt;
 uint8_t *miso = buffer_in; // input data&lt;br /&gt;
 &lt;br /&gt;
 struct spi_ioc_transfer spi_trans;&lt;br /&gt;
 memset(&amp;amp;spi_trans, 0, sizeof(spi_trans));&lt;br /&gt;
 &lt;br /&gt;
 spi_trans.tx_buf = (unsigned long) mosi;&lt;br /&gt;
 spi_trans.rx_buf = (unsigned long) miso;&lt;br /&gt;
 spi_trans.cs_change = true;&lt;br /&gt;
 spi_trans.len = size;&lt;br /&gt;
 &lt;br /&gt;
 int status = ioctl (spi, SPI_IOC_MESSAGE(1), &amp;amp;spi_trans);&lt;br /&gt;
&lt;br /&gt;
To access GPIOs, you first need to export them (to make them accessible via ''/sys/class/gpio''. As you can see in the dmesg output, GPIOs from 496 to 511 were registered, which means we can export 16 GPIOs. The mapping of these I/O is available in the [https://github.com/rogerjames99/spi-ch341-usb/blob/master/spi-ch341-usb.c#L148 source code of the driver]. For example, pin ''slct'' is the 12th, meaning we need to export GPIO 496+12 = 508.&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/export&amp;quot;, O_WRONLY)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
   exit(-1);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, &amp;quot;508&amp;quot;, 3) == -1){&lt;br /&gt;
   perror (&amp;quot;write export 508&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Once exported, the GPIO is available in ''/sys/class/gpio/sclt'' (the naming is specified by the driver). You can read the pin in C:&lt;br /&gt;
&lt;br /&gt;
 int  fd;&lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/slct/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 char buf;&lt;br /&gt;
 if (read(fd, &amp;amp;buf, 1) == -1) {&lt;br /&gt;
    perror(&amp;quot;read&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 int value = (buf == '0') ? 0 : 1;&lt;br /&gt;
&lt;br /&gt;
You can also write it:&lt;br /&gt;
&lt;br /&gt;
 int  fd; &lt;br /&gt;
 if ((fd = open(&amp;quot;/sys/class/gpio/ini/value&amp;quot;, O_RDWR)) == -1)   {&lt;br /&gt;
   perror(&amp;quot;open ini&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 if (write(fd, value ? &amp;quot;1&amp;quot; : &amp;quot;0&amp;quot;, 1) == -1) {&lt;br /&gt;
    perror (&amp;quot;write&amp;quot;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== Driver for the SX1262 LoRa module ===&lt;br /&gt;
Now that we can talk to the SX1262 via the CH341 USB converter chip, we need to send actual commands to make it emit or receive LoRa messages. To do this, you can implement the driver yourself using info from the datasheet, or use an existing driver (you can easily find drivers for the Arduino framework, for example. &lt;br /&gt;
I found [https://github.com/YukiWorkshop/sx126x_driver this C++ driver]. It's well written, lightweight and easily portable across many platforms. All you have to do is implement 3 HAL function : read GPIO, write GPIO and transfer data on SPI. I wrote a quick'n'dirty app that emits a LoRa frame. It's [https://gist.github.com/JF002/f1af5595874942427eea9d375c18fc73 available here]. &lt;br /&gt;
&lt;br /&gt;
As I don't have any 'raw' LoRa device on hands, I check that it was actually transmitting something using my SDR setup (simple TNT usb key and '''Gqrx''' software):&lt;br /&gt;
&lt;br /&gt;
[[File:pine64-lora-usb-adapter-sdr.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Documents ===&lt;br /&gt;
* Schematics : [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]]&lt;br /&gt;
* CH341 datasheet : [[File:CH341DS1.pdf]]&lt;br /&gt;
* Semtech SX1262 datasheet : [https://semtech.my.salesforce.com/sfc/p/#E0000000JelG/a/2R000000HT76/7Nka9W5WgugoZe.xwIHJy6ebj1hW8UJ.USO_Pt2CLLo File on Semtech website (file is too big for the wiki)]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pine64-lora-usb-adapter-sdr.png&amp;diff=11022</id>
		<title>File:Pine64-lora-usb-adapter-sdr.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pine64-lora-usb-adapter-sdr.png&amp;diff=11022"/>
		<updated>2021-08-15T15:17:28Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Lora-usb-pins.jpg&amp;diff=11020</id>
		<title>File:Lora-usb-pins.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Lora-usb-pins.jpg&amp;diff=11020"/>
		<updated>2021-08-15T14:29:52Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:CH341DS1.pdf&amp;diff=11019</id>
		<title>File:CH341DS1.pdf</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:CH341DS1.pdf&amp;diff=11019"/>
		<updated>2021-08-15T14:04:01Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:Pine64-lora-usb-adapter.jpg&amp;diff=11018</id>
		<title>File:Pine64-lora-usb-adapter.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:Pine64-lora-usb-adapter.jpg&amp;diff=11018"/>
		<updated>2021-08-15T13:58:41Z</updated>

		<summary type="html">&lt;p&gt;JF: The LoRa USB adapter with its antenna&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
The LoRa USB adapter with its antenna&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF&amp;diff=11017</id>
		<title>User:JF</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF&amp;diff=11017"/>
		<updated>2021-08-15T13:54:17Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Pages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I'm the maintainer of [https://github.com/JF002/Pinetime InfiniTime].&lt;br /&gt;
&lt;br /&gt;
== Pages ==&lt;br /&gt;
&lt;br /&gt;
- [[PineTime bootloader improvements]]&lt;br /&gt;
&lt;br /&gt;
- [[JF's note on PineDio devices]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=User:JF&amp;diff=11016</id>
		<title>User:JF</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=User:JF&amp;diff=11016"/>
		<updated>2021-08-15T13:54:04Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Pages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;I'm the maintainer of [https://github.com/JF002/Pinetime InfiniTime].&lt;br /&gt;
&lt;br /&gt;
== Pages ==&lt;br /&gt;
&lt;br /&gt;
- [[PineTime bootloader improvements]]&lt;br /&gt;
- [[JF's note on PineDio devices]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10247</id>
		<title>Upgrade PineTime to InfiniTime 1.0.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10247"/>
		<updated>2021-05-05T19:03:56Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Update Process */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to review and feedback.}}&lt;br /&gt;
&lt;br /&gt;
Congratulations on receiving your new PineTime!&lt;br /&gt;
&lt;br /&gt;
From the factory, it ships with InfiniTime 0.7.1, and an older bootloader. So now you're probably wondering exactly how on earth do you go about upgrading your watch to the latest and greatest version of InfiniTime - you know, that version you've seen all those great pictures, videos and reviews of. To those that of us that are developing stuff for it, its pretty easy and straightforward, but like with all technology, it is a bit tricky. &lt;br /&gt;
&lt;br /&gt;
{{warning|1=Some people ran into issues during the update process that would temporarily make their watch unusable (display frozen or blank). The only know workaround consists of waiting for the battery to drain completely and try again. With the display off, and battery fully charged, you can expect a wait of 5-7 days so it is best to not fully charge it. If it freezes with the display on, it will likely be flat by the end of the day. We've never heard of any PineTimes that were permanently bricked (were not recoverable), though. }} &lt;br /&gt;
&lt;br /&gt;
In a nutshell, you need to:&lt;br /&gt;
# Charge your watch, but '''not''' to 100% - keep it at approximately 50% - for the reason described above.&lt;br /&gt;
# Update InfiniTime&lt;br /&gt;
# Update the bootloader&lt;br /&gt;
# Install the recovery firmware&lt;br /&gt;
&lt;br /&gt;
= Update Process =&lt;br /&gt;
So how do you do this? Where do you start? Well, with a sealed PineTime, your only easy option is via Over The Air (OTA) Device Firmware Update (DFU), which is done via Bluetooth. There are a couple of different ways and apps you can use to do this. If you have an Android device, you can use [https://f-droid.org/en/packages/nodomain.freeyourgadget.gadgetbridge/ Gadgetbridge] or [https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp NRFConnect]. Otherwise, if your laptop or desktop computer has bluetooth and runs Linux, you can use [https://github.com/alexr4535/siglo Siglo] or [https://github.com/piggz/harbour-amazfish Amazfish]. You can also use this applications on your Pinebook Pro or Pinephone if you happen to have those devices. &lt;br /&gt;
&lt;br /&gt;
The reason for installing the updates in the the specified order is because newer versions of InfiniTime have a more robust bluetooth update process, and since we're updating everything over Bluetooth, the less retries and failures from that you have the better. It will still sometimes disconnect mid update, meaning you'll need to try again, and possibly restart the watch a few times as well. And since the recovery firmware is new to the 1.0.0 version of the bootloader, it's best to update that last. &lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529 This video] shows the bootloader and recovery firmware installation procedure.&lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e This video] shows the bootloader installation and firmware update using Amazfish.&lt;br /&gt;
&lt;br /&gt;
You can also read a [https://github.com/JF002/pinetime-mcuboot-bootloader/blob/339224cf5ed21f4e8b2d22eaeab9869120f7f752/docs/howToUpdate.md detailed installation procedure in the documentation of the bootloader].&lt;br /&gt;
&lt;br /&gt;
== Update InfiniTime ==&lt;br /&gt;
To update the main InfiniTime app, you want to flash [https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip pinetime-mcuboot-app-dfu-1.0.0.zip].&lt;br /&gt;
&lt;br /&gt;
=== Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Find the file in your file manager. &lt;br /&gt;
# 'Open With' Gadgetbridge F/W Installer (method varies by device) - on my phone, it is press and hold, select the file, and then choose 'open with app' from the more options menu&lt;br /&gt;
# If Gadgetbridge gives an 'Element cannot be installed' error, add '.fw' to the end of the downloaded zip file, and try again.&lt;br /&gt;
# Confirm that you wish to apply the update&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/Azi0uh8UZvI Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Open NRFConnect&lt;br /&gt;
# Scan for for your device&lt;br /&gt;
# Connect to it&lt;br /&gt;
# Choose the DFU option at the top right of the screen&lt;br /&gt;
# Ensure the 'Distribution packet (ZIP)' option is selected, and press OK&lt;br /&gt;
# Select your previously downloaded file&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/jnX7WwYDiDE Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
=== Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 1.0.0 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Amazfish ===&lt;br /&gt;
# Run Amazfish (service + UI)&lt;br /&gt;
# Pair with you device:&lt;br /&gt;
## Unzip the DFU file to extract the .bin file.&lt;br /&gt;
## Click on &amp;quot;pair with watch&amp;quot; on the top&lt;br /&gt;
## Select &amp;quot;PineTime&amp;quot; (if your device is running InfiniTime 0.7.1 or lower) or &amp;quot;InfiniTime (if it's running InfiniTime 0.8+) and choose your device in the list&lt;br /&gt;
# Click on &amp;quot;Download file&amp;quot; on the top &lt;br /&gt;
# Click on &amp;quot;Choose file&amp;quot; and select the .bin file you extracted from the DFU file&lt;br /&gt;
# Click on &amp;quot;Send file&amp;quot;&lt;br /&gt;
# Wait for the update to complete.&lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/41cfcf5d-b0e6-4323-8056-b0a6682d1f25 See it in action!]&lt;br /&gt;
&lt;br /&gt;
== Update the bootloader ==&lt;br /&gt;
To update the bootloader, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/reloader-mcuboot.zip reloader-mcuboot.zip]. &lt;br /&gt;
Once the bootloader is updated, you should notice that the boot logo has changed : previously, it was displaying a green &amp;quot;PineTime&amp;quot; logo, and now, it displays a big pinecone that is progressively drawn in green.&lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file. &lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
You might need to re-pair with your device by selecting &amp;quot;InfiniTime&amp;quot; (since you've already upgraded to InfiniTime 1.0) in the device type list. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Install the recovery firmware ==&lt;br /&gt;
{{warning|1=Don't do this before updating the bootloader, otherwise your PineTime will freeze at the end of the process, and you will need to wait for the battery to go flat }} &lt;br /&gt;
&lt;br /&gt;
To install the recovery firmware, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip]. You will know when this is running when it shows an InfiniTime logo with a progress bar running across the bottom whilst it is installing the recovery firmware. &lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
= Guides and Videos =&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
Sometimes during the update process, the connection will drop, and the update will fail. Your PineTime isn't broken, most likely the Bluetooth link dropped for a moment, so just try again. Try rebooting your phone, if it keeps failing, try restarting the watch by holding the power button down for approximately 8 seconds. Try to '''avoid''' holding down the button with the screen off. Or try with another device, just in case there are compatibility issues. &lt;br /&gt;
&lt;br /&gt;
Version 1.0.0 of InfiniTime is merely the first version that was considered sufficiently feature complete and stable enough for daily use. This isn't to say there aren't still bugs present ('cause there are!). So there are a few bugs still present in the update process and the bootloader. One unfortunate bug appears to be that sometimes when the watch tries to restart after an update, the bootloader locks up, and the watch won't turn on. In this case, you will need to wait until the watch battery goes flat, in order to force the watch to reset. This will most likely involve waiting for a week, and then when you put the watch on the charge cradle, it will power up and you should be right to try again.&lt;br /&gt;
&lt;br /&gt;
If you get stuck, or have any questions, join us on your preferred [https://wiki.pine64.org/index.php/Main_Page#Chat_Platforms chat platform] or on the product [https://forum.pine64.org/forumdisplay.php?fid=134 forum]. There's usually someone available who can help, or will get back to you in a few hours.&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10246</id>
		<title>Upgrade PineTime to InfiniTime 1.0.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10246"/>
		<updated>2021-05-05T19:03:39Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Update Process */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to review and feedback.}}&lt;br /&gt;
&lt;br /&gt;
Congratulations on receiving your new PineTime!&lt;br /&gt;
&lt;br /&gt;
From the factory, it ships with InfiniTime 0.7.1, and an older bootloader. So now you're probably wondering exactly how on earth do you go about upgrading your watch to the latest and greatest version of InfiniTime - you know, that version you've seen all those great pictures, videos and reviews of. To those that of us that are developing stuff for it, its pretty easy and straightforward, but like with all technology, it is a bit tricky. &lt;br /&gt;
&lt;br /&gt;
{{warning|1=Some people ran into issues during the update process that would temporarily make their watch unusable (display frozen or blank). The only know workaround consists of waiting for the battery to drain completely and try again. With the display off, and battery fully charged, you can expect a wait of 5-7 days so it is best to not fully charge it. If it freezes with the display on, it will likely be flat by the end of the day. We've never heard of any PineTimes that were permanently bricked (were not recoverable), though. }} &lt;br /&gt;
&lt;br /&gt;
In a nutshell, you need to:&lt;br /&gt;
# Charge your watch, but '''not''' to 100% - keep it at approximately 50% - for the reason described above.&lt;br /&gt;
# Update InfiniTime&lt;br /&gt;
# Update the bootloader&lt;br /&gt;
# Install the recovery firmware&lt;br /&gt;
&lt;br /&gt;
= Update Process =&lt;br /&gt;
So how do you do this? Where do you start? Well, with a sealed PineTime, your only easy option is via Over The Air (OTA) Device Firmware Update (DFU), which is done via Bluetooth. There are a couple of different ways and apps you can use to do this. If you have an Android device, you can use [https://f-droid.org/en/packages/nodomain.freeyourgadget.gadgetbridge/ Gadgetbridge] or [https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp NRFConnect]. Otherwise, if your laptop or desktop computer has bluetooth and runs Linux, you can use [https://github.com/alexr4535/siglo Siglo] or [https://github.com/piggz/harbour-amazfish Amazfish]. You can also use this applications on your Pinebook Pro or Pinephone if you happen to have those devices. &lt;br /&gt;
&lt;br /&gt;
The reason for installing the updates in the the specified order is because newer versions of InfiniTime have a more robust bluetooth update process, and since we're updating everything over Bluetooth, the less retries and failures from that you have the better. It will still sometimes disconnect mid update, meaning you'll need to try again, and possibly restart the watch a few times as well. And since the recovery firmware is new to the 1.0.0 version of the bootloader, it's best to update that last. &lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/831077c5-16f3-47b4-9b2b-c4bbfecc6529 This video] shows the bootloader and recovery firmware installation procedure.&lt;br /&gt;
[https://video.codingfield.com/videos/watch/f7bffb3d-a6a1-43c4-8f01-f4aeff4adf9e This video] shows the bootloader installation and firmware update using Amazfish.&lt;br /&gt;
You can also read a [https://github.com/JF002/pinetime-mcuboot-bootloader/blob/339224cf5ed21f4e8b2d22eaeab9869120f7f752/docs/howToUpdate.md detailed installation procedure in the documentation of the bootloader]&lt;br /&gt;
&lt;br /&gt;
== Update InfiniTime ==&lt;br /&gt;
To update the main InfiniTime app, you want to flash [https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip pinetime-mcuboot-app-dfu-1.0.0.zip].&lt;br /&gt;
&lt;br /&gt;
=== Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Find the file in your file manager. &lt;br /&gt;
# 'Open With' Gadgetbridge F/W Installer (method varies by device) - on my phone, it is press and hold, select the file, and then choose 'open with app' from the more options menu&lt;br /&gt;
# If Gadgetbridge gives an 'Element cannot be installed' error, add '.fw' to the end of the downloaded zip file, and try again.&lt;br /&gt;
# Confirm that you wish to apply the update&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/Azi0uh8UZvI Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Open NRFConnect&lt;br /&gt;
# Scan for for your device&lt;br /&gt;
# Connect to it&lt;br /&gt;
# Choose the DFU option at the top right of the screen&lt;br /&gt;
# Ensure the 'Distribution packet (ZIP)' option is selected, and press OK&lt;br /&gt;
# Select your previously downloaded file&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/jnX7WwYDiDE Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
=== Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 1.0.0 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Amazfish ===&lt;br /&gt;
# Run Amazfish (service + UI)&lt;br /&gt;
# Pair with you device:&lt;br /&gt;
## Unzip the DFU file to extract the .bin file.&lt;br /&gt;
## Click on &amp;quot;pair with watch&amp;quot; on the top&lt;br /&gt;
## Select &amp;quot;PineTime&amp;quot; (if your device is running InfiniTime 0.7.1 or lower) or &amp;quot;InfiniTime (if it's running InfiniTime 0.8+) and choose your device in the list&lt;br /&gt;
# Click on &amp;quot;Download file&amp;quot; on the top &lt;br /&gt;
# Click on &amp;quot;Choose file&amp;quot; and select the .bin file you extracted from the DFU file&lt;br /&gt;
# Click on &amp;quot;Send file&amp;quot;&lt;br /&gt;
# Wait for the update to complete.&lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/41cfcf5d-b0e6-4323-8056-b0a6682d1f25 See it in action!]&lt;br /&gt;
&lt;br /&gt;
== Update the bootloader ==&lt;br /&gt;
To update the bootloader, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/reloader-mcuboot.zip reloader-mcuboot.zip]. &lt;br /&gt;
Once the bootloader is updated, you should notice that the boot logo has changed : previously, it was displaying a green &amp;quot;PineTime&amp;quot; logo, and now, it displays a big pinecone that is progressively drawn in green.&lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file. &lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
You might need to re-pair with your device by selecting &amp;quot;InfiniTime&amp;quot; (since you've already upgraded to InfiniTime 1.0) in the device type list. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Install the recovery firmware ==&lt;br /&gt;
{{warning|1=Don't do this before updating the bootloader, otherwise your PineTime will freeze at the end of the process, and you will need to wait for the battery to go flat }} &lt;br /&gt;
&lt;br /&gt;
To install the recovery firmware, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip]. You will know when this is running when it shows an InfiniTime logo with a progress bar running across the bottom whilst it is installing the recovery firmware. &lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
= Guides and Videos =&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
Sometimes during the update process, the connection will drop, and the update will fail. Your PineTime isn't broken, most likely the Bluetooth link dropped for a moment, so just try again. Try rebooting your phone, if it keeps failing, try restarting the watch by holding the power button down for approximately 8 seconds. Try to '''avoid''' holding down the button with the screen off. Or try with another device, just in case there are compatibility issues. &lt;br /&gt;
&lt;br /&gt;
Version 1.0.0 of InfiniTime is merely the first version that was considered sufficiently feature complete and stable enough for daily use. This isn't to say there aren't still bugs present ('cause there are!). So there are a few bugs still present in the update process and the bootloader. One unfortunate bug appears to be that sometimes when the watch tries to restart after an update, the bootloader locks up, and the watch won't turn on. In this case, you will need to wait until the watch battery goes flat, in order to force the watch to reset. This will most likely involve waiting for a week, and then when you put the watch on the charge cradle, it will power up and you should be right to try again.&lt;br /&gt;
&lt;br /&gt;
If you get stuck, or have any questions, join us on your preferred [https://wiki.pine64.org/index.php/Main_Page#Chat_Platforms chat platform] or on the product [https://forum.pine64.org/forumdisplay.php?fid=134 forum]. There's usually someone available who can help, or will get back to you in a few hours.&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10245</id>
		<title>Upgrade PineTime to InfiniTime 1.0.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10245"/>
		<updated>2021-05-05T18:54:10Z</updated>

		<summary type="html">&lt;p&gt;JF: Add OTA instructions with Amazfish&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to review and feedback.}}&lt;br /&gt;
&lt;br /&gt;
Congratulations on receiving your new PineTime!&lt;br /&gt;
&lt;br /&gt;
From the factory, it ships with InfiniTime 0.7.1, and an older bootloader. So now you're probably wondering exactly how on earth do you go about upgrading your watch to the latest and greatest version of InfiniTime - you know, that version you've seen all those great pictures, videos and reviews of. To those that of us that are developing stuff for it, its pretty easy and straightforward, but like with all technology, it is a bit tricky. &lt;br /&gt;
&lt;br /&gt;
{{warning|1=Some people ran into issues during the update process that would temporarily make their watch unusable (display frozen or blank). The only know workaround consists of waiting for the battery to drain completely and try again. With the display off, and battery fully charged, you can expect a wait of 5-7 days so it is best to not fully charge it. If it freezes with the display on, it will likely be flat by the end of the day. We've never heard of any PineTimes that were permanently bricked (were not recoverable), though. }} &lt;br /&gt;
&lt;br /&gt;
In a nutshell, you need to:&lt;br /&gt;
# Charge your watch, but '''not''' to 100% - keep it at approximately 50% - for the reason described above.&lt;br /&gt;
# Update InfiniTime&lt;br /&gt;
# Update the bootloader&lt;br /&gt;
# Install the recovery firmware&lt;br /&gt;
&lt;br /&gt;
= Update Process =&lt;br /&gt;
So how do you do this? Where do you start? Well, with a sealed PineTime, your only easy option is via Over The Air (OTA) Device Firmware Update (DFU), which is done via Bluetooth. There are a couple of different ways and apps you can use to do this. If you have an Android device, you can use [https://f-droid.org/en/packages/nodomain.freeyourgadget.gadgetbridge/ Gadgetbridge] or [https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp NRFConnect]. Otherwise, if your laptop or desktop computer has bluetooth and runs Linux, you can use [https://github.com/alexr4535/siglo Siglo] or [https://github.com/piggz/harbour-amazfish Amazfish]. You can also use this applications on your Pinebook Pro or Pinephone if you happen to have those devices. &lt;br /&gt;
&lt;br /&gt;
The reason for installing the updates in the the specified order is because newer versions of InfiniTime have a more robust bluetooth update process, and since we're updating everything over Bluetooth, the less retries and failures from that you have the better. It will still sometimes disconnect mid update, meaning you'll need to try again, and possibly restart the watch a few times as well. And since the recovery firmware is new to the 1.0.0 version of the bootloader, it's best to update that last. &lt;br /&gt;
&lt;br /&gt;
== Update InfiniTime ==&lt;br /&gt;
To update the main InfiniTime app, you want to flash [https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip pinetime-mcuboot-app-dfu-1.0.0.zip].&lt;br /&gt;
&lt;br /&gt;
=== Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Find the file in your file manager. &lt;br /&gt;
# 'Open With' Gadgetbridge F/W Installer (method varies by device) - on my phone, it is press and hold, select the file, and then choose 'open with app' from the more options menu&lt;br /&gt;
# If Gadgetbridge gives an 'Element cannot be installed' error, add '.fw' to the end of the downloaded zip file, and try again.&lt;br /&gt;
# Confirm that you wish to apply the update&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/Azi0uh8UZvI Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
# Download the aforementioned file to your phone.&lt;br /&gt;
# Open NRFConnect&lt;br /&gt;
# Scan for for your device&lt;br /&gt;
# Connect to it&lt;br /&gt;
# Choose the DFU option at the top right of the screen&lt;br /&gt;
# Ensure the 'Distribution packet (ZIP)' option is selected, and press OK&lt;br /&gt;
# Select your previously downloaded file&lt;br /&gt;
# Wait for the update to complete&lt;br /&gt;
&lt;br /&gt;
[https://youtu.be/jnX7WwYDiDE Video showing how to start the update]&lt;br /&gt;
&lt;br /&gt;
=== Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 1.0.0 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Amazfish ===&lt;br /&gt;
# Run Amazfish (service + UI)&lt;br /&gt;
# Pair with you device:&lt;br /&gt;
## Unzip the DFU file to extract the .bin file.&lt;br /&gt;
## Click on &amp;quot;pair with watch&amp;quot; on the top&lt;br /&gt;
## Select &amp;quot;PineTime&amp;quot; (if your device is running InfiniTime 0.7.1 or lower) or &amp;quot;InfiniTime (if it's running InfiniTime 0.8+) and choose your device in the list&lt;br /&gt;
# Click on &amp;quot;Download file&amp;quot; on the top &lt;br /&gt;
# Click on &amp;quot;Choose file&amp;quot; and select the .bin file you extracted from the DFU file&lt;br /&gt;
# Click on &amp;quot;Send file&amp;quot;&lt;br /&gt;
# Wait for the update to complete.&lt;br /&gt;
&lt;br /&gt;
[https://video.codingfield.com/videos/watch/41cfcf5d-b0e6-4323-8056-b0a6682d1f25 See it in action!]&lt;br /&gt;
&lt;br /&gt;
== Update the bootloader ==&lt;br /&gt;
To update the bootloader, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/reloader-mcuboot.zip reloader-mcuboot.zip]. &lt;br /&gt;
Once the bootloader is updated, you should notice that the boot logo has changed : previously, it was displaying a green &amp;quot;PineTime&amp;quot; logo, and now, it displays a big pinecone that is progressively drawn in green.&lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file. &lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
You might need to re-pair with your device by selecting &amp;quot;InfiniTime&amp;quot; (since you've already upgraded to InfiniTime 1.0) in the device type list. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Install the recovery firmware ==&lt;br /&gt;
{{warning|1=Don't do this before updating the bootloader, otherwise your PineTime will freeze at the end of the process, and you will need to wait for the battery to go flat }} &lt;br /&gt;
&lt;br /&gt;
To install the recovery firmware, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip]. You will know when this is running when it shows an InfiniTime logo with a progress bar running across the bottom whilst it is installing the recovery firmware. &lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
=== Using Amazfish ===&lt;br /&gt;
&lt;br /&gt;
Same as above.&lt;br /&gt;
&lt;br /&gt;
= Guides and Videos =&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
Sometimes during the update process, the connection will drop, and the update will fail. Your PineTime isn't broken, most likely the Bluetooth link dropped for a moment, so just try again. Try rebooting your phone, if it keeps failing, try restarting the watch by holding the power button down for approximately 8 seconds. Try to '''avoid''' holding down the button with the screen off. Or try with another device, just in case there are compatibility issues. &lt;br /&gt;
&lt;br /&gt;
Version 1.0.0 of InfiniTime is merely the first version that was considered sufficiently feature complete and stable enough for daily use. This isn't to say there aren't still bugs present ('cause there are!). So there are a few bugs still present in the update process and the bootloader. One unfortunate bug appears to be that sometimes when the watch tries to restart after an update, the bootloader locks up, and the watch won't turn on. In this case, you will need to wait until the watch battery goes flat, in order to force the watch to reset. This will most likely involve waiting for a week, and then when you put the watch on the charge cradle, it will power up and you should be right to try again.&lt;br /&gt;
&lt;br /&gt;
If you get stuck, or have any questions, join us on your preferred [https://wiki.pine64.org/index.php/Main_Page#Chat_Platforms chat platform] or on the product [https://forum.pine64.org/forumdisplay.php?fid=134 forum]. There's usually someone available who can help, or will get back to you in a few hours.&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10219</id>
		<title>Upgrade PineTime to InfiniTime 1.0.0</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Upgrade_PineTime_to_InfiniTime_1.0.0&amp;diff=10219"/>
		<updated>2021-05-03T18:19:52Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to review and feedback.}}&lt;br /&gt;
&lt;br /&gt;
Congratulations on receiving your new PineTime!&lt;br /&gt;
&lt;br /&gt;
From the factory, it ships with InfiniTime 0.7.1, and an older bootloader. So now you're probably wondering exactly how on earth do you go about upgrading your watch to the latest and greatest version of InfiniTime - you know, that version you've seen all those great pictures, videos and reviews of. To those that of us that are developing stuff for it, its pretty easy and straightforward, but like with all technology, it is a bit tricky. &lt;br /&gt;
&lt;br /&gt;
{{warning|1=Some people ran into some issues during the update process that would temporarily make their watch unusable (display frozen). The only know workaround consists in waiting for the battery to drain completely and try again. We've never heard of PineTime that were permanently bricked, though. }} &lt;br /&gt;
&lt;br /&gt;
In a nutshell, you need to:&lt;br /&gt;
# Update InfiniTime&lt;br /&gt;
# Update the bootloader&lt;br /&gt;
# Install the recovery firmware&lt;br /&gt;
&lt;br /&gt;
= Update Process =&lt;br /&gt;
So how do you do this? Where do you start? Well, with a sealed PineTime, your only easy option is via Over The Air (OTA) Device Firmware Update (DFU), which is done via Bluetooth. There are a couple of different ways and apps you can use to do this. If you have an Android device, you can use [https://f-droid.org/en/packages/nodomain.freeyourgadget.gadgetbridge/ Gadgetbridge] or [https://play.google.com/store/apps/details?id=no.nordicsemi.android.mcp NRFConnect]. Otherwise, if your laptop or desktop computer has bluetooth and runs Linux, you can use [https://github.com/alexr4535/siglo Siglo]. You can also use [https://github.com/alexr4535/siglo Siglo] on your Pinebook Pro or Pinephone if you happen to have those devices. &lt;br /&gt;
&lt;br /&gt;
The reason for installing the updates in the the specified order is because newer versions of InfiniTime have a more robust bluetooth update process, and since we're updating everything over Bluetooth, the less retries and failures from that you have the better. It will still sometimes disconnect mid update, meaning you'll need to try again, and possibly restart the watch a few times as well. And since the recovery firmware is new to the 1.0.0 version of the bootloader, it's best to update that last. &lt;br /&gt;
&lt;br /&gt;
== Update InfiniTime ==&lt;br /&gt;
To update the main InfiniTime app, you want to flash [https://github.com/JF002/InfiniTime/releases/download/1.0.0/pinetime-mcuboot-app-dfu-1.0.0.zip pinetime-mcuboot-app-dfu-1.0.0.zip].&lt;br /&gt;
&lt;br /&gt;
=== Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
=== NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
=== Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 1.0.0 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Update the bootloader ==&lt;br /&gt;
To update the bootloader, you want to flash [https://github.com/JF002/InfiniTime/releases/download/0.14.1/pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip reloader-mcuboot.zip]. &lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Install the recovery firmware ==&lt;br /&gt;
To install the recovery firmware, you want to flash [https://github.com/JF002/InfiniTime/releases/tag/0.14.1 pinetime-mcuboot-recovery-loader-dfu-0.14.1.zip].&lt;br /&gt;
&lt;br /&gt;
=== Using Gadgetbridge ===&lt;br /&gt;
&lt;br /&gt;
=== Using NRFConnect ===&lt;br /&gt;
&lt;br /&gt;
=== Using Siglo ===&lt;br /&gt;
In Siglo, you can do this by picking the 0.14.1 tag, and flashing the aforementioned file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Guides and Videos =&lt;br /&gt;
&lt;br /&gt;
= Troubleshooting =&lt;br /&gt;
Sometimes during the update process, the connection will drop, and the update will fail. Your PineTime isn't broken, most likely the bluetooth link dropped out for a moment, so just try again. If it keeps failing, try restarting the watch by holding the power button down for approximately 8 seconds. Or try with another device, just in case there are compatibility issues. &lt;br /&gt;
&lt;br /&gt;
Version 1.0.0 of InfiniTime is merely the first version that was considered sufficiently feature complete and stable enough for daily use. This isn't to say there aren't still bugs present ('cause there are!). So there are a few bugs still present in the update process and the bootloader. One unfortunate bug appears to be that sometimes when the watch tries to restart after an update, the bootloader locks up, and the watch won't turn on. In this case, you will need to wait until the watch battery goes flat, in order to force the watch to reset. This will most likely involve waiting for a week, and then when you put the watch on the charge cradle, it will power up and you should be right to try again.&lt;br /&gt;
&lt;br /&gt;
If you get stuck, or have any questions, join us on your preferred [https://wiki.pine64.org/index.php/Main_Page#Chat_Platforms chat platform] or on the product [https://forum.pine64.org/forumdisplay.php?fid=134 forum]. There's usually someone available who can help, or will get back to you in a few hours.&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10151</id>
		<title>Pinedio</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10151"/>
		<updated>2021-04-28T18:56:47Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Connections */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to change. Project is in early development phase.}}&lt;br /&gt;
&lt;br /&gt;
LoRa is a long range, low power wireless platform that is being used by a lot of Internet of Things (IoT) products. Using LoRa and LoRaWAN, devices can communicate across the world using the internet, using various decentralised networks such as [https://www.thethingsnetwork.org/ The Things Network] or [https://www.helium.com/ Helium]. Since, PINE64 believes in openness, the LoRa gateway can connect to any network, per the developer implementation. If Helium Spots open up for PINE64 gateway and developers have implemented the hook for Helium, then this is good thing. The PINE64 LoRa gateway also open connect to The Things Network if developers implement support. The choice is yours!&lt;br /&gt;
&lt;br /&gt;
== Gateway ==&lt;br /&gt;
&lt;br /&gt;
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have &amp;quot;an aluminum, rugged and water resistant case&amp;quot;. &lt;br /&gt;
The indoor unit consists of a PINE A64-LTS, fitted with a purpose built hat (adapter) which uses a LoRa module by RakWireless. The chipset used is the SX1302, and the module via the SPI interface. There are two external connections on the enclosure for the GPS and loRa antenna. &lt;br /&gt;
&lt;br /&gt;
=== Connections ===&lt;br /&gt;
* GPS is connected to UART2 on the A64 board&lt;br /&gt;
* SX1302 on SPI0&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|RAK2287 module&lt;br /&gt;
|PI-2 connector&lt;br /&gt;
|PINE A64-LTS&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 SPI&lt;br /&gt;
|Pin 19 = MOSI / PC0&amp;lt;br/&amp;gt;Pin 21 = MISO/PC1&amp;lt;br/&amp;gt;Pin23 = CLK/PC2&amp;lt;br/&amp;gt;Pin24 = CS/PC3&lt;br /&gt;
|SPI0 (/dev/spidev0.0)&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 RESET&lt;br /&gt;
|Pin 11 = GPIO17/PC7&lt;br /&gt;
|GPIO71 (/sys/class/gpio/gpio71)&lt;br /&gt;
|-&lt;br /&gt;
|GPS UART&lt;br /&gt;
|Pin 8 = TX/&amp;lt;br&amp;gt;Pin 10 = RX&lt;br /&gt;
|UART2 (/dev/ttyS2)&lt;br /&gt;
|-&lt;br /&gt;
|GPS RESET&lt;br /&gt;
|Pin 33 = GPIO13/PC5&lt;br /&gt;
|GPIO69 (/sys/class/gpio/gpio69)&lt;br /&gt;
|-&lt;br /&gt;
|GPS Standby&lt;br /&gt;
|Pin 35 = GPIO19/PC9&lt;br /&gt;
|GPIO73 (/sys/class/gpio/gpio73)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-InsideLoRaGateway.jpg&lt;br /&gt;
File:Blog-april-InsideLoRaGateway2.jpeg&lt;br /&gt;
File:Discord-lora-gateway-20210413_143615.jpg&lt;br /&gt;
File:Discord-lora-gateway-20210413_1435271.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Armbian image for gateway ===&lt;br /&gt;
&lt;br /&gt;
Gateway is based on the pine64 A64-LTS, and the current Armbian_21.02.3 sopine image has a broken DTS. The fault and fix was identified by user dippywood on the Armbian forums [https://forum.armbian.com/topic/17333-unable-to-boot-focal-or-buster-images-on-sopine-clusterboard/ in this thread], and until a new version is released, patched versions are available [https://mega.nz/file/Wd5CGRhB#spBqSQrhLm_gIPtRexV9OOC8T3YoVk9VuHopFs4Ho9o here (576MB gz)] and [https://files.portabledev.xyz/f/c2895e3669bb481da9fd/ here (278MB xz)].&lt;br /&gt;
&lt;br /&gt;
== End nodes ==&lt;br /&gt;
&lt;br /&gt;
There are several end-node units planned:&lt;br /&gt;
* loRa back case for the PinePhone&lt;br /&gt;
* standalone USB dongle-type end-node adapter&lt;br /&gt;
* PineTab adapter&lt;br /&gt;
* as well as a SPI module (which can also be configured as a USB LoRa dongle)&lt;br /&gt;
* a LoRa stick powered by a single 18650 battery (using the [https://wiki.pine64.org/wiki/Nutcracker BL602], and can be fitted with GPS, an low-power OLED panel and additional sensors)&lt;br /&gt;
&lt;br /&gt;
All the end-nodes use the SX1262 chip. &lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-USB-LoRa-1024x655.jpg&lt;br /&gt;
File:Blog-april-LoRa-something-839x1024.jpg&lt;br /&gt;
File:Discord_20210421_lora_usb_closeup.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Datasheets and schematics ==&lt;br /&gt;
=== Gateway ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302 SX1302 datasheets and resources]&lt;br /&gt;
* [https://docs.rakwireless.com/Product-Categories/WisLink/RAK2247/Overview/ RAK2287 datasheets and resources]&lt;br /&gt;
* [https://wiki.pine64.org/images/5/54/PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf Pine64 LoRa Gateway module adapter schematic]&lt;br /&gt;
&lt;br /&gt;
=== End nodes ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1262 SX1262 datasheets and resources]&lt;br /&gt;
&lt;br /&gt;
=== Pinephone backplate ===&lt;br /&gt;
* [[File:Pinephone_LoRa_BackPanel_Schematic-v1.0-20210402.pdf]]&lt;br /&gt;
* [[File:CA-S01_LoRa_Chip_Antenna_in_Chinese.pdf]]&lt;br /&gt;
* [https://github.com/zschroeder6212/tiny-i2c-spi I2C SPI Bridge code running on ATtiny84]&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules]&lt;br /&gt;
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10150</id>
		<title>Pinedio</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10150"/>
		<updated>2021-04-28T18:48:26Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Gateway */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to change. Project is in early development phase.}}&lt;br /&gt;
&lt;br /&gt;
LoRa is a long range, low power wireless platform that is being used by a lot of Internet of Things (IoT) products. Using LoRa and LoRaWAN, devices can communicate across the world using the internet, using various decentralised networks such as [https://www.thethingsnetwork.org/ The Things Network] or [https://www.helium.com/ Helium]. Since, PINE64 believes in openness, the LoRa gateway can connect to any network, per the developer implementation. If Helium Spots open up for PINE64 gateway and developers have implemented the hook for Helium, then this is good thing. The PINE64 LoRa gateway also open connect to The Things Network if developers implement support. The choice is yours!&lt;br /&gt;
&lt;br /&gt;
== Gateway ==&lt;br /&gt;
&lt;br /&gt;
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have &amp;quot;an aluminum, rugged and water resistant case&amp;quot;. &lt;br /&gt;
The indoor unit consists of a PINE A64-LTS, fitted with a purpose built hat (adapter) which uses a LoRa module by RakWireless. The chipset used is the SX1302, and the module via the SPI interface. There are two external connections on the enclosure for the GPS and loRa antenna. &lt;br /&gt;
&lt;br /&gt;
=== Connections ===&lt;br /&gt;
* GPS is connected to UART2 on the A64 board&lt;br /&gt;
* SX1302 on SPI0&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|RAK2287 module&lt;br /&gt;
|PI-2 connector&lt;br /&gt;
|PINE A64-LTS&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 SPI&lt;br /&gt;
|Pin 19 = MOSI / PC0&amp;lt;br/&amp;gt;Pin 21 = MISO/PC1&amp;lt;br/&amp;gt;Pin23 = CLK/PC2&amp;lt;br/&amp;gt;Pin24 = CS/PC3&lt;br /&gt;
|SPI0 (/dev/spidev0.0)&lt;br /&gt;
|-&lt;br /&gt;
|SX1302 RESET&lt;br /&gt;
|Pin 11 = GPIO17/PC7&lt;br /&gt;
|GPIO71&lt;br /&gt;
|-&lt;br /&gt;
|GPS UART&lt;br /&gt;
|Pin 8 = TX/&amp;lt;br&amp;gt;Pin 10 = RX&lt;br /&gt;
|UART2 (/dev/ttyS2)&lt;br /&gt;
|-&lt;br /&gt;
|GPS RESET&lt;br /&gt;
|Pin 33 = GPIO13/PC5&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|GPS Standby&lt;br /&gt;
|Pin 35 = GPIO19/PC9&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-InsideLoRaGateway.jpg&lt;br /&gt;
File:Blog-april-InsideLoRaGateway2.jpeg&lt;br /&gt;
File:Discord-lora-gateway-20210413_143615.jpg&lt;br /&gt;
File:Discord-lora-gateway-20210413_1435271.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Armbian image for gateway ===&lt;br /&gt;
&lt;br /&gt;
Gateway is based on the pine64 A64-LTS, and the current Armbian_21.02.3 sopine image has a broken DTS. The fault and fix was identified by user dippywood on the Armbian forums [https://forum.armbian.com/topic/17333-unable-to-boot-focal-or-buster-images-on-sopine-clusterboard/ in this thread], and until a new version is released, patched versions are available [https://mega.nz/file/Wd5CGRhB#spBqSQrhLm_gIPtRexV9OOC8T3YoVk9VuHopFs4Ho9o here (576MB gz)] and [https://files.portabledev.xyz/f/c2895e3669bb481da9fd/ here (278MB xz)].&lt;br /&gt;
&lt;br /&gt;
== End nodes ==&lt;br /&gt;
&lt;br /&gt;
There are several end-node units planned:&lt;br /&gt;
* loRa back case for the PinePhone&lt;br /&gt;
* standalone USB dongle-type end-node adapter&lt;br /&gt;
* PineTab adapter&lt;br /&gt;
* as well as a SPI module (which can also be configured as a USB LoRa dongle)&lt;br /&gt;
* a LoRa stick powered by a single 18650 battery (using the [https://wiki.pine64.org/wiki/Nutcracker BL602], and can be fitted with GPS, an low-power OLED panel and additional sensors)&lt;br /&gt;
&lt;br /&gt;
All the end-nodes use the SX1262 chip. &lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-USB-LoRa-1024x655.jpg&lt;br /&gt;
File:Blog-april-LoRa-something-839x1024.jpg&lt;br /&gt;
File:Discord_20210421_lora_usb_closeup.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Datasheets and schematics ==&lt;br /&gt;
=== Gateway ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302 SX1302 datasheets and resources]&lt;br /&gt;
* [https://docs.rakwireless.com/Product-Categories/WisLink/RAK2247/Overview/ RAK2287 datasheets and resources]&lt;br /&gt;
* [https://wiki.pine64.org/images/5/54/PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf Pine64 LoRa Gateway module adapter schematic]&lt;br /&gt;
&lt;br /&gt;
=== End nodes ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1262 SX1262 datasheets and resources]&lt;br /&gt;
&lt;br /&gt;
=== Pinephone backplate ===&lt;br /&gt;
* [[File:Pinephone_LoRa_BackPanel_Schematic-v1.0-20210402.pdf]]&lt;br /&gt;
* [[File:CA-S01_LoRa_Chip_Antenna_in_Chinese.pdf]]&lt;br /&gt;
* [https://github.com/zschroeder6212/tiny-i2c-spi I2C SPI Bridge code running on ATtiny84]&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules]&lt;br /&gt;
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10149</id>
		<title>Pinedio</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Pinedio&amp;diff=10149"/>
		<updated>2021-04-28T18:28:37Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Gateway */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Note|Page under construction, information subject to change. Project is in early development phase.}}&lt;br /&gt;
&lt;br /&gt;
LoRa is a long range, low power wireless platform that is being used by a lot of Internet of Things (IoT) products. Using LoRa and LoRaWAN, devices can communicate across the world using the internet, using various decentralised networks such as [https://www.thethingsnetwork.org/ The Things Network] or [https://www.helium.com/ Helium]. Since, PINE64 believes in openness, the LoRa gateway can connect to any network, per the developer implementation. If Helium Spots open up for PINE64 gateway and developers have implemented the hook for Helium, then this is good thing. The PINE64 LoRa gateway also open connect to The Things Network if developers implement support. The choice is yours!&lt;br /&gt;
&lt;br /&gt;
== Gateway ==&lt;br /&gt;
&lt;br /&gt;
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have &amp;quot;an aluminum, rugged and water resistant case&amp;quot;. &lt;br /&gt;
The indoor unit consists of a PINE A64-LTS, fitted with a purpose built hat (adapter) which uses a LoRa module by RakWireless. The chipset used is the SX1302, and the module via the SPI interface. There are two external connections on the enclosure for the GPS and loRa antenna. &lt;br /&gt;
&lt;br /&gt;
=== Connections ===&lt;br /&gt;
* GPS is connected to UART2 on the A64 board&lt;br /&gt;
* SX1302 on SPI0&lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-InsideLoRaGateway.jpg&lt;br /&gt;
File:Blog-april-InsideLoRaGateway2.jpeg&lt;br /&gt;
File:Discord-lora-gateway-20210413_143615.jpg&lt;br /&gt;
File:Discord-lora-gateway-20210413_1435271.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Armbian image for gateway ===&lt;br /&gt;
&lt;br /&gt;
Gateway is based on the pine64 A64-LTS, and the current Armbian_21.02.3 sopine image has a broken DTS. The fault and fix was identified by user dippywood on the Armbian forums [https://forum.armbian.com/topic/17333-unable-to-boot-focal-or-buster-images-on-sopine-clusterboard/ in this thread], and until a new version is released, patched versions are available [https://mega.nz/file/Wd5CGRhB#spBqSQrhLm_gIPtRexV9OOC8T3YoVk9VuHopFs4Ho9o here (576MB gz)] and [https://files.portabledev.xyz/f/c2895e3669bb481da9fd/ here (278MB xz)].&lt;br /&gt;
&lt;br /&gt;
== End nodes ==&lt;br /&gt;
&lt;br /&gt;
There are several end-node units planned:&lt;br /&gt;
* loRa back case for the PinePhone&lt;br /&gt;
* standalone USB dongle-type end-node adapter&lt;br /&gt;
* PineTab adapter&lt;br /&gt;
* as well as a SPI module (which can also be configured as a USB LoRa dongle)&lt;br /&gt;
* a LoRa stick powered by a single 18650 battery (using the [https://wiki.pine64.org/wiki/Nutcracker BL602], and can be fitted with GPS, an low-power OLED panel and additional sensors)&lt;br /&gt;
&lt;br /&gt;
All the end-nodes use the SX1262 chip. &lt;br /&gt;
&lt;br /&gt;
=== Pictures ===&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:Blog-april-USB-LoRa-1024x655.jpg&lt;br /&gt;
File:Blog-april-LoRa-something-839x1024.jpg&lt;br /&gt;
File:Discord_20210421_lora_usb_closeup.jpg&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Datasheets and schematics ==&lt;br /&gt;
=== Gateway ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-gateways/sx1302 SX1302 datasheets and resources]&lt;br /&gt;
* [https://docs.rakwireless.com/Product-Categories/WisLink/RAK2247/Overview/ RAK2287 datasheets and resources]&lt;br /&gt;
* [https://wiki.pine64.org/images/5/54/PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf Pine64 LoRa Gateway module adapter schematic]&lt;br /&gt;
&lt;br /&gt;
=== End nodes ===&lt;br /&gt;
* [https://www.semtech.com/products/wireless-rf/lora-transceivers/sx1262 SX1262 datasheets and resources]&lt;br /&gt;
&lt;br /&gt;
=== Pinephone backplate ===&lt;br /&gt;
* [[File:Pinephone_LoRa_BackPanel_Schematic-v1.0-20210402.pdf]]&lt;br /&gt;
* [[File:CA-S01_LoRa_Chip_Antenna_in_Chinese.pdf]]&lt;br /&gt;
* [https://github.com/zschroeder6212/tiny-i2c-spi I2C SPI Bridge code running on ATtiny84]&lt;br /&gt;
&lt;br /&gt;
== Other resources ==&lt;br /&gt;
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules]&lt;br /&gt;
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf&amp;diff=10148</id>
		<title>File:PINE64 LoRa Gateway Module Adapter Schematic-v1.0-20210308.pdf</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:PINE64_LoRa_Gateway_Module_Adapter_Schematic-v1.0-20210308.pdf&amp;diff=10148"/>
		<updated>2021-04-28T18:24:27Z</updated>

		<summary type="html">&lt;p&gt;JF: Schematic of the Pine64 LoRa gateway module adapter (installed in the early engineering samples)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Summary ==&lt;br /&gt;
Schematic of the Pine64 LoRa gateway module adapter (installed in the early engineering samples)&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Talk:PineTime_external_flash_partitioning&amp;diff=8340</id>
		<title>Talk:PineTime external flash partitioning</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Talk:PineTime_external_flash_partitioning&amp;diff=8340"/>
		<updated>2020-11-30T19:25:49Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Application */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==From JF:==&lt;br /&gt;
In my opinion, we should draw a hard line between the bootloader and the application firmwares.&lt;br /&gt;
&lt;br /&gt;
===Bootloader===&lt;br /&gt;
The bootloader '''cannot fail'''. If it fails, the device is bricked. One way to achieve this is to make it as simple as possible. If the bootloader have to take a partition table into account, it also have to handle degraded cases : it's got corrupted by a bug in a firmware, bad crc, incorrect offset/size mentionned,... &lt;br /&gt;
It turns out that the bootloader cannot recover from these degraded cases. Taking the partition table into account just adds some code (retrieve the partition table, search for partitions, process CRC, handles error codes,...) that will not be complete : there's no way we will write something meaningful in this code, for example:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;if(!check_crc(&amp;amp;data)) {&lt;br /&gt;
// ???&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Why not assume the data is where we expect it to be and coherent? The result will be the same : if the data is OK, it works, if the data is corrupt... the bootloader cannot do anything. Handling the partition table just gives the bootloader '''more chances to fail'''.&lt;br /&gt;
&lt;br /&gt;
With that in mind, I'm still convinced that the bootloader should just look for its data at fixed and hardcoded values : &lt;br /&gt;
&lt;br /&gt;
* bootloader code : internal flash 0 -&amp;gt; 0x7000&lt;br /&gt;
* primary slot : internal flash 0x8000 -&amp;gt; 0x7f000&lt;br /&gt;
* scratch : internal flash : 0x7f000 -&amp;gt; 0x80000&lt;br /&gt;
* factory firmware : external flash 0 -&amp;gt; 0x40000&lt;br /&gt;
* secondary slot : external flash 0x40000 -&amp;gt; 0xb4000&lt;br /&gt;
&lt;br /&gt;
There's no point to change these values : the internal flash is 100% allocated, the reloader cannot handle firmwares &amp;gt; ~180kB and the secondary slot must be the same size as the primary slot.&lt;br /&gt;
&lt;br /&gt;
The only '''shared knowledge''' between the bootloader and the application firmwares is that the application must be linked at offset 0x8000, should copy the OTA image in external flash at offset 0x40000, can use the external flash from offset 0xb4000 and must refresh the watchdog periodically.&lt;br /&gt;
&lt;br /&gt;
===Application===&lt;br /&gt;
The application firmwares, on the other side, can be more flexible, and a common partitioning scheme can have some sense '''if multiple firmware developers agree to implement it'''. They would have to agree on a partition table scheme, file system, file formats,... That won't be easy, but that's possible. In this case, the partition table can be stored in the FS section at offset 0xb4000, '''and the bootloader won't have any knowledge of it'''. As the external spi memory flash is mostly unused (to my knowledge, only wasp-os uses it), everything is still possible on that part of the memory.&lt;br /&gt;
&lt;br /&gt;
But... do we really need to share data between multiple firmwares installation? Let's compare with the PinePhone : when you install a new OS image on the EMMC or on the SD card, the user settings (wifi password, timezone, applications,...) won't be kept. If the user wants to keep files in the process, they have to backup them manually (on the SD card or on a computer) before flashing the new firmware and then restore them manually.&lt;br /&gt;
&lt;br /&gt;
Why would we want to solve issues that even more complex devices do not solve? Even Windows have a hard-time upgrading major versions of the OS while keeping applications and users settings untouched.&lt;br /&gt;
&lt;br /&gt;
Yet, this is still possible to do, but I wonder how firmwares will actually integrate this partition table? How will they know that they can use and existing partition or create a new one? What if there is not enough space available for the firmware you've just installed?&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=Talk:PineTime_external_flash_partitioning&amp;diff=8339</id>
		<title>Talk:PineTime external flash partitioning</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=Talk:PineTime_external_flash_partitioning&amp;diff=8339"/>
		<updated>2020-11-30T19:24:35Z</updated>

		<summary type="html">&lt;p&gt;JF: Created page with &amp;quot;==From JF:== In my opinion, we should draw a hard line between the bootloader and the application firmwares.  ===Bootloader=== The bootloader '''cannot fail'''. If it fails, t...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==From JF:==&lt;br /&gt;
In my opinion, we should draw a hard line between the bootloader and the application firmwares.&lt;br /&gt;
&lt;br /&gt;
===Bootloader===&lt;br /&gt;
The bootloader '''cannot fail'''. If it fails, the device is bricked. One way to achieve this is to make it as simple as possible. If the bootloader have to take a partition table into account, it also have to handle degraded cases : it's got corrupted by a bug in a firmware, bad crc, incorrect offset/size mentionned,... &lt;br /&gt;
It turns out that the bootloader cannot recover from these degraded cases. Taking the partition table into account just adds some code (retrieve the partition table, search for partitions, process CRC, handles error codes,...) that will not be complete : there's no way we will write something meaningful in this code, for example:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;if(!check_crc(&amp;amp;data)) {&lt;br /&gt;
// ???&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Why not assume the data is where we expect it to be and coherent? The result will be the same : if the data is OK, it works, if the data is corrupt... the bootloader cannot do anything. Handling the partition table just gives the bootloader '''more chances to fail'''.&lt;br /&gt;
&lt;br /&gt;
With that in mind, I'm still convinced that the bootloader should just look for its data at fixed and hardcoded values : &lt;br /&gt;
&lt;br /&gt;
* bootloader code : internal flash 0 -&amp;gt; 0x7000&lt;br /&gt;
* primary slot : internal flash 0x8000 -&amp;gt; 0x7f000&lt;br /&gt;
* scratch : internal flash : 0x7f000 -&amp;gt; 0x80000&lt;br /&gt;
* factory firmware : external flash 0 -&amp;gt; 0x40000&lt;br /&gt;
* secondary slot : external flash 0x40000 -&amp;gt; 0xb4000&lt;br /&gt;
&lt;br /&gt;
There's no point to change these values : the internal flash is 100% allocated, the reloader cannot handle firmwares &amp;gt; ~180kB and the secondary slot must be the same size as the primary slot.&lt;br /&gt;
&lt;br /&gt;
The only '''shared knowledge''' between the bootloader and the application firmwares is that the application must be linked at offset 0x8000, should copy the OTA image in external flash at offset 0x40000, can use the external flash from offset 0xb4000 and must refresh the watchdog periodically.&lt;br /&gt;
&lt;br /&gt;
===Application===&lt;br /&gt;
The application firmwares, on the other side, can be more flexible, and a common partitioning scheme can have some sense '''if multiple firmware developers agree to implement it'''. They would have to agree on a partition table scheme, file system, file formats,... That won't be easy, but that's possible. In this case, the partition table can be stored in the FS section at offset 0xb4000, and the bootloader won't have any knowledge of it. As the external spi memory flash is mostly unused (to my knowledge, only wasp-os uses it), everything is still possible on that part of the memory.&lt;br /&gt;
&lt;br /&gt;
But... do we really need to share data between multiple firmwares installation? Let's compare with the PinePhone : when you install a new OS image on the EMMC or on the SD card, the user settings (wifi password, timezone, applications,...) won't be kept. If the user wants to keep files in the process, they have to backup them manually (on the SD card or on a computer) before flashing the new firmware and then restore them manually.&lt;br /&gt;
&lt;br /&gt;
Why would we want to solve issues that even more complex devices do not solve? Even Windows have a hard-time upgrading major versions of the OS while keeping applications and users settings untouched.&lt;br /&gt;
&lt;br /&gt;
Yet, this is still possible to do, but I wonder how firmwares will actually integrate this partition table? How will they know that they can use and existing partition or create a new one? What if there is not enough space available for the firmware you've just installed?&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8320</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8320"/>
		<updated>2020-11-29T19:46:25Z</updated>

		<summary type="html">&lt;p&gt;JF: Add bootloader workflow diagram&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Request for comments == &lt;br /&gt;
In this page, I explain the changes and improvements I would like to implement to the MCUBoot bootloader to make it more reliable, and to allow bootloader upgrade and switch (mcuboot &amp;lt;-&amp;gt; wasp-bootloader, for example). &lt;br /&gt;
I try to explain why I made these choices too.&lt;br /&gt;
&lt;br /&gt;
Do not hesitate to edit this page and add a new section if you want to add any comment to these points (if you agree, disagree, want to try something else,...).&lt;br /&gt;
&lt;br /&gt;
== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
&lt;br /&gt;
[[PineTime| Pinetime Devkit0]] is using a nRF52832-QFAA MCU with 512kB flash and a [https://datasheet.lcsc.com/szlcsc/2005251035_XTX-XT25F32BSOIGU-S_C558851.pdf XT25F32B SPI NOR external flash] with 4096kB.&lt;br /&gt;
&lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash (512Kb):&lt;br /&gt;
* Page size is 4Kb.&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash (4096Kb):&lt;br /&gt;
* Page size is 256 bytes.&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Bootloader workflow ===&lt;br /&gt;
[[File:PineTimeBootloaderWorkflow.png]]&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
Embedding (and compressing) the boot logo inside the bootloader binary brings many advantages:&lt;br /&gt;
* All the data are available in memory at runtime. No need to load them &amp;amp; check them, and no need to handle errors and invalid corrupted data.&lt;br /&gt;
* The data is available and can be sent directly to the display controller&lt;br /&gt;
* 1 unique logo for the bootloader : easier to document and explain to the user that this specific logo is the logo from the bootloader mode.&lt;br /&gt;
&lt;br /&gt;
But it also has some disadvantages:&lt;br /&gt;
* 1-Bit RLE encoding (very effective compression) allows only 2 colors (background/foreground)&lt;br /&gt;
* The boot logo cannot be customized (unless you recompile and flash this new build of the bootloader)&lt;br /&gt;
* The size of the boot logo is limited (depending on the compression ratio)&lt;br /&gt;
&lt;br /&gt;
My (JF) point is that the bootloader must be as reliable as possible. I would like to remove all part of the code than can fail. If we read the boot logo from the SPI flash, we will write something like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;int ret;&lt;br /&gt;
boot_logo_info info;&lt;br /&gt;
ret = SpiNor_read(infoOffset, &amp;amp;info, sizeof(boot_logo_info));&lt;br /&gt;
if(ret != 0) {&lt;br /&gt;
  // Something went wrong while reading image info&lt;br /&gt;
  panic(); // ? reset ?&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(check_boot_logo_info(info) == false) {&lt;br /&gt;
  // image info are invalid (ex : size &amp;gt; 240*240), we cannot use them&lt;br /&gt;
  panic(); // ? reset ? Display nothing?&lt;br /&gt;
}&lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
We could find invalid image info if a firmware did not respect the memory map and erased/overwrote the external memory map. In this case, the bootloader couldn't run properly.&lt;br /&gt;
Of course, we can implement something smart in panic() (retry, use failover values,...), but again, this adds complexity and bug probability.&lt;br /&gt;
&lt;br /&gt;
All these if's that call panic() can be avoided by using hard-coded values at build-time.&lt;br /&gt;
&lt;br /&gt;
If the image is hard-coded, you won't be able to easily (not that easy, actually...) customize the boot logo. But remember that this logo is only display for a short time only when the device reset (manually or during an OTA).&lt;br /&gt;
&lt;br /&gt;
=== Why not add OTA functionality to the bootloader ? ===&lt;br /&gt;
This is exactly how the NRF bootloader/SoftDevice works: the bootloader is a standalone firmware that provides OTA functionality thanks to the SoftDevice. The downside is that the BLE stack needed to provide OTA is quite big and uses a lot of space in flash memory (~124kB according to the documentation). This is roughly 1/4 of the available space in the internal flash memory.&lt;br /&gt;
&lt;br /&gt;
Firmware based on the NRF SoftDevice share the BLE stack with the bootloader, it is mutualised between both entities.&lt;br /&gt;
The downside of this design is that firmwares developers are somewhat forced to use the NRF BLE stack. If they want to integrate another BLE stacak (NimBLE for example), these 120kB used by the SoftDevice would be wasted.&lt;br /&gt;
&lt;br /&gt;
That's why we decided to make the MCUBoot bootloader a simple bootloader without OTA functionality. It's very lighweight (less than 20kB) and leaves the developers the right to choose the BLE stack they want.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
A dynamic memory map, using a partition stored in a fixed place (at the beginning of the external flash, for example) would allow different firmware to customize the partition table, image sizes,... and use the memory for efficiently.&lt;br /&gt;
&lt;br /&gt;
But it has the downside to add complexity and code that could fail. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=File:PineTimeBootloaderWorkflow.png&amp;diff=8319</id>
		<title>File:PineTimeBootloaderWorkflow.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=File:PineTimeBootloaderWorkflow.png&amp;diff=8319"/>
		<updated>2020-11-29T19:45:46Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8304</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8304"/>
		<updated>2020-11-29T16:46:53Z</updated>

		<summary type="html">&lt;p&gt;JF: Add section &amp;quot;Why not add OTA functionality to the bootloader ?&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Request for comments == &lt;br /&gt;
In this page, I explain the changes and improvements I would like to implement to the MCUBoot bootloader to make it more reliable, and to allow bootloader upgrade and switch (mcuboot &amp;lt;-&amp;gt; wasp-bootloader, for example). &lt;br /&gt;
I try to explain why I made these choices too.&lt;br /&gt;
&lt;br /&gt;
Do not hesitate to edit this page and add a new section if you want to add any comment to these points (if you agree, disagree, want to try something else,...).&lt;br /&gt;
&lt;br /&gt;
== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
&lt;br /&gt;
[[PineTime| Pinetime Devkit0]] is using a nRF52832-QFAA MCU with 512kB flash and a [https://datasheet.lcsc.com/szlcsc/2005251035_XTX-XT25F32BSOIGU-S_C558851.pdf XT25F32B SPI NOR external flash] with 4096kB.&lt;br /&gt;
&lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash (512Kb):&lt;br /&gt;
* Page size is 4Kb.&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash (4096Kb):&lt;br /&gt;
* Page size is 256 bytes.&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
Embedding (and compressing) the boot logo inside the bootloader binary brings many advantages:&lt;br /&gt;
* All the data are available in memory at runtime. No need to load them &amp;amp; check them, and no need to handle errors and invalid corrupted data.&lt;br /&gt;
* The data is available and can be sent directly to the display controller&lt;br /&gt;
* 1 unique logo for the bootloader : easier to document and explain to the user that this specific logo is the logo from the bootloader mode.&lt;br /&gt;
&lt;br /&gt;
But it also has some disadvantages:&lt;br /&gt;
* 1-Bit RLE encoding (very effective compression) allows only 2 colors (background/foreground)&lt;br /&gt;
* The boot logo cannot be customized (unless you recompile and flash this new build of the bootloader)&lt;br /&gt;
* The size of the boot logo is limited (depending on the compression ratio)&lt;br /&gt;
&lt;br /&gt;
My (JF) point is that the bootloader must be as reliable as possible. I would like to remove all part of the code than can fail. If we read the boot logo from the SPI flash, we will write something like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;int ret;&lt;br /&gt;
boot_logo_info info;&lt;br /&gt;
ret = SpiNor_read(infoOffset, &amp;amp;info, sizeof(boot_logo_info));&lt;br /&gt;
if(ret != 0) {&lt;br /&gt;
  // Something went wrong while reading image info&lt;br /&gt;
  panic(); // ? reset ?&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(check_boot_logo_info(info) == false) {&lt;br /&gt;
  // image info are invalid (ex : size &amp;gt; 240*240), we cannot use them&lt;br /&gt;
  panic(); // ? reset ? Display nothing?&lt;br /&gt;
}&lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
We could find invalid image info if a firmware did not respect the memory map and erased/overwrote the external memory map. In this case, the bootloader couldn't run properly.&lt;br /&gt;
Of course, we can implement something smart in panic() (retry, use failover values,...), but again, this adds complexity and bug probability.&lt;br /&gt;
&lt;br /&gt;
All these if's that call panic() can be avoided by using hard-coded values at build-time.&lt;br /&gt;
&lt;br /&gt;
If the image is hard-coded, you won't be able to easily (not that easy, actually...) customize the boot logo. But remember that this logo is only display for a short time only when the device reset (manually or during an OTA).&lt;br /&gt;
&lt;br /&gt;
=== Why not add OTA functionality to the bootloader ? ===&lt;br /&gt;
This is exactly how the NRF bootloader/SoftDevice works: the bootloader is a standalone firmware that provides OTA functionality thanks to the SoftDevice. The downside is that the BLE stack needed to provide OTA is quite big and uses a lot of space in flash memory (~124kB according to the documentation). This is roughly 1/4 of the available space in the internal flash memory.&lt;br /&gt;
&lt;br /&gt;
Firmware based on the NRF SoftDevice share the BLE stack with the bootloader, it is mutualised between both entities.&lt;br /&gt;
The downside of this design is that firmwares developers are somewhat forced to use the NRF BLE stack. If they want to integrate another BLE stacak (NimBLE for example), these 120kB used by the SoftDevice would be wasted.&lt;br /&gt;
&lt;br /&gt;
That's why we decided to make the MCUBoot bootloader a simple bootloader without OTA functionality. It's very lighweight (less than 20kB) and leaves the developers the right to choose the BLE stack they want.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
A dynamic memory map, using a partition stored in a fixed place (at the beginning of the external flash, for example) would allow different firmware to customize the partition table, image sizes,... and use the memory for efficiently.&lt;br /&gt;
&lt;br /&gt;
But it has the downside to add complexity and code that could fail. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8264</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8264"/>
		<updated>2020-11-18T18:07:15Z</updated>

		<summary type="html">&lt;p&gt;JF: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Request for comments == &lt;br /&gt;
In this page, I explain the changes and improvements I would like to implement to the MCUBoot bootloader to make it more reliable, and to allow bootloader upgrade and switch (mcuboot &amp;lt;-&amp;gt; wasp-bootloader, for example). &lt;br /&gt;
I try to explain why I made these choices too.&lt;br /&gt;
&lt;br /&gt;
Do not hesitate to edit this page and add a new section if you want to add any comment to these points (if you agree, disagree, want to try something else,...).&lt;br /&gt;
&lt;br /&gt;
== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash:&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash:&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
Embedding (and compressing) the boot logo inside the bootloader binary brings many advantages:&lt;br /&gt;
* All the data are available in memory at runtime. No need to load them &amp;amp; check them, and no need to handle errors and invalid corrupted data.&lt;br /&gt;
* The data is available and can be sent directly to the display controller&lt;br /&gt;
* 1 unique logo for the bootloader : easier to document and explain to the user that this specific logo is the logo from the bootloader mode.&lt;br /&gt;
&lt;br /&gt;
But it also has some disadvantages:&lt;br /&gt;
* 1-Bit RLE encoding (very effective compression) allows only 2 colors (background/foreground)&lt;br /&gt;
* The boot logo cannot be customized (unless you recompile and flash this new build of the bootloader)&lt;br /&gt;
* The size of the boot logo is limited (depending on the compression ratio)&lt;br /&gt;
&lt;br /&gt;
My (JF) point is that the bootloader must be as reliable as possible. I would like to remove all part of the code than can fail. If we read the boot logo from the SPI flash, we will write something like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;int ret;&lt;br /&gt;
boot_logo_info info;&lt;br /&gt;
ret = SpiNor_read(infoOffset, &amp;amp;info, sizeof(boot_logo_info));&lt;br /&gt;
if(ret != 0) {&lt;br /&gt;
  // Something went wrong while reading image info&lt;br /&gt;
  panic(); // ? reset ?&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(check_boot_logo_info(info) == false) {&lt;br /&gt;
  // image info are invalid (ex : size &amp;gt; 240*240), we cannot use them&lt;br /&gt;
  panic(); // ? reset ? Display nothing?&lt;br /&gt;
}&lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
We could find invalid image info if a firmware did not respect the memory map and erased/overwrote the external memory map. In this case, the bootloader couldn't run properly.&lt;br /&gt;
Of course, we can implement something smart in panic() (retry, use failover values,...), but again, this adds complexity and bug probability.&lt;br /&gt;
&lt;br /&gt;
All these if's that call panic() can be avoided by using hard-coded values at build-time.&lt;br /&gt;
&lt;br /&gt;
If the image is hard-coded, you won't be able to easily (not that easy, actually...) customize the boot logo. But remember that this logo is only display for a short time only when the device reset (manually or during an OTA).&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
A dynamic memory map, using a partition stored in a fixed place (at the beginning of the external flash, for example) would allow different firmware to customize the partition table, image sizes,... and use the memory for efficiently.&lt;br /&gt;
&lt;br /&gt;
But it has the downside to add complexity and code that could fail. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8263</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8263"/>
		<updated>2020-11-18T18:03:47Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Fixed vs dynamic memory map */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash:&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash:&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
Embedding (and compressing) the boot logo inside the bootloader binary brings many advantages:&lt;br /&gt;
* All the data are available in memory at runtime. No need to load them &amp;amp; check them, and no need to handle errors and invalid corrupted data.&lt;br /&gt;
* The data is available and can be sent directly to the display controller&lt;br /&gt;
* 1 unique logo for the bootloader : easier to document and explain to the user that this specific logo is the logo from the bootloader mode.&lt;br /&gt;
&lt;br /&gt;
But it also has some disadvantages:&lt;br /&gt;
* 1-Bit RLE encoding (very effective compression) allows only 2 colors (background/foreground)&lt;br /&gt;
* The boot logo cannot be customized (unless you recompile and flash this new build of the bootloader)&lt;br /&gt;
* The size of the boot logo is limited (depending on the compression ratio)&lt;br /&gt;
&lt;br /&gt;
My (JF) point is that the bootloader must be as reliable as possible. I would like to remove all part of the code than can fail. If we read the boot logo from the SPI flash, we will write something like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;int ret;&lt;br /&gt;
boot_logo_info info;&lt;br /&gt;
ret = SpiNor_read(infoOffset, &amp;amp;info, sizeof(boot_logo_info));&lt;br /&gt;
if(ret != 0) {&lt;br /&gt;
  // Something went wrong while reading image info&lt;br /&gt;
  panic(); // ? reset ?&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(check_boot_logo_info(info) == false) {&lt;br /&gt;
  // image info are invalid (ex : size &amp;gt; 240*240), we cannot use them&lt;br /&gt;
  panic(); // ? reset ? Display nothing?&lt;br /&gt;
}&lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
We could find invalid image info if a firmware did not respect the memory map and erased/overwrote the external memory map. In this case, the bootloader couldn't run properly.&lt;br /&gt;
Of course, we can implement something smart in panic() (retry, use failover values,...), but again, this adds complexity and bug probability.&lt;br /&gt;
&lt;br /&gt;
All these if's that call panic() can be avoided by using hard-coded values at build-time.&lt;br /&gt;
&lt;br /&gt;
If the image is hard-coded, you won't be able to easily (not that easy, actually...) customize the boot logo. But remember that this logo is only display for a short time only when the device reset (manually or during an OTA).&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
A dynamic memory map, using a partition stored in a fixed place (at the beginning of the external flash, for example) would allow different firmware to customize the partition table, image sizes,... and use the memory for efficiently.&lt;br /&gt;
&lt;br /&gt;
But it has the downside to add complexity and code that could fail. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8262</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8262"/>
		<updated>2020-11-18T18:01:25Z</updated>

		<summary type="html">&lt;p&gt;JF: /* Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash:&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash:&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
Embedding (and compressing) the boot logo inside the bootloader binary brings many advantages:&lt;br /&gt;
* All the data are available in memory at runtime. No need to load them &amp;amp; check them, and no need to handle errors and invalid corrupted data.&lt;br /&gt;
* The data is available and can be sent directly to the display controller&lt;br /&gt;
* 1 unique logo for the bootloader : easier to document and explain to the user that this specific logo is the logo from the bootloader mode.&lt;br /&gt;
&lt;br /&gt;
But it also has some disadvantages:&lt;br /&gt;
* 1-Bit RLE encoding (very effective compression) allows only 2 colors (background/foreground)&lt;br /&gt;
* The boot logo cannot be customized (unless you recompile and flash this new build of the bootloader)&lt;br /&gt;
* The size of the boot logo is limited (depending on the compression ratio)&lt;br /&gt;
&lt;br /&gt;
My (JF) point is that the bootloader must be as reliable as possible. I would like to remove all part of the code than can fail. If we read the boot logo from the SPI flash, we will write something like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;int ret;&lt;br /&gt;
boot_logo_info info;&lt;br /&gt;
ret = SpiNor_read(infoOffset, &amp;amp;info, sizeof(boot_logo_info));&lt;br /&gt;
if(ret != 0) {&lt;br /&gt;
  // Something went wrong while reading image info&lt;br /&gt;
  panic(); // ? reset ?&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
if(check_boot_logo_info(info) == false) {&lt;br /&gt;
  // image info are invalid (ex : size &amp;gt; 240*240), we cannot use them&lt;br /&gt;
  panic(); // ? reset ? Display nothing?&lt;br /&gt;
}&lt;br /&gt;
... &lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
We could find invalid image info if a firmware did not respect the memory map and erased/overwrote the external memory map. In this case, the bootloader couldn't run properly.&lt;br /&gt;
Of course, we can implement something smart in panic() (retry, use failover values,...), but again, this adds complexity and bug probability.&lt;br /&gt;
&lt;br /&gt;
All these if's that call panic() can be avoided by using hard-coded values at build-time.&lt;br /&gt;
&lt;br /&gt;
If the image is hard-coded, you won't be able to easily (not that easy, actually...) customize the boot logo. But remember that this logo is only display for a short time only when the device reset (manually or during an OTA).&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
	<entry>
		<id>https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8261</id>
		<title>PineTime bootloader improvements</title>
		<link rel="alternate" type="text/html" href="https://wiki.pine64.org/index.php?title=PineTime_bootloader_improvements&amp;diff=8261"/>
		<updated>2020-11-18T17:42:14Z</updated>

		<summary type="html">&lt;p&gt;JF: Add bootloader/application boundaries&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction == &lt;br /&gt;
This pages describes the improvements I propose to make to the bootloader and OTA to make the whole process more reliable.&lt;br /&gt;
&lt;br /&gt;
My goals are:&lt;br /&gt;
&lt;br /&gt;
* KISS : Keep It Stupid Simple. Simple code contains less bugs than complicated/complex code.&lt;br /&gt;
* As reliable as possible. 100% reliability is not feasible with the current hardware (no physical reset button, no bootloader in ROM code,...), but let's try to reach 99.9% reliability :)&lt;br /&gt;
* Provide a read-only factory image we'll be able to restore in case of unrecoverable errors during OTA&lt;br /&gt;
* Provide a way to upgrade the bootloader&lt;br /&gt;
* Provide a way to switch from MCUBoot to NRF bootloaders&lt;br /&gt;
&lt;br /&gt;
== Current memory map == &lt;br /&gt;
[[File:MemoryMap.png]]&lt;br /&gt;
&lt;br /&gt;
Internal flash:&lt;br /&gt;
* Bootloader contains the MCUBoot bootloader. &lt;br /&gt;
* Boot log is currently not used. Can be use to provide reboot logs to the application&lt;br /&gt;
* App is the PRIMARY SLOT for MCUBoot : the firmware that is currently running.&lt;br /&gt;
* Scratch is used by MCUBoot as temporary storage for swap operation&lt;br /&gt;
&lt;br /&gt;
External flash:&lt;br /&gt;
* Bootloader assets : boot logo&lt;br /&gt;
* OTA : SECONDARY SLOT for MCUBoot. During OTA, this is where the new version of the firmware is stored.&lt;br /&gt;
* FS : space available for the application firmware.&lt;br /&gt;
&lt;br /&gt;
This memory map allows a strong boundary between the bootloader and the application :&lt;br /&gt;
* The bootloader is ran by the MCU at reset time and loads its boot logo from the SPI flash&lt;br /&gt;
* The bootloader (MCUBoot) swaps images from primary and secondary slots if necessary&lt;br /&gt;
* The bootloader starts the watchdog&lt;br /&gt;
* The bootloader jumps to 0x8000 to run the application&lt;br /&gt;
&lt;br /&gt;
The application don't know anything about the bootloader except that:&lt;br /&gt;
* it must be linked @0x8000&lt;br /&gt;
* it must refresh the watchdog periodically&lt;br /&gt;
* it must store the image for OTA at a specific location in the external SPI flash memory&lt;br /&gt;
&lt;br /&gt;
In this configuration, the boot logo is part of the bootloader, not of the application : the same logo will be displayed whatever application firmware will be loaded.&lt;br /&gt;
&lt;br /&gt;
== Changes == &lt;br /&gt;
&lt;br /&gt;
=== Factory image ===&lt;br /&gt;
The factory image is a 'light' build of InfiniTime that contains the bare minimum code to provide OTA to the user : basic UI, BLE and OTA. No apps, no fancy functionalities,...&lt;br /&gt;
This factory image will be stored in the &amp;quot;bootloader assets&amp;quot; area of the external flash memory.&lt;br /&gt;
&lt;br /&gt;
This factory image will be restored either automatically, when the bootloader detect it cannot boot from primary slot (App in internal memory) and secondary slot (OTA from exeternal).&lt;br /&gt;
The user can also request to restore this factory image if necessary (using the button?).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader assets ===&lt;br /&gt;
Graphics can be compressed using a simple RLE encoding. RLE encoding on 1 bits (2 colors images) is very efficient (115200KB -&amp;gt; 1-5KB).&lt;br /&gt;
&lt;br /&gt;
In order to simplify the code, the graphics will be stored into the bootloader code instead of storing them into the external flash:&lt;br /&gt;
 - Less code.&lt;br /&gt;
 - Easier to document : 1 specific logo = bootloader mode&lt;br /&gt;
 - Do not have to worry about the dynamic size of the logo (the binary size of the graphics will vary with the content when they are RLE encoded).&lt;br /&gt;
&lt;br /&gt;
=== Bootloader === &lt;br /&gt;
* Display the bootloader version on the screen and expose the version to the application firmware&lt;br /&gt;
* Provide a way to revert the firmware to the last working version AND to the factory firmware&lt;br /&gt;
* Display status and progression (progress bar similar to wasp-reloader, color code,...)&lt;br /&gt;
* Test as much as possible&lt;br /&gt;
&lt;br /&gt;
=== Upgrade &amp;amp; Reloader === &lt;br /&gt;
The reloader is a tool that allows to upgrade the current version of the bootloader AND to switch from MCUBoot to NRF and vice versa.&lt;br /&gt;
&lt;br /&gt;
==== How does it work ? ====&lt;br /&gt;
* Upgrade&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader upgrade the current bootloader and resets the system. It does NOT flag the image as validated. It resets the MCU.&lt;br /&gt;
** The new version of MCUBoot notice that the last upgrade is not validated and reverts to the firmware that was running just before.&lt;br /&gt;
** Voilà, you're running your firmware and a new version of the bootloader&lt;br /&gt;
&lt;br /&gt;
* Switch bootloader&lt;br /&gt;
** The reloader is first OTAed like any firmware upgrade.&lt;br /&gt;
** When the system resets, MCUBoot swaps the application firmware with the reloader. The reloader overwrite the current bootloader with a new one and reset.&lt;br /&gt;
** The new bootloader is running.&lt;br /&gt;
&lt;br /&gt;
* Switch&lt;br /&gt;
** From InfiniTime to wasp-os : the reloader contains the NRF Bootloader and Softdevice. This bootloader provides the OTA mecanism out of the box. Wasp-os is downloaded when the NRF bootloader is running&lt;br /&gt;
** From wasp-os to InfiniTime : the reloader contains the factory image (infinitime-factory). The complete version of InfiniTime will be OTAed when this factory image is running.&lt;br /&gt;
&lt;br /&gt;
== Discussions == &lt;br /&gt;
=== Boot Logo : embedded into the bootloader binary vs stored in the external SPI flash ===&lt;br /&gt;
&lt;br /&gt;
=== Fixed vs dynamic memory map ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:PineTime]]&lt;/div&gt;</summary>
		<author><name>JF</name></author>
	</entry>
</feed>