Skip to content

Commit 10f68ef

Browse files
authored
Merge pull request #4 from jerryneedell/jerryn_power
Fix power and frequency initiailzations
2 parents 902ac23 + 66492ff commit 10f68ef

File tree

4 files changed

+63
-44
lines changed

4 files changed

+63
-44
lines changed

README.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ This is easily achieved by downloading
2929
Usage Example
3030
=============
3131

32-
See examples/simpletest.py for a demo of the usage.
33-
Note: the default baudrate for the SPI is 10000000 (10MHz). This works well when you are using a board with
34-
the radio module built in (FeatherM0 RFM9x) or with an RFM9x FeatherWing mounted directly to a feather board.
32+
See examples/rfm9x_simpletest.py for a demo of the usage.
33+
Note: the default baudrate for the SPI is 50000000 (5MHz). The maximum setting is 10Mhz but
34+
transmission errors have been observed expecially when using breakout boards.
3535
For breakout boards or other configurations where the boards are separated, it may be necessary to reduce
3636
the baudrate for reliable data transmission.
3737
The baud rate may be specified as an keyword parameter when initializing the board.

adafruit_rfm9x.py

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
adapted from the Radiohead library RF95 code from:
2828
http: www.airspayce.com/mikem/arduino/RadioHead/
2929
30-
* Author(s): Tony DiCola
30+
* Author(s): Tony DiCola, Jerry Needell
3131
"""
3232
import time
3333
import digitalio
@@ -120,7 +120,7 @@
120120
_RH_RF95_PA_RAMP_2MS = const(0x01)
121121
_RH_RF95_PA_RAMP_1MS = const(0x02)
122122
_RH_RF95_PA_RAMP_500US = const(0x03)
123-
_RH_RF95_PA_RAMP_250US = const(0x0)
123+
_RH_RF95_PA_RAMP_250US = const(0x04)
124124
_RH_RF95_PA_RAMP_125US = const(0x05)
125125
_RH_RF95_PA_RAMP_100US = const(0x06)
126126
_RH_RF95_PA_RAMP_62US = const(0x07)
@@ -212,7 +212,7 @@
212212
_RH_RF95_FXOSC = 32000000.0
213213

214214
# The Frequency Synthesizer step = RH_RF95_FXOSC / 2^^19
215-
_RH_RF95_FSTEP = (_RH_RF95_FXOSC // 524288)
215+
_RH_RF95_FSTEP = (_RH_RF95_FXOSC / 524288)
216216

217217
# RadioHead specific compatibility constants.
218218
_RH_BROADCAST_ADDRESS = const(0xFF)
@@ -266,7 +266,7 @@ class RFM9x:
266266
# at least as large as the FIFO on the chip (256 bytes)! Keep this on the
267267
# class level to ensure only one copy ever exists (with the trade-off that
268268
# this is NOT re-entrant or thread safe code by design).
269-
_BUFFER = bytearray(256)
269+
_BUFFER = bytearray(10)
270270

271271
class _RegisterBits:
272272
# Class to simplify access to the many configuration bits avaialable
@@ -334,9 +334,10 @@ def __set__(self, obj, val):
334334
rx_done = _RegisterBits(_RH_RF95_REG_12_IRQ_FLAGS, offset=6, bits=1)
335335

336336
def __init__(self, spi, cs, reset, frequency, *, preamble_length=8,
337-
high_power=True, baudrate=10000000):
337+
high_power=True, baudrate=5000000):
338338
self.high_power = high_power
339339
# Device support SPI mode 0 (polarity & phase = 0) up to a max of 10mhz.
340+
# Set Default Baudrate to 5MHz to avoid problems
340341
self._device = spi_device.SPIDevice(spi, cs, baudrate=baudrate,
341342
polarity=0, phase=0)
342343
# Setup reset as a digital input (default state for reset line according
@@ -361,20 +362,23 @@ def __init__(self, spi, cs, reset, frequency, *, preamble_length=8,
361362
raise RuntimeError('Failed to configure radio for LoRa mode, check wiring!')
362363
except OSError:
363364
raise RuntimeError('Failed to communicate with radio, check wiring!')
365+
# clear default setting for access to LF registers if frequency > 525MHz
366+
if frequency > 525:
367+
self.low_frequency_mode = 0
364368
# Setup entire 256 byte FIFO
365369
self._write_u8(_RH_RF95_REG_0E_FIFO_TX_BASE_ADDR, 0x00)
366370
self._write_u8(_RH_RF95_REG_0F_FIFO_RX_BASE_ADDR, 0x00)
367371
# Set mode idle
368372
self.idle()
369-
# Set modem config to RadioHead comaptible Bw125Cr45Sf128 mode.
373+
# Set modem config to RadioHead compatible Bw125Cr45Sf128 mode.
370374
# Note no sync word is set for LoRa mode either!
371375
self._write_u8(_RH_RF95_REG_1D_MODEM_CONFIG1, 0x72) # Fei msb?
372376
self._write_u8(_RH_RF95_REG_1E_MODEM_CONFIG2, 0x74) # Fei lsb?
373377
self._write_u8(_RH_RF95_REG_26_MODEM_CONFIG3, 0x00) # Preamble lsb?
374378
# Set preamble length (default 8 bytes to match radiohead).
375379
self.preamble_length = preamble_length
376380
# Set frequency
377-
self.frequency = frequency
381+
self.frequency_mhz = frequency
378382
# Set TX power to low defaut, 13 dB.
379383
self.tx_power = 13
380384

@@ -494,6 +498,10 @@ def tx_power(self):
494498
high power devices (RFM95/96/97/98, high_power=True) or -1 to 14 for low
495499
power devices. Only integer power levels are actually set (i.e. 12.5
496500
will result in a value of 12 dBm).
501+
The actual maximum setting for high_power=True is 20dBm but for values > 20
502+
the PA_BOOST will be enabled resulting in an additional gain of 3dBm.
503+
The actual setting is reduced by 3dBm.
504+
The reported value will reflect the reduced setting.
497505
"""
498506
if self.high_power:
499507
return self.output_power + 5
@@ -505,14 +513,17 @@ def tx_power(self, val):
505513
if self.high_power:
506514
assert 5 <= val <= 23
507515
# Enable power amp DAC if power is above 20 dB.
516+
# Lower setting by 3db when PA_BOOST enabled - see Data Sheet Section 6.4
508517
if val > 20:
509518
self.pa_dac = _RH_RF95_PA_DAC_ENABLE
519+
val -= 3
510520
else:
511521
self.pa_dac = _RH_RF95_PA_DAC_DISABLE
512522
self.pa_select = True
513523
self.output_power = (val - 5) & 0x0F
514524
else:
515525
assert -1 <= val <= 14
526+
self.pa_select = False
516527
self.max_power = 0b111 # Allow max power output.
517528
self.output_power = (val + 1) & 0x0F
518529

@@ -523,10 +534,11 @@ def rssi(self):
523534
# Remember in LoRa mode the payload register changes function to RSSI!
524535
return self._read_u8(_RH_RF95_REG_1A_PKT_RSSI_VALUE) - 137
525536

526-
def send(self, data):
537+
def send(self, data, timeout=2.):
527538
"""Send a string of data using the transmitter. You can only send 252
528539
bytes at a time (limited by chip's FIFO size and appended headers). Note
529540
this appends a 4 byte header to be compatible with the RadioHead library.
541+
The timeout is just to prevent a hang (arbitrarily set to 2 Seconds).
530542
"""
531543
# Disable pylint warning to not use length as a check for zero.
532544
# This is a puzzling warning as the below code is clearly the most
@@ -551,16 +563,21 @@ def send(self, data):
551563
self.transmit()
552564
# Wait for tx done interrupt with explicit polling (not ideal but
553565
# best that can be done right now without interrupts).
554-
while not self.tx_done:
555-
pass
556-
# Clear interrupts.
557-
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
566+
start = time.monotonic()
567+
timed_out = False
568+
while not timed_out and not self.tx_done:
569+
if (time.monotonic() - start) >= timeout:
570+
timed_out = True
558571
# Go back to idle mode after transmit.
559572
self.idle()
573+
# Clear interrupts.
574+
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
575+
if timed_out:
576+
raise RuntimeError('Timeout during packet send')
560577

561-
def receive(self, timeout_s=0.5, keep_listening=True):
578+
def receive(self, timeout=0.5, keep_listening=True):
562579
"""Wait to receive a packet from the receiver. Will wait for up to
563-
timeout_s amount of seconds for a packet to be received and decoded. If
580+
timeout amount of seconds for a packet to be received and decoded. If
564581
a packet is found the payload bytes are returned, otherwise None is
565582
returned (which indicates the timeout elapsed with no reception). Note
566583
this assumes a 4-byte header is prepended to the data for compatibilty
@@ -576,32 +593,34 @@ def receive(self, timeout_s=0.5, keep_listening=True):
576593
# enough, however it's the best that can be done from Python without
577594
# interrupt supports.
578595
start = time.monotonic()
579-
while not self.rx_done:
580-
if (time.monotonic() - start) >= timeout_s:
581-
return None # Exceeded timeout.
582-
# Clear interrupt.
583-
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
596+
timed_out = False
597+
while not timed_out and not self.rx_done:
598+
if (time.monotonic() - start) >= timeout:
599+
timed_out = True
584600
# Payload ready is set, a packet is in the FIFO.
585601
packet = None
586-
# Enter idle mode to stop receiving other packets.
587-
self.idle()
588-
# Grab the length of the received packet and check it has at least 5
589-
# bytes to indicate the 4 byte header and at least 1 byte of user data.
590-
length = self._read_u8(_RH_RF95_REG_13_RX_NB_BYTES)
591-
if length < 5:
592-
packet = None
593-
else:
594-
# Have a good packet, grab it from the FIFO.
595-
# Reset the fifo read ptr to the beginning of the packet.
596-
current_addr = self._read_u8(_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR)
597-
self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr)
598-
# Read the first 4 bytes to grab the header.
599-
self._read_into(_RH_RF95_REG_00_FIFO, self._BUFFER, length=4)
600-
length -= 4
601-
# Next read the remaining data into a result packet buffer.
602-
packet = bytearray(length)
603-
self._read_into(_RH_RF95_REG_00_FIFO, packet)
604-
# Listen again if necessary and return the result packet.
602+
if not timed_out:
603+
# Grab the length of the received packet and check it has at least 5
604+
# bytes to indicate the 4 byte header and at least 1 byte of user data.
605+
length = self._read_u8(_RH_RF95_REG_13_RX_NB_BYTES)
606+
if length < 5:
607+
packet = None
608+
else:
609+
# Have a good packet, grab it from the FIFO.
610+
# Reset the fifo read ptr to the beginning of the packet.
611+
current_addr = self._read_u8(_RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR)
612+
self._write_u8(_RH_RF95_REG_0D_FIFO_ADDR_PTR, current_addr)
613+
packet = bytearray(length)
614+
# Read the packet.
615+
self._read_into(_RH_RF95_REG_00_FIFO, packet)
616+
# strip off the header
617+
packet = packet[4:]
618+
# Listen again if necessary and return the result packet.
605619
if keep_listening:
606620
self.listen()
621+
else:
622+
# Enter idle mode to stop receiving other packets.
623+
self.idle()
624+
# Clear interrupt.
625+
self._write_u8(_RH_RF95_REG_12_IRQ_FLAGS, 0xFF)
607626
return packet

docs/examples.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ Simple test
33

44
Ensure your device works with this simple test.
55

6-
.. literalinclude:: ../examples/simpletest.py
7-
:caption: examples/simpletest.py
6+
.. literalinclude:: ../examples/rfm9x_simpletest.py
7+
:caption: examples/rfm9x_simpletest.py
88
:linenos:

examples/simpletest.py renamed to examples/rfm9x_simpletest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
while True:
4848
packet = rfm9x.receive()
4949
# Optionally change the receive timeout from its default of 0.5 seconds:
50-
#packet = rfm9x.receive(timeout_s=5.0)
50+
#packet = rfm9x.receive(timeout=5.0)
5151
# If no packet was received during the timeout then None is returned.
5252
if packet is None:
5353
print('Received nothing! Listening again...')

0 commit comments

Comments
 (0)