📄 adc_elmb.c
字号:
//for( i=0; i<4; ++i, ++ptr ) microvolts[i] = *ptr;
}
else
{
/* Bipolar measurement: use signed numbers ! */
INT16 *padc_cnt;
INT32 adc_volts_l;
float adc_volts_f;
INT32 *ptr;
/* Interpret the UINT16 as an INT16 */
padc_cnt = (INT16 *) &adc_count;
/* Do the ADC-count to microVolts calculation */
adc_volts_f = (((float)(*padc_cnt)) / 32767.0) * fullscale;
/* Cast to an INT32 */
adc_volts_l = (INT32) adc_volts_f;
/* Copy the INT32 into the BYTE array */
ptr = (INT32 *) microvolts;
*ptr = adc_volts_l;
}
}
/* ------------------------------------------------------------------------ */
BYTE adc_status( BYTE *status )
{
*status = AdcError;
return 1; /* Return number of bytes */
}
/* ------------------------------------------------------------------------ */
BOOL adc_get_config( BYTE subindex, BYTE *nbytes, BYTE *par )
{
*nbytes = 1;
#ifdef __VARS_IN_EEPROM__
AdcChans = eeprom_read( EE_ADCCHANS );
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
switch( subindex )
{
case 0:
/* Number of entries */
par[0] = 21;
break;
case 1:
par[0] = AdcChans;
break;
case 2:
par[0] = ((AdcConfig & CS23_CSR_WORDRATE_MASK) >>
CS23_CSR_WORDRATE_SHIFT);
break;
case 3:
par[0] = ((AdcConfig & CS23_CSR_GAIN_MASK) >>
CS23_CSR_GAIN_SHIFT);
break;
case 4:
par[0] = (AdcConfig & CS23_CSR_UNIPOLAR);
break;
case 6:
{
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
ADC_SELECT();
/* Read the Configuration Register */
cs5523_read_reg( CS23_CMD_CONFIG_REG, 0, par );
ADC_DESELECT();
*nbytes = 4;
}
break;
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
{
BYTE reg, phys_chan_no;
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
if( subindex & 1 ) reg = CS23_CMD_OFFSET_REG;
else reg = CS23_CMD_GAIN_REG;
phys_chan_no = (subindex - 7) >> 1;
ADC_SELECT();
/* Read Register */
cs5523_read_reg( reg, phys_chan_no, par );
ADC_DESELECT();
*nbytes = 4;
}
break;
case 15:
case 16:
case 17:
case 18:
{
BYTE csr_data[4*2*2], *csr, i;
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
ADC_SELECT();
/* Read current CSR content */
cs5523_read_csr( csr_data );
ADC_DESELECT();
subindex -= 15;
/* Extract required CSR data */
csr = &csr_data[subindex << 2];
for( i=0; i<4; ++i ) par[i] = csr[i];
*nbytes = 4;
}
break;
case 19:
{
BYTE wordrate_id;
wordrate_id = ((AdcConfig & CS23_CSR_WORDRATE_MASK) >>
CS23_CSR_WORDRATE_SHIFT);
par[0] = HZ_WORDRATE[wordrate_id];
}
break;
case 20:
{
BYTE adc_range_id;
float v_range_f;
UINT32 v_range_l;
UINT32 *ptr;
adc_range_id = ((AdcConfig & CS23_CSR_GAIN_MASK) >>
CS23_CSR_GAIN_SHIFT);
/* Beware: the conversion from float to UINT32 does NOT
work on V_FULLSCALE (which is stored flash) directly !
(a compiler feature?) */
v_range_f = V_FULLSCALE[adc_range_id];
v_range_l = (UINT32) v_range_f;
/* Copy result to the output BYTE array */
ptr = (UINT32 *) par;
*ptr = v_range_l;
// The following also works:
//BYTE *ptr, i;
//ptr = (BYTE *) &v_range_l;
//for( i=0; i<4; ++i, ++ptr ) par[i] = *ptr;
*nbytes = 4;
}
break;
case 21:
par[0] = AdcOptoDelay;
break;
default:
return FALSE;
}
return TRUE;
}
/* ------------------------------------------------------------------------ */
BOOL adc_set_config( BYTE subindex, BYTE nbytes, BYTE *par )
{
/* If 'nbytes' is zero it means the data set size was
not indicated in the SDO message */
/* Can't do anything if the ADC is in use... */
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
#ifdef __VARS_IN_EEPROM__
AdcChans = eeprom_read( EE_ADCCHANS );
AdcConfig = eeprom_read( EE_ADCCONFIG );
AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
switch( subindex )
{
case 1:
if( nbytes > 1 || par[0] > ADC_MAX_INPUTS ) return FALSE;
AdcChans = par[0];
break;
case 2:
{
if( nbytes > 1 || par[0] > CS23_WORDRATE_7 ) return FALSE;
AdcConfig &= ~CS23_CSR_WORDRATE_MASK;
AdcConfig |= (par[0] << CS23_CSR_WORDRATE_SHIFT);
/* Prepare wordrate-dependent setting for ADC Configuration Register */
if( par[0] == CS23_WORDRATE_61 ||
par[0] == CS23_WORDRATE_84 ||
par[0] == CS23_WORDRATE_101 )
AdcConfReg_2 = ADC_CNFREG_2_CHOP4096;
else
AdcConfReg_2 = ADC_CNFREG_2_CHOP256;
ADC_SELECT();
/* Write the updated setting to the Config Register */
adc_init_confreg();
ADC_DESELECT();
}
break;
case 3:
if( nbytes > 1 || par[0] > CS23_GAIN_2V5 ) return FALSE;
AdcConfig &= ~CS23_CSR_GAIN_MASK;
AdcConfig |= (par[0] << CS23_CSR_GAIN_SHIFT);
break;
case 4:
if( nbytes > 1 || par[0] > 1 ) return FALSE;
if( par[0] == 1 )
AdcConfig |= CS23_CSR_UNIPOLAR;
else
AdcConfig &= ~CS23_CSR_UNIPOLAR;
break;
case 5:
{
BYTE adc_conf_reg[3];
if( nbytes > 1 || par[0] > 1 ) return FALSE;
if( par[0] == 1 )
adc_conf_reg[1] = ADC_CNFREG_1 | CS23_CNF_POWER_SAVE;
else
adc_conf_reg[1] = ADC_CNFREG_1 & (~CS23_CNF_POWER_SAVE);
adc_conf_reg[0] = ADC_CNFREG_0;
adc_conf_reg[2] = AdcConfReg_2;
ADC_SELECT();
/* Write the new setting to the Config Register */
cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, adc_conf_reg );
ADC_DESELECT();
}
break;
case 6:
{
if( !(nbytes == 4 || nbytes == 0) ) return FALSE;
ADC_SELECT();
/* Write the Configuration Register */
cs5523_write_reg( CS23_CMD_CONFIG_REG, 0, par );
ADC_DESELECT();
}
break;
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
{
BYTE reg, phys_chan_no;
if( !(nbytes == 4 || nbytes == 0) ) return FALSE;
if( subindex & 1 ) reg = CS23_CMD_OFFSET_REG;
else reg = CS23_CMD_GAIN_REG;
phys_chan_no = (subindex - 7) >> 1;
ADC_SELECT();
/* Write Register */
cs5523_write_reg( reg, phys_chan_no, par );
ADC_DESELECT();
}
break;
case 15:
case 16:
case 17:
case 18:
{
BYTE csr_data[4*2*2], *csr, i;
if( !(nbytes == 4 || nbytes == 0) ) return FALSE;
ADC_SELECT();
/* Read current CSR content */
cs5523_read_csr( csr_data );
subindex -= 15;
/* Adjust CSR content */
csr = &csr_data[subindex << 2];
for( i=0; i<4; ++i ) csr[i] = par[i];
/* Write new CSR content */
cs5523_write_csr( 4, csr_data );
ADC_DESELECT();
}
break;
case 21:
if( nbytes > 1 || par[0] < 10 ) return FALSE;
AdcOptoDelay = par[0];
break;
default:
return FALSE;
}
#ifdef __VARS_IN_EEPROM__
/* Store values in EEPROM, if changed */
if( eeprom_read( EE_ADCCHANS ) != AdcChans )
eeprom_write( EE_ADCCHANS, AdcChans );
if( eeprom_read( EE_ADCCONFIG ) != AdcConfig )
eeprom_write( EE_ADCCONFIG, AdcConfig );
if( eeprom_read( EE_ADCCONFREG2 ) != AdcConfReg_2 )
eeprom_write( EE_ADCCONFREG2, AdcConfReg_2 );
if( eeprom_read( EE_ADCOPTODELAY ) != AdcOptoDelay )
eeprom_write( EE_ADCOPTODELAY, AdcOptoDelay );
#endif /* __VARS_IN_EEPROM__ */
if( subindex == 3 || subindex == 4 )
/* Recalibrate using the new setting of Input Range or uni/bipolar! */
adc_reset_and_calibrate( TRUE );
return TRUE;
}
/* ------------------------------------------------------------------------ */
BOOL adc_reset_and_calibrate( BYTE send_emergency )
{
BOOL result;
/* Initialise (hardware) error status */
AdcError &= ~ADC_ERR_IN_HARDWARE;
/* Perform calibration only if reset succeeded */
if( (result = adc_reset( send_emergency )) == TRUE )
result = adc_set_calib_regs( send_emergency );
return result;
}
/* ------------------------------------------------------------------------ */
BOOL adc_reset( BOOL send_emergency )
{
BOOL reset_result;
BYTE err_id;
/* Not allowed when ADC scan cycle in progress... */
if( (AdcConvInProgress & TRUE) == TRUE ) return FALSE;
#ifdef __VARS_IN_EEPROM__
AdcConfReg_2 = eeprom_read( EE_ADCCONFREG2 );
AdcOptoDelay = eeprom_read( EE_ADCOPTODELAY );
#endif
/* Select ADC */
ADC_SELECT();
/* Initialize the ADC's serial port interface */
cs5523_serial_init();
/* Reset the ADC */
reset_result = cs5523_reset( &err_id );
/* Initialize Channel Setup Registers */
adc_init_csr();
/* Initialize Configuration Register:
Chop Frequency: 256 Hz (at freq <= 30 Hz), 4096 Hz (other freq)
(recommended by Crystal, CS5523 datasheet pg 14)
Depth Pointer : 001 (read/write 1 CSR at a time) */
adc_init_confreg();
/* Deselect ADC */
ADC_DESELECT();
if( reset_result == FALSE )
{
/* Reset failed */
AdcError |= ADC_ERR_RESET;
/* Generate emergency message ? */
if( send_emergency )
{
/* CANopen Error Code 0x5000: device hardware */
can_write_emergency( 0x00, 0x50, EMG_ADC_RESET, 0, err_id, 0,
ERRREG_MANUFACTURER );
}
return FALSE;
}
return TRUE;
}
/* ------------------------------------------------------------------------ */
static BOOL adc_set_calib_regs( BOOL send_emergency )
{
BOOL result;
BYTE adc_range_id;
BYTE phys_chan_no;
BYTE calibcnst_b[4], gainreg_b[4];
UINT32 calibcnst_l, gainreg_l;
float calibcnst_f, gainreg_f;
/* First do a 'pure' self-calibration:
the calibration factors are applied to the resulting gains */
result = adc_self_calibrate( send_emergency );
/* Apply calibration parameters (when available !)
to adjust the value of the Gain Registers:
for each ADC physical channel (4x):
1. Read the gain factor from EEPROM
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -