From 6f9740f03fb210e41bb063264b57e94883b2278b Mon Sep 17 00:00:00 2001 From: Tomer Abramovich Date: Thu, 23 Jan 2020 22:25:00 +0200 Subject: [PATCH] moved register definitions to a different file and created higher level functions for using them; added preliminary support for 868 MHz mode, not fully working yet --- Multiprotocol/FrSkyR9_sx1276.ino | 179 ++++++++++++++----------------- Multiprotocol/SX1276_SPI.ino | 143 +++++++++++++++++++++++- Multiprotocol/iface_sx1276.h | 90 ++++++++++++++++ 3 files changed, 310 insertions(+), 102 deletions(-) create mode 100644 Multiprotocol/iface_sx1276.h diff --git a/Multiprotocol/FrSkyR9_sx1276.ino b/Multiprotocol/FrSkyR9_sx1276.ino index 471bfc2..04b447b 100644 --- a/Multiprotocol/FrSkyR9_sx1276.ino +++ b/Multiprotocol/FrSkyR9_sx1276.ino @@ -1,41 +1,11 @@ #if defined(FRSKYR9_SX1276_INO) +#include "iface_sx1276.h" -#define REG_IRQ_FLAGS_MASK 0x11 +#define FREQ_MAP_SIZE 29 -#define REG_PAYLOAD_LENGTH 0x22 +// TODO the channel spacing is equal, consider calculating the new channel instead of using lookup tables (first_chan + index * step) - -#define REG_FIFO_ADDR_PTR 0x0D -#define REG_FIFO_TX_BASE_ADDR 0x0E - -#define REG_OP_MODE 0x01 -#define REG_DETECT_OPTIMIZE 0x31 -#define REG_DIO_MAPPING1 0x40 -#define REG_VERSION 0x42 - - -#define REG_MODEM_CONFIG1 0x1D -#define REG_MODEM_CONFIG2 0x1E -#define REG_MODEM_CONFIG3 0x26 - -#define REG_PREAMBLE_LSB 0x21 -#define REG_DETECTION_THRESHOLD 0x37 - -#define REG_LNA 0x0C - -#define REG_HOP_PERIOD 0x24 - -#define REG_PA_DAC 0x4D - -#define REG_PA_CONFIG 0x09 - -#define REG_FRF_MSB 0x06 - -#define REG_FIFO 0x00 - -#define REG_OCP 0x0B - -static uint32_t _freq_map[] = +static uint32_t _freq_map_915[FREQ_MAP_SIZE] = { 914472960, 914972672, @@ -70,58 +40,74 @@ static uint32_t _freq_map[] = 0 }; -static uint8_t _step = 1; +static uint32_t _freq_map_868[FREQ_MAP_SIZE] = +{ + 859504640, + 860004352, + 860504064, + 861003776, + 861503488, + 862003200, + 862502912, + 863002624, + 863502336, + 864002048, + 864501760, + 865001472, + 865501184, + 866000896, + 866500608, + 867000320, + 867500032, + 867999744, + 868499456, + 868999168, + 869498880, + 869998592, + 870498304, + 870998016, + 871497728, + 871997440, + 872497152, -static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_temp( uint8_t i ) -{ //mapped 860,2140(125%) range to 64,1984(PXX values); - uint16_t chan_val=convert_channel_frsky(i)-1226; - if(i>7) chan_val|=2048; // upper channels offset - return chan_val; -} + // last two determined by _step + 0, + 0 +}; + +static uint8_t _step = 1; +static uint32_t* _freq_map = _freq_map_915; uint16_t initFrSkyR9() { set_rx_tx_addr(MProtocol_id_master); + if(sub_protocol == 0) // 915MHz + _freq_map = _freq_map_915; + else if(sub_protocol == 1) // 868MHz + _freq_map = _freq_map_868; + _step = 1 + (random(0xfefefefe) % 24); _freq_map[27] = _freq_map[_step]; _freq_map[28] = _freq_map[_step+1]; - SX1276_WriteReg(REG_OP_MODE, 0x80); // sleep - SX1276_WriteReg(REG_OP_MODE, 0x81); // standby + SX1276_SetMode(true, false, SX1276_OPMODE_SLEEP); + SX1276_SetMode(true, false, SX1276_OPMODE_STDBY); - uint8_t buffer[2]; - buffer[0] = 0x00; - buffer[1] = 0x00; - SX1276_WriteRegisterMulti(REG_DIO_MAPPING1, buffer, 2); + // uint8_t buffer[2]; + // buffer[0] = 0x00; + // buffer[1] = 0x00; + // SX1276_WriteRegisterMulti(SX1276_40_DIOMAPPING1, buffer, 2); - uint8_t val = SX1276_ReadReg(REG_DETECT_OPTIMIZE); - val = (val & 0b11111000) | 0b00000101; - SX1276_WriteReg(REG_DETECT_OPTIMIZE, val); - - // val = SX1276_ReadReg(REG_MODEM_CONFIG2); - // val = (val & 0b00011111) | 0b11000000; - // writeRegister(REG_MODEM_CONFIG2, val); - - SX1276_WriteReg(REG_MODEM_CONFIG1, 0x93); - - SX1276_WriteReg(REG_MODEM_CONFIG2, 0x60); - - val = SX1276_ReadReg(REG_MODEM_CONFIG3); - val = (val & 0b11110011); - SX1276_WriteReg(REG_MODEM_CONFIG3, val); - - SX1276_WriteReg(REG_PREAMBLE_LSB, 9); - - SX1276_WriteReg(REG_DETECTION_THRESHOLD, 0x0C); - - SX1276_WriteReg(REG_LNA, 0x23); - - SX1276_WriteReg(REG_HOP_PERIOD, 0x00); - - val = SX1276_ReadReg(REG_PA_DAC); - val = (val & 0b11111000) | 0b00000111; - SX1276_WriteReg(REG_PA_DAC, val); + SX1276_SetDetectOptimize(true, SX1276_DETECT_OPTIMIZE_SF6); + SX1276_ConfigModem1(SX1276_MODEM_CONFIG1_BW_500KHZ, SX1276_MODEM_CONFIG1_CODING_RATE_4_5, true); + SX1276_ConfigModem2(6, false, false); + SX1276_ConfigModem3(false, false); + SX1276_SetPreambleLength(9); + SX1276_SetDetectionThreshold(SX1276_MODEM_DETECTION_THRESHOLD_SF6); + SX1276_SetLna(1, true); + SX1276_SetHopPeriod(0); // 0 = disabled, we hope frequencies manually + SX1276_SetPaDac(true); // TODO this can probably be shorter return 20000; // start calling FrSkyR9_callback in 20 milliseconds @@ -129,47 +115,41 @@ uint16_t initFrSkyR9() uint16_t FrSkyR9_callback() { - static uint16_t index = 0; - uint8_t buffer[3]; + static uint16_t freq_hop_index = 0; + + SX1276_SetMode(true, false, SX1276_OPMODE_STDBY); - SX1276_WriteReg(REG_OP_MODE, 0x81); // STDBY - SX1276_WriteReg(REG_IRQ_FLAGS_MASK, 0xbf); // use only RxDone interrupt + //SX1276_WriteReg(SX1276_11_IRQFLAGSMASK, 0xbf); // use only RxDone interrupt - buffer[0] = 0x00; - buffer[1] = 0x00; - SX1276_WriteRegisterMulti(REG_DIO_MAPPING1, buffer, 2); // RxDone interrupt mapped to DIO0 (the rest are not used because of the REG_IRQ_FLAGS_MASK) + // uint8_t buffer[2]; + // buffer[0] = 0x00; + // buffer[1] = 0x00; + // SX1276_WriteRegisterMulti(SX1276_40_DIOMAPPING1, buffer, 2); // RxDone interrupt mapped to DIO0 (the rest are not used because of the REG_IRQ_FLAGS_MASK) // SX1276_WriteReg(REG_PAYLOAD_LENGTH, 13); // SX1276_WriteReg(REG_FIFO_ADDR_PTR, 0x00); - // SX1276_WriteReg(REG_OP_MODE, 0x85); // RXCONTINUOUS + // SX1276_WriteReg(SX1276_01_OPMODE, 0x85); // RXCONTINUOUS // delay(10); // 10 ms - // SX1276_WriteReg(REG_OP_MODE, 0x81); // STDBY + // SX1276_WriteReg(SX1276_01_OPMODE, 0x81); // STDBY - SX1276_WriteReg(REG_PA_CONFIG, 0xF0); + //SX1276_WriteReg(SX1276_09_PACONFIG, 0xF0); - uint32_t freq = _freq_map[index] / 61; - - buffer[0] = (freq & (0xFF << 16)) >> 16; - buffer[1] = (freq & (0xFF << 8)) >> 8; - buffer[2] = freq & 0xFF; - - SX1276_WriteRegisterMulti(REG_FRF_MSB, buffer, 3); // set current center frequency + // max power: 15dBm (10.8 + 0.6 * MaxPower [dBm]) + // output_power: 2 dBm (17-(15-OutputPower) (if pa_boost_pin == true)) + SX1276_SetPaConfig(true, 7, 0); + SX1276_SetFrequency(_freq_map[freq_hop_index]); // set current center frequency delayMicroseconds(500); - SX1276_WriteReg(REG_PAYLOAD_LENGTH, 26); - SX1276_WriteReg(REG_FIFO_TX_BASE_ADDR, 0x00); - SX1276_WriteReg(REG_FIFO_ADDR_PTR, 0x00); - uint8_t payload[26]; payload[0] = 0x3C; // ???? payload[1] = rx_tx_addr[3]; // unique radio id payload[2] = rx_tx_addr[2]; // unique radio id - payload[3] = index; // current channel index + payload[3] = freq_hop_index; // current channel index payload[4] = _step; // step size and last 2 channels start index payload[5] = RX_num; // receiver number from OpenTX @@ -223,12 +203,11 @@ uint16_t FrSkyR9_callback() payload[24] = crc; // low byte payload[25] = crc >> 8; // high byte - // write payload to fifo - SX1276_WriteRegisterMulti(REG_FIFO, payload, 26); + SX1276_WritePayloadToFifo(payload, 26); - index = (index + _step) % 29; + freq_hop_index = (freq_hop_index + _step) % FREQ_MAP_SIZE; - SX1276_WriteReg(REG_OP_MODE, 0x83); // TX + SX1276_SetMode(true, false, SX1276_OPMODE_TX); // need to clear RegIrqFlags? diff --git a/Multiprotocol/SX1276_SPI.ino b/Multiprotocol/SX1276_SPI.ino index 10b880a..3b6c49c 100644 --- a/Multiprotocol/SX1276_SPI.ino +++ b/Multiprotocol/SX1276_SPI.ino @@ -1,4 +1,5 @@ #ifdef SX1276_INSTALLED +#include "iface_sx1276.h" void SX1276_WriteReg(uint8_t address, uint8_t data) { @@ -12,19 +13,21 @@ void SX1276_WriteReg(uint8_t address, uint8_t data) uint8_t SX1276_ReadReg(uint8_t address) { SPI_CSN_off; - SPI_Write(address & 0b01111111); + SPI_Write(address & 0x7F); uint8_t result = SPI_Read(); SPI_CSN_on; return result; } -void SX1276_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length) +void SX1276_WriteRegisterMulti(uint8_t address, const uint8_t* data, uint8_t length) { SPI_CSN_off; SPI_Write(address | 0x80); // MSB 1 = write + for(uint8_t i = 0; i < length; i++) SPI_Write(data[i]); + SPI_CSN_on; } @@ -35,4 +38,140 @@ uint8_t SX1276_Reset() return 0; } +void SX1276_SetFrequency(uint32_t frequency) +{ + uint32_t f = frequency / 61; + uint8_t data[3]; + data[0] = (f & (0xFF << 16)) >> 16; + data[1] = (f & (0xFF << 8)) >> 8; + data[2] = f & 0xFF; + + SX1276_WriteRegisterMulti(SX1276_06_FRFMSB, data, 3); +} + +void SX1276_SetMode(bool lora, bool low_freq_mode, uint8_t mode) +{ + uint8_t data = 0x00; + + if(lora) + { + data = data | (1 << 7); + data = data & ~(1 << 6); + } + else + { + data = data & ~(1 << 7); + data = data | (1 << 6); + } + + if(low_freq_mode) + data = data | (1 << 3); + + data = data | mode; + + SX1276_WriteReg(SX1276_01_OPMODE, data); +} + +void SX1276_SetDetectOptimize(bool auto_if, uint8_t detect_optimize) +{ + uint8_t data = SX1276_ReadReg(SX1276_31_DETECTOPTIMIZE); + data = (data & 0b01111000) | detect_optimize; + data = data | (auto_if << 7); + + SX1276_WriteReg(SX1276_31_DETECTOPTIMIZE, data); +} + +void SX1276_ConfigModem1(uint8_t bandwidth, uint8_t coding_rate, bool implicit_header_mode) +{ + uint8_t data = 0x00; + data = data | (bandwidth << 4); + data = data | (coding_rate << 1); + data = data | implicit_header_mode; + + SX1276_WriteReg(SX1276_1D_MODEMCONFIG1, data); +} + +void SX1276_ConfigModem2(uint8_t spreading_factor, bool tx_continuous_mode, bool rx_payload_crc_on) +{ + uint8_t data = SX1276_ReadReg(SX1276_1E_MODEMCONFIG2); + data = data & 0b11; // preserve the last 2 bits + data = data | (spreading_factor << 4); + data = data | (tx_continuous_mode << 3); + data = data | (rx_payload_crc_on << 2); + + SX1276_WriteReg(SX1276_1E_MODEMCONFIG2, data); +} + +void SX1276_ConfigModem3(bool low_data_rate_optimize, bool agc_auto_on) +{ + uint8_t data = SX1276_ReadReg(SX1276_26_MODEMCONFIG3); + data = data & 0b11; // preserve the last 2 bits + data = data | (low_data_rate_optimize << 3); + data = data | (agc_auto_on << 2); + + SX1276_WriteReg(SX1276_26_MODEMCONFIG3, data); +} + +void SX1276_SetPreambleLength(uint16_t length) +{ + uint8_t data[2]; + data[0] = (length >> 8) & 0xFF; // high byte + data[1] = length & 0xFF; // low byte + + SX1276_WriteRegisterMulti(SX1276_20_PREAMBLEMSB, data, 2); +} + +void SX1276_SetDetectionThreshold(uint8_t threshold) +{ + SX1276_WriteReg(SX1276_37_DETECTIONTHRESHOLD, threshold); +} + +void SX1276_SetLna(uint8_t gain, bool high_freq_lna_boost) +{ + uint8_t data = SX1276_ReadReg(SX1276_0C_LNA); + data = data & 0b100; // preserve the third bit + data = data | (gain << 5); + + if(high_freq_lna_boost) + data = data | 0b11; + + SX1276_WriteReg(SX1276_0C_LNA, data); +} + +void SX1276_SetHopPeriod(uint8_t freq_hop_period) +{ + SX1276_WriteReg(SX1276_24_HOPPERIOD, freq_hop_period); +} + +void SX1276_SetPaDac(bool on) +{ + uint8_t data = SX1276_ReadReg(SX1276_4D_PADAC); + data = data & 0b11111000; // preserve the upper 5 bits + + if(on) + data = data | 0x07; + else + data = data | 0x04; + + SX1276_WriteReg(SX1276_4D_PADAC, data); +} + +void SX1276_SetPaConfig(bool pa_boost_pin, uint8_t max_power, uint8_t output_power) +{ + uint8_t data = 0x00; + data = data | (pa_boost_pin << 7); + data = data | (max_power << 4); + data = data | output_power; + + SX1276_WriteReg(SX1276_09_PACONFIG, data); +} + +void SX1276_WritePayloadToFifo(uint8_t* payload, uint8_t length) +{ + SX1276_WriteReg(SX1276_22_PAYLOAD_LENGTH, length); + SX1276_WriteReg(SX1276_0E_FIFOTXBASEADDR, 0x00); + SX1276_WriteReg(SX1276_0D_FIFOADDRPTR, 0x00); + SX1276_WriteRegisterMulti(SX1276_00_FIFO, payload, length); +} + #endif \ No newline at end of file diff --git a/Multiprotocol/iface_sx1276.h b/Multiprotocol/iface_sx1276.h new file mode 100644 index 0000000..bd69896 --- /dev/null +++ b/Multiprotocol/iface_sx1276.h @@ -0,0 +1,90 @@ +/* + This project is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Multiprotocol is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Multiprotocol. If not, see . + */ + +#ifndef _IFACE_SX1276_H_ +#define _IFACE_SX1276_H_ + +enum +{ + SX1276_00_FIFO = 0x00, + SX1276_01_OPMODE = 0x01, + SX1276_06_FRFMSB = 0x06, + SX1276_09_PACONFIG = 0x09, + SX1276_0B_OCP = 0x0B, + SX1276_0C_LNA = 0x0C, + SX1276_0D_FIFOADDRPTR = 0x0D, + SX1276_0E_FIFOTXBASEADDR = 0x0E, + SX1276_11_IRQFLAGSMASK = 0x11, + SX1276_1D_MODEMCONFIG1 = 0x1D, + SX1276_1E_MODEMCONFIG2 = 0x1E, + SX1276_20_PREAMBLEMSB = 0x20, + SX1276_22_PAYLOAD_LENGTH = 0x22, + SX1276_24_HOPPERIOD = 0x24, + SX1276_26_MODEMCONFIG3 = 0x26, + SX1276_31_DETECTOPTIMIZE = 0x31, + SX1276_37_DETECTIONTHRESHOLD = 0x37, + SX1276_40_DIOMAPPING1 = 0x40, + SX1276_42_VERSION = 0x42, + SX1276_4D_PADAC = 0x4D +}; + +enum +{ + SX1276_OPMODE_SLEEP = 0, + SX1276_OPMODE_STDBY, + SX1276_OPMODE_FSTX, + SX1276_OPMODE_TX, + SX1276_OPMODE_FSRX, + SX1276_OPMODE_RXCONTINUOUS, + SX1276_OPMODE_RXSINGLE, + SX1276_OPMODE_CAD +}; + +enum +{ + SX1276_DETECT_OPTIMIZE_SF7_TO_SF12 = 0x03, + SX1276_DETECT_OPTIMIZE_SF6 = 0x05 +}; + +enum +{ + SX1276_MODEM_CONFIG1_BW_7_8KHZ = 0, + SX1276_MODEM_CONFIG1_BW_10_4KHZ, + SX1276_MODEM_CONFIG1_BW_15_6KHZ, + SX1276_MODEM_CONFIG1_BW_20_8KHZ, + SX1276_MODEM_CONFIG1_BW_31_25KHZ, + SX1276_MODEM_CONFIG1_BW_41_7KHZ, + SX1276_MODEM_CONFIG1_BW_62_5KHZ, + SX1276_MODEM_CONFIG1_BW_125KHZ, + SX1276_MODEM_CONFIG1_BW_250KHZ, + SX1276_MODEM_CONFIG1_BW_500KHZ +}; + +enum +{ + SX1276_MODEM_CONFIG1_CODING_RATE_4_5 = 1, + SX1276_MODEM_CONFIG1_CODING_RATE_4_6, + SX1276_MODEM_CONFIG1_CODING_RATE_4_7, + SX1276_MODEM_CONFIG1_CODING_RATE_4_8 +}; + +enum +{ + SX1276_MODEM_DETECTION_THRESHOLD_SF7_TO_SF12 = 0x0A, + SX1276_MODEM_DETECTION_THRESHOLD_SF6 = 0x0C, + +}; + +#endif