Ga naar inhoud

De LoRa-transceiver

ZES WRAPPERS · STD_INIT · TCXO-TERUGVAL · REGISTERPATCH · RUISVLOER

De radio is het enige onderdeel dat een node tot node maakt. In de firmware is dat geen chip maar een klasse: RADIO_CLASS, per bord ingevuld met één van zes wrappers rond RadioLib. Dit hoofdstuk beschrijft wat die wrapper extra doet bovenop RadioLib — de initialisatie met terugval, de optionele vlaggen per bord, de registerpatch voor drie borden, en het feit dat de radio zijn eigen ruisvloer meet.

[!NOTE] Bron. Deze pagina is geverifieerd tegen de firmware zelf: MeshCore v1.16.0, commit 03b6ef4, 28 juli 2026 — bestanden src/helpers/radiolib/CustomSX1262.h, src/helpers/radiolib/RadioLibWrappers.cpp, de overige wrappers in src/helpers/radiolib/ en de radiovlaggen in variants/.

Blokschema van de radioketen: RADIO_CLASS als CustomSX1262 rond RadioLib,
met SPI naar de chip, DIO1 als interrupt, BUSY als statuslijn en DIO2 of
losse RXEN/TXEN-pinnen naar de RF-schakelaar

Zes chips, één patroon

src/helpers/radiolib/ bevat zes wrappers, elk met een bijbehorende …Wrapper.h:

Wrapper Chip Opvallend
CustomSX1262.h SX1262 de meest voorkomende; 868 MHz
CustomSX1268.h SX1268 zelfde familie, 433 MHz-variant
CustomLLCC68.h LLCC68 SX126x-familie, beperkte SF-reeks
CustomSX1276.h SX1276 oudere SX127x-familie, andere registers
CustomLR1110.h LR1110 met eigen resetroutine in LR11x0Reset.h
CustomSTM32WLx.h STM32WL radio zit ín de SoC, geen SPI

Welk bord welke chip heeft staat in Nodematrix en wordt hier niet herhaald. De keuze valt in de buildvlaggen:

variants/lilygo_tbeam_1w/platformio.ini

  -D RADIO_CLASS=CustomSX1262
  -D WRAPPER_CLASS=CustomSX1262Wrapper

De rest van de firmware kent alleen RADIO_CLASS en WRAPPER_CLASS. Dat is de reden dat er zes chipfamilies naast elkaar bestaan zonder dat er ergens buiten deze map een #ifdef op chiptype staat.

std_init(): de initialisatie met terugval

Elke wrapper heeft een std_init(). Die zet eerst de SPI-pinnen goed — per platform anders, zie De SPI-bus — en roept dan begin() van RadioLib aan.

src/helpers/radiolib/CustomSX1262.h r.45-55

      int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
      // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f
      if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) {
        tcxo = 0.0f;
        status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo);
      }
      if (status != RADIOLIB_ERR_NONE) {
        Serial.print("ERROR: radio init failed: ");
        Serial.println(status);
        return false;  // fail
      }

De terugval is het interessante deel. De TCXO-spanning staat standaard op 1.6f en wordt door SX126X_DIO3_TCXO_VOLTAGE overschreven. Faalt de initialisatie met -706 (RADIOLIB_ERR_SPI_CMD_INVALID) of -707 (RADIOLIB_ERR_SPI_CMD_FAILED), dan probeert de firmware het nog één keer met de TCXO-spanning op nul.

[!NOTE] Dat is precies het gedrag van een bord met een gewoon kristal in plaats van een TCXO: DIO3 stuurt dan niets aan en de chip weigert de opdracht. De firmware raadt dat niet vooraf uit de buildvlaggen, maar leidt het af uit de foutcode.

De drie vaste getallen in die aanroep komen uit de wortel-platformio.ini en zijn voor elk bord gelijk tenzij een variant ze overschrijft: LORA_FREQ=869.618, LORA_BW=62.5, LORA_SF=8. De coderatio is LORA_CR of anders 5, de preamblelengte is 16, en het syncwoord is het private syncwoord van de SX126x-familie.

[!NOTE] Dit zijn buildwaarden, geen netwerkinstellingen. LORA_SF=8 staat als default in platformio.ini; het Nederlandse netwerk draait op SF7, dat de node-configuratie er na het flashen overheen zet. Zie Aan de Slag.

Vier optionele vlaggen

Ná een geslaagde begin() staat CRC altijd aan en volgen vier blokken die alleen worden gecompileerd als de variant de bijbehorende vlag zet.

Vlag Doet Variantmappen
SX126X_CURRENT_LIMIT stroombegrenzing van de eindtrap 66
SX126X_DIO2_AS_RF_SWITCH DIO2 stuurt de RF-schakelaar 60
SX126X_RX_BOOSTED_GAIN gevoeliger ontvangst, meer stroom 64
SX126X_RXEN · SX126X_TXEN losse schakelpinnen 24

De telling is per variantmap en telt zowel -D-vlaggen in platformio.ini als #define-regels in een header binnen die map; uitgecommentarieerde regels tellen niet mee. Van de 79 variantmappen zetten er 60 de DIO2-vlag: 45 in platformio.ini, 22 in een header, 7 op beide plaatsen. Wat die schakelaar doet staat in Antenne.

Ontbreekt bij de losse schakelpinnen één van de twee, dan vult de wrapper hem zelf aan:

src/helpers/radiolib/CustomSX1262.h r.68-76

  #if defined(SX126X_RXEN) || defined(SX126X_TXEN)
    #ifndef SX126X_RXEN
      #define SX126X_RXEN RADIOLIB_NC
    #endif
    #ifndef SX126X_TXEN
      #define SX126X_TXEN RADIOLIB_NC
    #endif
      setRfSwitchPins(SX126X_RXEN, SX126X_TXEN);
  #endif 

RADIOLIB_NC betekent niet aangesloten. Een bord dat alleen SX126X_RXEN zet krijgt dus wél setRfSwitchPins(), met de TX-pin als niet-aangesloten — dat is geen fout maar het normale patroon bij een bord waar DIO2 het TX-pad schakelt en een losse pin het RX-pad.

Een registerpatch voor drie borden

Als laatste stap in std_init() staat een patch die alleen wordt gecompileerd achter SX126X_REGISTER_PATCH:

src/helpers/radiolib/CustomSX1262.h r.78-84

  // for improved RX with Heltec v4
  #ifdef SX126X_REGISTER_PATCH
    uint8_t r_data = 0;
    readRegister(0x8B5, &r_data, 1);
    r_data |= 0x01;
    writeRegister(0x8B5, &r_data, 1);
  #endif

Bit 0 van register 0x8B5 wordt gezet. Het commentaar noemt alleen de Heltec V4, maar drie variantmappen zetten de vlag: heltec_v4, heltec_tracker_v2 en rak3401 — de laatste met de aantekening dat het om de SKY66122-frontendmodule gaat. Het commentaar in de wrapper is dus smaller dan het gebruik. Zulke patches horen bij een bord en niet bij een chip; ze staan er omdat de fabrikant iets anders deed dan het referentieontwerp.

De radio meet zijn eigen ruisvloer

De laag boven de wrapper doet meer dan doorgeven. Tijdens ontvangst bemonstert RadioLibWrapper de RSSI om een ruisvloer te bepalen.

src/helpers/radiolib/RadioLibWrappers.cpp r.87-99

  if (state == STATE_RX && _num_floor_samples < NUM_NOISE_FLOOR_SAMPLES) {
      int rssi = getCurrentRSSI();
      if (rssi < _noise_floor + SAMPLING_THRESHOLD) {  // only consider samples below current floor + sampling THRESHOLD
        _num_floor_samples++;
        _floor_sample_sum += rssi;
      }
  } else if (_num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES && _floor_sample_sum != 0) {
    _noise_floor = _floor_sample_sum / NUM_NOISE_FLOOR_SAMPLES;
    if (_noise_floor < -120) {
      _noise_floor = -120;    // clamp to lower bound of -120dBi
    }

Drie dingen vallen op. Er worden 64 monsters gemiddeld (NUM_NOISE_FLOOR_SAMPLES). Een monster telt alleen mee als het onder de huidige vloer plus 14 dB ligt (SAMPLING_THRESHOLD), zodat een passerend pakket de meting niet omhoog trekt. En het resultaat wordt afgekapt op −120 dBm: lager dan dat rapporteert de firmware niet, ook niet als de omgeving stiller is.

Die vloer is geen statistiek voor de logs. Het kanaal geldt als bezet zodra de actuele RSSI boven vloer plus drempel uitkomt. Wat de vloer betekent voor haalbare afstand staat in Linkbudget.

Bronnen

Firmware, commit 03b6ef4 (v1.16.0, 28 juli 2026):

Verwante hoofdstukken: