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