outputting the voltage in the Ramp code for Cyclic Voltammetry

Hi there,

I'm now using the Ramp example code to do CV - it's working as expected. However, I'm trying to modify the code to output the voltage associated with each current in addition to the current (like how you can see the Voltage in SensorPal). But I'm not sure exactly how to derive the voltage value. Of course I can infer it from the parameters I set, but I'd like to be able to read it directly from the firmware to verify the assumptions I'm making about the Vzero values. I thought maybe I could use the AD5940_ADCCode2Volt function somehow, but I'm not sure how. Does anyone else have an idea how to do this?

Thank you!

  • Hi,

    You may add a line in AppRAMPDataProcess() as below:

    static int32_t AppRAMPDataProcess(int32_t *const pData, uint32_t *pDataCount)
    {
    uint32_t i, datacount;
    datacount = *pDataCount;
    float *pOut = (float *)pData;
    float temp;
    for(i = 0; i < datacount; i++)
    {
    pData[i] &= 0xffff;
    temp = -AD5940_ADCCode2Volt(pData[i], AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);

    printf(printf("Ramp voltage: %f \n", temp);


    pOut[i] = temp / AppRAMPCfg.RtiaValue.Magnitude * 1e3f; /* Result unit is uA. */
    }
    return 0;
    }

  • Hi Akila,

    Thanks for the reply -- but this isn't quite what I'm looking for. I'm trying to get the ramp voltage -- i.e. the voltage that's being applied (the one that's shaped like two sides of a triangle), not the output current transformed into a voltage. I realize it's possible to calculate it based on the input parameters, but I'd like to also output it as a sanity check.

  • Hi,

    You may modify AppRAMPSeqADCCtrlGen() as below:

    static AD5940Err AppRAMPSeqADCCtrlGen(void)
    {
    AD5940Err error = AD5940ERR_OK;
    const uint32_t *pSeqCmd;
    uint32_t SeqLen;
    DSPCfg_Type dsp_cfg;

    uint32_t WaitClks;
    ClksCalInfo_Type clks_cal;

    clks_cal.DataCount = 1; /* Sample one point everytime */
    clks_cal.DataType = DATATYPE_SINC3;
    clks_cal.ADCSinc3Osr = AppRAMPCfg.ADCSinc3Osr;
    clks_cal.ADCSinc2Osr = ADCSINC2OSR_1067; /* Don't care */
    clks_cal.ADCAvgNum = ADCAVGNUM_2; /* Don't care */
    clks_cal.RatioSys2AdcClk = AppRAMPCfg.SysClkFreq / AppRAMPCfg.AdcClkFreq;
    AD5940_ClksCalculate(&clks_cal, &WaitClks);

    AD5940_StructInit(&dsp_cfg, sizeof(dsp_cfg));
    dsp_cfg.ADCBaseCfg.ADCPga = AppRAMPCfg.AdcPgaGain;
    dsp_cfg.ADCFilterCfg.ADCSinc3Osr = AppRAMPCfg.ADCSinc3Osr;
    dsp_cfg.ADCFilterCfg.ADCRate = ADCRATE_800KHZ; /* ADC runs at 16MHz clock in this example, sample rate is 800kHz */
    dsp_cfg.ADCFilterCfg.BpSinc3 = bFALSE; /* We use data from SINC3 filter */
    dsp_cfg.ADCFilterCfg.Sinc2NotchEnable = bTRUE;
    dsp_cfg.ADCFilterCfg.BpNotch = bTRUE;
    dsp_cfg.ADCFilterCfg.ADCSinc2Osr = ADCSINC2OSR_1067; /* Don't care */
    dsp_cfg.ADCFilterCfg.ADCAvgNum = ADCAVGNUM_2; /* Don't care because it's disabled */

    AD5940_SEQGenCtrl(bTRUE);
    /*Measure ramp voltage*/
    dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_VZERO0
    dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_VBIAS0
    AD5940_DSPCfgS(&dsp_cfg);

    AD5940_SEQGpioCtrlS(AGPIO_Pin2);
    AD5940_AFECtrlS(AFECTRL_ADCPWR, bTRUE);
    AD5940_SEQGenInsert(SEQ_WAIT(16 * 250)); /* wait 250us for reference power up */
    AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE); /* Start ADC convert */
    AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); /* wait for first data ready */
    AD5940_AFECtrlS(AFECTRL_ADCPWR | AFECTRL_ADCCNV, bFALSE); /* Stop ADC */
    AD5940_SEQGpioCtrlS(0);

    /*Measure CV response*/
    dsp_cfg.ADCBaseCfg.ADCMuxN = ADCMUXN_LPTIA0_N;//ADCMUXN_VZERO0
    dsp_cfg.ADCBaseCfg.ADCMuxP = ADCMUXP_LPTIA0_P;//ADCMUXP_VBIAS0
    AD5940_DSPCfgS(&dsp_cfg);

    AD5940_SEQGpioCtrlS(AGPIO_Pin2);
    AD5940_AFECtrlS(AFECTRL_ADCPWR, bTRUE);
    AD5940_SEQGenInsert(SEQ_WAIT(16 * 250)); /* wait 250us for reference power up */
    AD5940_AFECtrlS(AFECTRL_ADCCNV, bTRUE); /* Start ADC convert*/
    AD5940_SEQGenInsert(SEQ_WAIT(WaitClks)); /* wait for first data ready */
    AD5940_AFECtrlS(AFECTRL_ADCPWR | AFECTRL_ADCCNV, bFALSE); /* Stop ADC */
    AD5940_SEQGpioCtrlS(0);
    AD5940_EnterSleepS();/* Goto hibernate */
    /* Sequence end. */
    error = AD5940_SEQGenFetchSeq(&pSeqCmd, &SeqLen);
    AD5940_SEQGenCtrl(bFALSE); /* Stop sequencer generator */

    if(error == AD5940ERR_OK)
    {
    AD5940_StructInit(&AppRAMPCfg.ADCSeqInfo, sizeof(AppRAMPCfg.ADCSeqInfo));
    if((SeqLen + AppRAMPCfg.InitSeqInfo.SeqLen) >= AppRAMPCfg.MaxSeqLen)
    return AD5940ERR_SEQLEN;
    AppRAMPCfg.ADCSeqInfo.SeqId = SEQID_2;
    AppRAMPCfg.ADCSeqInfo.SeqRamAddr = AppRAMPCfg.InitSeqInfo.SeqRamAddr + AppRAMPCfg.InitSeqInfo.SeqLen ;
    AppRAMPCfg.ADCSeqInfo.pSeqCmd = pSeqCmd;
    AppRAMPCfg.ADCSeqInfo.SeqLen = SeqLen;
    AppRAMPCfg.ADCSeqInfo.WriteSRAM = bTRUE;
    AD5940_SEQInfoCfg(&AppRAMPCfg.ADCSeqInfo);
    }
    else
    return error; /* Error */
    return AD5940ERR_OK;
    }

    and you may modify AppRAMPDataProcess() as below:

    static int32_t AppRAMPDataProcess(int32_t *const pData, uint32_t *pDataCount)
    {
    uint32_t i, datacount;
    datacount = *pDataCount;
    float *pVolt, *pCurrent;
    float *pOut = (float *)pData;
    float temp;
    for(i = 0; i < datacount; i++)
    {
    pVolt = pData++;
    pCurrent = pData;
    pVolt &= 0xffff;
    temp = -AD5940_ADCCode2Volt(pVolt, AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);
    Printf("Vbias - Vzero = %f/n",temp);

    pCurrent &= 0xffff;
    temp = -AD5940_ADCCode2Volt(pCurrent, AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);
    pOut[i] = temp / AppRAMPCfg.RtiaValue.Magnitude * 1e3f; /* Result unit is uA. */
    }
    return 0;
    }

    Via code, any measurement alteast goes through ADC. Can't measure it directly before ADC.

  • Hi Akila,

    Thanks for this! This is super helpful. A few follow-up questions.

    1. In the original AppRAMPSeqADCCtrlGen code, AD5940_SEQGenCtrl(bTRUE); gets called once right before  AD5940_SEQGpioCtrlS(AGPIO_Pin2); -- in this revised code it still only get called once right before "Measure Ramp Voltage" - can you confirm that it only needs to get called a single time?

    2. I'm aconfused about the revised code in AppRAMPDataProcess  - specifically:
      1. pVolt = pData++;  this throws an error: cannot assign to variable 'pData' with const qualified type. Given that pData is a const, I don't see how you can increment it. Also, how can you assign pData to pVolt when the latter is a float and the former is an int? Should I be trying to increment i instead of pData? is the pData array now alternating voltage / current values?
      2. Indeed, on the line pCurrent = pData; I get an incompatible pointer types warning because it assigns a const int pointer to a float pointer. 
      3. on the line  pVolt &= 0xffff; I get an error "invalid operands to binary expression ('float *' and 'int') - I get the idea that I'm doing this AND in order only look at the last 16 bits of pVolt, but this doesn't seem to work.

      4. on the line  temp = -AD5940_ADCCode2Volt(pVolt, AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt); - i also get a warning because AD5940_ADCCode2Volt expects an unsigned int to be the first argument but I'm passing a float *. 

    thanks again!

  • hi,

    1) Yes, it needs to be called only once.

    2) Yes.You may modify as below:

    static int32_t AppRAMPDataProcess(int32_t *const pData, uint32_t *pDataCount)
    {
    uint32_t i, datacount;
    datacount = *pDataCount;
    int32_t pVolt, pCurrent;
    float *pOut = (float *)pData;
    float temp;
    for(i = 0; i < datacount; i++)
    {
    pVolt = pData[i++];
    pCurrent = pData[i];
    pVolt &= 0xffff;
    temp = -AD5940_ADCCode2Volt(pVolt, AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);
    printf("Vbias - Vzero = %f/n",temp);

    pCurrent &= 0xffff;
    temp = -AD5940_ADCCode2Volt(pCurrent, AppRAMPCfg.AdcPgaGain, AppRAMPCfg.ADCRefVolt);
    pOut[i] = temp / AppRAMPCfg.RtiaValue.Magnitude * 1e3f; /* Result unit is uA. */
    }
    return 0;
    }