330 lines
9.7 KiB
C
330 lines
9.7 KiB
C
/* -*- mode: c; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4; coding: utf-8 -*- */
|
|
/************************************************************************************
|
|
** **
|
|
** UHSDR **
|
|
** a powerful firmware for STM32 based SDR transceivers **
|
|
** **
|
|
**---------------------------------------------------------------------------------**
|
|
** **
|
|
** File name: **
|
|
** Description: **
|
|
** Last Modified: **
|
|
** Licence: GNU GPLv3 **
|
|
************************************************************************************/
|
|
|
|
//
|
|
// SI570 frequency shift table
|
|
// 0-100 degrees C range
|
|
// shots from 20m band (56Mhz)
|
|
//
|
|
// This frequency compensation table referenced to 14.000 MHz by KA7OEI, 10/14 using
|
|
// a GPS reference in a temperature-controlled environment, extrapolated below 17C and above
|
|
// 70C.
|
|
//
|
|
// Temperature normalized to 43C, a temperature achieved very soon after power-up
|
|
// with both the Si570 and the temperature sensor thermally bonded.
|
|
//
|
|
// Note: The exact frequency/temperature dependencies will likely vary from unit to unit
|
|
// for each Si570, but the values below appear to approximately follow typical AT-cut
|
|
// temperature-frequency curves.
|
|
//
|
|
#include "uhsdr_board.h"
|
|
#include "soft_tcxo.h"
|
|
#include "radio_management.h"
|
|
#include "uhsdr_hw_i2c.h"
|
|
|
|
LoTcxo lo;
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
// Temperature sensor
|
|
// ------------------
|
|
#define MCP_ADDR (0x90)
|
|
|
|
// MCP registers
|
|
#define MCP_TEMP (0x00)
|
|
#define MCP_CONFIG (0x01)
|
|
#define MCP_HYSTR (0x02)
|
|
#define MCP_LIMIT (0x03)
|
|
|
|
// MCP CONFIG register bits
|
|
#define MCP_ONE_SHOT (7)
|
|
#define MCP_ADC_RES (5)
|
|
#define MCP_FAULT_QUEUE (3)
|
|
#define MCP_ALERT_POL (2)
|
|
#define MCP_INT_MODE (1)
|
|
#define MCP_SHUTDOWN (0)
|
|
#define R_BIT (1)
|
|
#define W_BIT (0)
|
|
|
|
#define MCP_ADC_RES_9 0
|
|
#define MCP_ADC_RES_10 1
|
|
#define MCP_ADC_RES_11 2
|
|
#define MCP_ADC_RES_12 3
|
|
|
|
#define MCP_POWER_UP 0
|
|
#define MCP_POWER_DOWN 1
|
|
|
|
static int32_t MCP9801_ConvExternalTemp(uint8_t *temp)
|
|
{
|
|
int32_t ts = 0;
|
|
|
|
ts = temp[1];
|
|
|
|
ts += (int8_t)temp[0] << 8;
|
|
ts *= 10000;
|
|
ts /= 256;
|
|
|
|
return ts;
|
|
}
|
|
|
|
|
|
/*
|
|
* @brief configures the MCP9801 external temperature sensor for monitoring Si570 temperature
|
|
* @returns 0 if detected and working, 1 if not detected on I2C, 2 for other errors
|
|
*/
|
|
static uint8_t MCP9801_InitExternalTempSensor(void)
|
|
{
|
|
uint8_t config, retval = 0;
|
|
uint16_t res;
|
|
|
|
// Read config reg
|
|
res = UhsdrHw_I2C_ReadRegister(MCP_I2C, MCP_ADDR, MCP_CONFIG, 1, &config);
|
|
if(res != 0)
|
|
{
|
|
retval = 1;
|
|
}
|
|
else
|
|
{
|
|
// Modify resolution
|
|
config &= ~(3 << MCP_ADC_RES);
|
|
config |= (MCP_ADC_RES_12 << MCP_ADC_RES);
|
|
|
|
// Modify power mode
|
|
config &= ~(1 << MCP_SHUTDOWN);
|
|
config |= (MCP_POWER_UP << MCP_SHUTDOWN);
|
|
|
|
// Write config reg
|
|
res = UhsdrHw_I2C_WriteRegister(MCP_I2C, MCP_ADDR, MCP_CONFIG, 1, config);
|
|
if(res != 0)
|
|
{
|
|
retval = 2;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
static uint8_t MCP9801_ReadExternalTempSensor(int32_t *temp)
|
|
{
|
|
uint8_t data[2];
|
|
uint8_t retval = 0;
|
|
|
|
|
|
// Read temperature
|
|
if(temp != NULL && UhsdrHw_I2C_ReadBlock(MCP_I2C, MCP_ADDR, MCP_TEMP, 1, data, 2) == 0)
|
|
{
|
|
*temp = MCP9801_ConvExternalTemp(data);
|
|
}
|
|
else
|
|
{
|
|
retval = 2;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
|
|
#define TCXO_TBL_SIZE 100
|
|
const short tcxo_table_20m[TCXO_TBL_SIZE] =
|
|
{
|
|
-165 // 0 C
|
|
-162, // 1 C
|
|
-160, // 2 C
|
|
-157, // 3 C
|
|
-155, // 4 C
|
|
-152, // 5 C
|
|
-150, // 6 C
|
|
-148, // 7 C
|
|
-144, // 8 C
|
|
-142, // 9 C
|
|
-136, // 10 C
|
|
-132, // 11 C
|
|
-130, // 12 C
|
|
-129, // 13 C
|
|
-126, // 14 C
|
|
-121, // 15 C
|
|
-116, // 16 C
|
|
-112, // 17 C
|
|
-108, // 18 C
|
|
-103, // 19 C
|
|
-99, // 20 C
|
|
-95, // 21 C
|
|
-90, // 22 C
|
|
-86, // 23 C
|
|
-81, // 24 C
|
|
-75, // 25 C
|
|
-70, // 26 C
|
|
-66, // 27 C
|
|
-61, // 28 C
|
|
-57, // 29 C
|
|
-53, // 30 C
|
|
-46, // 31 C
|
|
-42, // 32 C
|
|
-38, // 33 C
|
|
-32, // 34 C
|
|
-28, // 35 C
|
|
-25, // 36 C
|
|
-20, // 37 C
|
|
-17, // 38 C
|
|
-13, // 39 C
|
|
-9, // 40 C
|
|
-5, // 41 C
|
|
-2, // 42 C
|
|
1, // 43 C
|
|
4, // 44 C
|
|
7, // 45 C
|
|
10, // 46 C
|
|
12, // 47 C
|
|
15, // 48 C
|
|
16, // 49 C
|
|
18, // 50 C
|
|
20, // 51 C
|
|
21, // 52 C
|
|
22, // 53 C
|
|
23, // 54 C
|
|
23, // 55 C
|
|
24, // 56 C
|
|
23, // 57 C
|
|
23, // 58 C
|
|
22, // 59 C
|
|
21, // 60 C
|
|
20, // 61 C
|
|
18, // 62 C
|
|
16, // 63 C
|
|
14, // 64 C
|
|
11, // 65 C
|
|
7, // 66 C
|
|
3, // 67 C
|
|
-1, // 68 C
|
|
-5, // 69 C
|
|
-11,// 70 C
|
|
-17, // 71 C
|
|
-24, // 72 C
|
|
-31, // 73 C
|
|
-38, // 74 C
|
|
-45, // 75 C
|
|
-52, // 76 C
|
|
-58, // 77 C
|
|
-67, // 78 C
|
|
-71, // 79 C
|
|
-77, // 80 C
|
|
-83, // 81 C
|
|
-89, // 82 C
|
|
-95, // 83 C
|
|
-102, // 84 C
|
|
-108, // 85 C
|
|
-115, // 86 C
|
|
-121, // 87 C
|
|
-127, // 88 C
|
|
-134, // 89 C
|
|
-141, // 90 C
|
|
-147, // 91 C
|
|
-153, // 92 C
|
|
-159, // 93 C
|
|
-166, // 94 C
|
|
-177, // 95 C
|
|
-184, // 96 C
|
|
-190, // 97 C
|
|
-197, // 98 C
|
|
-203 // 99 C
|
|
};
|
|
|
|
void SoftTcxo_Init()
|
|
{
|
|
|
|
lo.comp = 0;
|
|
|
|
// Temp sensor setup
|
|
lo.sensor_present = MCP9801_InitExternalTempSensor() == 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* @brief measure local oscillator temperature and calculates compensation value
|
|
* @return true if the temperature value has been measured
|
|
*/
|
|
bool SoftTcxo_HandleLoTemperatureDrift()
|
|
{
|
|
int32_t temp = 0;
|
|
int comp, comp_p;
|
|
float dtemp, remain, t_index;
|
|
uchar tblp;
|
|
|
|
uint8_t temp_mode = RadioManagement_TcxoGetMode();
|
|
|
|
bool retval = false;
|
|
|
|
// No need to process if no chip avail or tcxo is disabled
|
|
if((lo.sensor_present == true) && RadioManagement_TcxoIsEnabled())
|
|
{
|
|
{
|
|
// Get current temperature
|
|
if(MCP9801_ReadExternalTempSensor(&temp) == 0)
|
|
{
|
|
// Get temperature from sensor with its maximum precision
|
|
dtemp = (float)temp; // get temperature
|
|
dtemp /= 10000; // convert to decimal degrees
|
|
remain = truncf(dtemp); // get integer portion of temperature
|
|
remain = dtemp - remain; // get fractional portion
|
|
|
|
// Compensate only if enabled
|
|
if((temp_mode == TCXO_ON))
|
|
{
|
|
// Temperature to unsigned table pointer
|
|
t_index = (uchar)((temp%1000000)/100000);
|
|
t_index *= 10;
|
|
t_index += (uchar)((temp%100000)/10000);
|
|
|
|
// Check for overflow - keep within the lookup table
|
|
if((t_index < 0) || (t_index > 150)) // the temperature sensor function "wraps around" below zero
|
|
{
|
|
t_index = 0; // point at the bottom of the temperature table
|
|
dtemp = 0; // zero out fractional calculations
|
|
remain = 0;
|
|
}
|
|
else if(t_index > TCXO_TBL_SIZE - 2) // High temperature - limit to maximum
|
|
{
|
|
t_index = TCXO_TBL_SIZE - 2; // Point to (near) top of table
|
|
dtemp = 0; // zero out fractional calculations
|
|
remain = 0;
|
|
}
|
|
|
|
tblp = (uchar)t_index; // convert to index
|
|
|
|
comp = tcxo_table_20m[tblp]; // get the first entry in the table
|
|
comp_p = tcxo_table_20m[tblp + 1]; // get the next entry in the table to determine fraction of frequency step
|
|
|
|
comp_p = comp_p - comp; // // get frequency difference between the two steps
|
|
|
|
dtemp = (float)comp_p; // change it to float for the calculation
|
|
dtemp *= remain; // get proportion of temperature difference between the two steps using the fraction
|
|
|
|
comp += (int)dtemp; // add the compensation value to the lower of the two frequency steps
|
|
|
|
// Change needed ?
|
|
if(lo.comp != comp) // is it there a difference?
|
|
{
|
|
// Update frequency, without reflecting it on the LCD
|
|
df.temp_factor = comp;
|
|
df.temp_factor_changed = true;
|
|
lo.comp = comp;
|
|
}
|
|
}
|
|
// Refresh UI
|
|
retval = true;
|
|
lo.temp = temp;
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|