kopia lustrzana https://github.com/open-ham/OpenGD77
398 wiersze
14 KiB
C
398 wiersze
14 KiB
C
/*
|
|
* Copyright (C)2019 Roger Clark, VK3KYY / G4KYF
|
|
* and Kai Ludwig, DG4KLU
|
|
*
|
|
* This program 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 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include "utils.h"
|
|
#include "functions/calibration.h"
|
|
#include "functions/trx.h"
|
|
|
|
static const uint32_t CALIBRATION_BASE = 0xF000;
|
|
|
|
const int MAX_PA_DAC_VALUE = 4095;
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t DigitalRxGainNarrowband_NOTCONFIRMED; // IF Gain, RX Fine
|
|
uint16_t DigitalTxGainNarrowband_NOTCONFIRMED; // IF Gain, TX Fine (hidden in cal window)
|
|
uint16_t DigitalRxGainWideband_NOTCONFIRMED; // IF Gain, RX Coarse
|
|
uint16_t DigitalTxGainWideband_NOTCONFIRMED; // IF Gain, TX Coarse (hidden in cal window)
|
|
|
|
uint16_t DACOscRefTune; // DAC word for frequency reference oscillator
|
|
|
|
uint8_t QMod2Offset;
|
|
|
|
/* Power settings
|
|
* UHF 400 to 475 in 5Mhz stps (16 steps)
|
|
* VHF 136Mhz, then 140MHz - 165Mhz in steps of 5Mhz, then 172Mhz (8 steps - upper 8 array entries contain 0xff )
|
|
*/
|
|
uint8_t PowerSettings[16][2];
|
|
|
|
uint8_t UnknownBlock3[8]; // Unknown
|
|
|
|
uint8_t UknownBlock9[8]; // Note
|
|
|
|
uint8_t UnknownBlock4[4]; // Seems to contain 0x00 on both VHF and UHF. Potentially unused
|
|
|
|
uint8_t AnalogSquelchThresholds[8]; // Different values on VHF and UHF byt all in the range 0x12 - 0x1D
|
|
|
|
// Analog Squelch controls
|
|
uint8_t Noise1ThresholdWideband[2];
|
|
uint8_t Noise2ThresholdWideband[2];
|
|
uint8_t RSSI3ThresholdWideband[2];
|
|
|
|
uint8_t Noise1ThresholdNarrowband[2];
|
|
uint8_t Noise2ThresholdNarrowband[2];
|
|
uint8_t RSSI3ThresholdNarrowband[2];
|
|
|
|
uint8_t RSSILowerThreshold;
|
|
uint8_t RSSIUpperThreshold;
|
|
|
|
/*
|
|
* VHF 136Mhz , 140Mhz - 165Mhz (in 5Mhz steps), 172Mhz
|
|
* UHF 405Mhz - 475Mhz (in 10Mhz steps)
|
|
*/
|
|
uint8_t Dmr4FskDeviation[8]; // Controls the DMR 4FSK deviation produced by the C6000 chip
|
|
|
|
uint8_t DigitalRxAudioGainAndBeepVolume; // The Rx audio gain and the beep volume seem linked together. 0x1D on VHF and UHF
|
|
|
|
// CAL_DEV_DTMF = 0, CAL_DEV_TONE = 1, CAL_DEV_CTCSS_WIDE = 2,CAL_DEV_CTCSS_NARROW = 3, CAL_DEV_DCS_WIDE = 4, CAL_DEV_DCS_NARROW = 5
|
|
uint8_t AnalogTxDeviations[6];
|
|
|
|
uint8_t PaDrvIBit;
|
|
uint8_t PgaGain;
|
|
|
|
uint8_t AnalogMicGain; // Both wide and narrow band
|
|
uint8_t ReceiveAGCGainTarget; // Receiver AGC target. Higher values give more gain. Reducing this may improve receiver overload with strong signals, but would reduce sensitivity
|
|
|
|
uint16_t AnalogTxOverallDeviationWideband; // CTCSS, DCS, DTMF & voice, deviation .Normally a very low value like 0x0027
|
|
uint16_t AnalogTxOverallDeviationNarrowband; // CTCSS, DCS, DTMF & voice, deviation .Normally a very low value like 0x0027
|
|
|
|
// Not sure why there are 2 of these and what the difference is.
|
|
uint8_t AnalogRxAudioGainWideband; // normally a 0x0F
|
|
uint8_t AnalogRxAudioGainNarrowband; // normally a 0x0F
|
|
|
|
uint8_t UnknownBlock7[2];
|
|
} CalibrationBandData_t;
|
|
|
|
typedef struct
|
|
{
|
|
CalibrationBandData_t band[CalibrationBandMAX];
|
|
} CalibrationData_t;
|
|
|
|
|
|
#define CALIBRATION_TABLE_LENGTH 0xE0 // Calibration table is 224 bytes long
|
|
static __attribute__((section(".data.$RAM2"))) CalibrationData_t calibrationData;
|
|
|
|
|
|
bool calibrationInit(void)
|
|
{
|
|
return (SPI_Flash_read(CALIBRATION_BASE, (uint8_t *)&calibrationData, CALIBRATION_TABLE_LENGTH));
|
|
}
|
|
|
|
bool calibrationGetSectionData(CalibrationBand_t band, CalibrationSection_t section, CalibrationDataResult_t *o)
|
|
{
|
|
switch(section)
|
|
{
|
|
/*
|
|
* Sent to HRC6000 register 0x37. This sets the DMR received Audio Gain. (And Beep Volume)
|
|
* Effective for DMR Receive Only.
|
|
* only the low 4 bits are used. 1.5dB change per increment 0-331
|
|
*/
|
|
case CalibrationSection_DACDATA_SHIFT:
|
|
o->value = SAFE_MIN(calibrationData.band[band].DigitalRxAudioGainAndBeepVolume + 1, 31);
|
|
o->value |= 0x80;
|
|
break;
|
|
|
|
/*
|
|
* Sent to HRC6000 register 0x47 and 0x48 to set the DC level of the Mod1 output. This sets the frequency of the AT1846 Reference Oscillator.
|
|
* Effective for DMR and FM Receive and Transmit. Calibrates the receive and transmit frequencies.
|
|
* Only one setting should be required for all frequencies but the Cal table has separate entries for VHF and UHF.
|
|
*/
|
|
case CalibrationSection_TWOPOINT_MOD:
|
|
o->value = calibrationData.band[band].DACOscRefTune;
|
|
break;
|
|
|
|
/*
|
|
*
|
|
* Sent to the HRC6000 register 0x04 which is the offset value for the Mod 2 output.
|
|
* However according to the schematics the Mod 2 output is not connected.
|
|
* Therefore the function of this setting is unclear. (possible datasheet error?)
|
|
*
|
|
*/
|
|
case CalibrationSection_Q_MOD2_OFFSET:
|
|
// The Cal table has one entry for each band and this is almost identical to 0x47 above.
|
|
o->value = calibrationData.band[band].QMod2Offset;
|
|
break;
|
|
|
|
/*
|
|
* Sent to the HRC6000 register 0x46. This adjusts the level of the DMR Modulation on the MOD1 output.
|
|
* Mod 1 controls the AT1846 Reference oscillator so this is effectively the deviation setting for DMR.
|
|
* Because it modulates the reference oscillator the deviation will change depending on the frequency being used.
|
|
*
|
|
* Only affects DMR Transmit. The Cal table has 8 calibration values for each band.
|
|
*/
|
|
case CalibrationSection_PHASE_REDUCE:
|
|
if (o->offset >= 8)
|
|
{
|
|
o->value = 0;
|
|
return false;
|
|
}
|
|
o->value = calibrationData.band[band].Dmr4FskDeviation[o->offset];
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x0a bits 6-10. Sets Voice Analogue Gain for FM Transmit.
|
|
*/
|
|
case CalibrationSection_PGA_GAIN:
|
|
o->value = (calibrationData.band[band].PgaGain & 0x1F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x41 bits 0-6. Sets Voice Digital Gain for FM Transmit.
|
|
*/
|
|
case CalibrationSection_VOICE_GAIN_TX:
|
|
o->value = (calibrationData.band[band].AnalogMicGain & 0x7F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x44 bits 8-11. Sets Voice Digital Gain after ADC for FM Transmit.
|
|
*/
|
|
case CalibrationSection_GAIN_TX:
|
|
o->value = (calibrationData.band[band].ReceiveAGCGainTarget & 0x0F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x0a bits 11-14. Sets PA Power Control for DMR and FM Transmit
|
|
*/
|
|
case CalibrationSection_PADRV_IBIT:
|
|
o->value = (calibrationData.band[band].PaDrvIBit & 0x0F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x59 bits 6-15. Sets Deviation for Wideband FM Transmit
|
|
*/
|
|
case CalibrationSection_XMITTER_DEV_WIDEBAND:
|
|
o->value = (calibrationData.band[band].AnalogTxOverallDeviationWideband & 0x03FF);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x59 bits 6-15. Sets Deviation for NarrowBand FM Transmit
|
|
*/
|
|
case CalibrationSection_XMITTER_DEV_NARROWBAND:
|
|
o->value = (calibrationData.band[band].AnalogTxOverallDeviationNarrowband & 0x03FF);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x59 bits 0-5. Sets Tones Deviation for FM Transmit
|
|
*/
|
|
case CalibrationSection_DEV_TONE:
|
|
if (o->offset >= 6)
|
|
{
|
|
o->value = 0;
|
|
return false;
|
|
}
|
|
o->value = calibrationData.band[band].AnalogTxDeviations[o->offset];
|
|
break;
|
|
|
|
/*
|
|
* Sets Digital Audio Gain for FM and DMR Receive.
|
|
* Sent to AT1846S register 0x44 bits 0-3.
|
|
*/
|
|
case CalibrationSection_DAC_VGAIN_ANALOG:
|
|
o->value = (calibrationData.band[band].AnalogRxAudioGainWideband & 0x0F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x44 bits 4-7.
|
|
* Sets Analog Audio Gain for FM and DMR Receive.
|
|
*/
|
|
case CalibrationSection_VOLUME_ANALOG:
|
|
o->value = (calibrationData.band[band].AnalogRxAudioGainNarrowband & 0x0F);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x48. Sets Noise 1 Threshold for FM Wideband Receive.
|
|
*/
|
|
case CalibrationSection_NOISE1_TH_WIDEBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].Noise1ThresholdWideband[0] & 0x7F) << 7) + ((calibrationData.band[band].Noise1ThresholdWideband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x48. Sets Noise 1 Threshold for FM Narrowband Receive.
|
|
*/
|
|
case CalibrationSection_NOISE1_TH_NARROWBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].Noise1ThresholdNarrowband[0] & 0x7F) << 7) + ((calibrationData.band[band].Noise1ThresholdNarrowband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x60. Sets Noise 2 Threshold for FM Wideband Receive.
|
|
*/
|
|
case CalibrationSection_NOISE2_TH_WIDEBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].Noise2ThresholdWideband[0] & 0x7F) << 7) + ((calibrationData.band[band].Noise2ThresholdWideband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x60. Sets Noise 2 Threshold for FM Narrowband Receive.
|
|
*/
|
|
case CalibrationSection_NOISE2_TH_NARROWBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].Noise2ThresholdNarrowband[0] & 0x7F) << 7) + ((calibrationData.band[band].Noise2ThresholdNarrowband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x3F. Sets RSSI3 Threshold for Wideband Receive.
|
|
*/
|
|
case CalibrationSection_RSSI3_TH_WIDEBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].RSSI3ThresholdWideband[0] & 0x7F) << 7) + ((calibrationData.band[band].RSSI3ThresholdWideband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* Sent to AT1846S register 0x3F. Sets RSSI3 Threshold for Narrowband Receive.
|
|
*/
|
|
case CalibrationSection_RSSI3_TH_NARROWBAND:
|
|
// that bitmask looks weird
|
|
o->value = ((calibrationData.band[band].RSSI3ThresholdNarrowband[0] & 0x7F) << 7) + ((calibrationData.band[band].RSSI3ThresholdNarrowband[1] & 0x7F) << 0);
|
|
break;
|
|
|
|
/*
|
|
* THE DESCRIPTION OF THIS FUNCTION IS WRONG
|
|
*
|
|
* Sent to At1846S register 0x49. sets squelch open threshold for FM Receive.
|
|
* 8 Cal Table Entries for each band. Frequency Dependent.
|
|
*/
|
|
case CalibrationSection_SQUELCH_TH:
|
|
if (o->offset >= 8)
|
|
{
|
|
o->value = 0;
|
|
return false;
|
|
}
|
|
uint8_t v1 = calibrationData.band[band].AnalogSquelchThresholds[o->offset] - o->mod;
|
|
uint8_t v2 = calibrationData.band[band].AnalogSquelchThresholds[o->offset] - o->mod - 3;
|
|
if ((v1 >= 127) || (v2 >= 127) || (v1 < v2))
|
|
{
|
|
v1 = 24;
|
|
v2 = 21;
|
|
}
|
|
o->value = (v1 << 7) + (v2 << 0);
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void calibrationGetPowerForFrequency(int freq, calibrationPowerValues_t *powerSettings)
|
|
{
|
|
CalibrationBand_t band;
|
|
int offset;
|
|
int limit;
|
|
|
|
if (trxCurrentBand[TRX_TX_FREQ_BAND] == RADIO_BAND_UHF)
|
|
{
|
|
band = CalibrationBandUHF;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_UHF].calTableMinFreq) / 500000;
|
|
limit = 15;
|
|
}
|
|
else
|
|
{
|
|
band = CalibrationBandVHF;
|
|
offset = (freq - RADIO_HARDWARE_FREQUENCY_BANDS[RADIO_BAND_VHF].calTableMinFreq) / 500000;
|
|
limit = 7;
|
|
}
|
|
|
|
offset = CLAMP(offset, 0, limit);
|
|
|
|
powerSettings->lowPower = (calibrationData.band[band].PowerSettings[offset][0] * MAX_PA_DAC_VALUE) / 255;// PA drive DAC is 12 bit (0 - 4095). Calibration data range is 0 - 255
|
|
powerSettings->highPower = (calibrationData.band[band].PowerSettings[offset][1] * MAX_PA_DAC_VALUE) / 255;// PA drive DAC is 12 bit (0 - 4095). Calibration data range is 0 - 255
|
|
}
|
|
|
|
bool calibrationGetRSSIMeterParams(calibrationRSSIMeter_t *rssiMeterValues)
|
|
{
|
|
CalibrationBand_t band = ((trxCurrentBand[TRX_RX_FREQ_BAND] == RADIO_BAND_UHF) ? CalibrationBandUHF : CalibrationBandVHF);
|
|
|
|
memcpy((uint8_t *)rssiMeterValues, (&calibrationData.band[band].RSSILowerThreshold), 2);
|
|
// OR
|
|
//rssiMeterValues->minVal = calibrationData.band[band].RSSILowerThreshold;
|
|
//rssiMeterValues->rangeVal = calibrationData.band[band].RSSIUpperThreshold;
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* This function is used to check if the calibration table has been copied to the common location
|
|
* 0xF000 and if not, to copy it to that location in the external Flash memory
|
|
*/
|
|
bool calibrationCheckAndCopyToCommonLocation(bool forceReload)
|
|
{
|
|
#if defined(PLATFORM_GD77) || defined(PLATFORM_GD77S)
|
|
|
|
const uint32_t VARIANT_CALIBRATION_BASE = 0x0008F000;
|
|
const int MARKER_BYTES_LENGTH = 8;
|
|
const uint8_t MARKER_BYTES[] = {0xA0 ,0x0F ,0xC0 ,0x12 ,0xA0 ,0x0F ,0xC0 ,0x12};
|
|
|
|
#elif defined(PLATFORM_DM1801)
|
|
|
|
const uint32_t VARIANT_CALIBRATION_BASE = 0x0006F000;
|
|
const int MARKER_BYTES_LENGTH = 2;
|
|
const uint8_t MARKER_BYTES[] = {0xA0 ,0x0F};// DM-1801 only seems to consistently have the first 2 bytes the same.
|
|
|
|
#elif defined(PLATFORM_RD5R)
|
|
|
|
const uint32_t VARIANT_CALIBRATION_BASE = 0x0008F000; // Found by marker bytes matching
|
|
const int MARKER_BYTES_LENGTH = 2;
|
|
const uint8_t MARKER_BYTES[] = {0xA0 ,0x0F};// ,0x50 ,0x14 ,0xA0 ,0x0F ,0x50 ,0x14};
|
|
|
|
#endif
|
|
|
|
uint8_t tmp[CALIBRATION_TABLE_LENGTH];
|
|
|
|
if (SPI_Flash_read(CALIBRATION_BASE, (uint8_t *)tmp, MARKER_BYTES_LENGTH))
|
|
{
|
|
|
|
if (!forceReload && (memcmp(MARKER_BYTES, tmp, MARKER_BYTES_LENGTH) == 0))
|
|
{
|
|
// found calibration table in common location.
|
|
return true;
|
|
}
|
|
// Need to copy the calibration
|
|
|
|
if (SPI_Flash_read(VARIANT_CALIBRATION_BASE, (uint8_t *)tmp, CALIBRATION_TABLE_LENGTH))
|
|
{
|
|
if (memcmp(MARKER_BYTES, tmp, MARKER_BYTES_LENGTH) == 0)
|
|
{
|
|
// found calibration table in variant location.
|
|
if (SPI_Flash_write(CALIBRATION_BASE, tmp, CALIBRATION_TABLE_LENGTH))
|
|
{
|
|
// Update current calibration data with the calibration data that just been read
|
|
memcpy(&calibrationData, tmp, CALIBRATION_TABLE_LENGTH);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false; // Something went wrong!
|
|
}
|