Source: Semtech SX1261/2 Data Sheet, Rev 2.2, DS.SX1261-2.W.APP, December 2024.
This document extracts the sections relevant for SX1262 LoRa driver development.
For the complete datasheet, see semtech.com.
The SX1261/2 is controlled via a serial SPI interface and a set of general purpose input/output (DIOs). At least one DIO must be used for IRQ and the BUSY line is mandatory. BUSY indicates that the chip is ready for new command only if this signal is low.
A complete “factory reset” can be issued by toggling pin NRESET. It is automatically followed by the standard calibration procedure and any previous context is lost. The pin should be held low for typically 100us for the Reset to happen.
The SPI interface uses a synchronous full-duplex protocol: CPOL = 0, CPHA = 0 (Mode 0). Only the slave side is implemented.
- MOSI is generated by the master on the falling edge of SCK and is sampled by the slave on the rising edge of SCK.
- MISO is generated by the slave on the falling edge of SCK.
- A transfer is always started by the NSS pin going low. MISO is high impedance when NSS is high.
- SPI runs on the external SCK clock to allow high speed up to 16 MHz.
| Symbol | Description | Min | Max | Unit |
| t1 | NSS falling to SCK setup time | 32 | - | ns |
| t2 | SCK period | 62.5 | - | ns |
| t6 | NSS falling to MISO delay | 0 | 15 | ns |
| t7 | SCK falling to MISO delay | 0 | 15 | ns |
| t8 | SCK to NSS rising hold time | 31.25 | - | ns |
| t9 | NSS high time | 125 | - | ns |
| t10 | NSS falling to SCK setup when switching from SLEEP to STDBY_RC | 100 | - | us |
| t11 | NSS falling to MISO delay when switching from SLEEP to STDBY_RC | 0 | 150 | us |
One way for the chip to leave Sleep mode is to wait for a falling edge of NSS. The delay between the falling edge of NSS and the first rising edge of SCK must take into account the wake-up sequence and the chip initialization. During Sleep mode and the initialization phase, BUSY is set high. Once the chip is in STDBY_RC mode, BUSY goes low and the host can start sending a command. This is also true for startup at battery insertion or after a hard reset.
The BUSY control line indicates the status of the internal state machine. When BUSY is held low, the internal state machine is in idle mode and the radio is ready for a command.
For all “write” commands, BUSY is asserted high after time T_SW. T_SW from NSS rising edge to BUSY rising edge is max 600 ns in all cases.
“Read” commands are handled directly without the internal state machine and BUSY remains low after a read command.
| Transition | T_SW_Mode Typical (us) |
| SLEEP to STBY_RC cold start | 3500 |
| SLEEP to STBY_RC warm start | 340 |
| STBY_RC to STBY_XOSC | 31 |
| STBY_RC to FS | 50 |
| STBY_RC to RX | 83 |
| STBY_RC to TX | 126 |
| STBY_XOSC to TX | 105 |
| Mode | DIO3 | DIO2 | DIO1 | BUSY | MISO | MOSI | SCK | NSS |
| Reset | PD | PD | PD | PU | HIZ | HIZ | HIZ | IN |
| Start-up | PD | PD | PD | PU | HIZ | HIZ | HIZ | IN |
| Sleep | PD | PD | PD | PU | HIZ | HIZ | HIZ | IN |
| STBY_RC | OUT | OUT | OUT | OUT | OUT | IN | IN | IN |
| STBY_XOSC | OUT | OUT | OUT | OUT | OUT | IN | IN | IN |
| FS / RX / TX | OUT | OUT | OUT | OUT | OUT | IN | IN | IN |
PU = pull up 50kOhm, PD = pull down 50kOhm, HIZ = high impedance, OUT = output, IN = input.
During Reset, Start-up, and Sleep: MISO is High-Impedance. Any SPI read during these states returns undefined data.
| Bit | IRQ | Description | Modulation |
| 0 | TxDone | Packet transmission completed | All |
| 1 | RxDone | Packet received | All |
| 2 | PreambleDetected | Preamble detected | All |
| 3 | SyncWordValid | Valid Sync Word detected | FSK |
| 4 | HeaderValid | Valid LoRa Header received | LoRa |
| 5 | HeaderErr | LoRa Header CRC error | LoRa |
| 6 | CrcErr | Wrong CRC received | All |
| 7 | CadDone | Channel activity detection finished | LoRa |
| 8 | CadDetected | Channel activity detected | LoRa |
| 9 | Timeout | Rx or Tx Timeout | All |
Note: If DIO2 or DIO3 are used to control the RF Switch or the TCXO, the IRQ is not generated even if it is mapped to the pins.
| Mode | Enabled Blocks |
| SLEEP | Optional registers, backup regulator, RC64k oscillator, data RAM |
| STDBY_RC | Top regulator (LDO), RC13M oscillator |
| STDBY_XOSC | Top regulator (DC-DC or LDO), XOSC |
| FS | All of the above + Frequency synthesizer at Tx frequency |
| TX | Frequency synthesizer and transmitter, Modem |
| RX | Frequency synthesizer and receiver, Modem |
At power-up or after a reset, the chip goes into STARTUP state. The BUSY pin is set to high. When the digital voltage and RC clock become available, the chip can boot up and the CPU takes control. At this stage the BUSY line goes down and the device is ready to accept commands.
The calibration procedure is automatically called in case of POR. Blocks calibrated: RC64k, RC13M, PLL, RX ADC, Image. Once calibration is finished, the chip enters STDBY_RC mode.
| Frequency Band [MHz] | Freq1 | Freq2 |
| 430 - 440 | 0x6B | 0x6F |
| 470 - 510 | 0x75 | 0x81 |
| 779 - 787 | 0xC1 | 0xC5 |
| 863 - 870 | 0xD7 | 0xDB |
| 902 - 928 | 0xE1 (default) | 0xE9 (default) |
By default, the image calibration is made in the 902-928 MHz band. When using a TCXO, the calibration fails and the user should request a complete calibration after calling SetDIO3AsTcxoCtrl(...).
In TX mode, after enabling and ramping-up the Power Amplifier (PA), the contents of the data buffer are transmitted. The timeout can be used as a security to ensure that if the TxDone IRQ is never triggered, the TxTimeout prevents waiting indefinitely. In TX mode, BUSY goes low as soon as the PA has ramped-up and transmission of preamble starts.
| Byte | 0 | [1:n] |
| Data from host (MOSI) | Opcode | Parameters |
| Data to host (MISO) | RFU | Status |
During byte 0 (the opcode byte), MISO returns RFU (Reserved for Future Use) – NOT the status byte. The status byte appears starting at byte 1.
The host terminates an SPI transaction with the rising NSS signal. The host must not raise NSS within the bytes of a transaction. All parameters must be sent before raising NSS.
| Command | Opcode | Parameters | Description |
| SetSleep | 0x84 | sleepConfig | Set Chip in SLEEP mode |
| SetStandby | 0x80 | standbyConfig | Set Chip in STDBY_RC or STDBY_XOSC mode |
| SetFs | 0xC1 | - | Set Chip in Frequency Synthesis mode |
| SetTx | 0x83 | timeout[23:0] | Set Chip in Tx mode |
| SetRx | 0x82 | timeout[23:0] | Set Chip in Rx mode |
| SetCad | 0xC5 | - | Set chip in RX mode with CAD parameters |
| SetTxContinuousWave | 0xD1 | - | Test command: CW at selected frequency |
| SetRegulatorMode | 0x96 | regModeParam | Select LDO or DC_DC+LDO |
| Calibrate | 0x89 | calibParam | Calibrate RC13, RC64, ADC, PLL, Image |
| CalibrateImage | 0x98 | freq1, freq2 | Image calibration at given frequencies |
| SetPaConfig | 0x95 | paDutyCycle, HpMax, deviceSel, paLUT | Configure PA |
| SetRxTxFallbackMode | 0x93 | fallbackMode | Mode after TX/RX done |
| Command | Opcode | Parameters |
| WriteRegister | 0x0D | address[15:0], data[0:n] |
| ReadRegister | 0x1D | address[15:0] |
| WriteBuffer | 0x0E | offset, data[0:n] |
| ReadBuffer | 0x1E | offset |
| Command | Opcode | Parameters |
| SetDioIrqParams | 0x08 | IrqMask[15:0], Dio1Mask[15:0], Dio2Mask[15:0], Dio3Mask[15:0] |
| GetIrqStatus | 0x12 | - |
| ClearIrqStatus | 0x02 | ClearIrqParam[15:0] |
| SetDIO2AsRfSwitchCtrl | 0x9D | enable |
| SetDIO3AsTcxoCtrl | 0x97 | tcxoVoltage, timeout[23:0] |
| Command | Opcode | Parameters |
| SetRfFrequency | 0x86 | rfFreq[31:0] |
| SetPacketType | 0x8A | protocol |
| SetTxParams | 0x8E | power, rampTime |
| SetModulationParams | 0x8B | ModParam1..8 |
| SetPacketParams | 0x8C | (preamble, header, payload, crc, iq) |
| SetBufferBaseAddress | 0x8F | TX base address, RX base address |
| SetLoRaSymbNumTimeout | 0xA0 | SymbNum |
| Byte | 0 | 1 |
| Data from host | 0x80 | StdbyConfig |
StdbyConfig: 0 = STDBY_RC, 1 = STDBY_XOSC.
| Byte | 0 | 1-3 |
| Data from host | 0x83 | timeout[23:0] |
- Starting from STDBY_RC mode, the oscillator is switched ON followed by PLL, then the PA ramps up.
- When the last bit has been sent, an IRQ TX_DONE is generated, the PA ramps down, and the chip goes back to STDBY_RC mode.
- A TIMEOUT IRQ is triggered if TX_DONE is not generated within the timeout period.
- Timeout duration = Timeout * 15.625us
- Timeout = 0x000000: No timeout, device stays in TX until packet is transmitted and returns to STBY_RC.
| Byte | 0 | 1-3 |
| Data from host | 0x82 | timeout[23:0] |
| Timeout | Duration |
| 0x000000 | Single mode: stays in RX until reception, then returns to STBY_RC |
| 0xFFFFFF | Continuous mode: remains in RX until host sends a mode change command |
| Others | Timeout active: returns to STBY_RC on timeout or reception. Max timeout is 262s. |
| Byte | 0 | 1 |
| Data from host | 0x96 | regModeParam |
regModeParam: 0 = Only LDO, 1 = DC_DC+LDO (used for STBY_XOSC, FS, RX and TX modes).
| Byte | 0 | 1 |
| Data from host | 0x89 | calibParam |
calibParam is a bitmask: Bit 0=RC64k, 1=RC13M, 2=PLL, 3=ADC pulse, 4=ADC bulk N, 5=ADC bulk P, 6=Image. 0x7F = calibrate all. Total calibration time ~3.5ms. BUSY is high during calibration.
| Byte | 0 | 1 | 2 | 3 | 4 |
| Data from host | 0x95 | paDutyCycle | hpMax | deviceSel | paLut |
- deviceSel: 0 = SX1262, 1 = SX1261
- paLut: reserved, always 0x01
- For SX1262, paDutyCycle should not be higher than 0x04.
| Output Power | paDutyCycle | hpMax | deviceSel | paLut | SetTxParams power |
| +22dBm | 0x04 | 0x07 | 0x00 | 0x01 | +22dBm |
| +20dBm | 0x03 | 0x05 | 0x00 | 0x01 | +22dBm |
| +17dBm | 0x02 | 0x03 | 0x00 | 0x01 | +22dBm |
| +14dBm | 0x02 | 0x02 | 0x00 | 0x01 | +22dBm |
| Byte | 0 | 1 |
| Data from host | 0x93 | fallbackMode |
| Fallback Mode | Value | Description |
| FS | 0x40 | Go to FS mode after TX/RX |
| STDBY_XOSC | 0x30 | Go to STDBY_XOSC after TX/RX |
| STDBY_RC | 0x20 | Go to STDBY_RC after TX/RX (default) |
| Byte | 0 | 1 | 2 | 3 | … | n |
| MOSI | 0x0D | addr[15:8] | addr[7:0] | data@addr | … | data@addr+(n-3) |
| MISO | RFU | Status | Status | Status | … | Status |
| Byte | 0 | 1 | 2 | 3 | 4 | … |
| MOSI | 0x1D | addr[15:8] | addr[7:0] | NOP | NOP | … |
| MISO | RFU | Status | Status | Status | data@addr | … |
Note: The host must send an NOP after the 2 bytes of address to start receiving data bytes on the next NOP sent.
| Byte | 0 | 1 | 2 | … | n |
| MOSI | 0x0E | offset | data@offset | … | data@offset+(n-2) |
| MISO | RFU | Status | Status | … | Status |
| Byte | 0 | 1 | 2 | 3 | … |
| MOSI | 0x1E | offset | NOP | NOP | … |
| MISO | RFU | Status | Status | data@offset | … |
Note: An NOP must be sent after sending the offset.
| Byte | 0 | 1-2 | 3-4 | 5-6 | 7-8 |
| Data from host | 0x08 | IrqMask[15:0] | DIO1Mask[15:0] | DIO2Mask[15:0] | DIO3Mask[15:0] |
The interrupt causes a DIO to be set if the corresponding bit in DioxMask AND IrqMask are both set. For example, to route TxDone to DIO1: set bit 0 of both IrqMask and DIO1Mask.
| Byte | 0 | 1 | 2-3 |
| MOSI | 0x12 | NOP | NOP |
| MISO | RFU | Status | IrqStatus[15:0] |
| Byte | 0 | 1-2 |
| MOSI | 0x02 | ClearIrqParam[15:0] |
enable=1: DIO2 controls RF switch. DIO2=1 during TX, DIO2=0 otherwise.
| Byte | 0 | 1 | 2-4 |
| MOSI | 0x97 | tcxoVoltage | delay[23:0] |
| Value | Output Voltage |
| 0x00 | 1.6V |
| 0x01 | 1.7V |
| 0x02 | 1.8V |
| 0x03 | 2.2V |
| 0x06 | 3.0V |
| 0x07 | 3.3V |
Delay duration = delay[23:0] * 15.625us
The XOSC_START_ERR flag is raised at POR or wake-up from Sleep in cold-start condition when TCXO is used. This is expected and should be cleared with ClearDeviceErrors.
Note: The user should take the delay period into account when going into Tx or Rx mode from STDBY_RC mode, since the time needed to switch modes increases with the duration of delay.
| Byte | 0 | 1-4 |
| MOSI | 0x86 | RfFreq[31:0] |
RF_frequency = RF_Freq * F_XTAL / 2^25, where F_XTAL = 32 MHz.
To compute RF_Freq from Hz: RF_Freq = freq_hz * 2^25 / 32_000_000
| Byte | 0 | 1 | 2 |
| MOSI | 0x8E | power | RampTime |
power: -9 to +22 dBm (encoded as 0xF7 to 0x16) for high power PA (SX1262).
| RampTime | Value | Time (us) |
| SET_RAMP_10U | 0x00 | 10 |
| SET_RAMP_20U | 0x01 | 20 |
| SET_RAMP_40U | 0x02 | 40 |
| SET_RAMP_80U | 0x03 | 80 |
| SET_RAMP_200U | 0x04 | 200 |
| SET_RAMP_800U | 0x05 | 800 |
| Byte | 0 | 1 | 2 | 3 | 4 | 5-8 |
| MOSI | 0x8B | SF | BW | CR | LdOpt | unused (0x00) |
- ModParam1 = SF (Spreading Factor)
- ModParam2 = BW (Bandwidth)
- ModParam3 = CR (Coding Rate)
- ModParam4 = LdOpt (Low Data Rate Optimization)
| Byte | 0 | 1 |
| MOSI | 0xC0 | NOP |
| MISO | RFU | Status |
| Bit 7 | Bits 6:4 | Bits 3:1 | Bit 0 |
| Reserved | Chip mode | Command status | Reserved |
Chip mode:
| Value | Mode |
| 0x0 | Unused |
| 0x2 | STBY_RC |
| 0x3 | STBY_XOSC |
| 0x4 | FS |
| 0x5 | RX |
| 0x6 | TX |
Command status:
| Value | Meaning |
| 0x0 | Reserved |
| 0x2 | Data is available to host |
| 0x3 | Command timeout |
| 0x4 | Command processing error |
| 0x5 | Failure to execute command |
| 0x6 | Command TX done |
| Byte | 0 | 1 | 2 | 3 |
| MOSI | 0x13 | NOP | NOP | NOP |
| MISO | RFU | Status | PayloadLengthRx | RxStartBufferPointer |
| Byte | 0 | 1 | 2 | 3 | 4 |
| MOSI | 0x14 | NOP | NOP | NOP | NOP |
| MISO | RFU | Status | RssiPkt | SnrPkt | SignalRssiPkt |
- Actual signal power = -RssiPkt/2 (dBm)
- Actual SNR = SnrPkt/4 (dB)
Before any packet transmission, bit #2 at register address 0x0889 shall be set to:
- 0 if the LoRa BW = 500kHz
- 1 for any other LoRa BW or (G)FSK configuration
Must be applied before each packet transmission.
During chip initialization on the SX1262, the register TxClampConfig at address 0x08D8 should be modified. Bits 4-1 must be set to “1111” (default value “0100”).
value = ReadRegister(0x08D8)
value = value | 0x1E
WriteRegister(value, 0x08D8)
Must be done after POR or wake-up from cold start.
After ANY Rx with Timeout active sequence, stop the RTC and clear the timeout event:
WriteRegister(0x00, 0x0920)
value = ReadRegister(0x0944)
value = value | 0x02
WriteRegister(value, 0x0944)
Bit 2 at address 0x0736 must be set to:
- “0” when using inverted IQ polarity
- “1” when using standard IQ polarity
| Address | Name | Description |
| 0x0740 | LoRaSyncword | LoRa sync word (2 bytes, MSB first). 0x1424=private, 0x3444=public. |
| 0x0889 | TxModulation | BW500 workaround (bit 2) |
| 0x08AC | RxGain | 0x94=power saving (default), 0x96=boosted gain |
| 0x08D8 | TxClampConfig | PA clamp workaround (bits 4:1 = 0xF) |
| 0x0736 | IqPolarity | Inverted IQ workaround (bit 2) |
| 0x0902 | RtcControl | RTC stop (write 0x00 after Rx with timeout) |
| 0x0944 | EventMask | Clear timeout event (bit 1) |
| 0x029F | RetentionList count | Number of retention registers |
| 0x02A0-0x02A1 | RetentionList[0] | First retention register address (0x08AC) |
- Hardware reset (NRESET LOW 100us, HIGH, wait BUSY LOW)
- SetStandby(STBY_RC)
[0x80, 0x00]
- SetRegulatorMode(DC_DC)
[0x96, 0x01]
- SetDIO2AsRfSwitchCtrl(enable)
[0x9D, 0x01]
- ClearDeviceErrors
[0x07, 0x00, 0x00]
- SetDIO3AsTcxoCtrl(1.8V, timeout)
[0x97, 0x02, t2, t1, t0]
- Calibrate(all)
[0x89, 0x7F] — wait BUSY LOW (~3.5ms)
- CalibrateImage(863-870MHz)
[0x98, 0xD7, 0xDB]
- SetPacketType(LoRa)
[0x8A, 0x01]
- SetRfFrequency(freq)
[0x86, f3, f2, f1, f0]
- SetPaConfig(0x04, 0x07, 0x00, 0x01) for +22dBm SX1262
- SetTxParams(power, ramp)
[0x8E, pwr, ramp]
- SetBufferBaseAddress(0, 0)
[0x8F, 0x00, 0x00]
- SetModulationParams(SF, BW, CR, LDRO)
[0x8B, sf, bw, cr, ldro, 0,0,0,0]
- SetPacketParams(preamble, header, len, crc, iq)
[0x8C, ...]
- Write LoRa sync word to register 0x0740
- Apply workarounds: TxClamp (0x08D8), BW500 (0x0889), IQ (0x0736)
- Set RxGain to 0x96 (boosted) at register 0x08AC
- SetDioIrqParams(TxDone|Timeout on DIO1)
[0x08, mask_hi, mask_lo, dio1_hi, dio1_lo, 0,0, 0,0]
- ClearIrqStatus(all)
[0x02, 0xFF, 0xFF]
- WriteBuffer(0, payload)
[0x0E, 0x00, data...]
- SetTx(timeout)
[0x83, t2, t1, t0] — timeout=0 for no timeout
- Wait for DIO1 HIGH (TxDone IRQ)
- ClearIrqStatus(TxDone)
[0x02, 0x00, 0x01]
- SetDioIrqParams(RxDone|Timeout|CrcErr on DIO1)
- ClearIrqStatus(all)
[0x02, 0xFF, 0xFF]
- SetRx(timeout)
[0x82, t2, t1, t0]
- Wait for DIO1 HIGH
- GetIrqStatus — check RxDone vs Timeout vs CrcErr
- GetRxBufferStatus
[0x13, ...] — get length + start pointer
- ReadBuffer(start, length)
[0x1E, start, NOP, data...]
- GetPacketStatus
[0x14, ...] — get RSSI, SNR
- ClearIrqStatus
- Apply workaround 15.3 (stop RTC after Rx with timeout)