From 77bf17967dd4d99780c980755c31fd8fb8998c02 Mon Sep 17 00:00:00 2001 From: Tomer Abramovich Date: Tue, 21 Jan 2020 17:42:33 +0200 Subject: [PATCH 1/3] initial working version of R9M, 8 CH and BINDING support only --- Multiprotocol/FrSkyDVX_common.ino | 2 +- Multiprotocol/FrSkyR9_sx1276.ino | 238 ++++++++++++++++++++++++++++++ Multiprotocol/Multi_Names.ino | 5 + Multiprotocol/Multiprotocol.h | 1 + Multiprotocol/Multiprotocol.ino | 15 +- Multiprotocol/SX1276_SPI.ino | 38 +++++ Multiprotocol/_Config.h | 3 + 7 files changed, 299 insertions(+), 3 deletions(-) create mode 100644 Multiprotocol/FrSkyR9_sx1276.ino create mode 100644 Multiprotocol/SX1276_SPI.ino diff --git a/Multiprotocol/FrSkyDVX_common.ino b/Multiprotocol/FrSkyDVX_common.ino index 1674440..7bfc346 100644 --- a/Multiprotocol/FrSkyDVX_common.ino +++ b/Multiprotocol/FrSkyDVX_common.ino @@ -17,7 +17,7 @@ /** FrSky D and X routines **/ /******************************/ -#if defined(FRSKYX_CC2500_INO) || defined(FRSKY_RX_CC2500_INO) +#if defined(FRSKYX_CC2500_INO) || defined(FRSKY_RX_CC2500_INO) || defined(FRSKYR9_SX1276_INO) //**CRC** const uint16_t PROGMEM FrSkyX_CRC_Short[]={ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, diff --git a/Multiprotocol/FrSkyR9_sx1276.ino b/Multiprotocol/FrSkyR9_sx1276.ino new file mode 100644 index 0000000..471bfc2 --- /dev/null +++ b/Multiprotocol/FrSkyR9_sx1276.ino @@ -0,0 +1,238 @@ +#if defined(FRSKYR9_SX1276_INO) + +#define REG_IRQ_FLAGS_MASK 0x11 + +#define REG_PAYLOAD_LENGTH 0x22 + + +#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[] = +{ + 914472960, + 914972672, + 915472384, + 915972096, + 916471808, + 916971520, + 917471232, + 917970944, + 918470656, + 918970368, + 919470080, + 919969792, + 920469504, + 920969216, + 921468928, + 921968640, + 922468352, + 922968064, + 923467776, + 923967488, + 924467200, + 924966912, + 925466624, + 925966336, + 926466048, + 926965760, + 927465472, + + // last two determined by _step + 0, + 0 +}; + +static uint8_t _step = 1; + +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; +} + +uint16_t initFrSkyR9() +{ + set_rx_tx_addr(MProtocol_id_master); + + _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 + + uint8_t buffer[2]; + buffer[0] = 0x00; + buffer[1] = 0x00; + SX1276_WriteRegisterMulti(REG_DIO_MAPPING1, 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); + + // TODO this can probably be shorter + return 20000; // start calling FrSkyR9_callback in 20 milliseconds +} + +uint16_t FrSkyR9_callback() +{ + static uint16_t index = 0; + uint8_t buffer[3]; + + SX1276_WriteReg(REG_OP_MODE, 0x81); // STDBY + SX1276_WriteReg(REG_IRQ_FLAGS_MASK, 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) + + // SX1276_WriteReg(REG_PAYLOAD_LENGTH, 13); + + // SX1276_WriteReg(REG_FIFO_ADDR_PTR, 0x00); + + // SX1276_WriteReg(REG_OP_MODE, 0x85); // RXCONTINUOUS + // delay(10); // 10 ms + + // SX1276_WriteReg(REG_OP_MODE, 0x81); // STDBY + + SX1276_WriteReg(REG_PA_CONFIG, 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 + + 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[4] = _step; // step size and last 2 channels start index + payload[5] = RX_num; // receiver number from OpenTX + + // binding mode: 0x00 regular / 0x41 bind? + if(IS_BIND_IN_PROGRESS) + payload[6] = 0x41; + else + payload[6] = 0x00; + + // TODO + payload[7] = 0x00; // fail safe related (looks like the same sequence of numbers as FrskyX protocol) + + // two channel are spread over 3 bytes. + // each channel is 11 bit + 1 bit (msb) that states whether + // it's part of the upper channels (9-16) or lower (1-8) (0 - lower 1 - upper) + + const int payload_offset = 8; + const bool is_upper = false; + + int chan_index = 0; + + for(int i = 0; i < 8; i += 3) + { + // map channel values (0-2047) to (64-1984) + uint16_t ch1 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index]); + uint16_t ch2 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index + 1]); + + chan_index += 2; + + payload[payload_offset + i] = ch1; + + if(is_upper) + { + payload[payload_offset + i + 1] = ((ch1 >> 8) | 0b1000) | (ch2 << 4); + payload[payload_offset + i + 2] = (ch2 >> 4) | 0b10000000; + } + else + { + payload[payload_offset + i + 1] = ((ch1 >> 8) & 0b0111) | (ch2 << 4); + payload[payload_offset + i + 2] = (ch2 >> 4) & 0b01111111; + } + } + + payload[20] = 0x08; // ???? + payload[21] = 0x00; // ???? + payload[22] = 0x00; // ???? + payload[23] = 0x00; // ???? + + uint16_t crc = FrSkyX_crc(payload, 24); + + payload[24] = crc; // low byte + payload[25] = crc >> 8; // high byte + + // write payload to fifo + SX1276_WriteRegisterMulti(REG_FIFO, payload, 26); + + index = (index + _step) % 29; + + SX1276_WriteReg(REG_OP_MODE, 0x83); // TX + + // need to clear RegIrqFlags? + + return 19400; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/Multi_Names.ino b/Multiprotocol/Multi_Names.ino index 759906d..e4887ba 100644 --- a/Multiprotocol/Multi_Names.ino +++ b/Multiprotocol/Multi_Names.ino @@ -78,6 +78,7 @@ const char STR_PELIKAN[] ="Pelikan"; const char STR_TIGER[] ="Tiger"; const char STR_XK[] ="XK"; const char STR_XN297DUMP[] ="XN297DP"; +const char STR_FRSKYR9[] ="FrSkyR9"; const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20"; const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501"; @@ -118,6 +119,7 @@ const char STR_SUBTYPE_XN297DUMP[] = "\x07""250Kbps""1Mbps\0 ""2Mbps\0 ""Auto\0 const char STR_SUBTYPE_ESKY150[] = "\x03""4CH""7CH"; const char STR_SUBTYPE_V911S[] = "\x04""Std\0""E119"; const char STR_SUBTYPE_XK[] = "\x04""X450""X420"; +const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz"; enum { @@ -324,6 +326,9 @@ const mm_protocol_definition multi_protocols[] = { #endif #if defined(XN297DUMP_NRF24L01_INO) {PROTO_XN297DUMP, STR_XN297DUMP, 4, STR_SUBTYPE_XN297DUMP, OPTION_RFCHAN }, +#endif +#if defined(FRSKYR9_SX1276_INO) + {PROTO_FRSKY_R9, STR_FRSKYR9, 2, STR_SUBTYPE_FRSKYR9, OPTION_NONE }, #endif {0x00, nullptr, 0, nullptr, 0 } }; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index ffbf423..7f56565 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -91,6 +91,7 @@ enum PROTOCOLS PROTO_XK = 62, // =>NRF24L01 PROTO_XN297DUMP = 63, // =>NRF24L01 PROTO_FRSKYX2 = 64, // =>CC2500 + PROTO_FRSKY_R9 = 65 // =>SX1276 }; enum Flysky diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e9e2cef..233916f 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1504,6 +1504,14 @@ static void protocol_init() break; #endif #endif + #ifdef SX1276_INSTALLED + #if defined(FRSKYR9_SX1276_INO) + case PROTO_FRSKY_R9: + next_callback = initFrSkyR9(); + remote_callback = FrSkyR9_callback; + break; + #endif + #endif } debugln("Protocol selected: %d, sub proto %d, rxnum %d, option %d", protocol, sub_protocol, RX_num, option); #ifdef MULTI_NAMES @@ -1723,8 +1731,8 @@ void update_serial_data() else if( ((rx_ok_buff[1]&0x80)==0) && ((cur_protocol[1]&0x80)!=0) ) // Bind flag has been reset { // Request protocol to end bind - #if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO) - if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A ) + #if defined(FRSKYD_CC2500_INO) || defined(FRSKYX_CC2500_INO) || defined(FRSKYV_CC2500_INO) || defined(AFHDS2A_A7105_INO) || defined(FRSKYR9_SX1276_INO) + if(protocol==PROTO_FRSKYD || protocol==PROTO_FRSKYX || protocol==PROTO_FRSKYV || protocol==PROTO_AFHDS2A || protocol==PROTO_FRSKY_R9 ) BIND_DONE; else #endif @@ -1871,6 +1879,9 @@ void modules_reset() #ifdef NRF24L01_INSTALLED NRF24L01_Reset(); #endif + #ifdef SX1276_INSTALLED + SX1276_Reset(); + #endif //Wait for every component to reset delayMilliseconds(100); diff --git a/Multiprotocol/SX1276_SPI.ino b/Multiprotocol/SX1276_SPI.ino new file mode 100644 index 0000000..10b880a --- /dev/null +++ b/Multiprotocol/SX1276_SPI.ino @@ -0,0 +1,38 @@ +#ifdef SX1276_INSTALLED + +void SX1276_WriteReg(uint8_t address, uint8_t data) +{ + SPI_CSN_off; + SPI_Write(address | 0x80); // MSB 1 = write + NOP(); + SPI_Write(data); + SPI_CSN_on; +} + +uint8_t SX1276_ReadReg(uint8_t address) +{ + SPI_CSN_off; + SPI_Write(address & 0b01111111); + uint8_t result = SPI_Read(); + SPI_CSN_on; + + return result; +} + +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; +} + +uint8_t SX1276_Reset() +{ + //TODO + + return 0; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 731b5fd..bd42cc7 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -77,6 +77,7 @@ #define CYRF6936_INSTALLED #define CC2500_INSTALLED #define NRF24L01_INSTALLED +//#define SX1276_INSTALLED /** OrangeRX TX **/ //If you compile for the OrangeRX TX module you need to select the correct board type. @@ -223,6 +224,8 @@ #define YD717_NRF24L01_INO #define ZSX_NRF24L01_INO +//The protocols below need a SX1276 to be installed +//#define FRSKYR9_SX1276_INO /***************************/ /*** PROTOCOLS SETTINGS ***/ From 6f9740f03fb210e41bb063264b57e94883b2278b Mon Sep 17 00:00:00 2001 From: Tomer Abramovich Date: Thu, 23 Jan 2020 22:25:00 +0200 Subject: [PATCH 2/3] 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 From 945ad2e7bd58527c9244629a73e241576c940b26 Mon Sep 17 00:00:00 2001 From: Tomer Abramovich Date: Thu, 23 Jan 2020 22:29:57 +0200 Subject: [PATCH 3/3] now using FrSkyX_scaleForPXX to scale channel values for FrSky R9 instead of using floating point math --- Multiprotocol/FrSkyR9_sx1276.ino | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/FrSkyR9_sx1276.ino b/Multiprotocol/FrSkyR9_sx1276.ino index 04b447b..177ff90 100644 --- a/Multiprotocol/FrSkyR9_sx1276.ino +++ b/Multiprotocol/FrSkyR9_sx1276.ino @@ -174,8 +174,11 @@ uint16_t FrSkyR9_callback() for(int i = 0; i < 8; i += 3) { // map channel values (0-2047) to (64-1984) - uint16_t ch1 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index]); - uint16_t ch2 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index + 1]); + //uint16_t ch1 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index]); + //uint16_t ch2 = 64 + (uint16_t)((1920.0f / 2047.0f) * Channel_data[chan_index + 1]); + + uint16_t ch1 = FrSkyX_scaleForPXX(chan_index); + uint16_t ch2 = FrSkyX_scaleForPXX(chan_index + 1); chan_index += 2;