📄 adc_elmb.c
字号:
2. Read the ADC Gain Register
3. Multiply the Gain Register value with the gain factor
4. Write the resulting value to the Gain Register */
#ifdef __VARS_IN_EEPROM__
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
adc_range_id = ((AdcConfig & CS23_CSR_GAIN_MASK) >> CS23_CSR_GAIN_SHIFT);
for( phys_chan_no=0; phys_chan_no<4; ++phys_chan_no )
{
/* Read the gain factor from EEPROM and apply (only if available) */
if( adc_get_calib_const( RANGE_ID[adc_range_id],
phys_chan_no, calibcnst_b, send_emergency ) )
{
UINT32 *ptr;
BYTE *bptr;
/* Read Gain Register (that's just 3 bytes) */
ADC_SELECT();
cs5523_read_reg( CS23_CMD_GAIN_REG, phys_chan_no, gainreg_b );
ADC_DESELECT();
gainreg_b[3] = 0x00;
/* Convert Gain Register value to float */
ptr = (UINT32 *) gainreg_b;
gainreg_l = *ptr;
gainreg_f = (float) gainreg_l;
/* or (less efficient, but portable):
gainreg_l = (((UINT32) gainreg_b[0]) |
(((UINT32) gainreg_b[1]) << 8) |
(((UINT32) gainreg_b[2]) << 16));
gainreg_f = (float) gainreg_l;
*/
/* Convert the gain factor value to float */
ptr = (UINT32 *) calibcnst_b;
calibcnst_l = *ptr;
calibcnst_f = ((float) calibcnst_l) / 1000000.0;
/* or (less efficient, but portable):
calibcnst_l = (((UINT32) gain_b[0]) |
(((UINT32) gain_b[1]) << 8) |
(((UINT32) gain_b[2]) << 16));
calibcnst_f = ((float) gain_l) / 1000000.0;
*/
/* Make sure it has a sensible value */
if( calibcnst_f >= 4.0 || calibcnst_f <= 0.1 ) calibcnst_f = 1.0;
/* Multiply Gain Register value with the gain factor */
gainreg_f = (gainreg_f * calibcnst_f) + 0.5;
/* Convert Gain Register float value back to an array of bytes */
gainreg_l = (UINT32) gainreg_f;
bptr = (BYTE *) &gainreg_l;
/* Write the corrected Gain Register value */
ADC_SELECT();
cs5523_write_reg( CS23_CMD_GAIN_REG, phys_chan_no, bptr );
ADC_DESELECT();
}
}
return result;
}
/* ------------------------------------------------------------------------ */
static BOOL adc_self_calibrate( BOOL send_emergency )
{
BOOL result;
/* Not allowed when ADC conversion in progress... */
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
/* =================================== */
/* OFFSET calibration */
ADC_SELECT();
/* Do a Self Offset calibration... */
#ifdef __VARS_IN_EEPROM__
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
result = cs5523_calibrate( CS23_CMD_OFFSET_SELF_CALIB, AdcConfig );
ADC_DESELECT();
if( result == FALSE )
{
/* Calibration error... */
AdcError |= ADC_ERR_CALIBRATION;
if( send_emergency )
{
/* CANopen Error Code 0x5000: device hardware */
can_write_emergency( 0x00, 0x50, EMG_ADC_OFFSET_CALIB, 0, 0, 0,
ERRREG_MANUFACTURER );
}
adc_serial_init();
return FALSE;
}
/* =================================== */
/* GAIN calibration */
ADC_SELECT();
/* ...followed by a Self Gain calibration */
#ifdef __VARS_IN_EEPROM__
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
result = cs5523_calibrate( CS23_CMD_GAIN_SELF_CALIB, AdcConfig );
ADC_DESELECT();
if( result == FALSE )
{
/* Calibration error... */
AdcError |= ADC_ERR_CALIBRATION;
if( send_emergency )
{
/* CANopen Error Code 0x5000: device hardware */
can_write_emergency( 0x00, 0x50, EMG_ADC_GAIN_CALIB, 0, 0, 0,
ERRREG_MANUFACTURER );
}
adc_serial_init();
return FALSE;
}
/* =================================== */
return TRUE;
}
/* ------------------------------------------------------------------------ */
static void adc_init_confreg( void )
{
/* Remember to select the ADC (if necessary)
before calling this routine (and to deselect afterwards) */
BYTE adc_conf_reg[3];
adc_conf_reg[0] = ADC_CNFREG_0;
adc_conf_reg[1] = ADC_CNFREG_1;
adc_conf_reg[2] = AdcConfReg_2;
/* Write to the Config Register */
cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, adc_conf_reg );
}
/* ------------------------------------------------------------------------ */
static void adc_init_csr( void )
{
/* Remember to select the ADC (if necessary)
before calling this routine (and to deselect afterwards) */
/* Channel Setup Register data
(4 registers, each for 2 Logical Channels,
each consisting of 2 bytes) */
BYTE csr_data[4*2*2];
BYTE i;
/* Settings for Logical Channels 1 to 4 in CSR #1 and #2
(only LC #1 will be used) */
for( i=0; i<4; ++i )
{
csr_data[2*i] = 0; /* LC low byte */
csr_data[2*i+1] = 0; /* LC high byte */
}
/* Settings for Logical Channels 5 to 8 in CSR #3 and #4: these Logical
Channels are used only to set A1A0 pins to be latched !
(to select one of the four 16-chan input banks;
so do that at the maximum possible conversion rate) */
for( i=0; i<4; ++i )
{
BYTE a1a0;
a1a0 = i;
/* LC low byte */
//csr_data[2*(4+i)] = CS23_WORDRATE_101 << CS23_CSR_WORDRATE_SHIFT;
/* ###Don't change the wordrate to do this, because the ADC displays
some erratic behaviour / noisy conversions when changing wordrates */
csr_data[2*(4+i)] = AdcConfig;
/* LC high byte */
csr_data[2*(4+i)+1] = a1a0 << CS23_CSR_A1A0_SHIFT;
}
/* Load initial settings in the CSRs: LC 5 to 8 are used
to select the four 16-chan input banks (via A1A0 latch outputs) */
cs5523_write_csr( 4, csr_data );
}
/* ------------------------------------------------------------------------ */
void adc_serial_init( void )
{
ADC_SELECT();
cs5523_serial_init();
ADC_DESELECT();
}
/* ------------------------------------------------------------------------ */
void adc_pdo_scan_start( BOOL volts, BOOL force_readout )
{
/* Start scanning only if scanning not already in progress, unless
'force_readout' is true AND ADC-readout-on-change is enabled,
then stop the current scan cycle and initiate a new scan cycle
forcing read-out of the ADC channels */
#ifdef __VARS_IN_EEPROM__
AdcChans = eeprom_read( EE_ADCCHANS );
#endif
/* Refresh Data-Direction Register settings */
#ifdef __MOTHERBOARD1__
/* Old Motherboard configuration */
ADC_INIT_DDR_V1();
#endif
#ifndef __ALL_MOTHERBOARDS__
/* Motherboard V3 configuration */
ADC_INIT_DDR_V3();
#endif
#ifdef __VARS_IN_EEPROM__
AdcReadoutOnChange = eeprom_read( EE_ADCREADOUTONCHANGE );
#endif /* __VARS_IN_EEPROM__ */
if( AdcReadoutOnChange && force_readout )
{
/* Stop any ongoing scan cycle */
adc_pdo_scan_stop();
/* Force read-out of all channels at next scan cycle */
AdcForcedReadout = TRUE;
}
if( (AdcScanInProgress & TRUE) == FALSE && AdcChans > 0 )
{
#ifdef __VARS_IN_EEPROM__
AdcCalibBeforeScan = eeprom_read( EE_ADCCALIBBEFORESCAN );
#endif /* __VARS_IN_EEPROM__ */
if( AdcCalibBeforeScan )
{
/* Perform a reset/calibration procedure before each scan... */
adc_reset_and_calibrate( TRUE );
}
else
{
#ifdef __VARS_IN_EEPROM__
AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
ADC_SELECT();
/* Refresh the Configuration Register before each scan... */
adc_init_confreg();
/* Refresh the Channel Setup Registers before each scan... */
adc_init_csr();
ADC_DESELECT();
}
/* Send ADC readout in the form of ADC-counts or voltages ? */
if( (volts & TRUE) == TRUE )
{
/* Readout in volts, if possible */
if( adc_calibrated() )
{
AdcScanVolts = TRUE;
}
else
{
AdcScanVolts = FALSE; /* Do a scan nevertheless?.. */
//return; /* ..or not ? */
}
}
else
{
/* Readout in ADC counts */
AdcScanVolts = FALSE;
}
/* Start an ADC-channels-to-PDOs scan cycle */
AdcChanNo = 0;
AdcScanInProgress = adc_scan_next();
}
}
/* ------------------------------------------------------------------------ */
void adc_pdo_scan_stop( void )
{
/* Abort a channel scan cycle in-progress:
wait for a possibly ongoing ADC conversion... */
if( (AdcScanInProgress & TRUE) == TRUE )
{
if( (AdcConvInProgress & TRUE) == TRUE )
{
#define __ADC_CLEAN_STOP__
#ifdef __ADC_CLEAN_STOP__
/* Wait for the conversion to finish and read out the ADC data */
ADC_SELECT();
/* Wait for SDO to go low flagging the conversion is done,
but use a timeout (ca. 600 ms, sufficient at 1.88 Hz wordrate) */
//if( cs5523_await_sdo_low( 60 ) )
if( cs5523_await_sdo_low( 120 ) ) // Make that 1200 ms...
{
/* Generate 8 SCLKs to clear the SDO flag */
cs5523_write_byte( 0 );
/* Read 24 bits (3 bytes) of conversion data */
cs5523_read_byte();
cs5523_read_byte();
cs5523_read_byte();
}
ADC_DESELECT();
#else /* !__ADC_CLEAN_STOP__ */
/* Is this sufficient ? --> NO!!
(ADC config appears to have changed afterwards) */
adc_serial_init();
#endif /* !__ADC_CLEAN_STOP__ */
}
}
/* Initialize variables for scanning operations */
AdcChanNo = 0;
AdcScanInProgress = FALSE;
AdcConvInProgress = FALSE;
AdcLatchBeingSet = FALSE;
AdcLatchSet = FALSE;
}
/* ------------------------------------------------------------------------ */
void adc_pdo_scan( void )
{
/* Handle an on-going ADC channel scan, or start up
a channel scan cycle when ADC-readout-on-change is enabled */
if( (AdcScanInProgress & TRUE) == TRUE )
{
/* Read out next ADC channel */
AdcScanInProgress = adc_scan_next();
}
else
{
#ifdef __VARS_IN_EEPROM__
/* Refresh some global variables before every scan */
AdcReadoutOnChange = eeprom_read( EE_ADCREADOUTONCHANGE );
#endif /* __VARS_IN_EEPROM__ */
/* Do we have to scan continuously ? (if yes, then start
a new scan immediately when the previous one finished) */
if( AdcReadoutOnChange )
{
#ifdef __VARS_IN_EEPROM__
/* Refresh some global variables before every scan */
AdcDeltaScanEnabled = eeprom_read( EE_ADCDELTASCANENABLED );
AdcWindowScanEnabled = eeprom_read( EE_ADCWINDOWSCANENABLED );
AdcWindowCounterInit = eeprom_read( EE_ADCWINDOWCOUNTERINIT );
#endif /* __VARS_IN_EEPROM__ */
if( AdcDeltaScanEnabled || AdcWindowScanEnabled )
{
/* Yes, but this call to 'adc_pdo_scan_start()' is not a forced
readout, so the parameter is set to FALSE, unless... */
//adc_pdo_scan_start( TRUE, FALSE );
/* ...this is the first scan cycle after the node
has been set to 'Operational' state, in which case
the reference ADC counts ('last-sent') need to be initialized
('AdcInitRefCount' in that case has been set elsewhere to
'TRUE') and read-out of the ADC-channels is forced */
if( (AdcInitRefCount & TRUE) == TRUE )
adc_pdo_scan_start( TRUE, TRUE );
else
adc_pdo_scan_start( TRUE, FALSE );
}
}
}
}
/* ------------------------------------------------------------------------ */
static BOOL adc_scan_next( void )
{
BYTE pdo_data[8];
if( (AdcConvInProgress & TRUE) == TRUE )
{
ADC_SELECT();
/* ! Make sure no delay is necessary here
(due to optocouplers in the interface) !
###Not necessary because we don't deselect the ADC during a scan */
//timer2_delay_mus( AdcOptoDelay );
/* Conversion in progress: check if done */
if( ADC_SDO_LOW() )
{
/* SDO went low --> conversion ready ! */
if( (AdcLatchBeingSet & TRUE) == TRUE )
{
/* This conversion only served to set the A1A0 latches...,
but we *have* to read out the ADC data */
/* Now latch this data */
ADC_CLEAR_MUX_LATCH();
/* Need to insert a delay... */
//timer2_delay_mus( CS23_ELMB_SIGNAL_RISETIME );
timer2_delay_mus( AdcOptoDelay );
ADC_SET_MUX_LATCH();
/* Generate 8 SCLKs to clear the SDO flag */
cs5523_write_byte( 0 );
/* Read 24 bits (3 bytes) of (dummy) ADC conversion data */
cs5523_read_byte();
cs5523_read_byte();
cs5523_read_byte();
ADC_DESELECT();
AdcLatchBeingSet = FALSE;
AdcLatchSet = TRUE;
AdcConvInProgress = FALSE;
}
else
{
/* This conversion results in real data
that we're interested in... */
BYTE adc_stat;
BOOL send_pdo;
UINT16 adc_count;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -