From 77bf17967dd4d99780c980755c31fd8fb8998c02 Mon Sep 17 00:00:00 2001 From: Tomer Abramovich Date: Tue, 21 Jan 2020 17:42:33 +0200 Subject: [PATCH] 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 ***/