parent
ae1bdde11c
commit
7793c72308
@ -0,0 +1,213 @@ |
|||||||
|
import time |
||||||
|
|
||||||
|
import gex |
||||||
|
import sx_fsk as sx |
||||||
|
|
||||||
|
|
||||||
|
# we're demonstrating the use of the QFSK mode of the SX1278 |
||||||
|
# this is an example of how GEX can be used to control a peripheral module - in this case evaluating |
||||||
|
# it for use in GEX remote |
||||||
|
|
||||||
|
|
||||||
|
class LoRa: |
||||||
|
def __init__(self, |
||||||
|
rst: gex.DOut, |
||||||
|
spi: gex.SPI, ssnum): |
||||||
|
self.ss = ssnum |
||||||
|
self.rst = rst |
||||||
|
self.spi = spi |
||||||
|
|
||||||
|
def reset(self): |
||||||
|
self.rst.pulse_us(100, active=False) |
||||||
|
time.sleep(0.005) |
||||||
|
|
||||||
|
def rd(self, addr): |
||||||
|
return self.spi.query(self.ss, [addr], 1)[0] |
||||||
|
|
||||||
|
def wr(self, addr, value): |
||||||
|
self.spi.write(self.ss, [addr | 0x80, value]) |
||||||
|
|
||||||
|
def rds(self, start, count=1): |
||||||
|
return self.spi.query(self.ss, [start], count) |
||||||
|
|
||||||
|
def wrs(self, start, values): |
||||||
|
ba = bytearray() |
||||||
|
ba.append(start | 0x80) |
||||||
|
ba.extend(values) |
||||||
|
self.spi.write(self.ss, ba) |
||||||
|
|
||||||
|
def rmw(self, addr, keep, set): |
||||||
|
""" rmw, first and-ing the register with mask and then oring with set """ |
||||||
|
val = self.rd(addr) |
||||||
|
self.wr(addr, (val & keep) | set) |
||||||
|
|
||||||
|
def waitModeSwitch(self): |
||||||
|
while 0 == (self.rd(sx.REG_IRQFLAGS1) & sx.RF_IRQFLAGS1_MODEREADY): |
||||||
|
time.sleep(0.001) |
||||||
|
|
||||||
|
def waitSent(self): |
||||||
|
while 0 == (self.rd(sx.REG_IRQFLAGS2) & sx.RF_IRQFLAGS2_PACKETSENT): |
||||||
|
time.sleep(0.001) |
||||||
|
|
||||||
|
def fsk_set_defaults(self): |
||||||
|
# Set default values (semtech patches: * in DS) |
||||||
|
self.rmw(sx.REG_RXCONFIG, |
||||||
|
sx.RF_RXCONFIG_RXTRIGER_MASK, |
||||||
|
sx.RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT) |
||||||
|
|
||||||
|
self.wr(sx.REG_PREAMBLEDETECT, |
||||||
|
sx.RF_PREAMBLEDETECT_DETECTOR_ON | |
||||||
|
sx.RF_PREAMBLEDETECT_DETECTORSIZE_2 | |
||||||
|
sx.RF_PREAMBLEDETECT_DETECTORTOL_10) |
||||||
|
|
||||||
|
self.rmw(sx.REG_OSC, sx.RF_OSC_CLKOUT_MASK, sx.RF_OSC_CLKOUT_OFF) |
||||||
|
|
||||||
|
self.rmw(sx.REG_FIFOTHRESH, |
||||||
|
sx.RF_FIFOTHRESH_TXSTARTCONDITION_MASK, |
||||||
|
sx.RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY) |
||||||
|
|
||||||
|
self.rmw(sx.REG_IMAGECAL, |
||||||
|
sx.RF_IMAGECAL_AUTOIMAGECAL_MASK, |
||||||
|
sx.RF_IMAGECAL_AUTOIMAGECAL_OFF) |
||||||
|
|
||||||
|
def configure_for_fsk(self, address): |
||||||
|
self.rmw(sx.REG_OPMODE, |
||||||
|
sx.RF_OPMODE_LONGRANGEMODE_MASK & sx.RF_OPMODE_MODULATIONTYPE_MASK & sx.RF_OPMODE_MASK, |
||||||
|
sx.RF_OPMODE_LONGRANGEMODE_OFF | |
||||||
|
sx.RF_OPMODE_MODULATIONTYPE_FSK | |
||||||
|
sx.RF_OPMODE_STANDBY) |
||||||
|
self.waitModeSwitch() |
||||||
|
|
||||||
|
self.fsk_set_defaults() |
||||||
|
self.wr(sx.REG_NODEADRS, address) |
||||||
|
self.wr(sx.REG_BROADCASTADRS, 0xFF) |
||||||
|
# use whitening and force address matching |
||||||
|
self.rmw(sx.REG_PACKETCONFIG1, |
||||||
|
sx.RF_PACKETCONFIG1_DCFREE_MASK & sx.RF_PACKETCONFIG1_ADDRSFILTERING_MASK, |
||||||
|
sx.RF_PACKETCONFIG1_DCFREE_WHITENING | |
||||||
|
sx.RF_PACKETCONFIG1_ADDRSFILTERING_NODEBROADCAST) |
||||||
|
|
||||||
|
self.wr(sx.REG_RXCONFIG, |
||||||
|
sx.RF_RXCONFIG_AFCAUTO_ON | |
||||||
|
sx.RF_RXCONFIG_AGCAUTO_ON | |
||||||
|
sx.RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT) |
||||||
|
|
||||||
|
XTAL_FREQ = 32000000 |
||||||
|
FREQ_STEP = 61.03515625 |
||||||
|
FSK_FDEV = 60000 # Hz NOTE: originally: 25000, seems to help increasing |
||||||
|
FSK_DATARATE = 200000 # bps - originally 50000 |
||||||
|
|
||||||
|
MAX_RFPOWER = 0 # 0-7 boost - this doesnt seem to have a huge impact |
||||||
|
|
||||||
|
FSK_PREAMBLE_LENGTH = 5 # Same for Tx and Rx |
||||||
|
|
||||||
|
fdev = round(FSK_FDEV / FREQ_STEP) |
||||||
|
self.wr(sx.REG_FDEVMSB, fdev >> 8) |
||||||
|
self.wr(sx.REG_FDEVLSB, fdev & 0xFF) |
||||||
|
|
||||||
|
datarate = round(XTAL_FREQ / FSK_DATARATE) |
||||||
|
print("dr=%d"%datarate) |
||||||
|
self.wr(sx.REG_BITRATEMSB, datarate >> 8) |
||||||
|
self.wr(sx.REG_BITRATELSB, datarate & 0xFF) |
||||||
|
|
||||||
|
preamblelen = FSK_PREAMBLE_LENGTH |
||||||
|
self.wr(sx.REG_PREAMBLEMSB, preamblelen >> 8) |
||||||
|
self.wr(sx.REG_PREAMBLELSB, preamblelen & 0xFF) |
||||||
|
|
||||||
|
# bandwidths - 1 MHz |
||||||
|
self.wr(sx.REG_RXBW, 0x0A) # FSK_BANDWIDTH |
||||||
|
self.wr(sx.REG_AFCBW, 0x0A) # FSK_AFC_BANDWIDTH |
||||||
|
|
||||||
|
# max payload len to rx |
||||||
|
self.wr(sx.REG_PAYLOADLENGTH, 0xFF) |
||||||
|
|
||||||
|
self.rmw(sx.REG_PARAMP, 0x9F, 0x40) # enable gauss 0.5 |
||||||
|
|
||||||
|
# pick the sync word size |
||||||
|
self.rmw(sx.REG_SYNCCONFIG, |
||||||
|
sx.RF_SYNCCONFIG_SYNCSIZE_MASK, |
||||||
|
sx.RF_SYNCCONFIG_SYNCSIZE_3) |
||||||
|
|
||||||
|
# sync word (network ID) |
||||||
|
self.wrs(sx.REG_SYNCVALUE1, [ |
||||||
|
0xe7, 0x3d, 0xfa, 0x01, 0x5e, 0xa1, 0xc9, 0x98 # something random |
||||||
|
]) |
||||||
|
|
||||||
|
# enable LNA boost (?) |
||||||
|
self.rmw(sx.REG_LNA, |
||||||
|
sx.RF_LNA_BOOST_MASK, |
||||||
|
sx.RF_LNA_BOOST_ON) |
||||||
|
|
||||||
|
# experiments with the pa config |
||||||
|
self.rmw(sx.REG_PACONFIG, |
||||||
|
sx.RF_PACONFIG_PASELECT_MASK|0x8F, # max power mask |
||||||
|
sx.RF_PACONFIG_PASELECT_PABOOST | MAX_RFPOWER<<4) |
||||||
|
|
||||||
|
# we could also possibly adjust the Tx power |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
with gex.Client(gex.TrxRawUSB()) as client: |
||||||
|
spi = gex.SPI(client, 'spi') |
||||||
|
rst1 = gex.DOut(client, 'rst1') |
||||||
|
rst2 = gex.DOut(client, 'rst2') |
||||||
|
|
||||||
|
a = LoRa(rst1, spi, 0) |
||||||
|
b = LoRa(rst2, spi, 1) |
||||||
|
|
||||||
|
# reset the two transceivers to ensure they start in a defined state |
||||||
|
a.reset() |
||||||
|
b.reset() |
||||||
|
|
||||||
|
# go to sleep mode, select FSK |
||||||
|
a.configure_for_fsk(0x33) |
||||||
|
b.configure_for_fsk(0x44) |
||||||
|
|
||||||
|
print("Devices configured") |
||||||
|
|
||||||
|
for j in range(0, 240): |
||||||
|
if(j>0 and j%60==0): |
||||||
|
print() |
||||||
|
|
||||||
|
# --- Send a message from 1 to 2 --- |
||||||
|
msg = [ |
||||||
|
51, # len |
||||||
|
0x44, # address |
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, |
||||||
|
0, 1, 2, 3, 4, 5, 6, 7, 8, j |
||||||
|
] |
||||||
|
|
||||||
|
a.wrs(sx.REG_FIFO, msg) |
||||||
|
|
||||||
|
b.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_RECEIVER) |
||||||
|
# time.sleep(0.005) |
||||||
|
|
||||||
|
# trigger A |
||||||
|
a.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_TRANSMITTER) |
||||||
|
a.waitModeSwitch() |
||||||
|
a.waitSent() |
||||||
|
# time.sleep(0.02) |
||||||
|
|
||||||
|
# print("a irq flags = ", ["0x%02x"%x for x in a.rds(sx.REG_IRQFLAGS1, 2)]) |
||||||
|
# print("b irq flags = ", ["0x%02x"%x for x in b.rds(sx.REG_IRQFLAGS1, 2)]) |
||||||
|
|
||||||
|
rxd = [b.rd(sx.REG_FIFO) for x in range(0,len(msg))] |
||||||
|
if rxd == msg: |
||||||
|
print("\x1b[32;1m+\x1b[0m", end="", flush=True) |
||||||
|
else: |
||||||
|
print("\x1b[31m-\x1b[0m", end="", flush=True) |
||||||
|
# |
||||||
|
# for i in range(0,8): |
||||||
|
# print("0x%02x" % rxd[i],end=" ") |
||||||
|
# print() |
||||||
|
# print() |
||||||
|
print() |
||||||
|
|
||||||
|
# good night |
||||||
|
a.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_SLEEP) |
||||||
|
b.rmw(sx.REG_OPMODE, sx.RF_OPMODE_MASK, sx.RF_OPMODE_SLEEP) |
||||||
|
|
||||||
|
|
@ -0,0 +1,78 @@ |
|||||||
|
## UNITS.INI |
||||||
|
## GEX v0.0.1 on STM32F072-HUB |
||||||
|
## built Mar 17 2018 at 17:53:15 |
||||||
|
|
||||||
|
[UNITS] |
||||||
|
# Create units by adding their names next to a type (e.g. DO=A,B), |
||||||
|
# remove the same way. Reload to update the unit sections below. |
||||||
|
|
||||||
|
# Digital output |
||||||
|
DO=rst1,rst2 |
||||||
|
# Digital input with triggers |
||||||
|
DI= |
||||||
|
# Neopixel RGB LED strip |
||||||
|
NPX= |
||||||
|
# I2C master |
||||||
|
I2C= |
||||||
|
# SPI master |
||||||
|
SPI=spi |
||||||
|
# Serial port |
||||||
|
USART= |
||||||
|
# 1-Wire master |
||||||
|
1WIRE= |
||||||
|
# Analog/digital converter |
||||||
|
ADC= |
||||||
|
# Shift register driver (595, 4094) |
||||||
|
SIPO= |
||||||
|
# Frequency and pulse measurement |
||||||
|
FCAP= |
||||||
|
# Capacitive touch sensing |
||||||
|
TOUCH= |
||||||
|
# Simple PWM output |
||||||
|
PWMDIM= |
||||||
|
# Two-channel analog output with waveforms |
||||||
|
DAC= |
||||||
|
|
||||||
|
[DO:rst1@2] |
||||||
|
# Port name |
||||||
|
port=B |
||||||
|
# Pins (comma separated, supports ranges) |
||||||
|
pins=2 |
||||||
|
# Initially high pins |
||||||
|
initial=2 |
||||||
|
# Open-drain pins |
||||||
|
open-drain= |
||||||
|
|
||||||
|
[DO:rst2@3] |
||||||
|
# Port name |
||||||
|
port=B |
||||||
|
# Pins (comma separated, supports ranges) |
||||||
|
pins=6 |
||||||
|
# Initially high pins |
||||||
|
initial=6 |
||||||
|
# Open-drain pins |
||||||
|
open-drain= |
||||||
|
|
||||||
|
[SPI:spi@1] |
||||||
|
# Peripheral number (SPIx) |
||||||
|
device=1 |
||||||
|
# Pin mappings (SCK,MISO,MOSI) |
||||||
|
# SPI1: (0) A5,A6,A7 (1) B3,B4,B5 |
||||||
|
# SPI2: (0) B13,B14,B15 |
||||||
|
remap=1 |
||||||
|
|
||||||
|
# Prescaller: 2,4,8,...,256 |
||||||
|
prescaller=64 |
||||||
|
# Clock polarity: 0,1 (clock idle level) |
||||||
|
cpol=0 |
||||||
|
# Clock phase: 0,1 (active edge, 0-first, 1-second) |
||||||
|
cpha=0 |
||||||
|
# Transmit only, disable MISO |
||||||
|
tx-only=N |
||||||
|
# Bit order (LSB or MSB first) |
||||||
|
first-bit=MSB |
||||||
|
|
||||||
|
# SS port name |
||||||
|
port=B |
||||||
|
# SS pins (comma separated, supports ranges) |
||||||
|
pins=1-0 |
Loading…
Reference in new issue