daqifi / daqifi-nyquist-firmware

MIT License
0 stars 0 forks source link

Convert Differential ADC Measurements to Signed Voltage Value #2

Closed cptkoolbeenz closed 8 months ago

cptkoolbeenz commented 1 year ago

Differential measurements are not properly converted to Volts through the SCPI command.

cptkoolbeenz commented 8 months ago

To reproduce the error, connect a battery (<=5V) or other floating source positive to pin 9 and negative to pin 8. This should create a negative differential voltage when reading channel 8. However the response needs to be converted (from 2's compliment) or the ADC output format changed: SYSTem:POWer:STATe 1 CONFigure:ADC:CHANnel 8,1 CONFigure:ADC:CHANnel 9,1 CONFigure:ADC:SINGleend 8,0 CONFigure:ADC:SINGleend 9,0 MEASure:VOLTage:DC? 8

-2.8V across pin 8 and 9 results in a value of 5242878.67675781.

adbenGHM commented 8 months ago

Although I have added code to covert to 2's complement still not giving a correct reading. after adding 2's complement : (connecting a AA alkaline cell, +ve to ch 8 and -ve to channel 9) channel 9 reads : 0 channel 8 reads: randomly between 0.7 v to 1.3v (connecting a AA alkaline cell, +ve to ch 9 and -ve to channel 8) channel 9 reads : ~0.85 channel 8 reads: approx -1.2

adbenGHM commented 8 months ago

i added this part to mc12badc.c

static double Convert2sComplementToSignedInt(uint32_t uVal) {
    if (uVal & 0x80000000) {
        uVal = (~uVal) + 1;
        return -(double)uVal;
    } else {
        return (double)uVal;
    }
}
double MC12b_ConvertToVoltage(                                              \
                        const MC12bChannelConfig* channelConfig,            \
                        const AInRuntimeConfig* runtimeConfig,              \
                        const AInSample* sample)
{

    double dataOut = 0.0;
    double range = pModuleRuntimeConfigMC12->Range;
    double scale = channelConfig->InternalScale;
    double CalM = runtimeConfig->CalM;

    dataOut = ( range * scale * CalM * Convert2sComplementToSignedInt(sample->Value))/              \
                        (pModuleConfigMC12->Resolution) + runtimeConfig->CalB;
    return (dataOut);
}
cptkoolbeenz commented 8 months ago

I think the MC12b_ConvertToVoltage function needs to be slightly revised:

double MC12b_ConvertToVoltage(                                              \
                        const MC12bChannelConfig* channelConfig,            \
                        const AInRuntimeConfig* runtimeConfig,              \
                        const AInSample* sample)
{

    double dataOut = 0.0;
    double range = pModuleRuntimeConfigMC12->Range;
    double scale = channelConfig->InternalScale;
    double CalM = runtimeConfig->CalM;
    bool isDiff = runtimeConfig->IsDifferential;

    if(isDiff)
    {
        dataOut = ( range * scale * CalM * 2 * Convert2sComplementToSignedInt(sample->Value))/              \
                        (pModuleConfigMC12->Resolution) + runtimeConfig->CalB;
    }
    else
    {
        dataOut = ( range * scale * CalM * (double)sample->Value)/              \
                            (pModuleConfigMC12->Resolution) + runtimeConfig->CalB;       
    }
    return (dataOut);
}

Note, the scalar 2 in the differential measurement. This is related to the range comment for differential measurements. However, I think there are bigger issues with the way the input is divided before the ADC. Essentially, the divider causes the input to be centered at 0V which will clip half of the signal.

adbenGHM commented 8 months ago

ss1 ss2 ss3 I found another major bug, when _Streaming_Deferred_Interrupt_Task runs it calls Streaming_TriggerADC(&pBoardConfig->AInModules.Data[i]) after checking if the pBoardData->AInState.Data[i].AInTaskState == AINTASK_IDLE, whihc in truns calls ADC_TriggerConversion function, which in turn calls BoardData_Set to set the AInTaskState to AINTASK_CONVSTART. Inside the function BoardData_Set there is a checking

if( index < g_BoardData.AInState.Size )
            {
                memcpy(                                                     \
                            &g_BoardData.AInState.Data[ index ].AInTaskState,\
                            pSetValue,                                      \
                            sizeof(AInSample) );
            }

but is g_BoardData.AInState.Size never initialized so its always zero, thus this if statement is never true and AInTaskState is never set to AINTASK_CONVSTART , ie its always AINTASK_IDLE, thus there is a chance that another conversion might start before the previous is fished

adbenGHM commented 8 months ago

I think the MC12b_ConvertToVoltage function needs to be slightly revised:

double MC12b_ConvertToVoltage(                                              \
                        const MC12bChannelConfig* channelConfig,            \
                        const AInRuntimeConfig* runtimeConfig,              \
                        const AInSample* sample)
{

    double dataOut = 0.0;
    double range = pModuleRuntimeConfigMC12->Range;
    double scale = channelConfig->InternalScale;
    double CalM = runtimeConfig->CalM;
    bool isDiff = runtimeConfig->IsDifferential;

    if(isDiff)
    {
        dataOut = ( range * scale * CalM * 2 * Convert2sComplementToSignedInt(sample->Value))/              \
                        (pModuleConfigMC12->Resolution) + runtimeConfig->CalB;
    }
    else
    {
        dataOut = ( range * scale * CalM * (double)sample->Value)/              \
                            (pModuleConfigMC12->Resolution) + runtimeConfig->CalB;       
    }
    return (dataOut);
}

Note, the scalar 2 in the differential measurement. This is related to the range comment for differential measurements. However, I think there are bigger issues with the way the input is divided before the ADC. Essentially, the divider causes the input to be centered at 0V which will clip half of the signal.

Yes, I though the same because the there is a input divider referenced to ground

adbenGHM commented 8 months ago

I was able to figure out the problem, I removed REP5_5 resistor array and sorted the input and out, then connected the battery to 8 and 9 and it +/-1.5 depending on polarity. So i think without iterating the hardware we wont be able to give support for differential input.

cptkoolbeenz commented 8 months ago

I was able to figure out the problem, I removed REP5_5 resistor array and sorted the input and out, then connected the battery to 8 and 9 and it +/-1.5 depending on polarity. So i think without iterating the hardware we wont be able to give support for differential input.

Agreed. Let's clean up the modifications and keep them in the code for future use.