some fixes + semtech demo
This commit is contained in:
+213
@@ -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)
|
||||
|
||||
|
||||
+3
-3
@@ -25,19 +25,19 @@ class DOut(gex.Unit):
|
||||
pb.u16(pins)
|
||||
self._send(CMD_WRITE, pb.close(), confirm=confirm)
|
||||
|
||||
def set(self, pins, confirm=True):
|
||||
def set(self, pins=1, confirm=True):
|
||||
""" Set pins high - packed, int or list """
|
||||
pb = gex.PayloadBuilder()
|
||||
pb.u16(self.pins2int(pins))
|
||||
self._send(CMD_SET, pb.close(), confirm=confirm)
|
||||
|
||||
def clear(self, pins, confirm=True):
|
||||
def clear(self, pins=1, confirm=True):
|
||||
""" Set pins low - packed, int or list """
|
||||
pb = gex.PayloadBuilder()
|
||||
pb.u16(self.pins2int(pins))
|
||||
self._send(CMD_CLEAR, pb.close(), confirm=confirm)
|
||||
|
||||
def toggle(self, pins, confirm=True):
|
||||
def toggle(self, pins=1, confirm=True):
|
||||
""" Toggle pins - packed, int or list """
|
||||
pb = gex.PayloadBuilder()
|
||||
pb.u16(self.pins2int(pins))
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user