This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

MSPM0G3507: ADC value update freeze, using DMA.

Part Number: MSPM0G3507
Other Parts Discussed in Thread: SYSCONFIG,

Tool/software:

Hi all,

I am reading data through ADC using DMA and implemented a firmware for an ev charger.
There is an AC voltage reading which i am reading from a the power board of my charger.
Now there is a random scenario where my adc raw values are gettting 0 or sometimes, they are not getting updated, which is affecting my charger's functionality.
On a MCU reset, they start updating correctly, but problem manifests itself again randomly.
The firmware was working perfectly with an earlier version of charger.
Now there is an update in power board but the input for AC mains is working fine and verified via scope.

I have done probing on the MCU pin from where i am taking input for "ac_mains_voltage". The input is working perfectly(in the range of 0 to 3.3V) which was verified on Oscilloscope.
But the raw ADC values are shown as 0, or they remain constant. I have logged this info using CAN msgs and the firmware is not in an infinite loop or any hard fault or seg fault.
Can anyone please help me to solve this and reach to the root cause of this issue?

Thanks in advance.

  • Hi,

    If possible, could you please provide more details like your Sysconfig configuration(file or screenshot) or just a test project for us to check whether we can reproduce the issue from our side.

    Best Regards,
    Peter 

  • Hi Peter,

    It would not be possible to share the complete firmware details but I am sharing the ADC and DMA configuration in the attached file.
    Also the issue is observed when it is connected with battery and current is flowing.

    Is this related to the issue observed in the following forum
    e2e.ti.com/.../am335x-tsc_adc-hangs

    void ADC_DRV_Config(ADC12_Regs * const adc_inst, const adc_converter_config_t * const config , const adc_config_Conversion_Mem_t * const ConfigMem )
    {
        assert(config != NULL);
        uint32_t NoAdcChannel;
        uint32_t adcMemIdx = 0;
    
        NoAdcChannel = config->AdctotalChannel;
    
        DL_ADC12_setClockConfig(adc_inst, config->clkSetting);
    
        if(config->AdcConversionMode == 1u)
        {
            DL_ADC12_initSeqSample(adc_inst, DL_ADC12_REPEAT_MODE_DISABLED, config->AdcSamplingSource, config->AdcTriggerSource,
                                   config->AdcSeqStartAddr, config->AdcSeqStopAddr, config->AdcSampConvResolution, config->AdcSampConvDataForamt);
    
            for(uint32_t AdcChannel = 0; AdcChannel <= NoAdcChannel; AdcChannel++)
             {
                 DL_ADC12_configConversionMem(adc_inst, adcMemIdx,AdcChannel, ConfigMem->vref, ConfigMem->stime, ConfigMem->avgen,ConfigMem->bcsen, ConfigMem->trig, ConfigMem->wincomp);
                 adcMemIdx++;
             }
    
           ADC_Dma_Config(adc_inst);
        }
        else
        {
            if(NoAdcChannel == 0u && config->AdcConversionMode == 0u)
            {
                DL_ADC12_configConversionMem(adc_inst, adcMemIdx, NoAdcChannel, ConfigMem->vref, ConfigMem->stime, ConfigMem->avgen,ConfigMem->bcsen, ConfigMem->trig, ConfigMem->wincomp);
            }
        }
    
        if(config->AdcInterruptEnable == 1u)
        {
            ADC_Interrupt_enable(adc_inst, config->AdcinterruptMask);
        }
        else
        {
             __NOP();
        }
    }
    
    adc_converter_config_t adConv1_ConvConfig0 = {
      .clkSetting            = &gADC12_1ClockConfig,
      .AdcRepeatMode         = DL_ADC12_REPEAT_MODE_ENABLED,
      .AdcSampConvDataForamt = DL_ADC12_SAMP_CONV_DATA_FORMAT_UNSIGNED,
      .AdcSampConvResolution = DL_ADC12_SAMP_CONV_RES_12_BIT,
      .AdcSamplingSource     = DL_ADC12_SAMPLING_SOURCE_AUTO,
      .AdcTriggerSource      = DL_ADC12_TRIG_SRC_SOFTWARE,
      .AdcSeqStartAddr       = DL_ADC12_SEQ_START_ADDR_00,
      .AdcSeqStopAddr        = DL_ADC12_SEQ_END_ADDR_06,
      .AdcinterruptMask      = DL_ADC12_INTERRUPT_DMA_DONE,
      .AdctotalChannel       = TotalAdcChannel,
      .AdcConversionMode     = MultiChannel,
      .AdcInterruptEnable    = 1u,
      .sampleTime            = 500u,
    };
    
    adc_config_Conversion_Mem_t adcConfig_ConvMem ={
      .vref  = DL_ADC12_REFERENCE_VOLTAGE_VDDA,
      .stime = DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP0,
      .avgen = DL_ADC12_AVERAGING_MODE_DISABLED,
      .bcsen = DL_ADC12_BURN_OUT_SOURCE_DISABLED,
      .trig  = DL_ADC12_TRIGGER_MODE_AUTO_NEXT,
      .wincomp = DL_ADC12_WINDOWS_COMP_MODE_DISABLED,
    };
    
    IVEC_McalStatus_e xMCAL_AdcInit(void* adc)
    {
        assert(adc != NULL);
    
        assert(adc == ADC0 || adc == ADC1);
    
        if(b_AdcInitFlag == FALSE)
        {
            ADC_DRV_Config(adc, &adConv1_ConvConfig0, &adcConfig_ConvMem);
    
            b_AdcInitFlag = TRUE;
    
            return IVEC_MCAL_STATUS_SUCCESS;
        }
        else
        {
            return IVEC_MCAL_STATUS_INIT_FAIL;
        }
    }
    
    IVEC_McalStatus_e xMCAL_DmaInit(void* dma)
    {
        assert(dma != NULL);
    
        if(b_dmaInitFlag == FALSE)
        {
            DMA_DRV_Config(dma, &dma_config);
    
            b_dmaInitFlag = TRUE;
    
            return IVEC_MCAL_STATUS_SUCCESS;
        }
        else
        {
            return IVEC_MCAL_STATUS_INIT_FAIL;
        }
    }
    
    dma_config_t dma_config = {
      .dmaConfig = &dmaCh0Config,
      .SrcIncrement = DMA_DMACTL_DMASRCINCR_INCREMENT,
      .DmaDestIncrement = DMA_DMACTL_DMASRCINCR_INCREMENT,
      .dmaChannelID = 0u,
      .dmaSample = 7u,
    };

  • Since you're using DL_ADC12_REPEAT_MODE_DISABLED, my first guess is that there is a race in the completion logic which sometimes fails to restart the ADC (or maybe the DMA).

    Can you show your ADC completion ISR?

  • Hi Bruce,

    Below is the ADC ISR implementation in my firmware. I have tried toggling a LED within ecu_al_measurements_load_conversion and sending a CAN message within the ADC1_IRQHandler.

    My finding is that while in working condition I am receiving CAN message and LED toggle but after some time the LED toggle and CAN message both stops. What might be the possible reason for the issue?

    void ADC1_IRQHandler(void)
    {
        charger_diag_t retu = {0};
        g_ret = (uint8_t)DL_ADC12_getPendingInterrupt(ADC1);
        retu.current = g_ret;
        J1939_CAN_Transmit(0x1f0,(uint8_t*)&retu, sizeof(charger_diag_t));
        switch (g_ret)
        {
        case DL_ADC12_IIDX_DMA_DONE:
            xMCAL_DmaAddrConfig(DMA, xMCAL_AdcgetMemaddress(ADC1),(uint32_t)&adc_raw_value.u16_gADCSamples[0]);
            ecu_al_measurements_load_conversion();
            break;
        default:
            break;
        }
    }
    
    IVEC_McalStatus_e xMCAL_DmaAddrConfig(void* dma, uint32_t SrcAddr, uint32_t DestAddr)
    {
        assert(dma != NULL);
    
        if(b_dmaInitFlag == TRUE)
        {
            DMA_ADDR_Config(dma, &dma_config, SrcAddr, DestAddr);
    
            return IVEC_MCAL_STATUS_SUCCESS;
        }
        else
        {
            return IVEC_MCAL_STATUS_INIT_FAIL;
        }
    }
    
    void DMA_ADDR_Config(DMA_Regs * const dma_inst , const dma_config_t * const config, uint32_t srcAddr, uint32_t destAddr)
    {
        DL_DMA_setSrcAddr(dma_inst, config->dmaChannelID, srcAddr);//(uint32_t)DL_ADC12_getMemResultAddress(ADC12_1_INST,DL_ADC12_MEM_IDX_0));
    
        DL_DMA_setDestAddr(dma_inst, config->dmaChannelID, destAddr);//(uint32_t)&gADCSamples[0]);
    
        DL_DMA_setTransferSize(dma_inst, config->dmaChannelID, config->dmaSample); //ADC_DMA_SAMPLES);
    
        DL_DMA_enableChannel(dma_inst, config->dmaChannelID);
    }
    
    dma_config_t dma_config = {
      .dmaConfig = &dmaCh0Config,
      .SrcIncrement = DMA_DMACTL_DMASRCINCR_INCREMENT,
      .DmaDestIncrement = DMA_DMACTL_DMASRCINCR_INCREMENT,
      .dmaChannelID = 0u,
      .dmaSample = 7u,
    };

  • I see where you're restarting the DMA, but not where you restart the ADC. Does that happen in ecu_al_measurements_load_conversion()?

  • Hi Bruce, I am also working on this exact issue. The reason of not restarting the ADC is that, a timer is configured to start / trigger the ADC conversion every 2ms. And it does the work correctly. After a random interval of time(maybe 15 mins, for sometimes even 90-100 mins), the ADC values just 'freeze'. all other loops and processes and interrupts continue to function.

  • Hi Bruce,

    I am updating the ADC values when there is a pending interrupt from DMA. This is the time when new values are ready to be fetched from ADC and I use this in my application code. Below is the definition of the ecu_al_measurements_load_conversion() function for your reference.

     

    void ecu_al_measurements_load_conversion(void)
    {
        adc_raw_info_t.u16_pfc_mosfet_temp[adc_samples] = adc_raw_value.u16_gADCSamples[0];
        adc_raw_info_t.u16_llc_temp[adc_samples] =  adc_raw_value.u16_gADCSamples[1];
        adc_raw_info_t.u16_llc_trans_temp[adc_samples] =  adc_raw_value.u16_gADCSamples[2];
        adc_raw_info_t.u16_diode_temp[adc_samples] =  adc_raw_value.u16_gADCSamples[3];
        adc_raw_info_t.u16_ac_mains[adc_samples] =  adc_raw_value.u16_gADCSamples[4];
        adc_raw_info_t.u16_battery_current[adc_samples] =  adc_raw_value.u16_gADCSamples[5];
        adc_raw_info_t.u16_battery_volt[adc_samples] =  adc_raw_value.u16_gADCSamples[6];
    
        ++adc_samples;
    
        if(adc_samples >= NUM_OF_ADC_SAMPLES)
        {
            adc_samples = 0;
        }
        ecu_al_hardware_yellow_led_toggle();
    }

  • Hi Duke, This is the exact issue I am also facing in my firmware. So did you get any lead on the solution for this?

  • Considering that you're using a (2ms) timer trigger, now I wonder if the call to J1939_CAN_Transmit() is taking longer than you expect sometimes, and the DMA isn't ready by the time the ADC is triggered again.

    Do you get a different result if you move that call to somewhere after the switch() statement?

  • Hi Bruce,

    Actually I have earlier tested this without the J1939_CAN_Transmit(). I was just using the ADC1_IRQHandler() as mentioned below. The issue persisted in this too. The CAN transmit was implemented just for the debugging purpose at later point of time. 

    void ADC1_IRQHandler(void)
    {
        switch (DL_ADC12_getPendingInterrupt(ADC1))
        {
        case DL_ADC12_IIDX_DMA_DONE:
            xMCAL_DmaAddrConfig(DMA, xMCAL_AdcgetMemaddress(ADC1),(uint32_t)&adc_raw_value.u16_gADCSamples[0]);
            ecu_al_measurements_load_conversion();
            break;
        default:
            break;
        }
    
    }

    Following this concern let me test the firmware with reducing the load from ecu_al_measurements_load_conversion too and we'll check the behavior.

  • Update:  I have reduced the overhead from the ADC1_IRQHandler and ecu_al_measurements_load_conversion so that ADC will receive via only single channel ie. 4. But still I am facing the same issue.

  • Hey all,

    Below is the schematics with the MCU.

  • Hi Yash,

    Sorry, I was out of office before, let me continue to follow up the case, I hope you can try the following two steps to make it easier for us to synchronize the problem on both sides.

    1. Since now you have used only one channel to do the test and still face the same issue, could you please try to use the example(adc12_max_freq_dma_LP_MSPM0G3507_nortos_ticlang) in our MSPM0-SDK to test it on your board? Just modify the input channel in the Sysconfig as shown below and then download into your board to see if the issue still exist? 

    2.  Could you please use both your code and the code provided in the SDK to test the internal temperature sensor(ADC0 Channel 11) to see if the issue still exist in these two codes? 

    Best Regards,
    Peter