// // HW_drivers.c // // Description: Contains the general hardware handler routines. // // History: // 2002.08.25 - Stephane Gauthier - Ported from Xtreme Overkill. // 2002.10.06 - Stephane Gauthier - Added adc_read(). // 2003.01.02 - Stephane Gauthier - Moved gpd_lookup[] to FLASH. // #include "AvrX.h" #include #include #include "hardware.h" #include "HW_drivers.h" #include "serialio.h" #include "generalio.h" #include "math.h" #include "I2C.h" #include "SCM/scm_cmds.h" static AVRX_MUTEX(ADC_Mutex); //extern ConfigData R_ParameterTable; //static const unsigned char gpd_lookup[] FLASH = static char gpd_lookup[] PROGMEM = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 60, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 46, 45, 44, 43, 43, 42, 41, 41, 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 33, 32, 32, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27, 27, 27, 26, 26, 26, 26, 25, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23, 23, 22, 22, 22, 22, 22, 21, 21, 21, 21, 21, 21, 20, 20, 20, 20, 20, 20, 19, 19, 19, 19, 19, 19, 19, 18, 18, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 17, 17, 17, 17, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}; // Function Name: InitADC() // // Description: Initialize ADC hardware. (Port Direction bits are assumed to be configured elsewhere) // // void InitADC(void) { /* Prime ADC mutex */ AvrXSetSemaphore(&ADC_Mutex); // configure ADC for left-adjusted results. ADCSR = ADCSR_INIT; ADMUX = ADMUX_INIT; SFIOR = SFIOR_INIT; } // Function: adc_read() // // Description: Start an ADC conversion on the specified channel and returns the result. // unsigned char adc_read(unsigned char channel) { unsigned char s; AvrXWaitSemaphore(&ADC_Mutex); // To make function re-entrant. s = SREG; // Save processor status BeginCritical(); // Select channel to read ADMUX = ADMUX & 0xE0; // Mask off select bits (5 bits) ADMUX = ADMUX | (channel & 0x1F); // truncate channel and apply it. // Clear completion flag (precaution??) sbi(ADCSR, ADIF); // Start conversion sbi(ADCSR, ADSC); // Wait 'till conversion is done. (measured to be around 30us so won't bother with semaphore) loop_until_bit_is_set(ADCSR, ADIF); // EndCritical(); SREG = s; // Restore processor status AvrXSetSemaphore(&ADC_Mutex); // Release to waiting tasks. return (ADCH); } // Function: gpd_read() // // Description: Read the selected GP2D12 sensor and convert to centimeters. // unsigned char gpd_read(unsigned char sensor) { unsigned char reading; unsigned char distance; unsigned int average; unsigned char i; average = 0; for (i = 0; i < GPD_SAMPLES ; i++) { reading = adc_read(sensor); // debug //PutChar('('); //PutDecWord(reading); //PutChar(')'); // fetch conversion factor from lookup table (in FLASH) average += PRG_RDB(&gpd_lookup[reading]); } distance = average/GPD_SAMPLES; // Compensate for the 10cm offset. Return distance from outside robot shell, not from sensor! if (distance == 255) return (255); else return (distance-10); } // Function Name: SCM_Init() // // Description: Initialize The Smart Camera Module (SCM). // // void SCM_Init(void) { // Init Exposure i2c_writebyte(SCM_I2C_ADDR, GB_C0, R_ParameterTable.scm_exposure_l); i2c_writebyte(SCM_I2C_ADDR, GB_C1, R_ParameterTable.scm_exposure_h); // Init min size and threshold i2c_writebyte(SCM_I2C_ADDR, SCM_TARGET_MIN_SIZE, R_ParameterTable.scm_min_size); i2c_writebyte(SCM_I2C_ADDR, SCM_THRESHOLD, R_ParameterTable.scm_threshold); // Apply changes i2c_writebyte(SCM_I2C_ADDR, SCM_UPDATE, 0x01); } // Function Name: SCM_calibrate() // // Description: Have the SCM calibrate to the current light conditions and candle. // Inputs: If save argument is TRUE, then save resulting exposure to EEPROM. // void SCM_calibrate(unsigned char save) { bit_set(LED0); //debug i2c_writebyte(SCM_I2C_ADDR, SCM_AUTO_CALIBRATE, TRUE); while (i2c_readbyte(SCM_I2C_ADDR, SCM_AUTO_CALIBRATE) != FALSE) ; bit_clear(LED0); // debug // If result was positive, save to EEPROM if (i2c_readbyte(SCM_I2C_ADDR, SCM_STATUS) == TRUE && save == TRUE) { eeprom_write_byte(&E_ParameterTable.scm_exposure_h, i2c_readbyte(SCM_I2C_ADDR, GB_C1)); eeprom_write_byte(&E_ParameterTable.scm_exposure_l, i2c_readbyte(SCM_I2C_ADDR, GB_C0)); } } // Function Name: Line_calibrate() // // Description: Sample the line sensors and calibrate. (Robot should be placed over a white line first) // Inputs: If save argument is TRUE, then save resulting exposure to EEPROM. // void Line_calibrate(unsigned char save) { unsigned int sample_l; unsigned int sample_r; unsigned char i; #define LINE_SAMPLES 3 // // Get Max reading for Both Line sensors // sample_l = 0x0; // Setup sample_r = 0x0; for (i = 0; i < LINE_CALIBRATE_SAMPLES; i++) { // Keep highest samples sample_l = MAX(adc_read(LINE_SENSOR_L), sample_l); sample_r = MAX(adc_read(LINE_SENSOR_R), sample_r); } // Debug PutDecWord(sample_l); PutChar('-'); PutDecWord(sample_r); // Save results to RAM parameter table (temporary) R_ParameterTable.line_threshold = MAX(sample_r, sample_l); PutChar('='); PutDecWord(R_ParameterTable.line_threshold); // Apply fudge factor and validify it. R_ParameterTable.line_threshold += ((R_ParameterTable.line_threshold * LINE_CALIBRATE_FUDGE_FACTOR) / LINE_CALIBRATE_FUDGE_DIV); PutChar('='); PutDecWord(R_ParameterTable.line_threshold); // Should we make those permanent? if (save == TRUE) { eeprom_write_byte(&E_ParameterTable.line_threshold, R_ParameterTable.line_threshold); } }