【问题标题】:Calibrating STM32 ADC (VREFINT)校准 STM32 ADC (VREFINT)
【发布时间】:2020-02-08 05:15:52
【问题描述】:

我正在尝试在 STM32F042 微控制器上读取 VDDA。当 VDD 为 3.29V 时,我得到了意想不到的结果。我一定错过了一些基本的东西。

输出:

VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1885; VREFINT_CAL=1524; VDDA=2668 mV
VREFINT=1913; VREFINT_CAL=1524; VDDA=2628 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV

adc_test.c:

#include <stdio.h>
#include "stm32f0xx.h"

#define VREFINT_CAL_ADDR                0x1FFFF7BA  /* datasheet p. 19 */
#define VREFINT_CAL ((uint16_t*) VREFINT_CAL_ADDR)

extern void initialise_monitor_handles(void);

int main(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     /* enable ADC peripheral clock */
    RCC->CR2 |= RCC_CR2_HSI14ON;            /* start ADC HSI */
    while (!(RCC->CR2 & RCC_CR2_HSI14RDY)); /* wait for completion */
    /* calibration */
    ADC1->CR |= ADC_CR_ADCAL;               /* start ADc CALibration */
    while (ADC1->CR & ADC_CR_ADCAL);        /* wait for completion */
    ADC1->CR |= ADC_CR_ADEN;                /* ADc ENable */
    while (!(ADC1->ISR & ADC_ISR_ADRDY));   /* wait for completion */
    ADC1->SMPR |= ADC_SMPR1_SMPR_0 |        /* sampling mode: longest */
      ADC_SMPR1_SMPR_1 |
      ADC_SMPR1_SMPR_2;
    /* VDD reference */
    ADC->CCR |= ADC_CCR_VREFEN;             /* VREF Enable */
    ADC1->CHSELR = ADC_CHSELR_CHSEL17;      /* CH17 = VREFINT */

    initialise_monitor_handles();           /* enable semihosting */

    while (1) {
        ADC1->CR |= ADC_CR_ADSTART;             /* start ADC conversion */
        while (!(ADC1->ISR & ADC_ISR_EOC));     /* wait for completion */
        uint32_t vdda = 3300UL * *VREFINT_CAL / ADC1->DR; /* ref. manual p. 252; constant and result in millivolts */
        printf("VREFINT=%lu; VREFINT_CAL=%lu; VDDA=%lu mV\n",
                (unsigned long)ADC1->DR,
                (unsigned long)*VREFINT_CAL,
                (unsigned long)vdda);
    }
}

数据表截图:

参考手册截图

注意这是指 .3V,但我认为这是一个错字,因为上面的数据表和下面较长的公式指的是 3.3V,而 .3V 低于这部分的最低工作电压

【问题讨论】:

  • 我看不出你的代码有什么明显错误,我可以确认参考手册中的.3而不是3.3确实是一个错字(我在网上找到的副本没有有那个错误)。关于这个问题的一个疯狂猜测——你是否可能让 Vssa 引脚悬空,而不是接地? (假设您使用的是实际上具有单独 Vssa 引脚的 STM32F042 变体。)您在计算 Vdda 时的错误可疑地接近一个二极管压降,如果负参考电压浮动,这似乎是一个合理的结果。
  • 这是一个有趣的想法,但是引脚(引脚 32)连接到 GND:imgur.com/gMo2GsH 有趣的是,散热垫没有连接任何东西。
  • 该原理图大错特错 - 它显示了该部件的 UFQFNP32 变体的部件号,但根据 LQFP32 变体(甚至没有导热垫)标记了引脚。在 UFQFPN32 上,引脚 16 和 32 是额外的端口 B I/O 引脚,散热垫是您的唯一接地连接,绝对需要正确操作。基本上,您的芯片仅通过某些 I/O 引脚上的 ESD 保护二极管接地,而 2.62V 是芯片接收到的电源的准确测量值。
  • Owwww......你说得对。以前版本的原理图需要 LQFP32,然后改为 UFQFNP32,我猜硬件人员没有仔细阅读数据表。这看起来很糟糕......我很惊讶芯片完全可以工作,而且做得很好(在数字领域)。显然必须在董事会的下一次旋转中解决这个问题。作为权宜之计,将 PB2 和 PB8 设置为输入而不是高阻值是否有助于将芯片中的更多电路连接到地,或者 ESD 二极管是唯一的接地路径?
  • 不要认为输入与 hi-Z 有任何区别。将引脚设置为输出低电平实际上可能会获得更好的接地路径,尽管这很危险——即使是短暂的输出高电平状态也可能会烧毁一些东西。如果芯片下方有一个没有走线的点,您也许可以从背面铣穿并实际连接到导热垫。 (嘿,可能会更糟 - 我见过类似的“错误足迹”电路板布局,其中两个足迹基本上旋转了 90° - 绝对没有任何东西连接到可用的引脚。)

标签: stm32 adc stm32f0


【解决方案1】:

我目前正在为 STM32L4 开发一个 ADC 驱动程序。在实施过程中,我遇到了几乎相同的问题。我认为第一个公式

计算的不是 VDDA,而是 VREF+。这是 ADC 评估 ADC-IN 通道所依据的电压。 此外,VREFINT_DATA 不是测量的 VREF+ 电压,而是取决于控制器的内部参考电压。就我而言,它在控制器数据表中定义:

这是我如何使用发布的公式的图片:

一些cmets: ln 102: 计算 VREF+ 而不是 VDDA

ln 105-110:计算所有等级/配置的序列

ln 108:计算ADCpin_x测量的电压

ln 109:乘以增益得到实际值

在我看来,通过计算每个转换序列的 VREF+,我会得到更好的结果,因为这样可以补偿 VREF+ 上的一些波纹。

【讨论】:

  • 就我而言,答案是接地不当。一旦我们正确连接接地,公式就可以正常工作。
【解决方案2】:

其实是计算Vdda,由于Vref计算很简单,所以你要读取ADC的对应通道,采样时间比数据手册中标注的要长(一般为10us)。如果 Vdda 为 2.0 V,则 4095 的值对应于 2.0(或更高)V 绝对值(相关 GND)。以线性方式,Vref 的值会比用 Vdda = 3.30 V 读取的值高得多。因此,需要对 2.0 V 读取的值进行补偿,才能知道电压的绝对值。 ADC 正在测量。如果不进行补偿,它们将是相对于 Vdda 在那一刻的电压电平的值。 此外,电源值达到,这将是有用的,以免超出单片机的规格。

【讨论】:

    【解决方案3】:

    正如@Artur所说Vref +不是Vdda,但通常(这就是我在硬件设计中的方式)Vref +连接到Vdda(根据数据表使用相应的滤波器),因此计算Vdda与计算 Vref +。

    我会告诉你如何计算 vdda,因为我有它基于 STM32L431。

    。您必须首先配置 ADC 以测量 VREFINT:

    void MX_ADC1_Init(void)
    {
    
        /* USER CODE BEGIN ADC1_Init 0 */
    
        /* USER CODE END ADC1_Init 0 */
    
        ADC_ChannelConfTypeDef sConfig = {0};
    
        /* USER CODE BEGIN ADC1_Init 1 */
    
        /* USER CODE END ADC1_Init 1 */
        /** Common config
         */
        hadc1.Instance = ADC1;
        hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
        hadc1.Init.Resolution = ADC_RESOLUTION_12B;
        hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
        hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
        hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
        hadc1.Init.LowPowerAutoWait = DISABLE;
        hadc1.Init.ContinuousConvMode = DISABLE;
        hadc1.Init.NbrOfConversion = 1;
        hadc1.Init.DiscontinuousConvMode = DISABLE;
        hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
        hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
        hadc1.Init.DMAContinuousRequests = DISABLE;
        hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
        hadc1.Init.OversamplingMode = DISABLE;
        if (HAL_ADC_Init(&hadc1) != HAL_OK)
        {
            Error_Handler();
        }
        /** Configure Regular Channel
         */
        sConfig.Channel = ADC_CHANNEL_VREFINT;
        sConfig.Rank = ADC_REGULAR_RANK_1;
        sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_5;
        sConfig.SingleDiff = ADC_SINGLE_ENDED;
        sConfig.OffsetNumber = ADC_OFFSET_NONE;
        sConfig.Offset = 0;
        if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
        {
            Error_Handler();
        }
        /* USER CODE BEGIN ADC1_Init 2 */
    
        /* USER CODE END ADC1_Init 2 */
    }
    

    。现在我将向您展示执行方程式的代码:

    vdda = 3.0 * (VREFINT_CAL /average);
    vch = VREF * (average / ADC_RESOLUTION);
    
    log("vdd = %.5f - ", vdda);
    log("vchn = %.5f", vch);
    

    地点:

    #define ADC_RESOLUTION 4095.0           // adc resolution 12 bits
    #define VREFINT_CAL 1655.00             // Raw data acquired at a temperature of 30 °C (± 5 °C), VDDA = VREF+ = 3.0 V (± 10 mV)
    #define VREF 3.3                        // voltage reference 3.3V
    

    注意:

    'average' 是 adc 采集的 256 个样本的平均值(它只是一个简单的过滤器)。

    'log'是我自己创建的一个函数,类似于uart的printf。

    “VREFINT_CAL”因型号而异。

    结果:

    vdd = 3.28035 - vchn = 1.21343
    

    我们看到 VREFINT 与数据表匹配(1.212V 典型值):

    VREFINT

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-20
      • 2020-07-08
      • 2020-11-12
      • 2014-09-07
      • 2016-05-10
      • 2015-04-03
      • 2018-06-20
      • 2023-01-26
      相关资源
      最近更新 更多