/* -*- 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; }