add more functionality

This commit is contained in:
soypat
2023-05-24 01:43:30 -03:00
parent 87658d8b62
commit 4634276950
3 changed files with 90 additions and 24 deletions
+7 -1
View File
@@ -40,7 +40,9 @@ func main() {
panic(err.Error()) panic(err.Error())
} }
dev := sx127x.NewLoRa(SX127X_SPI, SX127X_PIN_CS.Set, SX127X_PIN_RST.Set) dev := sx127x.NewLoRa(SX127X_SPI, SX127X_PIN_CS.Set, SX127X_PIN_RST.Set)
err = dev.Configure(sx127x.DefaultConfig(lora.Freq433_0M)) cfg := sx127x.DefaultConfig(lora.Freq433_0M)
cfg.TxPower = 0 // Minimum power.
err = dev.Configure(cfg)
if err != nil { if err != nil {
panic(err.Error()) panic(err.Error())
} }
@@ -57,5 +59,9 @@ func main() {
print(".") print(".")
} }
time.Sleep(2 * time.Second) time.Sleep(2 * time.Second)
// err = dev.Configure(cfg)
// if err != nil {
// println("got error configuring:", err.Error())
// }
} }
} }
+6 -5
View File
@@ -124,11 +124,12 @@ const (
irqCDDETD_MASK uint8 = 0x01 irqCDDETD_MASK uint8 = 0x01
// DIO function mappings D0D1D2D3 // DIO function mappings D0D1D2D3
mapDIO0_LORA_RXDONE uint8 = 0x00 // 00------
mapDIO0_LORA_TXDONE uint8 = 0x40 // 01------ mapDIO0_RXDONE uint8 = 0x00 // 00------ LoRa
mapDIO1_LORA_RXTOUT uint8 = 0x00 // --00---- mapDIO0_TXDONE uint8 = 0x40 // 01------ LoRa
mapDIO1_LORA_NOP uint8 = 0x30 // --11---- mapDIO1_RXTOUT uint8 = 0x00 // --00---- LoRa
mapDIO2_LORA_NOP uint8 = 0xC0 // ----11-- mapDIO1_NOP uint8 = 0x30 // --11---- LoRa
mapDIO2_NOP uint8 = 0xC0 // ----11-- LoRa
// SX127X_PAYLOAD_LENGTH uint8 = 0x40 // SX127X_PAYLOAD_LENGTH uint8 = 0x40
+77 -18
View File
@@ -84,12 +84,12 @@ func DefaultConfig(freq lora.Frequency) lora.Config {
SpreadFactor: lora.SF7, SpreadFactor: lora.SF7,
Bandwidth: 125 * lora.KiloHertz, Bandwidth: 125 * lora.KiloHertz,
CodingRate: lora.CR4_5, CodingRate: lora.CR4_5,
PreambleLength: 12, PreambleLength: 8,
HeaderType: lora.HeaderExplicit, HeaderType: lora.HeaderExplicit,
MaxImplicitPayloadLength: 0, // No need to be set when working with explicit headers. MaxImplicitPayloadLength: 0, // No need to be set when working with explicit headers.
CRC: true, CRC: true,
SyncWord: publicSyncword, SyncWord: publicSyncword,
TxPower: 0, // Low power by default. TxPower: 2, // Low power by default.
LDRO: false, LDRO: false,
IQInversion: false, IQInversion: false,
} }
@@ -150,6 +150,7 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
if err != nil { if err != nil {
return err return err
} }
time.Sleep(15 * time.Millisecond) // Wait for sleep to take effect.
err = d.setFrequency(cfg.Frequency) err = d.setFrequency(cfg.Frequency)
if err != nil { if err != nil {
return err return err
@@ -170,10 +171,11 @@ func (d *DeviceLoRa) Configure(cfg lora.Config) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = d.setTxPower(cfg.TxPower) err = d.setTxPower(cfg.TxPower, false)
if err != nil { if err != nil {
return err return err
} }
// TODO(soypat): Use default OCP?
err = d.setSyncWord(cfg.SyncWord) err = d.setSyncWord(cfg.SyncWord)
if err != nil { if err != nil {
return err return err
@@ -330,6 +332,10 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = d.SetIRQTxDoneOnDIO0()
if err != nil {
return err
}
d.write8(regFIFO_TX_BASE_ADDR, 0) d.write8(regFIFO_TX_BASE_ADDR, 0)
d.write8(regFIFO_ADDR_PTR, 0) d.write8(regFIFO_ADDR_PTR, 0)
for i := 0; i < len(packet); i++ { for i := 0; i < len(packet); i++ {
@@ -364,6 +370,36 @@ func (d *DeviceLoRa) Tx(packet []byte) (err error) {
return nil return nil
} }
// SetRxDoneOnDIO0 sets the TxDone interrupt on the DIO0 pin of the device.
func (d *DeviceLoRa) SetIRQTxDoneOnDIO0() (err error) {
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP.
err = d.write8(regDIO_MAPPING_1, mapDIO0_TXDONE)
if err != nil {
return err
}
err = d.clearIRQ(0xff) // Clear all radio IRQ Flags to avoid instant interrupt raise.
if err != nil {
return err
}
// Unmask TxDone interrupt.
return d.writeMasked8(regIRQ_FLAGS_MASK, irqTXDONE_MASK, 0)
}
// SetRxDoneOnDIO0 sets the RxDone interrupt on the DIO0 pin of the device.
func (d *DeviceLoRa) SetIRQRxDoneOnDIO0() (err error) {
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP.
err = d.write8(regDIO_MAPPING_1, mapDIO0_RXDONE)
if err != nil {
return err
}
err = d.clearIRQ(0xff) // Clear all radio IRQ Flags to avoid instant interrupt raise.
if err != nil {
return err
}
// Unmask RxDone interrupt.
return d.writeMasked8(regIRQ_FLAGS_MASK, irqRXDONE_MASK, 0)
}
// RxSingle receives a single packet over LoRa network and blocks until packet is // RxSingle receives a single packet over LoRa network and blocks until packet is
// received or timeout occurs. Timeout is controlled by value set in [SetSymbolTimeout]. // received or timeout occurs. Timeout is controlled by value set in [SetSymbolTimeout].
func (d *DeviceLoRa) RxSingle(dst []byte) (uint8, error) { func (d *DeviceLoRa) RxSingle(dst []byte) (uint8, error) {
@@ -701,15 +737,21 @@ func (d *DeviceLoRa) enableTxContinuousMode(enable bool) error {
return d.writeMasked8(regMODEM_CONFIG_2, 1<<3, b2u8(enable)<<3) return d.writeMasked8(regMODEM_CONFIG_2, 1<<3, b2u8(enable)<<3)
} }
// PA_HF and PA_LF are high efficiency amplifiers capable of yielding RF power programmable in 1 dB steps from -4 to // setTxPower sets the transmit power of the device in dBm.
// +14dBm directly into a 50 ohm load with low current consumption. PA_LF covers the lower bands (up to 525 MHz), whilst // The useRFO parameter selects between the PA_BOOST and RFO pin. Usually PA_BOOST is used.
// PA_HF will cover the upper bands (from 779 MHz). The output power is sensitive to the power supply voltage, and typically //
// their performance is expressed at 3.3V. // # It is important to set Over Current Protection (OCP) when using high power to prevent device damage.
func (d *DeviceLoRa) setTxPower(txPow int8, useRFO bool) error {
if useRFO {
return d.setRFOTxPower(txPow)
}
return d.setPABoostTxPower(txPow)
}
// setTxPower sets the transmit power without using te PA_BOOST. // setRFOTxPower sets the transmit power without using te PA_BOOST.
func (d *DeviceLoRa) setTxPower(txPow int8) error { func (d *DeviceLoRa) setRFOTxPower(txPow int8) error {
if txPow >= 16 { if txPow < -4 || txPow >= 16 {
return errors.New("requested tx power exceeds capabilities without PA_BOOST") return errors.New("RFO tx power out of range -4..15")
} }
MaxPower, OutputPower := rfoPowReg(txPow) MaxPower, OutputPower := rfoPowReg(txPow)
// This unsets PaSelect bit which switches mode of operation to RFO pin (limited to 14dBm power). // This unsets PaSelect bit which switches mode of operation to RFO pin (limited to 14dBm power).
@@ -717,9 +759,25 @@ func (d *DeviceLoRa) setTxPower(txPow int8) error {
if err != nil { if err != nil {
return err return err
} }
// Set to minimal current. return nil
return d.setOCP(45) }
// return d.write8(regOCP, 0) // TODO: Disable OCP?
func (d *DeviceLoRa) setPABoostTxPower(txPow int8) error {
if txPow < 2 || txPow > 23 {
return errors.New("PA_BOOST tx power out of range 2..23")
}
const PASelect = 0x80
const MaxPower = 0b111 << 4
// It's possible to add 3dBm by setting regPADAC.
// if txPow > 20 {
// txPow -= 3
// d.write8(regPA_DAC, 0x07) // Enable PA_DAC
// } else {
// d.write8(regPA_DAC, 0x04) // Disable PA_DAC
// }
outputPower := paBoostPowReg(txPow)
return d.write8(regPA_CONFIG, PASelect|MaxPower|outputPower)
} }
func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) { func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) {
@@ -728,7 +786,7 @@ func rfoPowReg(txPow int8) (MaxPower, OutputPower uint8) {
// Pout = Pmax - (15 - OutputPower) => OutputPower = 15 - (Pmax - Pout) // Pout = Pmax - (15 - OutputPower) => OutputPower = 15 - (Pmax - Pout)
// Where Pmax=10.8+0.6*MaxPower [dBm] // Where Pmax=10.8+0.6*MaxPower [dBm]
// To solve this combined equation we set MaxPower depending on txPow // To solve this combined equation we set MaxPower depending on txPow
// and solve from there on. The result is error margin +/- 0.3dBm. See tests. // and solve from there on. The result has an error margin of +/- 0.3dBm. See tests.
switch { switch {
case txPow < 2: case txPow < 2:
MaxPower = 0b000 MaxPower = 0b000
@@ -749,9 +807,9 @@ func paBoostPowReg(txPow int8) (OutputPower uint8) {
return OutputPower return OutputPower
} }
// setOCP defines Overload Current Protection configuration. It receives // SetOCP defines Overload Current Protection configuration. It receives
// the max current (Imax) in milliamperes. // the max current (Imax) in milliamperes.
func (d *DeviceLoRa) setOCP(mA uint8) error { func (d *DeviceLoRa) SetOCP(mA uint8) error {
const ocpEnabledMask = 1 << 5 const ocpEnabledMask = 1 << 5
return d.write8(regOCP, ocpEnabledMask|(0x1F&ocpTrim(mA))) return d.write8(regOCP, ocpEnabledMask|(0x1F&ocpTrim(mA)))
} }
@@ -905,7 +963,7 @@ func (d *DeviceLoRa) write8(addr, value byte) error {
d.csEnable(true) d.csEnable(true)
err := d.bus.Tx(writeBuf, readBuf) err := d.bus.Tx(writeBuf, readBuf)
d.csEnable(false) d.csEnable(false)
if debugBufSize > 0 { if debugBufSize > 0 && addr != regFIFO {
d.debugWrite[addr] = value d.debugWrite[addr] = value
d.debugMask[addr] = 0xFF d.debugMask[addr] = 0xFF
d.read8(addr) // refresh address value. d.read8(addr) // refresh address value.
@@ -917,6 +975,7 @@ func (d *DeviceLoRa) csEnable(b bool) {
d.cs(!b) d.cs(!b)
} }
//go:inline
func b2u8(b bool) uint8 { func b2u8(b bool) uint8 {
if b { if b {
return 1 return 1