Difference between revisions of "Pinedio"
(Add new section about the USB LoRa adapter) |
|||
Line 135: | Line 135: | ||
Dietpi Official Website: https://www.dietpi.com | Dietpi Official Website: https://www.dietpi.com | ||
== | == USB adapter == | ||
[[File:Pine64-lora-usb-adapter.jpg|500px]] | |||
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: | |||
-------- -------------------------- | |||
| | | USB LoRa Adapter | | |||
| PC | <--USB--> | CH341 <--SPI--> SX1262 | | |||
| | | <--I/O--> | | |||
-------- -------------------------- | |||
=== Pins === | |||
[[File:Lora-usb-pins.jpg|500px]] | |||
{| class="wikitable" | |||
!SX1262 Pin | |||
!Name | |||
!Description | |||
|- | |||
|1 | |||
|ANT | |||
|Antenna | |||
|- | |||
|2 | |||
|GND2 | |||
| | |||
|- | |||
|3 | |||
|VREG | |||
| | |||
|- | |||
|4 | |||
|DCC | |||
| | |||
|- | |||
|5 | |||
|VCC | |||
| | |||
|- | |||
|6 | |||
|DIO1 | |||
|Connected on CH341 Pin 7 | |||
|- | |||
|7 | |||
|DIO2 | |||
|Connected on CH341 Pin6 | |||
|- | |||
|8 | |||
|DIO3 | |||
|Connected on CH341 Pin 5 | |||
|- | |||
|9 | |||
|GND | |||
| | |||
|- | |||
|10 | |||
|MISO | |||
|SPI MISO | |||
|- | |||
|11 | |||
|MOSI | |||
|SPI MOSI | |||
|- | |||
|12 | |||
|SCK | |||
|SPI clock | |||
|- | |||
|13 | |||
|NSS | |||
|SPI Chip select | |||
|- | |||
|14 | |||
|POR | |||
|Reset pin | |||
|- | |||
|15 | |||
|Busy | |||
|Busy pin | |||
|- | |||
|16 | |||
|GND | |||
| | |||
|} | |||
=== Kernel module for CH341 === | |||
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). | |||
$ git clone https://github.com/rogerjames99/spi-ch341-usb.git | |||
$ cd spi-ch341-usb | |||
$ make | |||
$ sudo make install | |||
Once the driver is installed, unload the module ''ch341'' if it has been automatically loaded: | |||
$ lsmod |grep ch341 | |||
$ sudo rmmod ch341 | |||
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. | |||
Then load the new module: | |||
$ sudo modprobe spi-ch341-usb | |||
Plug your USB adapter and check that the module is correctly loaded : | |||
$ dmesg | |||
[20141.872107] usb 1-1.1: USB disconnect, device number 4 | |||
[20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform | |||
[20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04 | |||
[20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0 | |||
[20143.973434] usb 1-1.1: Product: USB UART-LPT | |||
[20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device | |||
[20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3 | |||
[20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=0 type=2 dir=1 addr=2 | |||
[20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=1 type=2 dir=0 addr=2 | |||
[20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=2 type=3 dir=1 addr=1 | |||
[20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0 | |||
[20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 | |||
[20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1 | |||
[20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 | |||
[20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2 | |||
[20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 | |||
[20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input gpio4 gpio=3 irq=3 | |||
[20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input gpio6 gpio=4 irq=4 | |||
[20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input err gpio=5 irq=5 | |||
[20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input pemp gpio=6 irq=6 | |||
[20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input int gpio=7 irq=7 (hwirq) | |||
[20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input slct gpio=8 irq=8 | |||
[20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input wait gpio=9 irq=9 | |||
[20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input autofd gpio=10 irq=10 | |||
[20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input addr gpio=11 irq=11 | |||
[20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 | |||
[20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 | |||
[20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 | |||
[20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 | |||
[20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start | |||
[20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1 | |||
[20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created | |||
[20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created | |||
[20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created | |||
[20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done | |||
[20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start | |||
[20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103 | |||
[20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done | |||
[20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start | |||
[20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0 | |||
[20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0 | |||
[20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0 | |||
[20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1 | |||
[20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1 | |||
[20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1 | |||
[20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1 | |||
[20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1 | |||
[20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1 | |||
[20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1 | |||
[20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1 | |||
[20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1 | |||
[20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0 | |||
[20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0 | |||
[20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0 | |||
[20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0 | |||
[20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511 | |||
[20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done | |||
[20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start | |||
[20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected | |||
[20144.756250] usbcore: registered new interface driver ch341 | |||
[20144.756334] usbserial: USB Serial support registered for ch341-uart | |||
=== Driver development === | |||
Once the module ''spi-ch341-usb'' is correctly loaded, here's how you can transfer data on the SPI bus (in C): | |||
/* Open the SPI bus */ | |||
int spi = open("/dev/spidev1.0", O_RDWR); | |||
uint8_t mmode = SPI_MODE_0; | |||
uint8_t lsb = 0; | |||
ioctl(spi, SPI_IOC_WR_MODE, &mmode); | |||
ioctl(spi, SPI_IOC_WR_LSB_FIRST, &lsb); | |||
/* Transfer data */ | |||
/* TODO: Init buffer_out, buffer_in and size */ | |||
const uint8_t *mosi = buffer_out; // output data | |||
uint8_t *miso = buffer_in; // input data | |||
struct spi_ioc_transfer spi_trans; | |||
memset(&spi_trans, 0, sizeof(spi_trans)); | |||
spi_trans.tx_buf = (unsigned long) mosi; | |||
spi_trans.rx_buf = (unsigned long) miso; | |||
spi_trans.cs_change = true; | |||
spi_trans.len = size; | |||
int status = ioctl (spi, SPI_IOC_MESSAGE(1), &spi_trans); | |||
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. | |||
int fd; | |||
if ((fd = open("/sys/class/gpio/export", O_WRONLY)) == -1) { | |||
perror("open ini"); | |||
exit(-1); | |||
} | |||
if (write(fd, "508", 3) == -1){ | |||
perror ("write export 508"); | |||
} | |||
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: | |||
int fd; | |||
if ((fd = open("/sys/class/gpio/slct/value", O_RDWR)) == -1) { | |||
perror("open"); | |||
} | |||
char buf; | |||
if (read(fd, &buf, 1) == -1) { | |||
perror("read"); | |||
} | |||
int value = (buf == '0') ? 0 : 1; | |||
You can also write it: | |||
int fd; | |||
if ((fd = open("/sys/class/gpio/ini/value", O_RDWR)) == -1) { | |||
perror("open ini"); | |||
} | |||
if (write(fd, value ? "1" : "0", 1) == -1) { | |||
perror ("write"); | |||
} | |||
=== Driver for the SX1262 LoRa module === | |||
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. | |||
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]. | |||
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): | |||
[[File:pine64-lora-usb-adapter-sdr.png|500px]] | |||
== Other end nodes == | |||
There are several end-node units planned: | There are several end-node units planned: | ||
Line 170: | Line 409: | ||
=== USB LoRa adapter === | === USB LoRa adapter === | ||
* [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]] | * [[File:USB_LoRa_adapter-PINE64_RFM90_SCH_2021_04_26.pdf]] | ||
* CH341 datasheet : [[File:CH341DS1.pdf]] | |||
* 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)] | |||
== Other resources == | == Other resources == | ||
* [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules] | * [https://www.youtube.com/watch?v=cJ0wpANpbyc Video: A peek at Pine64's LoRa gateway and modules] | ||
* [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform] | * [https://iotw.io/ IOTW - Blockchain-Enabled IoT Data Platform] |
Revision as of 18:06, 20 August 2021
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 The Things Network or 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!
Gateway
The gateway will be available in two variants - indoor and outdoor. All that is known about the outdoor unit is that it will have "an aluminum, rugged and water resistant case". 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.
Connections
- GPS is connected to UART2 on the A64 board
- SX1302 on SPI0
RAK2287 module | PI-2 connector | PINE A64-LTS |
SX1302 SPI | Pin 19 = MOSI / PC0 Pin 21 = MISO/PC1 Pin23 = CLK/PC2 Pin24 = CS/PC3 |
SPI0 (/dev/spidev0.0) |
SX1302 RESET | Pin 11 = GPIO17/PC7 | GPIO71 (/sys/class/gpio/gpio71) |
GPS UART | Pin 8 = TX/ Pin 10 = RX |
UART2 (/dev/ttyS2) |
GPS RESET | Pin 33 = GPIO13/PC5 | GPIO69 (/sys/class/gpio/gpio69) |
GPS Standby | Pin 35 = GPIO19/PC9 | GPIO73 (/sys/class/gpio/gpio73) |
Pictures
Operating System Options
Pinedio Gateway carries the A64-LTS board. Based on ram specifications SOPINE images are also compatible.
Armbian
Gateway is based on the pine64 A64-LTS, and the current Armbian_sopine image download options can be found here: https://www.armbian.com/sopine-a64/
(Previous issues in DTS have been fixed by Armbian developers and Armbian_sopine_21.05.1 is confirmed to boot).
Armbian Official Website: https://www.armbian.com
Default Credentials
Login: root password: 1234
After your first login you will be guided through creating your user account (create a strong password).
Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):
Inside armbian-config -> system -> Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):
overlays=spi-spidev uart2 i2c0 param_spidev_spi_bus=0
Or you may hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.
Save. Reboot.
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot). Make sure to offer GPS antenna a strong signal, preferably by a window (if indoors).
Dietpi
NOTE: IMAGE CURRENTLY EXPERIMENTAL. FOR TESTING. NOT CONSIDERED STABLE.
HIGHLY SUGGESTED TO USE ARMBIAN (AT THIS TIME). THIS SECTION WILL BE UPDATED.
Download current Dietpi image (for Pinedio/SOPINE/LTS): https://mega.nz/file/7VpmAQ6S#CxOpSHBHgFkynXIOKVQEQk8864-DLsNnFtbpCH6PU6o
Login: dietpi Password: SoPinePass!
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.
Dietpi Commands:
dietpi-launcher: access all dietpi tools/menus
dietpi-software: select from numerous optimized servers/services to install
dietpi-config: feature rich configuration tool
dietpi-autostart: choose software to run after boot
dietpi-update: update/upgrade system
The entire list of software available for installation (inside dietpi-software) can be found here: https://dietpi.com/docs/software/
Steps To Enable spidev0.0 (rakwireless concentrator/GPS device):
As Dietpi strips down the system to a minimum level (deleting original Armbian commands), we can either install armbian-config command by issuing:
sudo apt install armbian-config
Inside armbian-config -> system -> Bootenv (edit boot environment), enter the following 2 lines (to create spidev0.0):
overlays=spi-spidev uart2 i2c0 param_spidev_spi_bus=0
Or, instead of installing the above armbian-config, hand edit: /boot/armbianEnv.txt to add the above overlays/param_spidev_spi_bus lines.
Save. Reboot.
After rebooting you should see a new device /dev/spidev0.0. This will be the concentrator device for gateway related setup.
GPS will be /dev/ttyS2 and should work (after editing armbianEnv.txt + reboot).
Dietpi Official Website: https://www.dietpi.com
USB adapter
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:
-------- -------------------------- | | | USB LoRa Adapter | | PC | <--USB--> | CH341 <--SPI--> SX1262 | | | | <--I/O--> | -------- --------------------------
Pins
SX1262 Pin | Name | Description |
---|---|---|
1 | ANT | Antenna |
2 | GND2 | |
3 | VREG | |
4 | DCC | |
5 | VCC | |
6 | DIO1 | Connected on CH341 Pin 7 |
7 | DIO2 | Connected on CH341 Pin6 |
8 | DIO3 | Connected on CH341 Pin 5 |
9 | GND | |
10 | MISO | SPI MISO |
11 | MOSI | SPI MOSI |
12 | SCK | SPI clock |
13 | NSS | SPI Chip select |
14 | POR | Reset pin |
15 | Busy | Busy pin |
16 | GND |
Kernel module for CH341
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 this driver from rogerjames99 on my desktop computer (running Manjaro Linux) and on my Pinebook Pro (ARM64, running Manjaro ARM Linux).
$ git clone https://github.com/rogerjames99/spi-ch341-usb.git $ cd spi-ch341-usb $ make $ sudo make install
Once the driver is installed, unload the module ch341 if it has been automatically loaded:
$ lsmod |grep ch341 $ sudo rmmod ch341
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.
Then load the new module:
$ sudo modprobe spi-ch341-usb
Plug your USB adapter and check that the module is correctly loaded :
$ dmesg [20141.872107] usb 1-1.1: USB disconnect, device number 4 [20143.820756] usb 1-1.1: new full-speed USB device number 5 using ehci-platform [20143.973366] usb 1-1.1: New USB device found, idVendor=1a86, idProduct=5512, bcdDevice= 3.04 [20143.973413] usb 1-1.1: New USB device strings: Mfr=0, Product=2, SerialNumber=0 [20143.973434] usb 1-1.1: Product: USB UART-LPT [20143.975137] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connect device [20143.975164] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: bNumEndpoints=3 [20143.975183] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=0 type=2 dir=1 addr=2 [20143.975206] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=1 type=2 dir=0 addr=2 [20143.975229] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: endpoint=2 type=3 dir=1 addr=1 [20143.975254] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 SPI slave with cs=0 [20143.975273] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs0 gpio=0 irq=0 [20143.975295] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 SPI slave with cs=1 [20143.975313] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs1 gpio=1 irq=1 [20143.975334] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 SPI slave with cs=2 [20143.975352] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output cs2 gpio=2 irq=2 [20143.975373] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input gpio4 gpio=3 irq=3 [20143.975394] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input gpio6 gpio=4 irq=4 [20143.975415] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input err gpio=5 irq=5 [20143.975435] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input pemp gpio=6 irq=6 [20143.975456] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input int gpio=7 irq=7 (hwirq) [20143.975478] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input slct gpio=8 irq=8 [20143.975499] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input wait gpio=9 irq=9 [20143.975520] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input autofd gpio=10 irq=10 [20143.975542] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: input addr gpio=11 irq=11 [20143.975564] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output ini gpio=12 irq=12 [20143.975585] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output write gpio=13 irq=13 [20143.975607] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output scl gpio=14 irq=14 [20143.975628] spi-ch341-usb 1-1.1:1.0: ch341_cfg_probe: output sda gpio=15 irq=15 [20143.975650] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: start [20143.975677] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI master connected to SPI bus 1 [20143.977831] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.0 created [20143.978183] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.1 created [20143.978552] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: SPI device /dev/spidev1.2 created [20143.978726] spi-ch341-usb 1-1.1:1.0: ch341_spi_probe: done [20143.978735] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: start [20143.979133] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: irq_base=103 [20143.979154] spi-ch341-usb 1-1.1:1.0: ch341_irq_probe: done [20143.979162] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: start [20143.979220] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs0 dir=0 [20143.979229] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs1 dir=0 [20143.979237] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=cs2 dir=0 [20143.979245] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio4 dir=1 [20143.979253] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=gpio6 dir=1 [20143.979260] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=err dir=1 [20143.979268] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=pemp dir=1 [20143.979275] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=int dir=1 [20143.979283] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=slct dir=1 [20143.979290] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=wait dir=1 [20143.979298] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=autofd dir=1 [20143.979306] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=addr dir=1 [20143.979314] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=ini dir=0 [20143.979321] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=write dir=0 [20143.979329] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=scl dir=0 [20143.979337] spi-ch341-usb 1-1.1:1.0: ch341_gpio_get_direction: gpio=sda dir=0 [20143.979831] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: registered GPIOs from 496 to 511 [20143.981152] spi-ch341-usb 1-1.1:1.0: ch341_gpio_probe: done [20143.981212] spi-ch341-usb 1-1.1:1.0: ch341_gpio_poll_function: start [20143.981291] spi-ch341-usb 1-1.1:1.0: ch341_usb_probe: connected [20144.756250] usbcore: registered new interface driver ch341 [20144.756334] usbserial: USB Serial support registered for ch341-uart
Driver development
Once the module spi-ch341-usb is correctly loaded, here's how you can transfer data on the SPI bus (in C):
/* Open the SPI bus */ int spi = open("/dev/spidev1.0", O_RDWR); uint8_t mmode = SPI_MODE_0; uint8_t lsb = 0; ioctl(spi, SPI_IOC_WR_MODE, &mmode); ioctl(spi, SPI_IOC_WR_LSB_FIRST, &lsb); /* Transfer data */ /* TODO: Init buffer_out, buffer_in and size */ const uint8_t *mosi = buffer_out; // output data uint8_t *miso = buffer_in; // input data struct spi_ioc_transfer spi_trans; memset(&spi_trans, 0, sizeof(spi_trans)); spi_trans.tx_buf = (unsigned long) mosi; spi_trans.rx_buf = (unsigned long) miso; spi_trans.cs_change = true; spi_trans.len = size; int status = ioctl (spi, SPI_IOC_MESSAGE(1), &spi_trans);
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 source code of the driver. For example, pin slct is the 12th, meaning we need to export GPIO 496+12 = 508.
int fd; if ((fd = open("/sys/class/gpio/export", O_WRONLY)) == -1) { perror("open ini"); exit(-1); } if (write(fd, "508", 3) == -1){ perror ("write export 508"); }
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:
int fd; if ((fd = open("/sys/class/gpio/slct/value", O_RDWR)) == -1) { perror("open"); } char buf; if (read(fd, &buf, 1) == -1) { perror("read"); } int value = (buf == '0') ? 0 : 1;
You can also write it:
int fd; if ((fd = open("/sys/class/gpio/ini/value", O_RDWR)) == -1) { perror("open ini"); } if (write(fd, value ? "1" : "0", 1) == -1) { perror ("write"); }
Driver for the SX1262 LoRa module
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. I found 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 available here.
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):
Other end nodes
There are several end-node units planned:
- loRa back case for the PinePhone
- standalone USB dongle-type end-node adapter
- PineTab adapter
- as well as a SPI module (which can also be configured as a USB LoRa dongle)
- a LoRa stick powered by a single 18650 battery (using the BL602, and can be fitted with GPS, an low-power OLED panel and additional sensors)
All the end-nodes use the SX1262 chip.
Pictures
Datasheets and schematics
Gateway
- SX1302 datasheets and resources
- RAK2287 datasheets and resources
- Pine64 LoRa Gateway module adapter schematic
End nodes
Pinephone backplate
- File:Pinephone LoRa BackPanel Schematic-v1.0-20210402.pdf
- File:CA-S01 LoRa Chip Antenna in Chinese.pdf
- I2C SPI Bridge code running on ATtiny84
USB LoRa adapter
- File:USB LoRa adapter-PINE64 RFM90 SCH 2021 04 26.pdf
- CH341 datasheet : File:CH341DS1.pdf
- Semtech SX1262 datasheet : File on Semtech website (file is too big for the wiki)