/* * _adc->c * * Created on: Mar 31, 2023 * Author: Keith.Lloyd */ #include #include #include "fsl_device_registers.h" #include "fsl_debug_console.h" #include "pin_mux.h" #include "board.h" #include "fsl_adc.h" #include "fsl_clock.h" #include "fsl_power.h" //Application includes #include "timer.h" #include "adc.h" //#include "frq.h" #include "ports.h" #include "utils.h" #include "hwFixes.h" #include "System/system.h" #include "driver.h" /******************************************************************************* * Definitions ******************************************************************************/ #define DEMO_ADC_BASE ADC0 #define DEMO_ADC_SAMPLE_CHANNEL_NUMBER 7U #define DEMO_ADC_CLOCK_DIVIDER 1U /******************************************************************************* * Prototypes ******************************************************************************/ static void ADC_Configuration(void); extern uint8_t Port_State[]; uint32_t what_val1,what_val2; extern uint8_t frequency; extern FREQUENCY_t freqArray[FREQ_MAX_NUM]; float32_t volts_check; extern float32_t Watts_Filt; extern HARDWARE_FIX_t hwf; extern SYSTEM_DATA_t sys; /******************************************************************************* * Variables ******************************************************************************/ static ADC_t *_adc; adc_result_info_t adcResultInfoStruct; /* * Current measurement scaling vs frequency for LOW gain * This is used to look up and interpolate current scaling * Number of rows is not specified and can be any length * Number of columns hard coded at 2: frequency, scale */ //Values from SN ONION using offset compensated single point @ 1000mA float32_t currentTableLowGain[][ADC_TABLE_COLUMNS] = { { 256 , 0.002118644 } , { 360 , 0.001926782 } , { 512 , 0.001858736 } , { 640 , 0.001821494 } , { 1170 , 0.001785714 } , { 3140 , 0.001769912 } , { 8192 , 0.00177305 } , { 14000 , 0.001778726 } , { 20000 , 0.001786991 } , { 29430 , 0.001801802 } , { 32800 , 0.001806685 } , { 44500 , 0.001828154 } , #if 1 //temporary change { 66100 , 0.001874414 * 1.28} ,//1.28 { 88800 , 0.001931621 * 1.84} ,//1.84 { 99000 , 0.001960784 * 1.58} ,//1.58 { 150000 , 0.00213858 } , { 200000 , 0.002364066 } , #else //original values { 66100 , 0.001874414 } , { 88800 , 0.001931621 } , { 99000 , 0.001960784 } , { 150000 , 0.00213858 } , { 200000 , 0.002364066 } , #endif }; //High gain current table - Works same as low gain table. Values from SN ONION float32_t currentTableHighGain[][ADC_TABLE_COLUMNS] = { { 256 , 5.27426E-05 } , { 360 , 4.92126E-05 } , { 512 , 4.64684E-05 } , { 640 , 4.54959E-05 } , { 1170 , 4.44444E-05 } , { 3140 , 4.42087E-05 } , { 8192 , 4.53309E-05 } , { 14000 , 4.77464E-05 } , { 20000 , 5.13663E-05 } , { 29430 , 5.9004E-05 } , { 32800 , 6.21891E-05 } , { 44500 , 7.47831E-05 } , { 66100 , 0.000103907 } , { 88800 , 0.000143349 } , { 99000 , 0.000165017 } , { 150000 , 0.000340136 } , { 200000 , 0.000702247 } , }; /* * Voltage measurement scaling vs frequency for LOW gain * This is used to look up and interpolate current scaling * Number of rows is not specified and can be any length * Number of columns hard coded at 2: frequency, scale */ float32_t voltageTableLowGain[][ADC_TABLE_COLUMNS] = { { 256 , 0.182338205 } , { 360 , 0.165825101 } , { 512 , 0.159240069 } , { 640 , 0.155824916 } , { 870 , 0.147733711 } , { 1170 , 0.14674221 } , { 3140 , 0.146165644 } , { 5600 , 0.146347826 } , { 8192 , 0.146907216 } , { 14000 , 0.148426509 } , { 20000 , 0.148590381 } , { 29430 , 0.147376717 } , { 32800 , 0.152678378 } , { 44500 , 0.149038462 } , { 66100 , 0.179871383 } , { 88800 , 0.19462585 } , { 99000 , 0.202585604 } , { 150000 , 0.252818035 } , { 200000 , 0.312444837 } , }; //Values from SN ONION (208023) using offset compensated single point @ 500mA float32_t currentTableLowGain208023[][ADC_TABLE_COLUMNS] = { { 256 , 0.00203666 } , { 360 , 0.00187970 } , { 512 , 0.00181818 } , { 640 , 0.00179856 } , { 1170 , 0.00175747 } , { 3140 , 0.00174459 } , { 8192 , 0.00174825 } , { 14000 , 0.00176056 } , { 20000 , 0.00177431 } , { 29430 , 0.00179856 } , { 32800 , 0.00180897 } , { 44500 , 0.00184502 } , { 66100 , 0.00192678 } , { 88800 , 0.00202840 } , { 99000 , 0.00208333 } , { 150000 , 0.00241313 } , { 200000 , 0.00286862 } , }; //High gain current table - Works same as low gain table. Values from SN ONION float32_t currentTableHighGain208023[][ADC_TABLE_COLUMNS] = { { 256 , 0.00005171 } , { 360 , 0.00004817 } , { 512 , 0.00004695 } , { 640 , 0.00004600 } , { 1170 , 0.00004505 } , { 3140 , 0.00004464 } , { 8192 , 0.00004452 } , { 14000 , 0.00004460 } , { 20000 , 0.00004468 } , { 29430 , 0.00004492 } , { 32800 , 0.00004500 } , { 44500 , 0.00004533 } , { 66100 , 0.00004610 } , { 88800 , 0.00004707 } , { 99000 , 0.00004762 } , { 150000 , 0.00005086 } , { 200000 , 0.00005513 } , }; /* * Voltage measurement scaling vs frequency for LOW gain * This is used to look up and interpolate current scaling * Number of rows is not specified and can be any length * Number of columns hard coded at 2: frequency, scale */ float32_t voltageTableLowGain208023[][ADC_TABLE_COLUMNS] = { { 98 , 0.155877863 } , { 256 , 0.155877863 } , { 360 , 0.151178571 } , { 512 , 0.148143054 } , { 640 , 0.147208986 } , { 870 , 0.146820809 } , { 1170 , 0.14350365 } , { 3140 , 0.145137645 } , { 5600 , 0.146038095 } , { 8192 , 0.146697229 } , { 14000 , 0.146918994 } , { 20000 , 0.147096457 } , { 29430 , 0.145183742 } , { 32800 , 0.14886061 } , { 44500 , 0.150783939 } , { 66100 , 0.157547751 } , { 88800 , 0.163411541 } , { 99000 , 0.166688103 } , { 150000 , 0.187197232 } , { 200000 , 0.21567892 } , }; //Values from SN 2060-00424 (208025) using offset compensated single point @ 500mA float32_t currentTableLowGain208025[][ADC_TABLE_COLUMNS2] = { { 98 , 0.00124072 , 0.000 } , { 256 , 0.00124072 , 0.000 } , { 360 , 0.00116692 , 0.000 } , { 512 , 0.00112509 , 0.000 } , { 640 , 0.00110724 , 0.000 } , { 1170 , 0.00108541 , 0.000 } , { 3140 , 0.00107574 , 0.000 } , { 8192 , 0.00107574 , 0.000 } , { 14000 , 0.00107870 , 0.000 } , { 20000 , 0.00108242 , 0.000 } , { 29430 , 0.00108918 , 0.000 } , { 32800 , 0.00109183 , 0.000 } , { 44500 , 0.00110334 , 0.000 } , { 66100 , 0.00112671 * 1.1052 , 0.000 } , { 88800 , 0.00115831 * 1.1052, 0.000 } , { 99000 , 0.00117346 * 1.2413, 0.000 } , { 150000 , 0.00127086 * 1.6322 , 0.000 } , //1.327 { 200000 , 0.00140135 * 2.4123 , 0.000 } ,//2.805 }; //High gain current table. Values from SN 2060-00424 (208025) //Scale values are Amps/count, offsets are in Amps float32_t currentTableHighGain208025[][ADC_TABLE_COLUMNS2] = { { 98 , 0.00004951 , 0.000 } , { 256 , 0.00004951 , 0.000 } , { 360 , 0.00004662 , 0.000 } , { 512 , 0.00004499 , 0.000 } , { 640 , 0.00004437 , 0.000 } , { 1170 , 0.00004342 , 0.000 } , { 3140 , 0.00004296 , 0.000 } , { 8192 , 0.00004289 , 0.000 } , { 14000 , 0.00004289 , 0.000 } , { 20000 , 0.00004293 , 0.000 } , { 29430 , 0.00004304 , 0.000 } , { 32800 , 0.00004308 , 0.000 } , { 44500 , 0.00004327 , 0.000 } , { 66100 , 0.00004374 , 0.000 } , { 88800 , 0.00004437 , 0.000 } , { 99000 , 0.00004470 , 0.000 } , { 150000 , 0.00004685 , 0.000 } , { 200000 , 0.00004967 , 0.000 } , }; /******************************************************************************* * Static Functions ******************************************************************************/ static void ADC_ClockPower_Configuration(void) { /* SYSCON power. */ POWER_DisablePD(kPDRUNCFG_PD_ADC0); /* Power on the ADC converter. */ POWER_DisablePD(kPDRUNCFG_PD_VD7_ENA); /* Power on the analog power supply. */ POWER_DisablePD(kPDRUNCFG_PD_VREFP_SW); /* Power on the reference voltage source. */ POWER_DisablePD(kPDRUNCFG_PD_TEMPS); /* Power on the temperature sensor. */ CLOCK_EnableClock(kCLOCK_Adc0); /* SYSCON->AHBCLKCTRL[0] |= SYSCON_AHBCLKCTRL_ADC0_MASK; */ } static void ADC_Configuration(void) { adc_config_t adcConfigStruct; adc_conv_seq_config_t adcConvSeqConfigStruct; /* Configure the converter. */ adcConfigStruct.clockMode = kADC_ClockSynchronousMode; /* Using sync clock source. */ adcConfigStruct.clockDividerNumber = DEMO_ADC_CLOCK_DIVIDER; adcConfigStruct.resolution = kADC_Resolution12bit; adcConfigStruct.enableBypassCalibration = false; adcConfigStruct.sampleTimeNumber = 0U; ADC_Init(DEMO_ADC_BASE, &adcConfigStruct); /* Use the temperature sensor input to channel 0. */ ADC_EnableTemperatureSensor(DEMO_ADC_BASE, false); //was true /* Enable channel DEMO_ADC_SAMPLE_CHANNEL_NUMBER's conversion in Sequence A. */ adcConvSeqConfigStruct.channelMask = (1U << 7) | (1 << 5) | (1 << 6) | ( 1 << 10 ) | (1 << 9) | ( 1 << 8) | (1 << 4) | (1 << 3) | ( 1 << 1) | (1 << 0); // added ID1 and 2 //adcConvSeqConfigStruct.channelMask = // (1 << 5) |(1 << 6); // ACCY1 and 2 only adcConvSeqConfigStruct.triggerMask = 0U; adcConvSeqConfigStruct.triggerPolarity = kADC_TriggerPolarityPositiveEdge; adcConvSeqConfigStruct.enableSingleStep = false; adcConvSeqConfigStruct.enableSyncBypass = false; adcConvSeqConfigStruct.interruptMode = kADC_InterruptForEachSequence; ADC_SetConvSeqAConfig(DEMO_ADC_BASE, &adcConvSeqConfigStruct); ADC_EnableConvSeqA(DEMO_ADC_BASE, true); /* Enable the conversion sequence A. */ /* Clear the result register. */ ADC_DoSoftwareTriggerConvSeqA(DEMO_ADC_BASE); while (!ADC_GetChannelConversionResult(DEMO_ADC_BASE, 6, &adcResultInfoStruct)) //MAKE SURE THIS CHANNEL IS USED! { } ADC_GetConvSeqAGlobalConversionResult(DEMO_ADC_BASE, &adcResultInfoStruct); } /* * Get Current for LOW gain * @arg input raw ADC counts * @return */ static float32_t ScaleLowGainCurrent(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(currentTableLowGain) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in currentTableLowGain that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableLowGain[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableLowGain[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = currentTableLowGain[numEntries][ADC_TABLE_SCALE]; } else if(currentTableLowGain[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableLowGain[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = currentTableLowGain[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableLowGain[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableLowGain[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableLowGain[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_LOW_GAIN_CURR_CLIP_THRESH); return (input * scale); } /* * Get Current for HIGH gain * @arg input raw ADC counts * @return */ static float32_t ScaleHighGainCurrent(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(currentTableHighGain) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in currentTableHighGain that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableHighGain[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableHighGain[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = currentTableHighGain[numEntries][ADC_TABLE_SCALE]; } else if(currentTableHighGain[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableHighGain[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = currentTableHighGain[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableHighGain[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableHighGain[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableHighGain[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_HIGH_GAIN_CURR_CLIP_THRESH); return (input * scale); } /* * Get Voltage for LOW gain * @arg input raw ADC counts * @return */ static float32_t ScaleLowGainVoltage(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(voltageTableLowGain) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in voltageTableLowGain that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((voltageTableLowGain[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(voltageTableLowGain[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = voltageTableLowGain[numEntries][ADC_TABLE_SCALE]; } else if(voltageTableLowGain[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = voltageTableLowGain[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = voltageTableLowGain[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = voltageTableLowGain[highIndex][ADC_TABLE_FREQ]; float32_t y1 = voltageTableLowGain[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = voltageTableLowGain[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->votageClipping _adc->voltageClipping = (input > ADC_LOW_GAIN_VOLT_CLIP_THRESH); return (input * scale); } /* * Get Current for LOW gain * @arg input raw ADC counts * @return corrected current */ static float32_t ScaleLowGainCurrent208023(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(currentTableLowGain208023) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in currentTableLowGain208023 that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableLowGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableLowGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = currentTableLowGain208023[numEntries][ADC_TABLE_SCALE]; } else if(currentTableLowGain208023[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableLowGain208023[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = currentTableLowGain208023[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableLowGain208023[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableLowGain208023[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableLowGain208023[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_LOW_GAIN_CURR_CLIP_THRESH); return (input * scale); } /* * Get Current for HIGH gain * @arg input raw ADC counts * @return corrected current */ static float32_t ScaleHighGainCurrent208023(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(currentTableHighGain208023) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in currentTableHighGain208023 that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableHighGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableHighGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = currentTableHighGain208023[numEntries][ADC_TABLE_FREQ]; } else if(currentTableHighGain208023[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableHighGain208023[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = currentTableHighGain208023[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableHighGain208023[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableHighGain208023[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableHighGain208023[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_HIGH_GAIN_CURR_CLIP_THRESH); return (input * scale); } /* * Get Voltage for LOW gain 208023. Also used for 208025 * @arg input raw ADC counts * @return corrected voltage */ static float32_t ScaleLowGainVoltage208023(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0;//scale factor for the frequency. input * scale = current //Get number of entries in table uint32_t numEntries = sizeof(voltageTableLowGain208023) / sizeof(float32_t) / 2; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in voltageTableLowGain208023 that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((voltageTableLowGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(voltageTableLowGain208023[highIndex][ADC_TABLE_FREQ] < targetFreq)//If targetFreq is too large, use the highest table value { scale = voltageTableLowGain208023[numEntries][ADC_TABLE_SCALE]; } else if(voltageTableLowGain208023[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = voltageTableLowGain208023[highIndex][ADC_TABLE_SCALE]; } else //else interpolate { lowIndex = highIndex-1; float32_t x = targetFreq; float32_t x1 = voltageTableLowGain208023[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = voltageTableLowGain208023[highIndex][ADC_TABLE_FREQ]; float32_t y1 = voltageTableLowGain208023[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = voltageTableLowGain208023[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->votageClipping _adc->voltageClipping = (input > ADC_LOW_GAIN_VOLT_CLIP_THRESH); return (input * scale); } /* * Get Current for LOW gain * Apply scaling and offset from table * @arg input raw ADC counts * @return corrected current */ static float32_t ScaleLowGainCurrent208025(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0; //scale factor for the frequency. input * scale = current float32_t offset = 0; //offset for the frequency in Amps //Get number of entries in table uint32_t numEntries = sizeof(currentTableLowGain208025) / sizeof(float32_t) / 3; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 0 //TESTING - Use a specific frequency targetFreq = 384; #endif //Find the first index in currentTableLowGain208025 that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableLowGain208025[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableLowGain208025[highIndex][ADC_TABLE_FREQ] < targetFreq) //If targetFreq is too large, use the highest table value { scale = currentTableLowGain208025[numEntries][ADC_TABLE_SCALE]; offset = currentTableLowGain208025[numEntries][ADC_TABLE_OFFSET]; } else if(currentTableLowGain208025[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableLowGain208025[highIndex][ADC_TABLE_SCALE]; offset = currentTableLowGain208025[highIndex][ADC_TABLE_OFFSET]; } else //else interpolate { lowIndex = highIndex-1; //scale float32_t x = targetFreq; float32_t x1 = currentTableLowGain208025[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableLowGain208025[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableLowGain208025[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableLowGain208025[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); //OFFSET y1 = currentTableLowGain208025[lowIndex][ADC_TABLE_OFFSET]; y2 = currentTableLowGain208025[highIndex][ADC_TABLE_OFFSET]; offset = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_LOW_GAIN_CURR_CLIP_THRESH); return ((input * scale) + offset); } /* * Get Current for HIGH gain * Apply scaling and offset from table * @arg input raw ADC counts * @return corrected current */ static float32_t ScaleHighGainCurrent208025(float32_t input) { uint32_t lowIndex; //index of the closest table frequency below the target frequency uint32_t highIndex; //index of the closest table frequency above the target frequency float32_t scale = 0; //scale factor for the frequency. input * scale = current float32_t offset = 0; //offset for the frequency in Amps //Get number of entries in table uint32_t numEntries = sizeof(currentTableHighGain208025) / sizeof(float32_t) / 3; //Get target frequency //float32_t targetFreq = FREQ_GetFreqByIndex(frequency).frequency1; float32_t targetFreq = sys.driver->frequency->frequency; #if 1 //TESTING - Use a specific frequency targetFreq = 5666; #endif //Find the first index in currentTableHighGain208025 that is greater than or equal to targetFreq. This will be highIndex highIndex = 0; while((currentTableHighGain208025[highIndex][ADC_TABLE_FREQ] < targetFreq) && (highIndex < numEntries)) { highIndex++; } if(currentTableHighGain208025[highIndex][ADC_TABLE_FREQ] < targetFreq) //If targetFreq is too large, use the highest table value { scale = currentTableHighGain208025[numEntries][ADC_TABLE_SCALE]; offset = currentTableHighGain208025[numEntries][ADC_TABLE_OFFSET]; } else if(currentTableHighGain208025[highIndex][ADC_TABLE_FREQ] == targetFreq) //If it's equal, use the value in the table { scale = currentTableHighGain208025[highIndex][ADC_TABLE_SCALE]; offset = currentTableHighGain208025[highIndex][ADC_TABLE_OFFSET]; } else //else interpolate { lowIndex = highIndex-1; //scale float32_t x = targetFreq; float32_t x1 = currentTableHighGain208025[lowIndex][ADC_TABLE_FREQ]; float32_t x2 = currentTableHighGain208025[highIndex][ADC_TABLE_FREQ]; float32_t y1 = currentTableHighGain208025[lowIndex][ADC_TABLE_SCALE]; float32_t y2 = currentTableHighGain208025[highIndex][ADC_TABLE_SCALE]; scale = y1 + (x - x1) * (y2 - y1) / (x2 - x1); //OFFSET y1 = currentTableHighGain208025[lowIndex][ADC_TABLE_OFFSET]; y2 = currentTableHighGain208025[highIndex][ADC_TABLE_OFFSET]; offset = y1 + (x - x1) * (y2 - y1) / (x2 - x1); } //Update _adc->currentClipping _adc->currentClipping = (input > ADC_HIGH_GAIN_CURR_CLIP_THRESH); return ((input * scale) + offset); } /******************************************************************************* * Public Functions ******************************************************************************/ /*! * @brief Main function */ void ADC_SysInit(void) { _adc = &sys.adc; /* Enable the power and clock for ADC. */ ADC_ClockPower_Configuration(); uint32_t adcClockFreq = 0U; /* Calibration after power up. */ //DEMO_ADC_BASE->CTRL |= ADC_CTRL_BYPASSCAL_MASK; //This line skips adc offset calibration adcClockFreq = CLOCK_GetFreq(kCLOCK_BusClk); if (true == ADC_DoOffsetCalibration(DEMO_ADC_BASE, adcClockFreq)) //Also fixes ADCCLK (30MHZ max) { //PRINTF("ADC Calibration Done.\r\n"); } else { //PRINTF("ADC Calibration Failed.\r\n"); while(1); } /* Configure the converter and work mode. */ ADC_Configuration(); ADC_MeasureCurrentOffset(); //Start automatic ADC measurements (ctimer callback) _adc->measure = true; } //Measure offset for current measurement channel //Also output voltage channel void ADC_MeasureCurrentOffset(void) { //Measure current 8x and average //Store as _adc->I_Offset Delay_Ticks(7); //70mS for current signal to stabilize uint32_t currentOffsetSum = 0; uint32_t voltageOffsetSum = 0; uint32_t test[8]; for(uint32_t i = 0; i < 8; i++) //8 samples { ADC_Update(); Delay_Ticks(2); //20mS currentOffsetSum += _adc->rawCurrent; voltageOffsetSum += _adc->rawVoltage; test[i] = _adc->rawVoltage; //collect samples for testing } _adc->I_OffsetAdc = currentOffsetSum >> 3; //average of 8 samples #if ADC_USE_NOISE_OFFSET _adc->I_OffsetAdc -= ADC_NOISE_OFFSET_COUNTS; #endif #if 0 //TESTING: Allow larger offset if(abs((int32_t)(_adc->I_OffsetAdc) - ADC_HALF_COUNTS) <= 50) #else if(abs((int32_t)(_adc->I_OffsetAdc) - ADC_HALF_COUNTS) <= ADC_OFFSET_MAX_ERROR) //offset within 30 counts of mid scale #endif { _adc->iosOK = true; } else { _adc->iosOK = false; //This will NOT be needed after keith removes the restart when USB is disconnected } _adc->V_OffsetAdc = voltageOffsetSum >> 3; //average of 8 samples if(abs((int32_t)(_adc->V_OffsetAdc) - ADC_HALF_COUNTS) <= ADC_OFFSET_MAX_ERROR) //offset within 30 counts of mid scale { _adc->vosOK = true; } else { _adc->vosOK = false; } } /* * Measure analog voltages and convert to quantities * 100Hz sample rate * Voltage and current are sampled and filtered at 100Hz * All others are averages of 10 samples, so output at 10Hz */ void ADC_Update(void) { //start conversion ADC_DoSoftwareTriggerConvSeqA(DEMO_ADC_BASE); // Wait for the converter to be done with the LAST channel (10) while(!ADC_GetChannelConversionResult(DEMO_ADC_BASE, 10, &adcResultInfoStruct)); //Add measurement to adc struct _adc->V_BID_RAW += adcResultInfoStruct.result; //ch10 //CURRENT ADC_GetChannelConversionResult(DEMO_ADC_BASE, 0, &adcResultInfoStruct); _adc->rawCurrent = adcResultInfoStruct.result; _adc->I_OUT_RAW = _adc->rawCurrent; _adc->I_OUT = _adc->rawCurrent; //route raw current measurement to testIout #if 0 //TESTING: Don't use offset _adc->I_OUT -= ADC_HALF_COUNTS; #else if(_adc->iosOK) {_adc->I_OUT -= _adc->I_OffsetAdc; } else {_adc->I_OUT -= ADC_HALF_COUNTS; } #endif #if 1 //Testing filtered raw value _adc->IRaw = _adc->I_OUT; //ADC value with offset applied _adc->IRawFilt = _adc->I_OUT; //filtered ADC counts w/ offset _adc->IRawFilt = FILT_ExpAvgF32(_adc->IRawFilt,&_adc->IRawDelay,0.02); #endif #if ADC_CORRECT_FOR_CURRENT_NOISE //signal = SQRT( measurement^2 - noise^2) if(_adc->I_OUT > ADC_NOISE_OFFSET_COUNTS) //avoid sqrt(negative number) { _adc->I_OUT = sqrtf(_adc->I_OUT * _adc->I_OUT - ADC_NOISE_OFFSET_COUNTS * ADC_NOISE_OFFSET_COUNTS); } else { _adc->I_OUT = 0; } #endif //Current Scaling if((Port_State[MID_SR] & I_GAIN) > 0) //High Current Gain { if(hwf.mainPcbaPN >= 208025) { _adc->I_OUT = ScaleHighGainCurrent208025(_adc->I_OUT); } else if(hwf.mainPcbaPN == 208023) { _adc->I_OUT = ScaleHighGainCurrent208023(_adc->I_OUT); } else { _adc->I_OUT = ScaleHighGainCurrent(_adc->I_OUT); } } else //Low Current Gain { if(hwf.mainPcbaPN >= 208025) { _adc->I_OUT = ScaleLowGainCurrent208025(_adc->I_OUT); } else if(hwf.mainPcbaPN == 208023) { _adc->I_OUT = ScaleLowGainCurrent208025(_adc->I_OUT); } else { _adc->I_OUT = ScaleLowGainCurrent(_adc->I_OUT); } } //VOLTAGE ADC_GetChannelConversionResult(DEMO_ADC_BASE, 1, &adcResultInfoStruct); _adc->rawVoltage = adcResultInfoStruct.result; _adc->V_OUT_RAW = _adc->rawVoltage; _adc->V_OUT = _adc->rawVoltage; #if 0 //TESTING: Don't use offset _adc->V_OUT -= ADC_HALF_COUNTS; #else if(_adc->vosOK) {_adc->V_OUT -= _adc->V_OffsetAdc; } //use offset if in range else {_adc->V_OUT -= ADC_HALF_COUNTS; } //otherwise, use ADC_HALF_COUNTS #endif #if 1 //Testing filtered raw value _adc->VRaw = _adc->V_OUT; //ADC value with offset applied. Snapshot since V_OUT gets modified later _adc->VRawFilt = FILT_ExpAvgF32(_adc->VRaw,&_adc->VRawDelay,0.02); //filtered ADC counts w/ offset #endif #if 1 //Voltage Scaling if((Port_State[BOTTOM_SR] & 0x80) > 0) //High Voltage Gain { //Not implemented //_adc->V_OUT = MeasureHighGainVoltage(_adc->V_OUT); } else //Low Current Gain { if(hwf.mainPcbaPN >= 208023) //208023 and 208025 use the same table { _adc->V_OUT = ScaleLowGainVoltage208023(_adc->V_OUT); } else { _adc->V_OUT = ScaleLowGainVoltage(_adc->V_OUT); } } #else _adc->V_OUT = _adc->V_OUT / 4096.0 * ADC_VREF; //scale to input voltage //_adc->V_OUT = _adc->V_OUT * (804.0 + 10.0) / 10.0; //Scale for external voltage divider _adc->V_OUT = CompensateVout(_adc->V_OUT); //divider scaling sucked because AC... Measure_Volts(); #endif ADC_GetChannelConversionResult(DEMO_ADC_BASE, 3, &adcResultInfoStruct); _adc->V_PSU_RAW += adcResultInfoStruct.result; ADC_GetChannelConversionResult(DEMO_ADC_BASE, 4, &adcResultInfoStruct); _adc->V_BAT_RAW += adcResultInfoStruct.result; while(!ADC_GetChannelConversionResult(DEMO_ADC_BASE, 5, &adcResultInfoStruct)); _adc->V_ID2_RAW += adcResultInfoStruct.result; what_val2 = adcResultInfoStruct.result; while(!ADC_GetChannelConversionResult(DEMO_ADC_BASE, 6, &adcResultInfoStruct)); _adc->V_ID1_RAW += adcResultInfoStruct.result; what_val1 = adcResultInfoStruct.result; ADC_GetChannelConversionResult(DEMO_ADC_BASE, 7, &adcResultInfoStruct); _adc->V_CHK_RAW += adcResultInfoStruct.result; ADC_GetChannelConversionResult(DEMO_ADC_BASE, 8, &adcResultInfoStruct); _adc->V_TMP_RAW += adcResultInfoStruct.result; static uint32_t index = 0; //On nth measurement, calculate final variable and store in adc struct if(++index >= ADC_NUM_AVERAGES) { index = 0; //CHANNEL 5 _adc->V_ID1 = _adc->V_ID1_RAW / ADC_NUM_AVERAGES; //average _adc->V_ID1 = _adc->V_ID1 / 4096.0 * ADC_VREF; //scaling //CHANNEL 6 _adc->V_ID2 = _adc->V_ID2_RAW / ADC_NUM_AVERAGES; //average _adc->V_ID2 = _adc->V_ID2 / 4096.0 * ADC_VREF; //scaling //CHANNEL 4 _adc->V_BAT = _adc->V_BAT_RAW / ADC_NUM_AVERAGES; //average _adc->diag_bat = (_adc->V_BAT); _adc->V_BAT = _adc->V_BAT / 4096.0 * 3.3;//ADC_VREF; //scaling float temp; temp = 10000.0/59900.0; _adc->V_BAT = _adc->V_BAT / temp; //CHANNEL 3 _adc->V_PSU = _adc->V_PSU_RAW / ADC_NUM_AVERAGES; //average _adc->V_PSU = _adc->V_PSU / 4096.0 * ADC_VREF; //scaling //CHANNEL 8 _adc->V_TMP = _adc->V_TMP_RAW / ADC_NUM_AVERAGES; //average _adc->V_TMP = _adc->V_TMP / 4096.0 * ADC_VREF; //scaling //CHANNEL 10 - Battery ID _adc->V_BID = _adc->V_BID_RAW / ADC_NUM_AVERAGES; //average _adc->V_BID = _adc->V_BID / 4096.0 * 3.3;//ADC_VREF; //scaling //############# Added 2/5/24 // _adc->V_BID = _adc->V_BID * 1.09; // additional scaling factor temp = 10000.0/59900.0; _adc->V_BID = _adc->V_BID / temp; //############## //CHANNEL 7 _adc->V_CHK = _adc->V_CHK_RAW / ADC_NUM_AVERAGES; //average volts_check = _adc->V_CHK; //scaling _adc->V_PSU = _adc->V_PSU * (1000+47.5)/47.5; // vratio; _adc->V_CHK = _adc->V_CHK / 4096.0 * ADC_VREF; //ADC bits & ref voltage #if 1 //HV scaling _adc->V_CHK *= 2.0; //Divider in the LPF _adc->V_CHK += 0.7; //diode drop from rectifier _adc->V_CHK = _adc->V_CHK * (402.0 + 3.92) / 3.92; //voltage divider #else _adc->V_CHK *= 599.0 / 100.0; // Vin = Vadc* (R1+R2) / R2 _adc->V_CHK *= 100; //rough scale factor needs to be re done later #endif //clear raw sums _adc->V_ID1_RAW = 0; _adc->V_ID2_RAW = 0; _adc->V_CHK_RAW = 0; _adc->V_PSU_RAW = 0; _adc->V_BAT_RAW = 0; _adc->V_TMP_RAW = 0; _adc->V_BID_RAW = 0; } // ######################################################################### // New Filter Section // float32_t FILT_ExpAvgF32(float32_t input, float32_t *temp, float32_t k) float32_t k=0.02; float32_t fast_k=0.0951; _adc->V_OUT_SlowFilt = FILT_ExpAvgF32(_adc->V_OUT,&_adc->V_OUT_Delay,k); _adc->I_OUT_SlowFilt = FILT_ExpAvgF32(_adc->I_OUT,&_adc->I_OUT_Delay,k); _adc->V_OUT_FastFilt = FILT_ExpAvgF32(_adc->V_OUT,&_adc->V_OUT_FastDelay,fast_k); _adc->I_OUT_FastFilt = FILT_ExpAvgF32(_adc->I_OUT,&_adc->I_OUT_FastDelay,fast_k); if(_adc->I_OUT_FastFilt > 0) { _adc->Ohms_slowfilt = FILT_ExpAvgF32(_adc->V_OUT_FastFilt/_adc->I_OUT_FastFilt,&_adc->Ohms_SlowDelay,k); if(isnanf(_adc->Ohms_SlowDelay)) //Fix nan delay line { _adc->Ohms_SlowDelay = 0.00001; } } //########################################################################## Watts_Filt = _adc->V_OUT_FastFilt * (_adc->I_OUT_FastFilt); // Ohms_filt = _adc->V_OUT_Filt/_adc->I_OUT_Filt; #if ADC_MEASUREMENT_TEST //USAGE: Set _adc->testCollectData = 1; to start data collection //_adc->testIout = FILT_ExpAvgF32(_adc->testIout,&_adc->testIoutDelay,fast_k); //_adc->testVout = FILT_ExpAvgF32(_adc->testVout,&_adc->testVoutDelay,fast_k); //Test data collection for measuring filter responses static uint32_t idx = 0; static bool measure = 1; if(_adc->testCollectData && measure) { _adc->testData1[idx] = _adc->V_OUT_FastFilt; _adc->testData2[idx] = _adc->I_OUT_FastFilt * 1000.0; //convert to mA idx++; if(idx >= ADC_NUM_TEST) { _adc->testCollectData = 0; //stop data collection idx = 0; //reset idx measure = 0; //DO NOT take another measurement (Don't clear and it'll measure again) } } #endif } /* Exponential averaging filter * @input float32_t input * @*temp float32_t storage for temporary variable * @k float32_t filter constant k = 1 - exp(-1/T*Fs) */ float32_t FILT_ExpAvgF32(float32_t input, float32_t *temp, float32_t k) { return *temp += (input - *temp) * k; }