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.

LP-MSPM0G3519: ADC0 stability issues

Part Number: LP-MSPM0G3519
Other Parts Discussed in Thread: MSPM0G1518, LP-MSPM0G3507, SYSCONFIG, MSPM0G3519

Hello, 

the issue described in the following was already mentioned in this thread (https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1673781/mspm0g1518-synchronized-adc-sampling-issue-mspm0g1518-mspm0g1507-lp-mspm0g3519/6453952)

But since it is not the main issue being discussed there I thought it is worth to give it a own thread. 

 

In our project were using the MSPM0G1518 and for development the LP-MSPM0G3519. 

Due to the implementation of a safety library we observed major stability issues of the ADC0 instance compared to ADC1. 

 

Setup

In our reduced test project ADC0 and ADC1 convert 2 channels sequentially each:

  1. Supply monitor with reference VREF, 15µs sample time
  2. Supply monitor with reference VDDA, 15µs sample time

The conversion is started every 100µs within an ISR handling a SYSTICK interrupt. No other peripherals are configured. All unused pins are set to output low. 

The issue was reproduced using LP-MSPM0G3519 and multiple custom boards using MSPM0G1518.

 

Detail

In the following are some graphs showing the conversion results over 100ms. The ADC results are read in the ISR before restarting the ADCs. 

adc00: ADC0 memres0, adc10: ADC1 memres0, ...

lp_mspm0g3519.png

As it can be seen in the graph ADC1 results are very stable whereas the ADC0 results are much mor unstable with high dips. 

  • Even without starting ADC1, the results of ADC0 still look bad. 
  • Reducing the CPU clock to 32MHz or less did not changed anything.
  • Changing ADC0 clock source to SYSOSC instead of ULPCLK does not help either. 

 

To double check we migrated the project to use a LP-MSPM0G3507:

lp_mspm0g3507.png

Here all measurments a as stable as expected. 

 

Can someone confirm this issue and maybe provide a explanation/ solution?

 

Thanks in advance. 

 

Attachements:

Code:

main.c:

#include "ti_msp_dl_config.h"


volatile uint16_t adc00[1000u];
volatile uint16_t adc01[1000u];
volatile uint16_t adc10[1000u];
volatile uint16_t adc11[1000u];
volatile uint16_t     i;


/**
 * @brief Handle interrupts triggered by TIMER_SWTICK
 * @details
 *
 */
void SysTick_Handler( void ) {
  adc00[i] = DL_ADC12_getMemResult( ADC0_INST, DL_ADC12_MEM_IDX_0 );
  adc01[i] = DL_ADC12_getMemResult( ADC0_INST, DL_ADC12_MEM_IDX_1 );
  adc10[i] = DL_ADC12_getMemResult( ADC1_INST, DL_ADC12_MEM_IDX_0 );
  adc11[i] = DL_ADC12_getMemResult( ADC1_INST, DL_ADC12_MEM_IDX_1 );
  i++;

  if ( 1000 <= i ) {
    i = 0;
  }

  /* Enable and start ADC conversion */
  DL_ADC12_enableConversions( ADC0_INST );
  DL_ADC12_enableConversions( ADC1_INST );
  DL_ADC12_startConversion( ADC0_INST );
  DL_ADC12_startConversion( ADC1_INST);
}


int main(void)
{
    SYSCFG_DL_init();

    while (1) {
        __WFI();
    }
}

 

sysconfig:

/**
 * AI AGENTS: Do not edit this file directly. There is no validation or error feedback when
 * editing manually — mistakes will be silent until the file is loaded in SysConfig.
 * Use the SysConfig MCP server instead to make changes with immediate error reporting.
 *
 * These arguments were used when this file was generated. They will be automatically applied on subsequent loads
 * via the GUI or CLI. Run CLI with '--help' for additional information on how to override these arguments.
 * @cliArgs --device "MSPM0G351X" --part "Default" --package "LQFP-100(PZ)" --product "mspm0_sdk@2.11.00.07"
 * @v2CliArgs --device "MSPM0G3519" --package "LQFP-100(PZ)" --product "mspm0_sdk@2.11.00.07"
 * @versions {"tool":"1.28.0+4712"}
 */

/**
 * Import the modules used in this configuration.
 */
const ADC12   = scripting.addModule("/ti/driverlib/ADC12", {}, false);
const ADC121  = ADC12.addInstance();
const ADC122  = ADC12.addInstance();
const Board   = scripting.addModule("/ti/driverlib/Board");
const SYSCTL  = scripting.addModule("/ti/driverlib/SYSCTL");
const SYSTICK = scripting.addModule("/ti/driverlib/SYSTICK");
const VREF    = scripting.addModule("/ti/driverlib/VREF");

/**
 * Write custom configuration values to the imported modules.
 */
const divider7       = system.clockTree["PLL_PDIV"];
divider7.divideValue = 8;

const divider9       = system.clockTree["UDIV"];
divider9.divideValue = 2;

const gate8  = system.clockTree["MFPCLKGATE"];
gate8.enable = true;

const multiplier2         = system.clockTree["PLL_QDIV"];
multiplier2.multiplyValue = 39;

const mux8       = system.clockTree["HSCLKMUX"];
mux8.inputSelect = "HSCLKMUX_SYSPLL0";

const mux12                                     = system.clockTree["SYSPLLMUX"];
mux12.overrideworkaroundFCCPeriod_SYSPLL_ERR_01 = true;
mux12.workaroundFCCPeriod_SYSPLL_ERR_01         = 32;

const oscillator2           = system.clockTree["SYSOSC"];
oscillator2.enableSYSOSCFCL = true;

ADC121.$name                 = "ADC0";
ADC121.samplingOperationMode = "sequence";
ADC121.adcMem0_name          = "U_SUPPLY_VREF_0";
ADC121.adcMem0chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem0vref           = "VREF";
ADC121.adcMem0vrefp          = "INTREF";
ADC121.adcMem1_name          = "U_SUPPLY_VDDA_0";
ADC121.adcMem1chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem2_name          = "U_SUPPLY_VREF_1";
ADC121.adcMem2chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem2vref           = "VREF";
ADC121.adcMem2vrefp          = "INTREF";
ADC121.adcMem3_name          = "U_SUPPLY_VDDA_1";
ADC121.adcMem3chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem4_name          = "U_SUPPLY_VREF_2";
ADC121.adcMem4chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem4vref           = "VREF";
ADC121.adcMem4vrefp          = "INTREF";
ADC121.adcMem5_name          = "U_SUPPLY_VDDA_2";
ADC121.adcMem5chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem6_name          = "U_SUPPLY_VREF_3";
ADC121.adcMem6chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem6vref           = "VREF";
ADC121.adcMem6vrefp          = "INTREF";
ADC121.adcMem7_name          = "U_SUPPLY_VDDA3";
ADC121.adcMem7chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem8_name          = "U_SUPPLY_VREF_4";
ADC121.adcMem8chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem8vref           = "VREF";
ADC121.adcMem8vrefp          = "INTREF";
ADC121.adcMem9_name          = "U_SUPPLY_VDDA_4";
ADC121.adcMem9chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC121.adcMem2stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem3stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem4stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem5stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem6stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem7stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem8stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.adcMem9stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC121.enableFIFO            = true;
ADC121.sampCnt               = 1;
ADC121.enabledDMATriggers    = ["DL_ADC12_DMA_MEM1_RESULT_LOADED","DL_ADC12_DMA_MEM3_RESULT_LOADED","DL_ADC12_DMA_MEM5_RESULT_LOADED","DL_ADC12_DMA_MEM7_RESULT_LOADED","DL_ADC12_DMA_MEM9_RESULT_LOADED"];
ADC121.sampleTime0           = "15us";
ADC121.sampleTime1           = "5us";
ADC121.sampClkSrc            = "DL_ADC12_CLOCK_ULPCLK";
ADC121.endAdd                = 1;
ADC121.peripheral.$assign    = "ADC0";

ADC122.$name                 = "ADC1";
ADC122.samplingOperationMode = "sequence";
ADC122.adcMem0_name          = "U_SUPPLY_VREF_0";
ADC122.adcMem0chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem0vref           = "VREF";
ADC122.adcMem0vrefp          = "INTREF";
ADC122.adcMem1_name          = "U_SUPPLY_VDDA_0";
ADC122.adcMem1chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem2_name          = "U_SUPPLY_VREF_1";
ADC122.adcMem2chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem2vref           = "VREF";
ADC122.adcMem2vrefp          = "INTREF";
ADC122.adcMem3_name          = "U_SUPPLY_VDDA_1";
ADC122.adcMem3chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem4_name          = "U_SUPPLY_VREF_2";
ADC122.adcMem4chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem4vref           = "VREF";
ADC122.adcMem4vrefp          = "INTREF";
ADC122.adcMem5_name          = "U_SUPPLY_VDDA_2";
ADC122.adcMem5chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem6_name          = "U_SUPPLY_VREF_3";
ADC122.adcMem6chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem6vref           = "VREF";
ADC122.adcMem6vrefp          = "INTREF";
ADC122.adcMem7_name          = "U_SUPPLY_VDDA3";
ADC122.adcMem7chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem8_name          = "U_SUPPLY_VREF_4";
ADC122.adcMem8chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem8vref           = "VREF";
ADC122.adcMem8vrefp          = "INTREF";
ADC122.adcMem9_name          = "U_SUPPLY_VDDA_4";
ADC122.adcMem9chansel        = "DL_ADC12_INPUT_CHAN_15";
ADC122.adcMem2stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem3stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem4stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem5stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem6stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem7stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem8stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.adcMem9stime          = "DL_ADC12_SAMPLE_TIMER_SOURCE_SCOMP1";
ADC122.enableFIFO            = true;
ADC122.sampCnt               = 1;
ADC122.enabledDMATriggers    = ["DL_ADC12_DMA_MEM1_RESULT_LOADED","DL_ADC12_DMA_MEM3_RESULT_LOADED","DL_ADC12_DMA_MEM5_RESULT_LOADED","DL_ADC12_DMA_MEM7_RESULT_LOADED","DL_ADC12_DMA_MEM9_RESULT_LOADED"];
ADC122.sampleTime0           = "15us";
ADC122.sampleTime1           = "5us";
ADC122.sampClkSrc            = "DL_ADC12_CLOCK_ULPCLK";
ADC122.endAdd                = 1;
ADC122.peripheral.$assign    = "ADC1";

Board.configureUnused = true;

SYSCTL.clockTreeEn       = true;
SYSCTL.validateClkStatus = true;

SYSTICK.periodEnable    = true;
SYSTICK.period          = 7800;
SYSTICK.interruptEnable = true;
SYSTICK.systickEnable   = true;

VREF.basicIntVolt       = "DL_VREF_BUFCONFIG_OUTPUT_2_5V";
VREF.checkVREFReady     = true;
VREF.basicExtVolt       = 2.5;
VREF.peripheral.$assign = "VREF";

/**
 * Pinmux solution for unlocked pins/peripherals. This ensures that minor changes to the automatic solver in a future
 * version of the tool will not impact the pinmux you originally saw.  These lines can be completely deleted in order to
 * re-solve from scratch.
 */
Board.peripheral.$suggestSolution          = "DEBUGSS";
Board.peripheral.swclkPin.$suggestSolution = "PA20";
Board.peripheral.swdioPin.$suggestSolution = "PA19";
  • Hi, Want to check whether this issue is a new one?

    Or this E2E is just the same issue as previous E2E you mentioned in your question: e2e.ti.com/.../1673781

  • Hello, 

    thank you for the reply.

    As far as I got it, its a new issue. In the other thread the main issues have been the cyclic deviation and the shift of the stable measurement. Here it is the overall instability of ADC0.

    Maybe they are somehow connected, but the other issue we also observed on ADC1, this one here is only related to ADC0.

  • Understood.

    Before my detailly checking your question, you can go through this app note, for how to use ADC with low noise:

    https://www.ti.com/lit/pdf/SLAAEO8

  • Thank you for the link to the app note. I went through but could not find a possible solution for the issue. 
    Since the signal which is sampled in the test project is not external, but internal, most of the described notes do not apply. Furthermore ADC0 and ADC1 are configured similar and sample the same signal with the same reference voltage. 

    Thus I assume the issue is a MCU internal one or a badly configured project, which I don't want to exclude from the discussion at all. 

  • Can someone confirm this issue and maybe provide a explanation/ solution?

    I checked your test result detailly.

    It seems that there is some issue on ADC0.

    I understand that app note is not suitable for this issue.

    And do you have any other Launchpad? Better to check whether this happens on other Launchpad.

    At the same time, please send me your test code, I believe if your only provide a reproduce code to me for ADC/DMA part, it won't make your project details exposure to public.

  • Another suggestion, please try to extend your sampling time from 5us to 100us, try to see whether issue still happens.

  • Thank you for checking the issue. 

    I tested with another Launchpad, which shows the same behavior, similar to some further custom boards equipped with the MSPM0G1518. 

    Extending the sampling time does not help unfortunately. 

    Sharing the test code with you is fine, I will send it to you.  

  • Received and will check it ~

  • Hi, Have you ever check the ADC result out of debug mode?

    Debug interface sometime will bring noise to ADC (ADC and debug share the same GND/Vcc)

    Some tips to remove the noise:

    1. not connect debug port while ADC is sampling and conversion.

    2. ADC better not work with UART and other comm interface.

    3. After start ADC conversion, use __WFE/WFI to wait for ADC finishing, to make digital noise least.

    1.	        DL_ADC12_enableConversions(ADC12_0_INST);
    2.	        DL_ADC12_startConversion(ADC12_0_INST);
    3.	
    4.	        __WFE();
    5.	
    6.	        if(gCheckADC) {
    7.	            ADC_getResult();
    8.	            gCheckADC = false;
    9.	        }
    

    After ADC conversion is done in free run mode (#1 above), you can start project-less debug by right click the project, and load symbol generated by CCS build in debug folder .out file, to start to see your ADC result.

  • Hello, 
    thank you for your suggestion. It seems that the running debug mode is actually causing the ADC instability.

    We ran a modified version of the test project once with and once without active debug connection (disconnected session), while the ADC results were captured. The results show absolutely stable results, when no debug session is running:

    Since we know the cause now, do you have an idea/ suggestion how the instability can be avoided except for disabling debug session. It is not a complete dealbreaker for us, but we are using the debug interface a lot during development and also testing. 

    We already tried reducing the SWD CLK to the minimum 100kHz, which helps a bit, but does not remove the instability completely: 

  • Since we know the cause now, do you have an idea/ suggestion how the instability can be avoided except for disabling debug session.

    Because debug clock is always active when in CCS debug session, I still recommend you to test ADC without a debug session.

    And after all, in production, there will be no debug session ongoing, so this issue won't impact your final product.

    Set 100kHz debug speed will help a little, I hope you can accept this little noise when SWCLK = 100kHz.

    Actually, there is no other better method to optimize ADC result during debug on MSPM0G3519.