From a5120ffddc696ddee5fc95a2737fc6496c9260bb Mon Sep 17 00:00:00 2001 From: Silvano Seva Date: Fri, 5 Mar 2021 21:17:48 +0100 Subject: [PATCH] Radio driver for MD-UV3x0 targets --- meson.build | 7 +- openrtx/src/rtx.c | 30 +-- platform/drivers/baseband/AT1846S_UV3x0.c | 3 +- platform/drivers/baseband/radio_UV3x0.c | 218 ++++++++++++++++++++-- platform/targets/MD-3x0/hwconfig.h | 8 +- platform/targets/MD-UV380/hwconfig.h | 6 + 6 files changed, 240 insertions(+), 32 deletions(-) diff --git a/meson.build b/meson.build index 5b5a379d..f6a9af4c 100644 --- a/meson.build +++ b/meson.build @@ -179,8 +179,11 @@ mduv380_src = src + stm32f405_src + ['platform/drivers/display/HX8353_MDx.cpp', 'platform/drivers/ADC/ADC1_MDx.c', 'platform/drivers/tones/toneGenerator_MDx.c', 'platform/drivers/baseband/radio_UV3x0.c', - 'platform/drivers/GPS/GPS_MDx.cpp', - 'platform/targets/MD-UV380/platform.c'] + 'platform/drivers/GPS/GPS_MDx.c', + 'platform/targets/MD-UV380/platform.c', + 'platform/drivers/baseband/AT1846S_UV3x0.c', + 'platform/drivers/baseband/HR_C6000_UV3x0.c', + 'platform/drivers/baseband/interfaces_UV3x0.c'] mduv380_inc = inc + stm32f405_inc + ['platform/targets/MD-UV380'] mduv380_def = def + stm32f405_def + {'PLATFORM_MDUV380': ''} diff --git a/openrtx/src/rtx.c b/openrtx/src/rtx.c index e80fec95..4603fe69 100644 --- a/openrtx/src/rtx.c +++ b/openrtx/src/rtx.c @@ -43,13 +43,15 @@ float rssi; /* Current RSSI in dBm */ void _afCtrlInit() { - #if defined(PLATFORM_MD3x0) + #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV380) gpio_setMode(SPK_MUTE, OUTPUT); - gpio_setMode(AMP_EN, OUTPUT); - gpio_setMode(FM_MUTE, OUTPUT); + gpio_setMode(AUDIO_AMP_EN, OUTPUT); gpio_setMode(MIC_PWR, OUTPUT); + #ifdef PLATFORM_MD3x0 + gpio_setMode(FM_MUTE, OUTPUT); + #endif #elif defined(PLATFORM_GD77) || defined(PLATFORM_DM1801) - gpio_setMode(AUDIO_AMP_EN, OUTPUT); + gpio_setMode(AUDIO_AUDIO_AMP_EN, OUTPUT); #endif } @@ -57,20 +59,24 @@ void _afCtrlSpeaker(bool enable) { if(enable) { - #if defined(PLATFORM_MD3x0) - gpio_setPin(AMP_EN); - gpio_setPin(FM_MUTE); + #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV380) + gpio_setPin(AUDIO_AMP_EN); gpio_clearPin(SPK_MUTE); + #ifdef PLATFORM_MD3x0 + gpio_setPin(FM_MUTE); + #endif #elif defined(PLATFORM_GD77) || defined(PLATFORM_DM1801) gpio_setPin(AUDIO_AMP_EN); #endif } else { - #if defined(PLATFORM_MD3x0) - gpio_clearPin(AMP_EN); - gpio_clearPin(FM_MUTE); + #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV380) + gpio_clearPin(AUDIO_AMP_EN); gpio_setPin(SPK_MUTE); + #ifdef PLATFORM_MD3x0 + gpio_clearPin(FM_MUTE); + #endif #elif defined(PLATFORM_GD77) || defined(PLATFORM_DM1801) gpio_clearPin(AUDIO_AMP_EN); #endif @@ -81,13 +87,13 @@ void _afCtrlMic(bool enable) { if(enable) { - #if defined(PLATFORM_MD3x0) + #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV380) gpio_setPin(MIC_PWR); #endif } else { - #if defined(PLATFORM_MD3x0) + #if defined(PLATFORM_MD3x0) || defined(PLATFORM_MDUV380) gpio_clearPin(MIC_PWR); #endif } diff --git a/platform/drivers/baseband/AT1846S_UV3x0.c b/platform/drivers/baseband/AT1846S_UV3x0.c index 38792dc6..346827b0 100644 --- a/platform/drivers/baseband/AT1846S_UV3x0.c +++ b/platform/drivers/baseband/AT1846S_UV3x0.c @@ -187,7 +187,7 @@ void AT1846S_setOpMode(const AT1846S_op_t mode) { if(mode == AT1846S_OP_DMR) { - /* DMR mode */ + /* TODO: DMR mode */ } else @@ -213,6 +213,7 @@ void AT1846S_setFuncMode(const AT1846S_func_t mode) uint16_t value = ((uint16_t) mode) << 5; if(value > 0x0040) return; _maskSetRegister(0x30, 0x0060, value); +// i2c_writeReg16(0x44, 0x4ff); } void AT1846S_enableTxCtcss(tone_t freq) diff --git a/platform/drivers/baseband/radio_UV3x0.c b/platform/drivers/baseband/radio_UV3x0.c index 42d190c3..b032aa0c 100644 --- a/platform/drivers/baseband/radio_UV3x0.c +++ b/platform/drivers/baseband/radio_UV3x0.c @@ -18,68 +18,260 @@ * along with this program; if not, see * ***************************************************************************/ +#include #include +#include +#include +#include +#include +#include "HR_C6000.h" +#include "AT1846S.h" + +const mduv3x0Calib_t *calData; /* Pointer to calibration data */ + +int8_t currRxBand = -1; /* Current band for RX */ +int8_t currTxBand = -1; /* Current band for TX */ +uint8_t txpwr_lo = 0; /* APC voltage for TX output power control, low power */ +uint8_t txpwr_hi = 0; /* APC voltage for TX output power control, high power */ +tone_t tx_tone = 0; +tone_t rx_tone = 0; + +enum opmode currOpMode; /* Current operating mode, needed for TX control */ + +/** + * \internal + * Function to identify the current band (VHF or UHF), given an input frequency. + * + * @param freq frequency in Hz. + * @return 0 if the frequency is in the VHF band, + * 1 if the frequency is in the UHF band, + * -1 if the band to which the frequency belongs is neither VHF nor UHF. + */ +int8_t _getBandFromFrequency(freq_t freq) +{ + if((freq >= FREQ_LIMIT_VHF_LO) && (freq <= FREQ_LIMIT_VHF_HI)) return 0; + if((freq >= FREQ_LIMIT_UHF_LO) && (freq <= FREQ_LIMIT_UHF_HI)) return 1; + return -1; +} void radio_init() { + /* + * Load calibration data + */ + calData = ((const mduv3x0Calib_t *) platform_getCalibrationData()); + /* + * Configure RTX GPIOs + */ + gpio_setMode(VHF_LNA_EN, OUTPUT); + gpio_setMode(UHF_LNA_EN, OUTPUT); + gpio_setMode(PA_EN_1, OUTPUT); + gpio_setMode(PA_EN_2, OUTPUT); + gpio_setMode(PA_SEL_SW, OUTPUT); + + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(PA_EN_1); + gpio_clearPin(PA_EN_2); + gpio_clearPin(PA_SEL_SW); + + /* TODO: keep audio connected to HR_C6000, for volume control */ + gpio_setMode(RX_AUDIO_MUX, OUTPUT); + gpio_setPin(RX_AUDIO_MUX); + + /* + * Configure and enable DAC + */ + gpio_setMode(APC_REF, INPUT_ANALOG); + + RCC->APB1ENR |= RCC_APB1ENR_DACEN; + DAC->CR = DAC_CR_EN1; + DAC->DHR12R1 = 0; + + /* + * Configure AT1846S and HR_C6000 + */ + AT1846S_init(); + C6000_init(); } void radio_terminate() { - + radio_disableRtx(); + C6000_terminate(); } void radio_setBandwidth(const enum bandwidth bw) { - (void) bw; + switch(bw) + { + case BW_12_5: + AT1846S_setBandwidth(AT1846S_BW_12P5); + break; + + case BW_20: + case BW_25: + AT1846S_setBandwidth(AT1846S_BW_25); + break; + + default: + break; + } } void radio_setOpmode(const enum opmode mode) { - (void) mode; + currOpMode = mode; + switch(mode) + { + case FM: + AT1846S_setOpMode(AT1846S_OP_FM); + C6000_fmMode(); + break; + + case DMR: + AT1846S_setOpMode(AT1846S_OP_DMR); + C6000_dmrMode(); + break; + + default: + break; + } } void radio_setVcoFrequency(const freq_t frequency, const bool isTransmitting) { - (void) frequency; (void) isTransmitting; + AT1846S_setFrequency(frequency); } void radio_setCSS(const tone_t rxCss, const tone_t txCss) { - (void) rxCss; - (void) txCss; + rx_tone = rxCss; + tx_tone = txCss; } bool radio_checkRxDigitalSquelch() { - return false; + return true; } void radio_enableRx() { + gpio_clearPin(PA_EN_1); + gpio_clearPin(PA_EN_2); + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + DAC->DHR12R1 = 0; + if(currRxBand < 0) return; + + AT1846S_setFuncMode(AT1846S_RX); + + if(currRxBand == 0) + { + gpio_setPin(VHF_LNA_EN); + } + else + { + gpio_setPin(UHF_LNA_EN); + } } void radio_enableTx(const float txPower, const bool enableCss) { - (void) txPower; - (void) enableCss; + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(PA_EN_1); + gpio_clearPin(PA_EN_2); + + if(currTxBand < 0) return; + + /* + * TODO: increase granularity + */ + uint8_t power = (txPower > 1.0f) ? txpwr_hi : txpwr_lo; + DAC->DHR12L1 = power * 0xFF; + + if(currOpMode == FM) + { + C6000_startAnalogTx(); + } + + AT1846S_setFuncMode(AT1846S_TX); + + gpio_setPin(PA_EN_1); + + if(currTxBand == 0) + { + gpio_clearPin(PA_SEL_SW); + } + else + { + gpio_setPin(PA_SEL_SW); + } + + gpio_setPin(PA_EN_2); + + if(enableCss) + { + AT1846S_enableTxCtcss(tx_tone); + } } void radio_disableRtx() { - + gpio_clearPin(VHF_LNA_EN); + gpio_clearPin(UHF_LNA_EN); + gpio_clearPin(PA_EN_1); + gpio_clearPin(PA_EN_2); + AT1846S_disableCtcss(); + AT1846S_setFuncMode(AT1846S_OFF); + C6000_stopAnalogTx(); } -void radio_updateCalibrationParams(const rtxStatus_t* rtxCfg) +void radio_updateCalibrationParams(const rtxStatus_t *rtxCfg) { - (void) rtxCfg; + currRxBand = _getBandFromFrequency(rtxCfg->rxFrequency); + currTxBand = _getBandFromFrequency(rtxCfg->txFrequency); + + if((currRxBand < 0) || (currTxBand < 0)) return; + + /* TCXO bias voltage */ + uint8_t modBias = calData->vhfCal.freqAdjustMid; + if(currRxBand > 0) modBias = calData->uhfCal.freqAdjustMid; + C6000_setModOffset(modBias); + + freq_t *txCalPoints = calData->vhfCal.txFreq; + uint8_t *loPwrCal = calData->vhfCal.txLowPower; + uint8_t *hiPwrCal = calData->vhfCal.txLowPower; + uint8_t *qRangeCal = (rtxCfg->opMode == FM) ? + calData->vhfCal.analogSendQrange : calData->vhfCal.sendQrange; + + if(currTxBand > 0) + { + txCalPoints = calData->uhfCal.txFreq; + loPwrCal = calData->uhfCal.txLowPower; + hiPwrCal = calData->uhfCal.txLowPower; + qRangeCal = (rtxCfg->opMode == FM) ? calData->uhfCal.analogSendQrange + : calData->uhfCal.sendQrange; + } + + /* APC voltage for TX output power control */ + txpwr_lo = interpCalParameter(rtxCfg->txFrequency, txCalPoints, loPwrCal, 9); + txpwr_hi = interpCalParameter(rtxCfg->txFrequency, txCalPoints, hiPwrCal, 9); + + /* HR_C6000 modulation amplitude */ + uint8_t Q = interpCalParameter(rtxCfg->txFrequency, txCalPoints, qRangeCal, 9); + C6000_setModAmplitude(0, Q); } float radio_getRssi(const freq_t rxFreq) { (void) rxFreq; - return -100.0f; + + uint16_t val = AT1846S_readRSSI(); + int8_t rssi = -151 + (val >> 8); + return ((float) rssi); } diff --git a/platform/targets/MD-3x0/hwconfig.h b/platform/targets/MD-3x0/hwconfig.h index 2e8869cb..2f04fbee 100644 --- a/platform/targets/MD-3x0/hwconfig.h +++ b/platform/targets/MD-3x0/hwconfig.h @@ -139,10 +139,10 @@ #define MOD2_BIAS GPIOA,5 /* Audio control */ -#define AMP_EN GPIOB,9 -#define SPK_MUTE GPIOB,8 -#define FM_MUTE GPIOE,13 -#define MIC_PWR GPIOA,14 +#define AUDIO_AMP_EN GPIOB,9 +#define SPK_MUTE GPIOB,8 +#define FM_MUTE GPIOE,13 +#define MIC_PWR GPIOA,14 /* GPS, for the devices who have it */ #define GPS_EN GPIOD,8 diff --git a/platform/targets/MD-UV380/hwconfig.h b/platform/targets/MD-UV380/hwconfig.h index 7f55ece1..b3425860 100644 --- a/platform/targets/MD-UV380/hwconfig.h +++ b/platform/targets/MD-UV380/hwconfig.h @@ -108,6 +108,8 @@ /* Audio control */ #define AUDIO_AMP_EN GPIOB,9 #define SPK_MUTE GPIOB,8 +#define MIC_PWR GPIOA,13 +#define RX_AUDIO_MUX GPIOD,9 /* GPS, for the devices who have it */ #define GPS_EN GPIOA,9 @@ -116,6 +118,10 @@ /* RTX stage control */ #define VHF_LNA_EN GPIOA,5 #define UHF_LNA_EN GPIOA,2 +#define PA_EN_1 GPIOC,5 +#define PA_EN_2 GPIOC,4 +#define PA_SEL_SW GPIOC,6 +#define APC_REF GPIOA,4 /* I2C for AT1846S */ #define I2C_SDA GPIOC,9