Калибровка АЦП STM32 (VREFINT)

Я пытаюсь прочитать VDDA на микроконтроллере STM32F042. Я получаю неожиданные результаты с VDD при 3,29 В. Я, должно быть, упускаю что-то фундаментальное.

выход:

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

Скриншот из таблицы:

введите описание изображения здесь

Снимок экрана из справочного руководства

обратите внимание, что это относится к 0,3 В, но я считаю, что это опечатка, так как таблица данных выше и более длинная формула ниже относятся к 3,3 В, а 0,3 В ниже минимального рабочего напряжения для этой части

введите описание изображения здесь


person iter    schedule 10.10.2019    source источник
comment
Я не вижу ничего явно неправильного в вашем коде и могу подтвердить, что .3 вместо 3.3 в справочном руководстве действительно является опечаткой (копия, которую я нашел в Интернете, не содержала этой ошибки). Одно безумное предположение относительно проблемы - возможно, вы оставили контакт Vssa плавающим, а не заземленным? (Предполагая, что вы используете вариант STM32F042, который на самом деле имеет отдельный вывод Vssa.) Ваша ошибка при вычислении Vdda подозрительно близка к падению на одном диоде, что кажется вероятным результатом, если отрицательное опорное напряжение плавает.   -  person jasonharper    schedule 11.10.2019
comment
Это интересная идея, но контакт (контакт 32) подключен к GND: imgur.com/gMo2GsH Интересно, термопрокладка ни к чему не подключена.   -  person iter    schedule 11.10.2019
comment
Эта схема ОЧЕНЬ неверна - на ней показан номер детали для варианта детали UFQFNP32, но контакты на ней помечены в соответствии с вариантом LQFP32 (у которого даже нет термопрокладки). На UFQFPN32 контакты 16 и 32 являются дополнительными контактами ввода / вывода порта B, а термопрокладка - это ваше единственное соединение с землей, абсолютно необходимое для правильной работы. По сути, ваш чип видит землю только через диоды защиты от электростатического разряда на некоторых контактах ввода / вывода, а 2,62 В - это точное измерение напряжения питания, полученного микросхемой.   -  person jasonharper    schedule 11.10.2019
comment
Owwww ...... Вы совершенно правы. Предыдущая версия схемы требовала LQFP32, затем она была изменена на UFQFNP32, и я полагаю, что специалисты по аппаратному обеспечению недостаточно внимательно читали таблицу. Выглядит довольно плохо ... Я удивлен, что чип вообще работает, причем неплохо (в цифровой области). Очевидно, придется исправить это при следующем вращении доски. В качестве временной меры поможет ли установка PB2 и PB8 в качестве входов вместо высокого Z, для подключения большей части схемы в микросхеме к земле, или диоды ESD - единственный путь к земле?   -  person iter    schedule 11.10.2019
comment
Не думайте, что input vs. hi-Z будет иметь какое-то значение. Установка выводов на выход LOW может фактически получить лучший путь к земле, хотя это опасно - даже кратковременное выходное состояние HIGH может что-то поджарить. Если под чипом есть место без следов, вы можете прорезать его с обратной стороны и фактически подключиться к термопрокладке. (Эй, могло быть и хуже - я видел аналогичную неправильную компоновку платы для посадочных мест, где два посадочных места были в основном повернуты на 90 ° - абсолютно ничего не было подключено к пригодному для использования выводу.)   -  person jasonharper    schedule 11.10.2019
comment
Я слышу тебя. Это 4-х слойная доска. Под чипом в одном из внутренних слоев есть только один след, но другой внутренний слой представляет собой сплошную плоскость 3V3. Противоположный внешний слой - это земля. Не знаю, как легко было бы избежать короткого замыкания в земле и самолетах 3V3, если бы мы их просверлили.   -  person iter    schedule 11.10.2019
comment
@jasonharper: как вы говорите, активация раскрывающихся списков ничего не делает, но установка PB2 и PB8 в качестве (низких) выходов имеет большое значение. VDDA теперь выходит между 3110 и 3179 мВ. OpenOCD сообщает целевое напряжение как 3,243415. Мне любопытно, является ли последнее расхождение в 0,1 В разницей между АЦП на программаторе и целевом устройстве, или если заземление, которое видит чип, намного выше, чем реальное заземление. Если вы хотите продолжить и изложить свое мнение в ответ на этот вопрос, я с радостью его приму.   -  person iter    schedule 16.10.2019
comment
Я сомневаюсь, что OpenOCD может каким-либо образом измерить напряжение до 7 значащих цифр ... но, безусловно, существует реальное падение напряжения, поскольку весь рабочий ток чипа проходит через Rds (on) полевых транзисторов нижнего уровня на этих полевых транзисторах. два контакта. (Падение будет зависеть от того, что делает чип, и от тока, потребляемого другими выходами, поэтому ваши показания АЦП не будут очень точными.) Что касается публикации ответа: поскольку проблема оказалась в быть полностью аппаратным, я не думаю, что ему здесь место (и Electronics.SE не является одним из сайтов, на которые можно перенести вопросы).   -  person jasonharper    schedule 16.10.2019
comment
Оказалось, что это вопрос электроники, а не программного обеспечения / программирования вообще. Не могли бы вы переместить его на electronics.stackexchange?   -  person HelpingHand    schedule 01.06.2020
comment
Я вижу, откуда вы, @HelpingHand. Я также отмечаю, что как инженер-программист, обнаруживший проблему с этими симптомами, я бы поискал ответ здесь, а не в разделе оборудования. Я хочу, чтобы больше людей находили ответы на свои вопросы.   -  person iter    schedule 02.06.2020


Ответы (3)


В настоящее время я разрабатываю драйвер ADC для STM32L4. Во время реализации я сталкиваюсь почти с той же проблемой. На мой взгляд, первая формула  введите описание изображения здесь

вычисляет не VDDA, а VREF +. Это напряжение, относительно которого АЦП оценивает каналы ADC-IN. Кроме того, VREFINT_DATA - это не измеренное напряжение VREF +, а внутреннее опорное напряжение, которое зависит от контроллера. В моем случае это определено в таблице данных контроллера:  введите описание изображения здесь

Вот рис, как я использую опубликованные формулы:  введите описание изображения здесь

Некоторые комментарии: ln 102: вычисление VREF + not VDDA

ln 105-110: вычислить все ранги / сконфигурированную последовательность

ln 108: вычислить напряжение, измеренное ADCpin_x

ln 109: умножьте на усиление, чтобы получить реальную ценность

На мой взгляд, вычисляя VREF + для каждой последовательности преобразования, я получу лучшие результаты, потому что таким образом некоторые колебания на VREF + компенсируются.

person Artur Sparwasser    schedule 13.10.2020
comment
В моем случае ответом было неправильное заземление. Как только мы правильно соединили заземления, формула заработала нормально. - person iter; 14.10.2020

поскольку @Artur сказал, что Vref + не Vdda, но обычно (именно так я использую это в моем дизайне оборудования) Vref + подключен к Vdda (с соответствующими фильтрами в соответствии с таблицей данных), поэтому вычисление Vdda аналогично вычислению Vref + .

Я покажу вам, как рассчитать vdda, поскольку он у меня основан на STM32L431.

. Сначала необходимо настроить АЦП для измерения 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

Заметка:

«средний» - это в среднем 256 отсчетов, взятых АЦП (это всего лишь простой фильтр).

log - это созданная мной функция, похожая на printf для uart.

VREFINT_CAL зависит от модели.

результат:

vdd = 3.28035 - vchn = 1.21343

как мы видим, VREFINT совпадает с таблицей данных (тип 1,212 В):

VREFINT

person Alberto Stolowich    schedule 01.06.2021

Фактически, это вычисление Vdda, поскольку вычисление Vref очень простое, вы должны прочитать соответствующий канал АЦП с временем выборки, большим, чем тот, который отмечен в таблице данных (обычно 10 мкс). Если Vdda составляет 2,0 В, значение 4095 соответствует 2,0 (или более) В абсолютное (связанное с заземлением). При линейном способе значение Vref будет намного выше, чем если бы оно считывалось с Vdda = 3,30 В. Следовательно, компенсация значений, считываемых с помощью 2,0 В, необходима, чтобы знать абсолютные значения напряжения, которые АЦП измеряет. Если они не скомпенсированы, они будут значениями относительно уровня напряжения, которое Vdda имеет в данный момент. Кроме того, достигается величина блока питания, которая пригодится, чтобы не выходить за рамки технических характеристик микроконтроллера.

person Tristan    schedule 20.02.2021