Part Number: AM3358
(This is related to a prior inquiry and I think I have linked to it but the update system didn't make it clear that I did.) I have different questions this time.
For background, this sensor is being read with a BeagleBone Black under Linux with C code using pru0. Our problem is still that we get a 10-30mv drift up on the signal when the ADC steps are enabled. I will post our code below but here is the simple sensor circuit first. 
Basically, when light strikes CR1, the voltage output at TO_AINx)... approaches zero. When the light is blocked, the voltage output at TO_AINx rises toward 1.6V. This circuit is fundamental to our system and has worked very well for our application. Changing it is not currently an option.
The issue is that when we monitor TO_AINx through a unity-gain voltage follower and on a scope, the signal is near zero (e.g., 5 mV) when light is striking CR1, until we start reading the signal with the AM3558's ADC using the BeagleBone. Then, the signal drifts up anywhere from 10-30mv.
The signal currently goes into AIN0 on the ADC. We also use AIN5 as the second step to read another sensor. We have just two steps enabled. They are in one-shot mode. Again, I'll post the set up code below.
I have had a few suggestions about this and would like input from TI before making changes please.
1) It has been suggested that AIN5-AIN7 have less potential to do this because of how they are charge coupled. We can try using AIN6 without too much of a hack on the board. (But this signal would pass through a unity-gain voltage follower circuit mentioned above, combining the two changes.)
a) Is this suggestion valid?
b) If it is valid, must I cut the connection to AIN0 to eliminate the current effect even it I disable AIN0?
2) It has been suggested that all unused AIN inputs be tied to ground. Is there value in this toward solving this problem?
3) Are there any configuration options for the channels that would reduce the drift problem? We currently read the input in a loop as fast as we can.
4) The signal in to AIN5 does not appear to have this drift problem. However, in this case, the signal is coming through an op amp on the output stage of a custom current loop to analog converter. This, in my thinking, lends credence to the idea that there may be a leakage current on the section that has the drift.
Here are the two PRU code routines involved.
static void ADCConfigure(void)
{
unsigned int i, count, data;
// // Actual sensor name as been replaced with "SENSOR WITH DRIFT" to mask a bit of our proprietary process.
/* Enable ADC module clock */
HWREG(SOC_CM_WKUP_REGS + CM_WKUP_ADC_TSC_CLKCTRL) = 0x02;
/* Disable ADC module for configuration */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_CTRL) &= ~0x01;
/* fs = 24MHz / ((CLKDIV+1)*2*Channels*(OpenDly+Average*(14+SampleDly)))
* = 53.57kHz
* CLKDIV = 0
* Channels = 1
* Average = 16
* OpenDly = 0
* SampleDly = 0
*/
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_ADC_CLKDIV) = 0;
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_ADCRANGE) = 0xFFF << 16;
/* Disable all steps for now */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPENABLE) &= 0xFF;
/* Unlock step configuration */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_CTRL) |= 0x04;
//Step 0 config: SW mode, one shot mode, fifo 0, channel 0, AIN0 on the Beaglebone Black, 4 samples averaged
//SENSOR WITH DRIFT
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(0)) = 0x00000008;
//Step 1 config: SW mode, one shot mode, fifo 0, channel 1, AIN1 on the Beaglebone Black, 4 samples averaged
//FLOW METER
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(1)) = 0x00080000; //no averaging
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(1)) = 0x00080004; //averages 2 samples
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(1)) = 0x00080008; //averages 4 samples
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(1)) = 0x0008000C; //averages 8 samples
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(1)) = 0x00080010; //averages 16 samples
//Step 2 config: SW mode, one shot mode, fifo 0, channel 4, AIN4 on the Beaglebone Black, 4 samples averaged
//UNUSED
//HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(2)) = 0x00200008; //averages 4 samples
//Step 2 config: SW mode, one shot mode, fifo 0, channel 5, AIN5 on the Beaglebone Black, 4 samples averaged
//UNUSED
//HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPCONFIG(2)) = 0x00280008; //averages 4 samples
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(0)) = 0xFF000000; //255
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(1)) = 0xFF000000; //255
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(0)) = 0xC8000000; //200
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(1)) = 0xC8000000; //200
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(0)) = 0xAF000000; //175
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(1)) = 0xAF000000; //175
// HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPDELAY(2)) = 0xFF000000;
/* Enable channel ID tag */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_CTRL) |= 0x02;
/* Clear end-of-sequence interrupt */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_IRQSTATUS) = 0x02;
/* Enable end-of-sequence interrupt */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_IRQENABLE_SET) = 0x02;
/* Lock step configuration */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_CTRL) &= ~0x04;
/* Empty FIFO 0 */
count = HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_FIFOCOUNT(0));
for (i = 0; i < count; i++) {
data = HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_FIFODATA(0));
}
/* Enable ADC module */
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_CTRL) |= 0x01;
}
static void ReadSensorValues()
// Actual sensor name as been replaced with "Drifting Sensor" to mask a bit of our proprietary process.
//This procedure reads the current values from the Sensor with Drift and the Flow Sensor.
//(The Flow Sensor value returned is actually calculated by average the last 10 Flow Sensor values. - NOT TRUE CURRENTLY)
{
int i;
unsigned int count;
unsigned int StepRead; // the step that was read
unsigned int RawAnalog; //bottom detector data
// const unsigned int Flow_Sensor_Array_Size = 10;
// static unsigned int Flow_Sensor_Array[10];
// static unsigned int Flow_Sensor_Sum;
// static unsigned int Flow_Sensor_Avg;
// static unsigned int fspnr;
// Start step
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_STEPENABLE) = 0xE; // enables steps 1,2 and 3. TSC Charge is not enabled (bit 0)
// Wait for interrupt
while (!(HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_IRQSTATUS)&0x02));
// Clear interrupt
HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_IRQSTATUS) = 0x02;
Data = 0xFFFFFFFF;
count = HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_FIFOCOUNT(0));
// #PRAGMA MUST_ITERATE
for (i = 0; i < count; i++) // count is the number of readings
// in the ADC FIFO buffer
{
Data = HWREG(SOC_ADC_TSC_0_REGS + TSC_ADC_SS_FIFODATA(0));
StepRead = (Data >> 16) & 0xF;
RawAnalog = Data & 0xFFF;
switch (StepRead)
{
case 0: //DRIFTING SENSOR
DriftingSensor_Voltage = RawAnalog;
break;
case 1: //FLOW SENSOR
Curr_FlowSensorValue = RawAnalog;
if ((CALIBRATE_PID) && (GelPrimed) && (MaxFSVReached == 0))
{
ReadsToMaxFSV++;
if ((Curr_FlowSensorValue > Max_FSV) || (Curr_FlowSensorValue < 114))
//FSV still increasing or FSV is not above .05v yet
{
Max_FSV = Curr_FlowSensorValue;
ReadsSince_FSV_Increase = 0;
}
else
{
ReadsSince_FSV_Increase++;
if (ReadsSince_FSV_Increase > 900) //assume MaxFSVReached (4000 = 500 ms not increasing)
{
MaxFSVReached = 1;
// SavedMax = Max_FSV;
// __R30 |= SignalToSM; // set signal line to Singulator Module high
// SM_Signal_On = 1;
// SM_Read_Count = 0;
}
}
}
// if (Curr_FlowSensorValue > Max_FSV)
// Max_FSV = Curr_FlowSensorValue;
break;
// case 2:
// break;
default: // flash red LED indicating a problem
// for (j=0;j<20;j++)
// {
// FlashPanelLEDs(1,0,0,0,0,1,10);
// }
break;
} //end of Switch statement
} // bottom of for (i = 0; i < count; i++) loop
// finished loop reading all values from ADC FIFO buffer
}