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:使用 DMA 冻结 ADC 值更新。

Guru**** 2373360 points
Other Parts Discussed in Thread: SYSCONFIG
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1524761/mspm0g3507-adc-value-update-freeze-using-dma

器件型号:MSPM0G3507
主题中讨论的其他器件:SysConfig

工具/软件:

大家好!

我将使用 DMA 通过 ADC 读取数据、并为电动汽车充电器实现了固件。
有一个交流电压读数、我从充电器的电源板读取该读数。
现在有一种随机情况、我的 ADC 原始值设置为 0、有时甚至没有更新、这会影响充电器的功能。
在 MCU 复位时、它们开始正确更新、但问题再次随机出现。
固件可以与早期版本的充电器完美配合使用。
现在电源板有更新、但交流电源的输入正常、并通过示波器进行了验证。

我已经在 MCU 引脚上完成了探测、从中获取“AC_BONS_VOLTAGE"的“的输入。 输入正常工作(在 0V 至 3.3V 范围内)、已在示波器上验证。
但原始 ADC 值显示为 0、或保持不变。 我已使用 CAN 消息记录此信息、并且固件不在无限循环或任何硬故障或段故障中。
有人能帮我解决这个问题并找出问题的根本原因吗?

提前感谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    如果可能、您能否提供更多详细信息、例如您的 SysConfig 配置(文件或屏幕截图)、或者仅提供一个测试项目、以便我们检查我们是否可以从我们这边重现问题。

    此致、
    彼得  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Peter:

    无法共享完整的固件详细信息、但我在随附的文件中共享 ADC 和 DMA 配置。
    当它与电池相连且电流正在流动时、也会观察到该问题。

    这是否与在以下论坛中发现的问题有关
    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,
    };

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    由于您使用的 是 DL_ADC12_REPEAT_MODE_DISABLED、因此、我首先猜测完成逻辑存在竞争、有时会无法重新启动 ADC(可能是 DMA)。

    您能否显示 ADC 完成 ISR?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bruce、

    下面是固件中的 ADC ISR 实现。 我已尝试在 ECU_al_measurements_load_conversion 中切换 LED、并在 ADC1_IRQHandler 内发送 CAN 消息。

    我发现、在工作条件下我收到 CAN 消息和 LED 切换、但一段时间后、LED 切换和 CAN 消息都停止。 出现此问题的可能原因是什么?

    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,
    };

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我看到您正在重新启动 DMA 的位置、但没有看到您重新启动 ADC 的位置。 在 ECU_al_measurements_load_conversion() 中是否会发生这种情况?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bruce、我也在处理这个确切的问题。 不重新启动 ADC 的原因是、计时器配置为每 2ms 启动/触发一次 ADC 转换。 它能正常工作。 经过随机的时间间隔(可能为 15 分钟、有时甚至为 90-100 分钟)后、ADC 值只是“冻结“。 所有其他循环、进程和中断继续运行。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bruce、

    当 DMA 产生挂起的中断时、我会更新 ADC 值。 这是可以从 ADC 获取新值并且我在应用程序代码中使用这些值的时间。 下面是  ECU_al_measurements_load_conversion() 函数的定义、供您参考。

     

    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();
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗨 Duke、这是我在固件中也遇到的确切问题。 那么、您是否在解决方案方面获得了领先优势?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    考虑到您正在使用 (2ms) 计时器触发器、现在我想知道对 J1939 can_transmit() 的调用有时比您预期的时间长、并且 在 ADC 再次触发时 DMA 尚未准备就绪。

    如果您将该调用移动到 switch () 语句之后的某个位置,您会得到不同的结果吗?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Bruce、

    实际上我之前在没有 J1939 CAN_TRANSMIT () 的情况下测试过这个。 我只是使用 ADC1_IRQHandler (),如下所述。 这个问题仍然存在。 在稍后进行调试时、仅出于调试目的而实现了 CAN 传输。  

    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;
        }
    
    }

    遵循此问题、让我测试固件并减少 ECU_al_measurements_load_conversion 的负载、我们将检查行为。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    更新: 我减少了 ADC1_IRQHandler 和 ECU_al_measurements_load_conversion 的开销、以便 ADC 仅通过单通道(即)接收。  4.但我仍然面临着同样的问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、

    下面是 MCU 的原理图。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    尊敬的 Yash:

    对不起,我以前不在办公室,让我继续跟进此案,我 希望你可以尝试以下两个步骤,使我们更容易同步双方的问题.

    1.鉴于现在您仅使用一个通道进行测试、并且仍然面临相同的问题、您能否尝试使用 MSPM0-SDK 中的示例 (adc12_max_freq_DMA_LP_MSPM0G3507_nortos_ticlang) 在您的电路板上进行测试? 只需按如下所示修改 SysConfig 中的输入通道、然后下载到电路板中以查看问题是否仍然存在?  

    2. 您能否 使用您的代码和 SDK 中提供的代码来测试内部温度传感器 (ADC0 通道 11)、看看   这两个代码中是否仍然存在问题?  

    此致、
    彼得