CC2500 spectrum analyzer

This commit is contained in:
Goebish 2019-09-04 13:57:07 +02:00
parent 13574c921a
commit c688d63b8f
5 changed files with 209 additions and 146 deletions

View File

@ -23,7 +23,7 @@
#include <avr/pgmspace.h>
//#define DEBUG_PIN // Use pin TX for AVR and SPI_CS for STM32 => DEBUG_PIN_on, DEBUG_PIN_off, DEBUG_PIN_toggle
//#define DEBUG_SERIAL // Only for STM32_BOARD, compiled with Upload method "Serial"->usart1, "STM32duino bootloader"->USB serial
#define DEBUG_SERIAL // Only for STM32_BOARD, compiled with Upload method "Serial"->usart1, "STM32duino bootloader"->USB serial
#ifdef __arm__ // Let's automatically select the board if arm is selected
#define STM32_BOARD
@ -998,6 +998,14 @@ static void protocol_init()
remote_callback = ReadHITEC;
break;
#endif
#if defined(SCANNER_CC2500_INO)
case PROTO_SCANNER:
PE1_off;
PE2_on; //antenna RF2
next_callback = initScanner();
remote_callback = Scanner_callback;
break;
#endif
#endif
#ifdef CYRF6936_INSTALLED
#if defined(DSM_CYRF6936_INO)
@ -1072,13 +1080,6 @@ static void protocol_init()
remote_callback = ReadTRAXXAS;
break;
#endif
#if defined(SCANNER_CYRF6936_INO)
case PROTO_SCANNER:
PE2_on; //antenna RF4
next_callback = initScanner();
remote_callback = Scanner_callback;
break;
#endif
#endif
#ifdef NRF24L01_INSTALLED
#if defined(HISKY_NRF24L01_INO)

View File

@ -0,0 +1,196 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#if defined(SCANNER_CC2500_INO)
// Ported from DeviationTX frequency scanner
#include "iface_cc2500.h"
struct Scanner {
uint8_t rssi[255];
uint8_t chan_min;
uint8_t chan_max;
uint16_t averaging;
} Scanner;
#define MIN_RADIOCHANNEL 0x00
#define MAX_RADIOCHANNEL 255 //0x62
#define CHANNEL_LOCK_TIME 300 // slow scan_channel requires 270 usec for synthesizer to settle
#define INTERNAL_AVERAGE 1
#define AVERAGE_INTVL 50
static int scan_averages, scan_channel, scan_state;
static uint32_t rssi_sum;
static uint8_t calibration[MAX_RADIOCHANNEL];
static uint8_t calibration_fscal2, calibration_fscal3;
enum ScanStates {
SCAN_CHANNEL_CHANGE = 0,
SCAN_GET_RSSI = 1,
};
static void __attribute__((unused)) Scanner_cc2500_init()
{
/* Initialize CC2500 chip */
/*CC2500_WriteReg(0x30, 0x3d); // soft reset
CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x00); // packet automation control
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x00); // packet automation control
CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); // scan_channel number
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x08); // frequency synthesizer control
CC2500_WriteReg(CC2500_0C_FSCTRL0, 0x00); // frequency synthesizer control
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // frequency control word, high byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // frequency control word, middle byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xDE); // frequency control word, low byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x86); // modem configuration
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x83); // modem configuration
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x00); // modem configuration FSK for better sensitivity
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // modem configuration
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xA4); // modem configuration
CC2500_WriteReg(CC2500_15_DEVIATN, 0x44); // modem deviation setting 38.085938
CC2500_WriteReg(CC2500_17_MCSM1, 0x0F); // always stay in RX mode
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // disable auto-calibration
CC2500_WriteReg(CC2500_19_FOCCFG, 0x16); // frequency offset compensation configuration
CC2500_WriteReg(CC2500_1A_BSCFG, 0x6C); // bit synchronization configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x03); // agc control
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x40); // agc control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0x91); // agc control
CC2500_WriteReg(CC2500_21_FREND1, 0x56); // front end rx configuration
CC2500_WriteReg(CC2500_22_FREND0, 0x10); // front end tx configuration
CC2500_WriteReg(CC2500_23_FSCAL3, 0xA9); // frequency synthesizer calibration
CC2500_WriteReg(CC2500_24_FSCAL2, 0x0A); // frequency synthesizer calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // frequency synthesizer calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // frequency synthesizer calibration
CC2500_WriteReg(CC2500_2C_TEST2, 0x88); // various test settings
CC2500_WriteReg(CC2500_2D_TEST1, 0x31); // various test settings
CC2500_WriteReg(CC2500_2E_TEST0, 0x0B); // various test settings
CC2500_WriteReg(CC2500_3E_PATABLE, 0xfe);
CC2500_SetTxRxMode(RX_EN); // Receive mode
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SRX);*/
CC2500_WriteReg(0x30, 0x3D); // software reset
CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x0F); // Frequency Synthesizer Control (0x0F)
CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x12); // Packet Automation Control (0x12)
CC2500_WriteReg(CC2500_0D_FREQ2, 0x5C); // Frequency control word, high byte
CC2500_WriteReg(CC2500_0E_FREQ1, 0x4E); // Frequency control word, middle byte
CC2500_WriteReg(CC2500_0F_FREQ0, 0xDE); // Frequency control word, low byte
CC2500_WriteReg(CC2500_10_MDMCFG4, 0x0D); // Modem Configuration
CC2500_WriteReg(CC2500_11_MDMCFG3, 0x3B); // Modem Configuration (0x3B)
CC2500_WriteReg(CC2500_12_MDMCFG2, 0x00); // Modem Configuration 0x30 - OOK modulation, 0x00 - FSK modulation (better sensitivity)
CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); // Modem Configuration
CC2500_WriteReg(CC2500_14_MDMCFG0, 0xFF); // Modem Configuration (0xFF)
CC2500_WriteReg(CC2500_17_MCSM1, 0x0F); // Always stay in RX mode
CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // Main Radio Control State Machine Configuration (0x04)
CC2500_WriteReg(CC2500_19_FOCCFG, 0x15); // Frequency Offset Compensation configuration
CC2500_WriteReg(CC2500_1B_AGCCTRL2, 0x83); // AGC Control (0x83)
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0x00); // AGC Control
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0x91); // AGC Control
CC2500_WriteReg(CC2500_23_FSCAL3, 0xEA); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_24_FSCAL2, 0x0A); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_25_FSCAL1, 0x00); // Frequency Synthesizer Calibration
CC2500_WriteReg(CC2500_26_FSCAL0, 0x11); // Frequency Synthesizer Calibration
CC2500_SetTxRxMode(RX_EN);
delayMicroseconds(1000); // wait for RX to activate
}
static void __attribute__((unused)) _calibrate()
{
for (int c = 0; c < MAX_RADIOCHANNEL; c++) {
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_0A_CHANNR, c);
CC2500_Strobe(CC2500_SCAL);
delayMicroseconds(900);
calibration[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
}
calibration_fscal3 = CC2500_ReadReg(CC2500_23_FSCAL3); // only needs to be done once
calibration_fscal2 = CC2500_ReadReg(CC2500_24_FSCAL2); // only needs to be done once
CC2500_Strobe(CC2500_SIDLE);
}
static void __attribute__((unused)) _scan_next()
{
CC2500_WriteReg(CC2500_0A_CHANNR, Scanner.chan_min + scan_channel);
CC2500_WriteReg(CC2500_23_FSCAL3, calibration_fscal3);
CC2500_WriteReg(CC2500_24_FSCAL2, calibration_fscal2);
CC2500_WriteReg(CC2500_25_FSCAL1, calibration[scan_channel]);
//debugln("_scan_next %d", Scanner.chan_min + scan_channel);
}
static int __attribute__((unused)) _scan_rssi()
{
uint8_t rssi = CC2500_ReadReg(0x40 | CC2500_34_RSSI); // 0.5 db/count, RSSI value read from the RSSI status register is a 2s complement number
debugln("rssi %d", rssi);
uint8_t rssi_rel;
if (rssi >= 128) {
rssi_rel = rssi - 128; // relative power levels 0-127 (equals -137 to -72 dBm)
}
else {
rssi_rel = rssi + 128; // relativ power levels 128-255 (equals -73 to -10 dBm)
}
return rssi_rel;
}
uint16 Scanner_callback()
{
int rssi_value;
switch (scan_state) {
case SCAN_CHANNEL_CHANGE:
scan_channel++;
if (scan_channel >= (Scanner.chan_max - Scanner.chan_min + 1))
scan_channel = 0;
_scan_next();
scan_state = SCAN_GET_RSSI;
return CHANNEL_LOCK_TIME;
case SCAN_GET_RSSI:
rssi_value = _scan_rssi();
scan_state = SCAN_CHANNEL_CHANGE;
// debugln("%d\t%d", scan_channel, CC2500_ReadReg(CC2500_34_RSSI));
// send data to TX
pkt[0] = scan_channel; // scan_channel
pkt[1] = rssi_value; // Scanner.rssi[scan_channel]; // power
telemetry_link = 1;
}
return AVERAGE_INTVL;
}
uint16_t initScanner(void)
{
Scanner.chan_min = 1;//MIN_RADIOCHANNEL;
Scanner.chan_max = 1;//MAX_RADIOCHANNEL;
scan_averages = 0;
scan_channel = 0;
scan_state = SCAN_CHANNEL_CHANGE;
memset(Scanner.rssi, 0, sizeof(Scanner.rssi)); // clear old rssi values
CC2500_Reset();
Scanner_cc2500_init();
CC2500_SetPower();
CC2500_Strobe(CC2500_SRX);
_calibrate();
CC2500_Strobe(CC2500_SFSTXON);
delayMicroseconds(800);
CC2500_Strobe(CC2500_SIDLE);
CC2500_Strobe(CC2500_SRX); // Receive mode
BIND_DONE;
return 1250;
}
#endif

View File

@ -1,134 +0,0 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#if defined(SCANNER_CYRF6936_INO)
// Ported from DeviationTX frequency scanner
#include "iface_cyrf6936.h"
struct Scanner {
uint8_t rssi[255];
uint8_t chan_min;
uint8_t chan_max;
uint8_t attenuator;
uint16_t averaging;
} Scanner;
#define MIN_RADIOCHANNEL 0x00
#define MAX_RADIOCHANNEL 0x62
#define CHANNEL_LOCK_TIME 300 // slow channel requires 270 usec for synthesizer to settle
#define AVERAGE_INTVL 30
static int scan_averages, scan_channel, scan_state;
enum ScanStates {
SCAN_CHANNEL_CHANGE = 0,
SCAN_GET_RSSI = 1,
};
static void __attribute__((unused)) Scanner_cyrf_init()
{
/* Initialize CYRF chip */
CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x38); // FRC SEN (forces the synthesizer to start) + FRC AWAKE (force the oscillator to keep running at all times)
CYRF_WriteRegister(CYRF_03_TX_CFG, 0x08 | 7); // Data Code Length = 32 chip codes + Data Mode = 8DR Mode + max-power(+4 dBm)
CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); // LNA + FAST TURN EN + RXOW EN, enable low noise amplifier, fast turning, overwrite enable
CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00); // Reset power control
CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4); // SOP EN + SOP LEN = 32 chips + LEN EN + SOP TH = 04h
CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05); // TH32 = 0x05
CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E); // TH64 = 0Eh, set pn correlation threshold
CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); // STRIM LSB = 0x55, typical configuration
CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); // STRIM MSB = 0x05, typical configuration
CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C); // AUTO_CAL_TIME = 3Ch, typical configuration
CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); // AUTO_CAL_OFFSET = 14h, typical configuration
CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01); // ALL SLOW
CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10); // FRC RXDR (Force Receive Data Rate)
CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); // Reset TX overrides
CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10); // TX Length = 16 byte packet
CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02); // RXF, force receive clock
CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); // RXF, force receive clock enable
}
static void __attribute__((unused)) _scan_next()
{
CYRF_ConfigRFChannel(scan_channel + Scanner.chan_min);
switch (Scanner.attenuator) {
case 0: CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); break; // LNA on, ATT off
case 1: CYRF_WriteRegister(CYRF_06_RX_CFG, 0x0A); break; // LNA off, ATT off
default: CYRF_WriteRegister(CYRF_06_RX_CFG, 0x2A); break; // LNA off, no ATT on
}
}
static int __attribute__((unused)) _scan_rssi()
{
if (!(CYRF_ReadRegister(CYRF_05_RX_CTRL) & 0x80)) {
CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x80); // Prepare to receive
delayMicroseconds(1);
CYRF_ReadRegister(CYRF_13_RSSI); // dummy read
delayMicroseconds(1);
}
return CYRF_ReadRegister(CYRF_13_RSSI) & 0x1F;
}
uint16 Scanner_callback()
{
int rssi_value;
switch (scan_state) {
case SCAN_CHANNEL_CHANGE:
scan_averages = 0;
scan_channel++;
if (scan_channel == (Scanner.chan_max - Scanner.chan_min + 1))
scan_channel = 0;
_scan_next();
scan_state = SCAN_GET_RSSI;
return CHANNEL_LOCK_TIME;
case SCAN_GET_RSSI:
rssi_value = _scan_rssi();
Scanner.rssi[scan_channel] = (rssi_value + 9 * Scanner.rssi[scan_channel]) / 10; // fast exponential smoothing with alpha 0.1
scan_averages++;
if (scan_averages < Scanner.averaging)
return AVERAGE_INTVL + random(0xfefefefe) % 10; // make measurements slightly random in time
scan_state = SCAN_CHANNEL_CHANGE;
// send data to TX
pkt[0] = scan_channel; // channel
pkt[1] = Scanner.rssi[scan_channel]; // power
telemetry_link = 1;
return AVERAGE_INTVL;
}
}
uint16_t initScanner(void)
{
Scanner.chan_min = MIN_RADIOCHANNEL;
Scanner.chan_max = MAX_RADIOCHANNEL;
// todo: find optimal values or use user options
Scanner.averaging = 2;
Scanner.attenuator = 0;
scan_averages = 0;
scan_channel = 0;
scan_state = SCAN_CHANNEL_CHANGE;
memset(Scanner.rssi, 0, sizeof(Scanner.rssi)); // clear old rssi values
CYRF_Reset();
Scanner_cyrf_init();
CYRF_SetTxRxMode(RX_EN); // Receive mode
BIND_DONE;
return 1250;
}
#endif

View File

@ -177,7 +177,6 @@
#undef WFLY_CYRF6936_INO
#undef WK2x01_CYRF6936_INO
#undef TRAXXAS_CYRF6936_INO
#undef SCANNER_CYRF6936_INO
#endif
#ifndef CC2500_INSTALLED
#undef FRSKYD_CC2500_INO
@ -188,6 +187,7 @@
#undef REDPINE_CC2500_INO
#undef HITEC_CC2500_INO
#undef XN297L_CC2500_EMU
#undef SCANNER_CC2500_INO
#endif
#ifndef NRF24L01_INSTALLED
#undef BAYANG_NRF24L01_INO

View File

@ -23,7 +23,7 @@
//If you know parameters you want for sure to be enabled or disabled which survives in future, you can use a file named "_MyConfig.h".
//An example is given within the file named "_MyConfig.h.example" which needs to be renamed if you want to use it.
//To enable this config file remove the // from the line below.
//#define USE_MY_CONFIG
#define USE_MY_CONFIG
/*************************/
@ -32,7 +32,7 @@
//Allow flashing multimodule directly with TX(erky9x or opentx maintenance mode)
//Instructions:https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/docs/Flash_from_Tx.md
//To disable this feature add "//" at the begining of the next line. Requires a compatible bootloader or upload method to be selected when you use the Multi 4-in-1 Boards Manager definitions.
#define CHECK_FOR_BOOTLOADER
//#define CHECK_FOR_BOOTLOADER
/*******************/
@ -168,7 +168,6 @@
#define TRAXXAS_CYRF6936_INO
#define WFLY_CYRF6936_INO
#define WK2x01_CYRF6936_INO
#define SCANNER_CYRF6936_INO
//The protocols below need a CC2500 to be installed
#define CORONA_CC2500_INO
@ -178,6 +177,7 @@
#define HITEC_CC2500_INO
#define SFHSS_CC2500_INO
#define REDPINE_CC2500_INO
#define SCANNER_CC2500_INO
//The protocols below need a NRF24L01 to be installed
#define ASSAN_NRF24L01_INO