Added Heltec V4.3 support/FEM autodetection
This commit is contained in:
31
Boards.h
31
Boards.h
@@ -151,6 +151,10 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define LORA_PA_UNKNOWN 0x00
|
||||
#define LORA_PA_GC1109 0x01
|
||||
#define LORA_PA_KCT8103L 0x02
|
||||
|
||||
#define HAS_DISPLAY false
|
||||
#define HAS_BLUETOOTH false
|
||||
#define HAS_BLE false
|
||||
@@ -363,7 +367,7 @@
|
||||
#define HAS_SLEEP true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
@@ -411,8 +415,9 @@
|
||||
#define HAS_LORA_LNA true
|
||||
#define PIN_WAKEUP GPIO_NUM_0
|
||||
#define WAKEUP_LEVEL 0
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
#define Vext GPIO_NUM_36
|
||||
#define LORA_PA_MODEL LORA_PA_UNKNOWN;
|
||||
|
||||
const int pin_btn_usr1 = 0;
|
||||
|
||||
@@ -434,14 +439,17 @@
|
||||
|
||||
#define LORA_LNA_GAIN 17
|
||||
#define LORA_LNA_GVT 12
|
||||
#define LORA_PA_GC1109 true
|
||||
#define LORA_PA_PWR_EN 7
|
||||
#define LORA_PA_CSD 2
|
||||
#define LORA_PA_CPS 46
|
||||
#define LORA_PA_CSD 2 // Same pin on GC1109
|
||||
#define LORA_PA_CPS 46 // Same pin on GC1109
|
||||
#define LORA_PA_CTX 5 // Only used on KCT8103
|
||||
|
||||
#define PA_MAX_OUTPUT 28
|
||||
#define PA_GAIN_POINTS 22
|
||||
#define PA_GAIN_VALUES 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7
|
||||
|
||||
#define LORA_LNA_KCT8103L_GAIN 21
|
||||
const int PA_GC1109_VALUES[PA_GAIN_POINTS] = {11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 9, 9, 8, 7};
|
||||
const int PA_KCT8103L_VALUES[PA_GAIN_POINTS] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 9, 8, 7};
|
||||
|
||||
const int pin_cs = 8;
|
||||
const int pin_busy = 13;
|
||||
@@ -529,13 +537,10 @@
|
||||
const int pin_np = 12;
|
||||
const int pin_dac = 25;
|
||||
const int pin_adc = 34;
|
||||
// CBA already defined by framework
|
||||
//const int SD_MISO = 2;
|
||||
// CBA already defined by framework
|
||||
//const int SD_MOSI = 15;
|
||||
const int SD_MISO = 2;
|
||||
const int SD_MOSI = 15;
|
||||
const int SD_CLK = 14;
|
||||
// CBA already defined by framework
|
||||
//const int SD_CS = 13;
|
||||
const int SD_CS = 13;
|
||||
#if HAS_NP == false
|
||||
#if defined(EXTERNAL_LEDS)
|
||||
const int pin_led_rx = 12;
|
||||
@@ -980,7 +985,7 @@
|
||||
// Default OCP value if not specified
|
||||
// in board configuration
|
||||
#ifndef OCP_TUNED
|
||||
#define OCP_TUNED 0x18
|
||||
#define OCP_TUNED 0x28
|
||||
#endif
|
||||
|
||||
#ifndef PA_MAX_OUTPUT
|
||||
|
||||
@@ -1586,7 +1586,7 @@ void serial_callback(uint8_t sbyte) {
|
||||
if (txp > 13) txp = 13;
|
||||
#endif
|
||||
#else
|
||||
if (txp > 17) txp = 17;
|
||||
if (txp > 20) txp = 20;
|
||||
#endif
|
||||
|
||||
lora_txp = txp;
|
||||
@@ -2648,7 +2648,13 @@ void sleep_now() {
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
headless_led_off();
|
||||
headless_led_detach_pwm();
|
||||
digitalWrite(LORA_PA_CPS, LOW);
|
||||
#if LORA_PA_AUTO_DETECT
|
||||
if (sx126x_modem.isKCT8103L()) {
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
} else {
|
||||
digitalWrite(LORA_PA_CPS, LOW);
|
||||
}
|
||||
#endif
|
||||
digitalWrite(LORA_PA_CSD, LOW);
|
||||
digitalWrite(LORA_PA_PWR_EN, LOW);
|
||||
digitalWrite(Vext, HIGH);
|
||||
|
||||
22
Utilities.h
22
Utilities.h
@@ -1383,11 +1383,33 @@ int getTxPower() {
|
||||
}
|
||||
|
||||
#if HAS_LORA_PA
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
bool pa_values_determined = false;
|
||||
int tx_gain[PA_GAIN_POINTS] = {100};
|
||||
#else
|
||||
bool pa_values_determined = true;
|
||||
const int tx_gain[PA_GAIN_POINTS] = {PA_GAIN_VALUES};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
extern uint8_t lora_pa_model;
|
||||
void determine_pa_values() {
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_GC1109_VALUES[i]; }
|
||||
pa_values_determined = true;
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { tx_gain[i] = PA_KCT8103L_VALUES[i]; }
|
||||
pa_values_determined = true;
|
||||
for (int i=0; i < PA_GAIN_POINTS; i++) { Serial.print(" "); Serial.printf("%d", tx_gain[i]); }
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int map_target_power_to_modem_output(int target_tx_power) {
|
||||
#if HAS_LORA_PA
|
||||
if (!pa_values_determined) { determine_pa_values(); }
|
||||
int modem_output_dbm = -9;
|
||||
for (int i = 0; i < PA_GAIN_POINTS; i++) {
|
||||
int gain = tx_gain[i];
|
||||
|
||||
102
sx126x.cpp
102
sx126x.cpp
@@ -275,6 +275,21 @@ void sx126x::setPacketParams(long preamble_symbols, uint8_t headermode, uint8_t
|
||||
buf[7] = 0x00;
|
||||
buf[8] = 0x00;
|
||||
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
|
||||
|
||||
// SX1262 errata section 15.4: IQ polarity is inverted compared to
|
||||
// SX1276. The SetPacketParams command resets register 0x0736 to an
|
||||
// incorrect default. For standard IQ (no inversion), bit 2 must be
|
||||
// SET after every SetPacketParams call. For inverted IQ, bit 2 must
|
||||
// be CLEARED. Without this fix, LoRa RX demodulation fails silently
|
||||
// while TX continues to work.
|
||||
uint8_t iqreg = readRegister(0x0736);
|
||||
if (buf[5] == 0x00) {
|
||||
// Standard IQ: set bit 2
|
||||
writeRegister(0x0736, iqreg | 0x04);
|
||||
} else {
|
||||
// Inverted IQ: clear bit 2
|
||||
writeRegister(0x0736, iqreg & ~0x04);
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::reset(void) {
|
||||
@@ -287,6 +302,22 @@ void sx126x::reset(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void sx126x::setDCDCRegulator(void) {
|
||||
// Documentation
|
||||
// 5. Power Distribution -> 5.1 Selecting DC-DC Converter or LDO Regulation
|
||||
// 13.1.11 SetRegulatorMode
|
||||
|
||||
uint8_t mode_byte = MODE_STDBY_RC_6X;
|
||||
executeOpcode(OP_STANDBY_6X, &mode_byte, 1);
|
||||
|
||||
// Enable DC-DC regulator for high power operation
|
||||
uint8_t reg_mode = 0x01; // 0x00 = LDO, 0x01 = DC-DC
|
||||
executeOpcode(OP_REGULATOR_MODE_6X, ®_mode, 1);
|
||||
|
||||
delay(5);
|
||||
waitOnBusy();
|
||||
}
|
||||
|
||||
void sx126x::calibrate(void) {
|
||||
// Put in STDBY_RC mode before calibration
|
||||
uint8_t mode_byte = MODE_STDBY_RC_6X;
|
||||
@@ -319,10 +350,19 @@ int sx126x::begin(long frequency) {
|
||||
if (_rxen != -1) { pinMode(_rxen, OUTPUT); }
|
||||
if (_txen != -1) { pinMode(_txen, OUTPUT); }
|
||||
|
||||
//TODO: if it works, make it optional
|
||||
//#ifdef SX1262_USE_DCDC_REGULATOR
|
||||
setDCDCRegulator();
|
||||
//#endif
|
||||
|
||||
calibrate();
|
||||
calibrate_image(frequency);
|
||||
enableTCXO();
|
||||
#if HAS_TCXO
|
||||
enableTCXO();
|
||||
//13.1.15 SetRxTxFallbackMode to STDBY_XOSC
|
||||
uint8_t fallback_mode = 0x30; // STDBY_XOSC after TX/RX
|
||||
executeOpcode(OP_RX_TX_FALLBACK_MODE_6X, &fallback_mode, 1);
|
||||
#endif
|
||||
loraMode();
|
||||
standby();
|
||||
|
||||
@@ -339,7 +379,9 @@ int sx126x::begin(long frequency) {
|
||||
setFrequency(frequency);
|
||||
setTxPower(2);
|
||||
enableCrc();
|
||||
writeRegister(REG_LNA_6X, 0x96); // Set LNA boost
|
||||
writeRegister(REG_LNA_6X, 0x96); // Set LNA boosted gain mode
|
||||
// Undocumented SX1262 register patch recommended by Heltec/Semtech for improved RX sensitivity.
|
||||
writeRegister(0x08B5, readRegister(0x08B5) | 0x01);
|
||||
uint8_t basebuf[2] = {0}; // Set base addresses
|
||||
executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
|
||||
|
||||
@@ -347,7 +389,22 @@ int sx126x::begin(long frequency) {
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_UNKNOWN) {
|
||||
#if BOARD_MODEL == BOARD_HELTEC32_V4
|
||||
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
pinMode(LORA_PA_CSD, INPUT);
|
||||
digitalWrite(LORA_PA_PWR_EN, HIGH); delay(5);
|
||||
if (digitalRead(LORA_PA_CSD) == HIGH) {
|
||||
lora_pa_model = LORA_PA_KCT8103L;
|
||||
lora_lna_gain = LORA_LNA_KCT8103L_GAIN;
|
||||
} else {
|
||||
lora_pa_model = LORA_PA_GC1109;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Enable Vfem_ctl for supply to
|
||||
// PA power net.
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
@@ -372,7 +429,26 @@ int sx126x::begin(long frequency) {
|
||||
// is driven by the SX1262 DIO2
|
||||
// pin directly, so we do not
|
||||
// need to manually raise this.
|
||||
#endif
|
||||
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
// Enable Vfem_ctl for supply to
|
||||
// PA power net.
|
||||
pinMode(LORA_PA_PWR_EN, OUTPUT);
|
||||
digitalWrite(LORA_PA_PWR_EN, HIGH);
|
||||
|
||||
// Enable KCT8103L chip
|
||||
pinMode(LORA_PA_CSD, OUTPUT);
|
||||
digitalWrite(LORA_PA_CSD, HIGH);
|
||||
|
||||
// Enable receive LNA
|
||||
pinMode(LORA_PA_CTX, OUTPUT);
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
|
||||
// On Heltec V4.3, the PA CPS pin
|
||||
// is driven by the SX1262 DIO2
|
||||
// pin directly, so we do not
|
||||
// need to manually raise this.
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
@@ -382,14 +458,17 @@ void sx126x::end() { sleep(); SPI.end(); _preinit_done = false; }
|
||||
|
||||
int sx126x::beginPacket(int implicitHeader) {
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Enable PA CPS for transmit
|
||||
// digitalWrite(LORA_PA_CPS, HIGH);
|
||||
// Disabled since we're keeping it
|
||||
// on permanently as long as the
|
||||
// radio is powered up.
|
||||
#endif
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
digitalWrite(LORA_PA_CTX, HIGH);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_txen != -1) { digitalWrite(_txen, HIGH); } //Set TXen high when transmitting
|
||||
|
||||
standby();
|
||||
@@ -405,6 +484,7 @@ int sx126x::beginPacket(int implicitHeader) {
|
||||
|
||||
int sx126x::endPacket() {
|
||||
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
|
||||
|
||||
if (_rxen != -1) { digitalWrite(_rxen, LOW); } //Set RXen low when transmitting
|
||||
|
||||
uint8_t timeout[3] = {0}; // Put in single TX mode
|
||||
@@ -479,7 +559,7 @@ int ISR_VECT sx126x::currentRssi() {
|
||||
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
|
||||
int rssi = -(int(byte)) / 2;
|
||||
#if HAS_LORA_LNA
|
||||
rssi -= LORA_LNA_GAIN;
|
||||
rssi -= lora_lna_gain;
|
||||
#endif
|
||||
return rssi;
|
||||
}
|
||||
@@ -495,7 +575,7 @@ int ISR_VECT sx126x::packetRssi() {
|
||||
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
|
||||
int pkt_rssi = -buf[0] / 2;
|
||||
#if HAS_LORA_LNA
|
||||
pkt_rssi -= LORA_LNA_GAIN;
|
||||
pkt_rssi -= lora_lna_gain;
|
||||
#endif
|
||||
return pkt_rssi;
|
||||
}
|
||||
@@ -602,7 +682,7 @@ void sx126x::onReceive(void(*callback)(int)){
|
||||
|
||||
void sx126x::receive(int size) {
|
||||
#if HAS_LORA_PA
|
||||
#if LORA_PA_GC1109
|
||||
if (lora_pa_model == LORA_PA_GC1109) {
|
||||
// Disable PA CPS for receive
|
||||
// digitalWrite(LORA_PA_CPS, LOW);
|
||||
// That turned out to be a bad idea.
|
||||
@@ -610,7 +690,9 @@ void sx126x::receive(int size) {
|
||||
// on and off too quickly. We'll keep
|
||||
// it on permanently, as long as the
|
||||
// radio is powered up.
|
||||
#endif
|
||||
} else if (lora_pa_model == LORA_PA_KCT8103L) {
|
||||
digitalWrite(LORA_PA_CTX, LOW);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size > 0) {
|
||||
|
||||
7
sx126x.h
7
sx126x.h
@@ -74,6 +74,7 @@ public:
|
||||
void disableCrc();
|
||||
void enableTCXO();
|
||||
void disableTCXO();
|
||||
void setDCDCRegulator();
|
||||
|
||||
void rxAntEnable();
|
||||
void loraMode();
|
||||
@@ -97,6 +98,8 @@ public:
|
||||
|
||||
void dumpRegisters(Stream& out);
|
||||
|
||||
bool isKCT8103L() { return _kct8103l; }
|
||||
|
||||
private:
|
||||
void explicitHeaderMode();
|
||||
void implicitHeaderMode();
|
||||
@@ -107,7 +110,8 @@ public:
|
||||
// Poll for deferred DIO0 interrupt (call from main loop)
|
||||
void pollDio0();
|
||||
|
||||
private: uint8_t readRegister(uint16_t address);
|
||||
private:
|
||||
uint8_t readRegister(uint16_t address);
|
||||
void writeRegister(uint16_t address, uint8_t value);
|
||||
uint8_t singleTransfer(uint8_t opcode, uint16_t address, uint8_t value);
|
||||
|
||||
@@ -142,6 +146,7 @@ private:
|
||||
int _fifo_rx_addr_ptr;
|
||||
uint8_t _packet[255];
|
||||
bool _preinit_done;
|
||||
bool _kct8103l;
|
||||
volatile bool _dio0_risen;
|
||||
void (*_onReceive)(int);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user