00001 /* This file has been prepared for Doxygen automatic documentation generation.*/ 00053 00054 #define module_vadc_usage 1 00055 00056 // Include files 00057 #include <ioavr.h> 00058 #include <inavr.h> 00059 00060 #include "vadc_usage.h" 00061 #include "calibration.h" 00062 #include "ATmega8HVA_16HVA_signature.h" 00063 00064 00065 //File global variables for storing signature bytes/words. 00066 uint16_t vptat_coeff; 00067 uint16_t cell_gain[NO_CELLS]; 00068 int8_t cell_offset[NO_CELLS]; 00069 uint16_t vadc_gain[NO_VADC]; 00070 int8_t vadc_offset[NO_VADC]; 00071 00072 #ifndef USE_CAL_GAIN 00073 uint16_t raw_cal; 00074 #endif 00075 00076 uint16_t vadc_measurement[NO_VADC_CHANNELS]; 00077 uint16_t cell_v[NO_CELLS]; 00078 uint16_t vadc_v[NO_VADC]; 00079 uint16_t bg_temp; 00080 uint8_t vadc_scan_complete; 00081 00082 00083 00084 // Functions 00085 00091 void InitCoeff(void) 00092 { 00093 uint8_t signature_array[SIG_END_ADDRESS+1]; 00094 00095 for(uint8_t i=0 ; i <= SIG_END_ADDRESS ; i++){ 00096 signature_array[i] = READ_SIGNATUREBYTE(i); 00097 } 00098 00099 /* Please note that breaking within 2 cycles of completing a signature byte 00100 * reading will corrupt further AVR Studio flash readout until a reset is issued. 00101 */ 00102 00103 // Coefficient for temperature calculation from internal sensor. 00104 vptat_coeff = signature_array[SIG_VPTAT_L]; 00105 vptat_coeff |= signature_array[SIG_VPTAT_H] << 8; 00106 00107 // Coefficients for cell gain and offset. 00108 cell_gain[0] = signature_array[SIG_VADC_CELL1_GAIN_L]; 00109 cell_gain[0] |= signature_array[SIG_VADC_CELL1_GAIN_H] << 8; 00110 cell_offset[0] = signature_array[SIG_VADC_CELL1_OFFSET]; 00111 00112 cell_gain[1] = signature_array[SIG_VADC_CELL2_GAIN_L]; 00113 cell_gain[1] |= signature_array[SIG_VADC_CELL2_GAIN_H] << 8; 00114 cell_offset[1] = signature_array[SIG_VADC_CELL2_OFFSET]; 00115 00116 // Coefficients for VADC gain and offset. 00117 vadc_gain[0] = signature_array[SIG_VADC_ADC0_GAIN_L]; 00118 vadc_gain[0] |= signature_array[SIG_VADC_ADC0_GAIN_H] << 8; 00119 vadc_offset[0] = signature_array[SIG_VADC_ADC0_OFFSET]; 00120 00121 vadc_gain[1] = signature_array[SIG_VADC_ADC1_GAIN_L]; 00122 vadc_gain[1] |= signature_array[SIG_VADC_ADC1_GAIN_H] << 8; 00123 vadc_offset[1] = signature_array[SIG_VADC_ADC1_OFFSET]; 00124 00125 // Only load raw calibration values if needed. 00126 #ifndef USE_CAL_GAIN 00127 00128 // Using Cell1 for calibration. 00129 #ifdef USE_CELL1_CAL 00130 // RAW Cell1 measurements for 4096mV in. 00131 raw_cal = signature_array[SIG_VADC_RAW_CELL1_L]; 00132 raw_cal |= signature_array[SIG_VADC_RAW_CELL1_H] << 8; 00133 00134 // Using VADC0 for calibration. 00135 #else 00136 // RAW VADC0 measurements with (4096/5)mV in. 00137 raw_cal = signature_array[SIG_VADC_RAW_ADC0_L]; 00138 raw_cal |= signature_array[SIG_VADC_RAW_ADC0_H] << 8; 00139 #endif 00140 00141 #endif 00142 00143 } 00144 00145 00156 int8_t InitBandgap(void) 00157 { 00159 uint8_t bgccr_cal, bgcrr_cal; 00160 int8_t mode; 00161 00162 bgcrr_cal = READ_SIGNATUREBYTE(SIG_BGCRR_CALIB_25C); 00163 00164 #ifdef IGNORE_2ND_CAL 00165 // To do second point calibration on parts that already have. 00166 bgcrr_cal = 0xFF; 00167 #endif 00168 00169 /* Please note that breaking within 2 cycles of completing a signature byte 00170 * reading will corrupt further AVR Studio flash readout until a reset is issued. 00171 */ 00172 if ( bgcrr_cal != 0xFF ){ 00173 // Check to see if part was calibrated at room temperature. 00174 bgccr_cal = 0x3F & READ_SIGNATUREBYTE(SIG_BGCCR_CALIB_25C); 00175 mode = CALIB_ROOM; 00176 } else { 00177 bgcrr_cal = 0x0F; 00178 bgccr_cal = 0x3F & READ_SIGNATUREBYTE(SIG_BGCCR_CALIB_HOT); 00179 00180 if (bgccr_cal == 0x3F) { 00181 return FAILED; 00182 } 00183 00184 mode = CALIB_HOT; 00185 } 00186 00187 BGCRR = bgcrr_cal; 00188 00189 // If done this way device may enter BOD so use method below. 00190 // BGCCR = bgccr_cal; 00191 00192 while (BGCCR < bgccr_cal){ 00193 // Adjust BGCCR up if needed. Slowly to avoid BOD. 00194 BGCCR++; 00195 __delay_cycles(BANDGAP_ADJ_DELAY); 00196 } 00197 00198 // Adjust down if necessary. (Safe - but results in wrong ADC measurements until VREF is stabilized) 00199 BGCCR = bgccr_cal; 00200 00201 return mode; 00202 } 00203 00204 00205 00215 void StartVADCScan(void) 00216 { 00217 //disable ADC0-1 digital input buffer. 00218 DIDR0 = 0x03; 00219 vadc_scan_complete = 0; 00220 00221 // Start set up for first channel. 00222 VADMUX = FIRST_VADC_MEAS; 00223 00224 // Clear any pending interrupt 00225 VADCSR = (1<<VADEN) | (1<<VADCCIF); 00226 00227 //Start the first conversion & enable interrupts 00228 VADCSR = (1<<VADEN) | (1<<VADSC) | (1<<VADCCIE); 00229 00230 // Make sure interrupt are enabled. 00231 __enable_interrupt(); 00232 } 00233 00234 00235 00244 #pragma vector = VADC_vect 00245 __interrupt void VADC_ISR(void) 00246 { 00247 uint8_t temp; 00248 00249 // Used for indexing the vadc_measurement variable 00250 static uint8_t vadc_index = 0; 00251 00252 temp = VADMUX; 00253 00254 // Save the result 00255 vadc_measurement[vadc_index] = VADC; 00256 00257 /* Code could be added here to store current with the associated cell 00258 * voltage if doing cell impedance measurements. 00259 */ 00260 00261 temp++; 00262 vadc_index++; 00263 00264 /* Check for disabling of cell balancing could be inserted here or in "if" 00265 * below. Timing must be adjusted according to discharge time constant. 00266 */ 00267 00268 if(temp > LAST_VADC_MEAS){ 00269 // Finished with no cell inputs. Do cell measurements. 00270 temp = BOTTOM_CELL; 00271 } else { 00272 // Finished with all cells also? 00273 if(temp == (TOP_CELL+1)){ 00274 // Flag that we have new samples! 00275 vadc_scan_complete = 1; 00276 00277 /* Possibly re-enable cell balancing here. */ 00278 00279 // Disable this ADC and its Interrupt. 00280 VADCSR = 0; 00281 vadc_index = 0; 00282 return; 00283 } 00284 } 00285 00286 VADMUX = temp; 00287 00288 //Start next conversion now. 00289 VADCSR |= (1<<VADSC); 00290 } 00291 00292 00293 00300 void CalculateADCResults(void) 00301 { 00302 uint32_t calc; 00303 uint8_t index; 00304 00305 // Calculate new cell voltages. 00306 for(index = 0 ; index < NO_CELLS ; index++) { 00307 calc = vadc_measurement[index + CELL1]; 00308 calc -= cell_offset[index]; 00309 calc *= cell_gain[index]; 00310 cell_v[index] = (uint16_t)(calc >> VADC_SCALE_BITS); 00311 } 00312 00313 /* Code checking for under or over-voltage, and/or calculating cell 00314 * impedances could be inserted here. 00315 */ 00316 00317 // Calculate new VADC voltages. 00318 for(index = 0 ; index < NO_VADC ; index++) { 00319 calc = vadc_measurement[index + VADC0]; 00320 calc -= vadc_offset[index]; 00321 calc *= vadc_gain[index]; 00322 vadc_v[index] = (uint16_t)((calc >> VADC_SCALE_BITS)/10); 00323 } 00324 00325 // Calculate temperature from measurement of internal temp sensor (VPTAT). 00326 calc = vadc_measurement[VPTAT]; 00327 calc *= vptat_coeff; 00328 calc >>= VADC_SCALE_BITS; 00329 bg_temp = (uint16_t)(calc); 00330 00331 /* Code for calculating temperature from external thermistors connected to 00332 * VADC0 and/or VADC1 could be inserted here. Gain and offset coefficients for 00333 * vadc inputs are stored in signature row. 00334 */ 00335 } 00336 00337 00338 00353 int8_t CalibrateVREF(void) 00354 { 00355 volatile uint32_t temp; 00356 int16_t v_error; // Variable to keep error after conversion. 00357 int16_t last_v_error; // Value used to keep old error value during linear scan. 00358 int8_t counter; // Value used to count BGCCR value and index. 00359 00360 // Select terminal input defined in calibration.h 00361 VADMUX = CAL_CHANNEL; 00362 00363 // Enable the VADC. 00364 VADCSR = (1 << VADEN); 00365 00366 // Start a VADC conversion and clear any pending interrupts 00367 VADCSR |= (1 << VADSC) | (1 << VADCCIF); 00368 00369 // Wait while conversion in progress 00370 do {} while(!(VADCSR & (1 << VADCCIF))); 00371 00372 // Dummy read to ensure correct data for next conversion. 00373 temp = VADC; 00374 00375 00376 /* If using cell balancing (e.g ATmega406, and not on ATmega8/16HVA), 00377 * code should be inserted here to wait for error to cancel out. 00378 */ 00379 00380 // First we do the BGCRR / temperature stability calibration. 00381 v_error = MeasureVADCerror(); 00382 counter = 8; 00383 00384 // Check for all different test limits. 00385 while ( (v_error < vcalibration_level[counter]) && (counter >= 0) ) { 00386 counter--; 00387 } 00388 00389 // Set BGCRR to correct setting. 00390 BGCRR = temp_cal[counter]; 00391 00392 // Then we do the BGCCR / absolute value calibration. 00393 v_error = MeasureVADCerror(); 00394 00395 if (v_error < 0){ 00396 do { 00397 // Ratio_counter bit 6 set means calibration failed. 00398 if(--BGCCR == 0x40){ 00399 // Return with fail flag. 00400 return FAILED; 00401 } 00402 last_v_error = v_error; 00403 v_error = MeasureVADCerror(); 00404 00405 } while (v_error < 0); 00406 00407 // Neighbor check, as previous step can select the next best value. 00408 if (v_error > -last_v_error){ 00409 BGCCR++; 00410 } 00411 00412 }else{ 00413 do{ 00414 // Ratio_counter bit 6 set means calibration failed. 00415 if(++BGCCR == 0x40){ 00416 // Return with fail flag. 00417 return FAILED; 00418 } 00419 last_v_error = v_error; 00420 v_error = MeasureVADCerror(); 00421 00422 } while (v_error < 0); 00423 00424 // Neighbor check, as previous step can select the next best value. 00425 if(-v_error > last_v_error){ 00426 BGCCR--; 00427 } 00428 } 00429 00430 /* The found values should be stored in eeprom or possibly flash for 00431 * correct initialisation if device is reset. 00432 */ 00433 return SUCCESS; 00434 } 00435 00436 00444 int16_t MeasureVADCerror(void) 00445 { 00446 // Variable to keep error after conversion. 00447 int32_t vadc_error; 00448 00449 // Start a VADC conversion and clear any pending interrupts 00450 VADCSR |= (1 << VADSC) | (1 << VADCCIF); 00451 00452 // Wait while conversion in progress 00453 do {} while(!(VADCSR & (1 << VADCCIF))); 00454 00455 // Calculate error of VADC measurement. 00456 vadc_error = VADC; 00457 00458 #ifdef USE_CAL_GAIN 00459 vadc_error -= CAL_OFFSET; 00460 vadc_error *= CAL_GAIN; 00461 00462 // Divide by 16384. 00463 vadc_error >>= VADC_SCALE_BITS; 00464 #endif 00465 00466 vadc_error -= VCALIB_VALUE; 00467 return (int16_t) vadc_error; 00468 } 00469 00470
1.5.5