Skip to main content
Explorer
November 28, 2023
Solved

ADC output ranging about 2000 up to 4095

  • November 28, 2023
  • 9 replies
  • 5072 views

I'm running an STM32L452RCTX uC, and I'm trying to implement a 2.5Vref+ ADC.

Things weren't looking quite right on the pins I intend to implement, so for now I'm driving a floating TP with a power supply so I can directly test input vs output.

When driving the pin to ground, the output is around 2000 (I've seen it in the 198X through 200X range).

When increasing the voltage, I reach the full 4095 at 2.35V, which I feel is reasonably close to my measured 2.482 reference for my application.

I've scoured everywhere I can think of, and I can't seem to find any information on why this might happen.  The behavior is almost as if the Vref- is somewhere near -2.5V, but I have that pin (confirmed through measurement) tied to ground.

 

As for circuitry, I have 3.3V running through a 470 ohm resistor to the top of a 2.5V zener (LM4040), across two caps to ground (2.2uF and 0.1uF), and through a series 0 ohm resistor into the Vref+ pin.  The Vref- pin is soldered directly to the ground plane.  The test point I am driving is about 3mm from the pin of the uC.

 

And the programming, using the HAL drivers:

 

 

APTT_0-1701355234848.png

 

 

 

//Additional initializations beyond HAL implementation
	HAL_ADC_Stop(&hadc1);
 	HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);

//Battery checker, in main loop
	if(check_adc && ((hadc1.State & HAL_ADC_STATE_READY) == HAL_ADC_STATE_READY))
		{
		//Configure ADC for conversion
		adc_channel = TP_ADC;
		sConfig.Channel = adc_channel;
		sConfig.Rank = 1;
		if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
			{
			Error_Handler();
			}
		if (HAL_ADC_Start(&hadc1) != HAL_OK)
			{
			Error_Handler();
			}
		if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK)
			{
			Error_Handler();
			}
		if (HAL_ADC_Stop(&hadc1) != HAL_OK)
			{
			Error_Handler();
			}
		if (HAL_ADC_Start(&hadc1) != HAL_OK)
			{
			Error_Handler();
			}
		if (HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK)
			{
			Error_Handler();
			}
		uint16_t temmp = hadc1.Instance->DR;
		HAL_ADC_Stop(&hadc1);
		check_adc = NO;
		adc_check_timer = ADC_CHECK_TIME;
		}

 

 

 

Registers while device is paused, currently a floating pin:

APTT_0-1701354855868.png

APTT_1-1701354898880.png

 

And measured results of the DR register:
Pin grounded: 0x7C0

Pin floating: 0x8E2

Pin 3.324V: 0xFBF

 

    This topic has been closed for replies.
    Best answer by waclawek.jan

    > I'll post a screenshot (or a few) of my register readouts for ADC1 and ADC123_Common in the original post.

    OK so you've posted a screenshot, where ADC_SQR1=0x1C0, i.e. one conversion and that's on channel 7; and ADC_DIFSEL=0x80, which means the conversion on channel 7 is differential.

    The mcu does not work out of what you've clicked in CubeMX, it works out of the registers' content.

    JW

    9 replies

    Super User
    November 28, 2023

    Does calibration complete successfully? Does HAL_ADCEx_Calibration_Start return HAL_OK?

    I'd try removing the LM4040 (which effectively shorts VDD to VDDA via a 480 Ohm) and seeing if you get the same behavior. If so, probably a hardware issue.

    Does it happen on multiple chips?

    Can you try that code on known good hardware such as a nucleo board?

     

    APTTAuthor
    Explorer
    November 29, 2023

    I modified the code to check for any status != HAL_OK on the calibration, and a nop for a breakpoint, and the code operates right past it without issue.

    I tried the same code on an STM32L4P5CETX with identical Vref setup, floating test point, and results.

    I do have an STM32L4R9 Discovery kit I'll try it on next.  If it works fine on there, I'll look into testing my board without the LM4040.

    I'm hesitant to suspect a defective LM4040 (I assume that's what you're getting at), as I've measured that voltage with both DMM and O-scope, it's a clean 2.482V even during conversions.

    Super User
    November 29, 2023

    I don't suspect a defective LM4040 either, but the problem has to lie somewhere. Eliminating LM4040 from the equation certainly simplifies things.

    If, after removing LM4040, it starts working, issue was something to do with LM4040, probably.

    If it still isn't working, issue is likely your hardware. Let's list the possibilities in no particular order:

    • Chip is damaged/defective.
    • Code is bad.
    • Pin isn't hooked up how you think it is.
    • You are misinterpreting the results in some manner.

    Could be missing one but I think that covers it.

     

    You don't mention what pin is having this issue. Some pins are hooked up internally to things or otherwise require some setup beyond the norm.

    Testing it on known good hardware would absolve the code of bugs, mostly, and suggest the issue is related to your hardware. Bummer your boards aren't working. This would also eliminate pin-related issues like the previous point.

    Super User
    November 29, 2023

    Taking ADC reading of the internal VREFINT and/or temperature sensor returns what value?

    Did you measure voltage directly on the pin you use as ADC input? And on VREF+ pin? You don't try to use the internal VREFBUF, do you?

    VDDA is connected how? Is this package with separate VDDA/VREF+? VSSA is connected to VSS?

    If you omit the LM4040 and connect VREF+ directly to VDD/VDDA, what is ADC result?

    JW

    APTTAuthor
    Explorer
    November 29, 2023

    ADC reading of internal VREFINT returns 0x5a +/- 2

    I measured voltages directly on the pins, as well as visually verifying good solder connections (I have good magnification available).  I do not try to use the internal VREFBUF.

    My VDDA pin is the same pin as VREF+, and is soldered directly to the ground plane.  Not the best idea with regards to noise, but I can deal with that.

    I have yet to eliminate the LM4040, I'm about finished trying to see if any of my dev boards still work.

    APTTAuthor
    Explorer
    November 29, 2023

    HCLK is set for 80MHz, ADC settings are below:

     

    APTT_0-1701290946013.png

     

    APTTAuthor
    Explorer
    November 29, 2023

    Removing the LM4040 from the board yielded similar results.

    The ADC pin reads around 0x83A when floating, 0x7C0 when grounded, and 0xFB0 when 3.3V is applied.

    Calibration came out fine.  Floating at 0x800s makes me think maybe an underflow resulting in negative values, but then why would ground not also show a sign mark?  But then, 12 bit numbers would sign on bit 15 or 31, right?

    Super User
    November 29, 2023

    The ADC channel could be in differential mode. Are you missing sConfig.SingleDiff = ADC_SINGLE_ENDED? Or other members of sConfig? That part of your code isn't shown.

    Perhaps run a known working example on your board, only changing the channel number to what you're testing:

    https://github.com/STMicroelectronics/STM32CubeL4/blob/master/Projects/NUCLEO-L452RE/Examples/ADC/ADC_RegularConversion_Polling/Src/main.c

    Super User
    November 29, 2023

    > ADC reading of internal VREFINT returns 0x5a +/- 2

    That sounds very wrong.

    > My VDDA pin is the same pin as VREF+, and is soldered directly to the ground plane.

    You surely meant VSSA and VREF-.

    > The ADC channel could be in differential mode.

    Sounds much like so.

    Read out and check/post content of ADC registers.

    JW

    Graduate
    November 29, 2023

    Are you using a 2 prong wall wart to supply the signal? Strange results can happen if the negative output is not well grounded.

    Graduate II
    November 30, 2023

    >> My VDDA pin is the same pin as VREF+, and is soldered directly to the ground plane.

    > You surely meant VSSA and VREF-.

    Hopefully, almost got a heart attack when I read that! :D

    > The ADC channel could be in differential mode.

    +1

    APTTAuthor
    Explorer
    November 30, 2023

    @TDK:

    This is single-ended, and configured as such.  I did post a screenshot of the ioc setup, I'll amend my original post with this information.

    I'll give it a shot, couldn't hurt.  I *can* tell you I've compared my code to several of the sample projects for ADC, as well as comparing with code written by my boss on a different project, and the code looks correct.

     

    @waclawek.jan:

    I agree, but it is what I see on ADC_CHANNEL_0 DR

    Yes, you are correct.  My brain likes to flip opposites.  On another note, I don't think I'll ever understand how to properly use pointers without looking it up first.

    I agree something seems fishy here, and that would be a nice solution, but alas, it is very much configured in single-ended mode.

    I'll post a screenshot (or a few) of my register readouts for ADC1 and ADC123_Common in the original post.

     

    @raptorhal2:

    I am using a BK Precision 1735A 30V/3A DC power supply, which itself is plugged into a 6-outlet extension strip to the wall, but an o-scope reading of all pins in question show expected voltage with very low noise.

     

    @LCE:

    I probably would have also, brain flip ;)

    As above, definitely configured for single-ended.

     

    I'll update the original post with all this additional info.

    Super User
    November 30, 2023

    > I'll post a screenshot (or a few) of my register readouts for ADC1 and ADC123_Common in the original post.

    OK so you've posted a screenshot, where ADC_SQR1=0x1C0, i.e. one conversion and that's on channel 7; and ADC_DIFSEL=0x80, which means the conversion on channel 7 is differential.

    The mcu does not work out of what you've clicked in CubeMX, it works out of the registers' content.

    JW

    APTTAuthor
    Explorer
    November 30, 2023

    So I guess when you configure one channel, you don't configure them all ;)

    Thank you so much for that!

    At ground, measuring 0x000.

    At 3.3V, measuring 0xFFF.

    At the middle of a 1/2 resistor divider, 0x7FF.