Description
Having taken the CircuitPython_RFM9x lib and heavily modifying it for my own applications, there are some general register settings that could be implemented to improve performance as well as some SX1276/7/8/9 errata that may want to be included.
General Performance Improvements
Many of these are not present in the HopeRF datasheet (but ARE described in the SX1276/7/8/9 datasheet). My testing with HopeRF RFM98PW modules has convinced me these specific semtech registers DO make a difference.
- Enabling automatic gain control has improved my LoRa Rx packet RSSI sensitivity in all situations I've encountered. I just created another registerbits instance:
auto_agc = _RegisterBits(_RH_RF95_REG_26_MODEM_CONFIG3, offset=2, bits=1)
and set itTrue
during init. See register 0x26 in either HopeRF or Semtech datasheet. - In it's current state, I'm unable to this library for low data rate operation in standard (benchtop) testing conditions. This can be remedied by setting bit 3 of register 0x26. Semtech calls it "Low Data Rate Optimization" but HopeRF calls this bit "MobileNode." See semtech datasheet for more detail.
- (for high frequency modules) setting LnaBoostHF (register 0x0C bits 0,1) to 0b11
Addressing Errata
Semtech has an: errata doc for the SX1276/7/8/9. For all my modules, the silicon version matches that which is specified in the beginning of the errata (0x12), and implementing the following fixes DID make a difference in performance.
- Section 2.1 Sensitivity Optimization with a 500 kHz Bandwidth -- which can be just an easy check & write in during the
signal_bandwidth
setter. - Section 2.3 Receiver Spurious Reception of a LoRa Signal -- a handful of different configuration cases will need to be accounted for, but I saw improved rejection for the bandwidths I'm utilizing.
My hacky implementation look like this:
@signal_bandwidth.setter
def signal_bandwidth(self, val):
# Set signal bandwidth (set to 125000 to match RadioHead Bw125).
for bw_id, cutoff in enumerate(self.bw_bins):
if val <= cutoff:
break
else:
bw_id = 9
self._write_u8(
_RH_RF95_REG_1D_MODEM_CONFIG1,
(self._read_u8(_RH_RF95_REG_1D_MODEM_CONFIG1) & 0x0F) | (bw_id << 4))
if val >= 500000:
# see Semtech SX1276 errata note 2.1
self._write_u8(0x36,0x02)
self._write_u8(0x3a,0x64)
else:
if val == 7800:
self._write_u8(0x2F,0x48)
elif val >= 62500:
# see Semtech SX1276 errata note 2.3
self._write_u8(0x2F,0x40)
else:
self._write_u8(0x2F,0x44)
self._write_u8(0x30,0)
@spreading_factor.setter
def spreading_factor(self, val):
# Set spreading factor (set to 7 to match RadioHead Sf128).
val = min(max(val, 6), 12)
self._write_u8(_RH_RF95_DETECTION_OPTIMIZE, 0xC5 if val == 6 else 0xC3)
if self.signal_bandwidth >= 5000000:
self._write_u8(_RH_RF95_DETECTION_OPTIMIZE, 0xC5 if val == 6 else 0xC3)
else:
# see Semtech SX1276 errata note 2.3
self._write_u8(_RH_RF95_DETECTION_OPTIMIZE, 0x45 if val == 6 else 0x43)
self._write_u8(_RH_RF95_DETECTION_THRESHOLD, 0x0C if val == 6 else 0x0A)
self._write_u8(
_RH_RF95_REG_1E_MODEM_CONFIG2,
(
(self._read_u8(_RH_RF95_REG_1E_MODEM_CONFIG2) & 0x0F)
| ((val << 4) & 0xF0)
),
)
I'm filing an issue rather than a PR since I don't have the time to implement and test atm 😇
EDIT: @jerryneedell this will likely remedy the "garbage" packets you were investigating last year