#ifdef __VISUALC__ #include #endif #ifdef CF__LINUX #define OutputDebugStringA printf #include #endif #include #include #include "USBPixI4DCS.h" #include "SiUSBLib.h" #include "defines.h" #include #ifdef CF__LINUX int min(int a, int b){ if(a 255) DACval = 255; if (DACval < 0) DACval = 0; SetDAC(myUSB, DAC_add, DACval); } void SupplyChannel::SetVoltageRaw(double val) { VoltageRaw = val; GetVoltageFromRaw(); return; } void SupplyChannel::SetCurrentRaw(double val) { CurrentRaw = val; GetCurrentFromRaw(); return; } double SupplyChannel::GetVoltageFromRaw() { return (Voltage = (double)((VoltageRaw - CalData.VmeasOffset) / CalData.VmeasGain)); } double SupplyChannel::GetCurrentFromRaw() { CurrentRawIq = CurrentRaw - (CalData.IqOffset + CalData.IqVgain * Voltage); return (Current = (double)((CurrentRawIq - CalData.ImeasOffset) / CalData.ImeasGain)); } double SupplyChannel::GetVoltage(bool getRaw) { if (getRaw) return VoltageRaw; else return Voltage; } double SupplyChannel::GetCurrent(int type) { switch(type) { case CALIBRATED: return Current; case RAW: return CurrentRaw; case RAW_IQ_COMPENSATED: return CurrentRawIq; default: return Current; } } void SupplyChannel::Enable(bool on_off) { ; } USBPixDCS::USBPixDCS(void * hUSB): ADC_MAX1239(), DAC_MAX520() { myUSB = (SiUSBDevice*)hUSB; calDataVersion = CAL_DATA_V1; IniFile = new CDataFile(); Id = -1; // ( *name, * hUSB, default, DACadd, ADCadd); PSU[VDDA1] = new SupplyChannel( "VDDA1", hUSB, 1.5, DAC_VDDA1, ADC_VDDA1); PSU[VDDA2] = new SupplyChannel( "VDDA2", hUSB, 1.5, DAC_VDDA2, ADC_VDDA2); PSU[VDDD1] = new SupplyChannel( "VDDD1", hUSB, 1.2, DAC_VDDD1, ADC_VDDD1); PSU[VDDD2] = new SupplyChannel( "VDDD2", hUSB, 1.2, DAC_VDDD2, ADC_VDDD2); // Init(); } USBPixDCS::~USBPixDCS(void) { //IniFile->Save(); delete PSU[VDDA1]; delete PSU[VDDD1]; delete PSU[VDDA2]; delete PSU[VDDD2]; delete IniFile; } void USBPixDCS::SetUSBHandle(void *hUSB) { myUSB = (SiUSBDevice*)hUSB; PSU[VDDA1]->SetUSBHandle(hUSB); PSU[VDDA2]->SetUSBHandle(hUSB); PSU[VDDD1]->SetUSBHandle(hUSB); PSU[VDDD2]->SetUSBHandle(hUSB); if (hUSB) Init(); } void USBPixDCS::Init(void) { SetupADC(myUSB, SETUP_FLAGS); if (getenv("DAQ_BASE") != NULL) IniFileName = std::string(getenv("DAQ_BASE"))+ std::string("\\config\\") + std::string(DEFAULT_ADC_INIFILE_NAME); else IniFileName = std::string(DEFAULT_ADC_INIFILE_NAME); IniFile->SetFileName(IniFileName); nAverage = 4; if (!ReadEEPROM()) // EPPROM not found or Rev 1.0 Adapter Card ReadCalDataFile(); // TODO load/save calibrated values TsenseCalData.R_NTC_25 = 1000.0; TsenseCalData.B_NTC = 3435.0; TsenseCalData.R1 = 3900.0; TsenseCalData.R2 = 4700.0; TsenseCalData.R4 = 10000.0; TsenseCalData.VREF = 2.5; } bool USBPixDCS::CalculateGainAndOffset(double x1, double y1, double x2, double y2, double &gain, double &offset) { double g_nom = y2 - y1; double g_denom = x2 - x1; if (g_denom == 0) return false; gain = g_nom/g_denom; offset = y1 - x1 * gain; return true; } bool USBPixDCS::ReadCalDataFile(const char * adcfilename) { bool status = false; std::stringstream ss; if (adcfilename != NULL) status = IniFile->Load(adcfilename); else status = IniFile->Load(IniFileName); for (int i = 0; i < MAX_SUPPLY_CHANNEL; i++) { ss.str(""); ss << PSU[i]->name << " calibration constants"; PSU[i]->CalData.DefaultVoltage = IniFile->GetFloat("Default Voltage", ss.str().c_str(), PSU[i]->CalData.DefaultVoltage); PSU[i]->CalData.VsetOffset = IniFile->GetFloat("DAC offset", ss.str().c_str(), PSU[i]->CalData.VsetOffset); PSU[i]->CalData.VsetGain = IniFile->GetFloat("DAC gain", ss.str().c_str(), PSU[i]->CalData.VsetGain); PSU[i]->CalData.VmeasOffset = IniFile->GetFloat("Voltage sense offset", ss.str().c_str(), PSU[i]->CalData.VmeasOffset); PSU[i]->CalData.VmeasGain = IniFile->GetFloat("Voltage sense gain", ss.str().c_str(), PSU[i]->CalData.VmeasGain); PSU[i]->CalData.ImeasOffset = IniFile->GetFloat("Current sense offset", ss.str().c_str(), PSU[i]->CalData.ImeasOffset); PSU[i]->CalData.ImeasGain = IniFile->GetFloat("Current sense gain", ss.str().c_str(), PSU[i]->CalData.ImeasGain); PSU[i]->CalData.IqOffset = IniFile->GetFloat("Quiesent current offset", ss.str().c_str(), PSU[i]->CalData.IqOffset); PSU[i]->CalData.IqVgain = IniFile->GetFloat("Quiesent current gain", ss.str().c_str(), PSU[i]->CalData.IqVgain); } TsenseCalData.R_NTC_25 = IniFile->GetFloat("NTC 25 °C resistance", "DCS calibration data", 10.000); TsenseCalData.B_NTC = IniFile->GetFloat("NTC 'b' coefficient", "DCS calibration data", 3435); TsenseCalData.R1 = IniFile->GetFloat("R1", "DCS calibration data", 3900); TsenseCalData.R2 = IniFile->GetFloat("R2", "DCS calibration data", 4700); TsenseCalData.R4 = IniFile->GetFloat("R4", "DCS calibration data", 10000); TsenseCalData.VREF = IniFile->GetFloat("VREF", "DCS calibration data", 2.5); return status; } bool USBPixDCS::WriteCalDataFile(const char * adcfilename) { std::stringstream ss; if (adcfilename != NULL) IniFile->SetFileName(adcfilename); else IniFile->SetFileName(IniFileName); for (int i = 0; i < MAX_SUPPLY_CHANNEL; i++) { ss.str(""); ss << PSU[i]->name << " calibration constants"; IniFile->SetFloat("Default Voltage", PSU[i]->CalData.DefaultVoltage, "Default voltage", ss.str().c_str()); IniFile->SetFloat("DAC offset", PSU[i]->CalData.VsetOffset, "DAC offset (counts)", ss.str().c_str()); IniFile->SetFloat("DAC gain", PSU[i]->CalData.VsetGain , "DAC gain (counts)", ss.str().c_str()); IniFile->SetFloat("Voltage sense offset", PSU[i]->CalData.VmeasOffset, "ADC offset (counts)", ss.str().c_str()); IniFile->SetFloat("Voltage sense gain", PSU[i]->CalData.VmeasGain , "ADC gain (counts/V)", ss.str().c_str()); IniFile->SetFloat("Current sense offset", PSU[i]->CalData.ImeasOffset, "ADC+TIA offset (counts)", ss.str().c_str()); IniFile->SetFloat("Current sense gain", PSU[i]->CalData.ImeasGain , "ADC+TIA gain (counts/A)", ss.str().c_str()); IniFile->SetFloat("Quiesent current offset", PSU[i]->CalData.IqOffset, "LDO offset (counts)", ss.str().c_str()); IniFile->SetFloat("Quiesent current gain", PSU[i]->CalData.IqVgain , "LDO gain (counts/V)", ss.str().c_str()); } IniFile->SetFloat("NTC 25 °C resistance", TsenseCalData.R_NTC_25 , "NTC resistance at 25°C", "DCS calibration data"); IniFile->SetFloat("NTC 'b' coefficient", TsenseCalData.B_NTC, "NTC B coefficient", "DCS calibration data"); IniFile->SetFloat("R1", TsenseCalData.R1, "resistor value for NTC voltage divider", "DCS calibration data"); IniFile->SetFloat("R2", TsenseCalData.R2, "value of R2 in the reference voltage divider", "DCS calibration data"); IniFile->SetFloat("R4", TsenseCalData.R4, "value of R4 in the reference voltage divider", "DCS calibration data"); IniFile->SetFloat("VREF", TsenseCalData.VREF, "supply voltage of the resitor bridge", "DCS calibration data"); return IniFile->Save(); } bool USBPixDCS::ReadEEPROM() { unsigned int size; unsigned short header; unsigned char *dataBuf; unsigned char tmpBuf[2]; unsigned int dataPtr; bool status; tmpBuf[0] = 0; tmpBuf[1] = 0; status = ReadCalEEPROMBytes(0, &tmpBuf[0], 2); header = (tmpBuf[0] << 8) + tmpBuf[1]; if (!status) { OutputDebugStringA("USBPixDCS::ReadEEPROM()... No EEPROM found\n"); return false; } switch (header) { case CAL_DATA_HEADER_V1: size = sizeof(eepromCalDataV1); calDataVersion = CAL_DATA_V1; break; case CAL_DATA_HEADER_V2: OutputDebugStringA("USBPixDCS::ReadEEPROM()... CAL_DATA_VERSION 2 not implemented yet\n"); break; default: OutputDebugStringA("USBPixDCS::ReadEEPROM()... No EEPROM or valid header found\n"); calDataVersion = CAL_DATA_FILE; return false; } dataBuf = 0; dataBuf = new unsigned char[size]; if (!dataBuf) return false; status = ReadCalEEPROMBytes(0, dataBuf, size); if (calDataVersion == CAL_DATA_V1) { // de-serialize data struct (portability!) dataPtr = 2; // skip header Id = (dataBuf[dataPtr] << 8) + dataBuf[dataPtr+1]; dataPtr += 2; for (int i = 0; i < MAX_SUPPLY_CHANNEL; i++) { memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.name), MAX_PSU_NAME_SIZE); dataPtr += MAX_PSU_NAME_SIZE; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.DefaultVoltage), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.ImeasGain), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.ImeasOffset), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.IqVgain), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.IqOffset), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VmeasGain), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VmeasOffset), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VsetGain), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VsetOffset), 8); dataPtr += 8; } memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.B_NTC), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R1), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R2), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R4), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R_NTC_25), 8); dataPtr += 8; memcpy_reverse(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.VREF), 8); dataPtr += 8; } else status = false; delete[] dataBuf; return status; } bool USBPixDCS::WriteEEPROM() { unsigned int size; unsigned char *dataBuf; unsigned int dataPtr = 0; bool status = true; switch(calDataVersion) { case CAL_DATA_V1: size = sizeof(eepromCalDataV1); break; //case CAL_DATA_V2: // size = sizeof(eepromCalDataV2); // break; case CAL_DATA_FILE: WriteCalDataFile(); return false; default: OutputDebugStringA("USBPixDCS::WriteEEPROM()... no CAL_DATA_VERSION defined\n"); return false; } dataBuf = 0; dataBuf = new unsigned char[size]; if (!dataBuf) return false; // serialize data struct (portability!) dataBuf[dataPtr++] = 0xff & (CAL_DATA_HEADER_V1 >> 8); dataBuf[dataPtr++] = 0xff & (CAL_DATA_HEADER_V1); dataBuf[dataPtr++] = 0xff & (Id >> 8); dataBuf[dataPtr++] = 0xff & (Id); for (int i = 0; i < MAX_SUPPLY_CHANNEL; i++) { memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.name), MAX_PSU_NAME_SIZE); dataPtr += MAX_PSU_NAME_SIZE; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.DefaultVoltage), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.ImeasGain), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.ImeasOffset), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.IqVgain), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.IqOffset), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VmeasGain), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VmeasOffset), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VsetGain), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&PSU[i]->CalData.VsetOffset), 8); dataPtr += 8; } memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.B_NTC), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R1), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R2), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R4), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.R_NTC_25), 8); dataPtr += 8; memcpy(&dataBuf[dataPtr], (unsigned char*)(&TsenseCalData.VREF), 8); dataPtr += 8; status &= WriteCalEEPROMBytes(0, dataBuf, size); delete[] dataBuf; return status; } bool USBPixDCS::WriteCalEEPROMBytes(int add, unsigned char * data, int size) { bool status = true; unsigned int nPages, nBytes; unsigned char add_data_buf[CAL_EEPROM_PAGE_SIZE + 2]; unsigned int dataPtr; unsigned int addrPtr; QMutexLocker locker(myUSB->getMutex()); nPages = size / CAL_EEPROM_PAGE_SIZE; nBytes = size % CAL_EEPROM_PAGE_SIZE; addrPtr = add; dataPtr = 0; for (unsigned int i = 0; i < nPages; i++) // 64 byte page write { // address offset TODO: fix non page boundary address offset add_data_buf[0] = (unsigned char)(0x3f & (addrPtr >> 8)); add_data_buf[1] = (unsigned char)(0xff & addrPtr); for (int j = 0; j < CAL_EEPROM_PAGE_SIZE; j++) add_data_buf[j + 2] = data[dataPtr + j]; if (myUSB != NULL) status &= myUSB->WriteI2Cnv(CAL_EEPROM_ADD, add_data_buf, CAL_EEPROM_PAGE_SIZE + 2); else status = false; dataPtr += CAL_EEPROM_PAGE_SIZE; addrPtr += CAL_EEPROM_PAGE_SIZE; } if (nBytes > 0) { // address offset TODO: fix non page boundary address offset add_data_buf[0] = (unsigned char)(0x3f & (addrPtr >> 8)); add_data_buf[1] = (unsigned char)(0xff & addrPtr); for (unsigned int j = 0; j < nBytes; j++) add_data_buf[j + 2] = data[dataPtr + j]; if (myUSB != NULL) status &= myUSB->WriteI2Cnv(CAL_EEPROM_ADD, add_data_buf, nBytes + 2); else status = false; } return status; } bool USBPixDCS::ReadCalEEPROMBytes(int add, unsigned char * data, int size) { bool status; unsigned char addBuf[2]; unsigned int nPages, nBytes; unsigned int dataPtr; QMutexLocker locker(myUSB->getMutex()); nPages = size / CAL_EEPROM_PAGE_SIZE; nBytes = size % CAL_EEPROM_PAGE_SIZE; addBuf[0] = (unsigned char)(0x3f & (add >> 8)); addBuf[1] = (unsigned char)(0xff & add); if (myUSB != NULL) status = myUSB->WriteI2C(CAL_EEPROM_ADD, addBuf, 2); else status = false; dataPtr = 0; for (unsigned int i = 0; i < nPages; i++) // 64 byte page write { if (myUSB != NULL) status &= myUSB->ReadI2C(CAL_EEPROM_ADD | 0x01, &data[dataPtr], CAL_EEPROM_PAGE_SIZE); else status = false; dataPtr += CAL_EEPROM_PAGE_SIZE; } if (nBytes > 0) { if (myUSB != NULL) status &= myUSB->ReadI2C(CAL_EEPROM_ADD | 0x01, &data[dataPtr], nBytes); else status = false; } return status; } void USBPixDCS::UpdateMeasurements() { unsigned char confByte = SCAN_ON | SINGLE_ENDED | ((0x1e) & (10 << 1)); unsigned char rawData[MAX_ADC_CHANNEL * 2]; double avgData[MAX_ADC_CHANNEL]; bool status; QMutexLocker locker(myUSB->getMutex()); for (int j = 0; j < nAverage; j++) { if (myUSB != NULL) status = myUSB->WriteI2C(MAX_1239_ADD, &confByte, 1); else status = false; if (!status) OutputDebugStringA("USBPixDCS::UpdateMeasurements()... WriteI2C() failed\n"); if (myUSB != NULL) status = myUSB->ReadI2C(MAX_1239_ADD | 0x01, rawData, 22); else status = false; if (!status) OutputDebugStringA("USBPixDCS::UpdateMeasurements()... ReadI2C() failed\n"); for (int i = 0; i < MAX_ADC_CHANNEL; i++) { if (j == 0) avgData[i] = (double)(((0x0f & rawData[2*i]) << 8) + rawData[2*i+1]); else avgData[i] += (double)(((0x0f & rawData[2*i]) << 8) + rawData[2*i+1]); } } for (int i = 0; i < MAX_ADC_CHANNEL; i++) avgData[i] = avgData[i] / (double)nAverage; for (int i = 0; i < MAX_SUPPLY_CHANNEL; i++) { PSU[i]->SetVoltageRaw(avgData[2*i]); PSU[i]->SetCurrentRaw(avgData[2*i+1]); } SetNTCTemperature(avgData[ADC_VNTC]); } double USBPixDCS::GetNTCTemperature(void) { return Temperature; } void USBPixDCS::SetNTCTemperature(double rawData) { /* NTC type SEMITEC 103KT1608 http://www.semitec.co.jp/english/products/pdf/KT_Thermistor.pdf R_NTC = R_25 * exp(B_NTC * (1/T - 1/T_25)) R_NTC measured NTC resistance R_NTC_25 resistance @ 25°C B_NTC temperature coefficient Temperature current temperature (Kelvin) T_25 298,15 K (25°C) */ double R_NTC; double V_ADC; double k; V_ADC = ((rawData - PSU[0]->CalData.VmeasOffset) / PSU[0]->CalData.VmeasGain); // voltage k = TsenseCalData.R4 / (TsenseCalData.R2 + TsenseCalData.R4); // reference voltage divider R_NTC = TsenseCalData.R1 * (k - V_ADC/TsenseCalData.VREF)/(1 - k + V_ADC / TsenseCalData.VREF); // NTC resistance Temperature = (TsenseCalData.B_NTC /(log(R_NTC) - log(TsenseCalData.R_NTC_25) + TsenseCalData.B_NTC/T_KELVIN_25)) - T_KELVIN_0; // NTC temperature } DAC_MAX520::DAC_MAX520() { ; } DAC_MAX520::~DAC_MAX520(void) { ; } bool DAC_MAX520::SetDAC(SiUSBDevice * myUSB, unsigned char channel, unsigned char val) { unsigned char buffer[2]; QMutexLocker locker(myUSB->getMutex()); buffer[0] = channel; buffer[1] = val; if (myUSB != NULL) return myUSB->WriteI2C(MAX_520_ADD, buffer, 2); else return false; } ADC_MAX1239::ADC_MAX1239() { nAverage = 8; } ADC_MAX1239::~ADC_MAX1239(void) { ; } double ADC_MAX1239::ReadADC(SiUSBDevice * myUSB, unsigned char channel) { unsigned char confByte = SCAN_OFF | SINGLE_ENDED | ((0x1e) & (channel << 1)); unsigned char rawData[2]; bool status; double mean_data = 0; QMutexLocker locker(myUSB->getMutex()); for (int i = 0; i < 2; i++) { if (myUSB != NULL) status = myUSB->WriteI2C(MAX_1239_ADD, &confByte, 1); else status = false; if (!status) { OutputDebugStringA("ADC_MAX1239::ReadADC:WriteI2C(...) failed\n"); } if (myUSB != NULL) status = myUSB->ReadI2C(MAX_1239_ADD | 0x01, rawData, 2); else status = false; if (!status) { OutputDebugStringA("ADC_MAX1239::ReadADC:ReadI2C(...) failed\n"); } } for (int i = 0; i < nAverage; i++) { if (myUSB != NULL) status = myUSB->WriteI2C(MAX_1239_ADD, &confByte, 1); else status = false; if (!status) { OutputDebugStringA("ADC_MAX1239::ReadADC:WriteI2C(...) failed\n"); } if (myUSB != NULL) status = myUSB->ReadI2C(MAX_1239_ADD | 0x01, rawData, 2); else status = false; if (!status) { OutputDebugStringA("ADC_MAX1239::ReadADC:ReadI2C(...) failed\n"); } mean_data += (double)(((0x0f & rawData[0]) << 8) + rawData[1]); } return mean_data / (double)nAverage; } bool ADC_MAX1239::SetupADC(SiUSBDevice * myUSB, unsigned char flags) { unsigned char setupData = flags; QMutexLocker locker(myUSB->getMutex()); if (myUSB != NULL) return myUSB->WriteI2C(MAX_1239_ADD, &setupData, 1); else return false; }