Embedded HandbookПриложения
Все разделы › III. Периферия
STM32F103, STM32F407, STM32F303, STM32L476 · уровень продвинутый · 18 мин чтения
Открыть в интерактивном справочнике

44. Аналоговые блоки внутри кристалла: OPAMP и COMP

Между датчиком и АЦП почти всегда стоит хотя бы один операционный усилитель, а рядом с силовым ключом — компаратор, который выключит ШИМ быстрее любого прерывания. У старших семейств STM32 и то и другое уже на кристалле: с резисторами усиления, с порогом от встроенного ЦАП, с выходом прямо в АЦП или в аварийный вход таймера. Раздел о том, что эти блоки умеют, чего не умеют и как из них собрать защиту по току, не добавив на плату ничего, кроме шунта.

Опорные камни здесь — G474 (шесть ОУ, семь компараторов) и L476 (по два); F103 и F407 упомянуты как семейства, у которых этих блоков нет и задача решается иначе.

Как это называется в документации

Оригинал Перевод
operational amplifier (op-amp, OPAMP) операционный усилитель, ОУ
comparator (COMP) компаратор
rail-to-rail вход и выход работают во всём диапазоне от земли до питания
input offset voltage напряжение смещения нуля, «смещение»
offset trimming, calibration подстройка смещения, калибровка
gain-bandwidth product (GBW) произведение усиления на полосу
slew rate скорость нарастания выходного напряжения
programmable gain amplifier (PGA) усилитель с программируемым усилением
follower, unity-gain buffer повторитель, буфер с усилением 1
common-mode input range диапазон синфазного (общего для обоих входов) напряжения
hysteresis гистерезис: разные пороги на включение и выключение
propagation delay задержка распространения: от пересечения порога до выхода
blanking гашение: на время помехи выход не учитывается
window comparator оконный компаратор: два порога, сигнал «внутри окна»
break input (BKIN) аварийный вход таймера
shunt resistor шунт: резистор, по падению на котором измеряют ток
internal voltage reference (VREFINT) внутреннее опорное напряжение

44.1 У кого что есть

Встроенная аналоговая обвязка — признак семейств, рассчитанных на управление двигателями и преобразователями. У «классики» её нет.

Семейство ОУ Компараторов Усиление PGA Чем заменить
F103, F407 — — — внешний ОУ; вместо компаратора — аналоговый сторож АЦП (раздел 14.8), но это микросекунды, не наносекунды
F303 4 7 ×2…×16 —
L476 2 2 ×2…×16 —
G431 3 4 ×2…×64 —
G474 6 7 ×2…×64 —

Число блоков и биты регистров ниже — из заголовков семейств; там, где раздел говорит «у G4», подразумеваются оба G4-камня, они отличаются только количеством.


44.2 Что умеет встроенный ОУ

Это не прецизионный усилитель из каталога, а быстрый и удобный «достаточно хороший» ОУ. Его параметры (G4, типовые; в скобках — предельные) надо знать, потому что из них следуют границы применения.

Параметр Значение Что это значит на практике
смещение после калибровки ±1,5 мВ при 25 °C (±3 мВ во всём диапазоне) ошибка, приведённая ко входу: при ×16 на выходе ±24…48 мВ
дрейф смещения ±10 мкВ/°C 60 °C нагрева — ещё 0,6 мВ
полоса (GBW) 13 МГц (не менее 7) делится на усиление: при ×16 — около 0,8 МГц, при ×64 — 0,2 МГц
скорость нарастания 6,5 В/мкс; в быстром режиме 45 В/мкс 0 → 3,3 В за 0,5 мкс или за 73 нс
выход до 100 мВ от каждой шины питания rail-to-rail; верхний предел шкалы — VDDA − 0,1 В
ток нагрузки 500 мкА (270 мкА в PGA) нагрузка не ниже ≈6,6 кОм (≈12 кОм в PGA); ёмкость до 50 пФ
усиление без ОС 95 дБ —
точность усиления PGA 1 % (2 % на краях: ×2, ×32, ×64) резисторы делителя ±15 %, но их отношение держится
пробуждение 3 мкс включать заранее, а не перед измерением
потребление 1,3 мА (0,45 мА при выходе внутрь) отключать в спящих режимах
входной ток утечка вывода: до ±100…150 нА — предел из таблицы выводов, типового нет источник до 10 кОм добавляет не больше смещения (1,5 мВ); 1 МОм при 100 нА — уже 100 мВ ошибки (раздел 56.4)

Вход и выход — rail-to-rail, синфазный диапазон 0…VDDA; отрицательного питания нет, поэтому усиливать можно только положительные сигналы — либо смещать их в середину шкалы.


44.3 Четыре включения без внешних деталей

Внутри — сам усилитель плюс мультиплексоры на входах и выходе и резистивный делитель обратной связи. Настройка ОУ — это настройка мультиплексоров.

Встроенный ОУ: четыре включения

Поле OPAMP_CSR Код Что подключено
VP_SEL (вход «+») 00 / 01 / 10 вывод VINP0 / VINP1 / VINP2
11 канал ЦАП (у второго ОУ — четвёртый вывод)
VM_SEL (вход «−») 00 / 01 вывод VINM0 / VINM1 — внешняя обратная связь
10 внутренний делитель — усилитель PGA
11 собственный выход — повторитель
PGA_GAIN 0…5 ×2, ×4, ×8, ×16, ×32, ×64
+8 инвертирующее включение: вход через R1 с вывода VINM0, усиление −1…−63; или внешнее смещение на VINM0
+16 к «−» дополнительно выведен VINM0 — под конденсатор фильтра
+24 инвертирующее с фильтром на VINM1
OPAINTOEN 1 выход внутрь, на канал АЦП; вывод VOUT свободен
HIGHSPEEDEN 1 быстрый режим (45 В/мкс, больше ток)

Делитель одинаков для обоих направлений: неинвертирующее усиление 1 + R2/R1 даёт ×2…×64, инвертирующее −R2/R1 на тех же резисторах — на единицу меньше: −1…−63.

Повторитель. Самое частое включение: буфер между высокоомным источником (делитель на мегаомах, пьезодатчик, фотодиод) и АЦП, которому нужен источник в единицы килоом (раздел 14.2).

/* Повторитель: вход VINP0, выход на вывод VOUT.
   ОУ и компараторы G4 тактируются вместе с SYSCFG. */
static void opamp1_follower(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    OPAMP1->CSR = (VPSEL_VINP0    << OPAMP_CSR_VPSEL_Pos)
                | (VMSEL_FOLLOWER << OPAMP_CSR_VMSEL_Pos)
                | OPAMP_CSR_OPAMPxEN;
}

Усилитель ×16 с выходом в АЦП. Ни одного внешнего резистора: сигнал с шунта приходит на VINP0, усиливается и уходит на внутренний канал.

static void opamp1_pga16_to_adc(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
    OPAMP1->CSR = (VPSEL_VINP0   << OPAMP_CSR_VPSEL_Pos)
                | (VMSEL_PGA     << OPAMP_CSR_VMSEL_Pos)
                | (PGA_CODE(16u) << OPAMP_CSR_PGGAIN_Pos)
                | OPAMP_CSR_OPAMPINTEN          /* вывод VOUT остаётся свободным */
                | OPAMP_CSR_OPAMPxEN;
}

Куда именно приходит внутренний выход — зафиксировано в заголовке: OPAMP1 → ADC1, канал 13; OPAMP2 → ADC2, канал 16; OPAMP3 → ADC3, канал 13. При чтении этого канала время выборки — не короче 200 нс (раздел 14.2).

⚠️ Полоса делится на усиление. ×64 — это уже 200 кГц, и импульс тока длительностью в микросекунду через такой усилитель пройдёт сглаженным. Для защиты быстрых ключей берут меньшее усиление и больший шунт либо ставят компаратор до усилителя.


44.4 Смещение и его подстройка

Смещение — главная погрешность ОУ, и усиление её не лечит, а умножает. На шунте 10 мОм смещение 1,5 мВ — это 150 мА ошибки тока, 3 мВ — 300 мА. Поэтому у встроенного ОУ есть два способа подстройки:

Подстроек две, потому что входной каскад двойной: один работает при низком синфазном напряжении, другой — при высоком. Каждый калибруют при своём напряжении: CALSEL подаёт на входы 3,3 / 10 / 50 / 90 % VDDA. Процедура: включить калибровку (CALON), выбрать напряжение, увеличивать код с нуля и после каждого шага ждать установления; первый код, при котором бит OUTCAL сменился с 1 на 0, — искомый.

extern void delay_ms(uint32_t ms);

static uint32_t trim_scan(uint32_t calsel, uint32_t pos, uint32_t msk)
{
    uint32_t code;
    OPAMP1->CSR = (OPAMP1->CSR & ~OPAMP_CSR_CALSEL_Msk) | (calsel << OPAMP_CSR_CALSEL_Pos);
    for (code = 0u; code < 32u; code++) {
        OPAMP1->CSR = (OPAMP1->CSR & ~msk) | (code << pos);
        delay_ms(2u);
        if ((OPAMP1->CSR & OPAMP_CSR_OUTCAL) == 0u)
            break;                                  /* первый код, при котором выход упал */
    }
    return code;
}

static void opamp1_user_calibrate(void)
{
    uint32_t work = OPAMP1->CSR;                    /* рабочая настройка — вернуть потом */
    OPAMP1->CSR = OPAMP_CSR_USERTRIM | OPAMP_CSR_CALON | OPAMP_CSR_OPAMPxEN;
    (void)trim_scan(CALSEL_90, OPAMP_CSR_TRIMOFFSETN_Pos, OPAMP_CSR_TRIMOFFSETN_Msk);
    (void)trim_scan(CALSEL_10, OPAMP_CSR_TRIMOFFSETP_Pos, OPAMP_CSR_TRIMOFFSETP_Msk);
    OPAMP1->CSR = (work & ~(OPAMP_CSR_TRIMOFFSETP_Msk | OPAMP_CSR_TRIMOFFSETN_Msk | OPAMP_CSR_CALON))
                | (OPAMP1->CSR & (OPAMP_CSR_TRIMOFFSETP_Msk | OPAMP_CSR_TRIMOFFSETN_Msk))
                | OPAMP_CSR_USERTRIM;
}

Библиотечная HAL_OPAMP_SelfCalibrate() делает то же самое двоичным поиском с паузой 2 мс на шаг. Калибруют при старте, когда кристалл прогрелся до рабочей температуры, и повторяют, если она заметно меняется: дрейф 10 мкВ/°C за 60 °C съедает 0,6 мВ.

Бит LOCK замораживает CSR до сброса: настройка защиты, которую не испортит случайная запись.


44.5 Выход внутрь, переключение по таймеру, буфер ЦАП

В АЦП без вывода. OPAINTOEN = 1 отсоединяет выход от вывода и подаёт его на внутренний канал АЦП. Экономится вывод, исчезает наводка на дорожку, потребление падает до 0,45 мА.

Переключение входов по событию таймера. Регистр OPAMP_TCMR задаёт второй набор входов (VPS_SEL, VMS_SEL) и разрешает переключать наборы по сигналам TIM1, TIM8 или TIM20 (T1CM_EN, T8CM_EN, T20CM_EN). Так один ОУ обслуживает два шунта двух двигателей: в первой половине периода ШИМ усиливает ток одного, во второй — другого, и АЦП забирает оба.

Буфер ЦАП. Вход «+» на код 11 берёт канал ЦАП, и у G4 это DAC3 или DAC4 (кроме второго ОУ — у него четвёртый вывод): своих выводов у этих ЦАП нет, и повторитель выводит их наружу — в этом главный смысл. Мёртвые зоны у шин при этом меньше, чем у собственного буфера ЦАП (0,2 В, раздел 15.3), но не исчезают: выход ОУ не доходит до шин на 0,1 В (таблица 44.2), а нагрузка — не ниже ≈6,6 кОм. Для быстрых сигналов — быстрый режим HIGHSPEEDEN.


44.6 Компаратор: устройство и параметры

Компаратор — ОУ без обратной связи и с цифровым выходом: «+» выше «−» — единица, ниже — ноль. Его достоинство — время: он не преобразует, а сравнивает.

Параметр (G4) Значение Замечание
задержка 17 нс типовая, 31 нс не более (VDDA ≥ 2,7 В) вход в прерывание при 170 МГц — 71 нс: компаратор быстрее самого перехода в обработчик
смещение −6/+2 мВ (не хуже −9/+3) хуже, чем у ОУ, — порог задавать с запасом
гистерезис 0…70 мВ, 8 ступеней код × 10 мВ номинально; типовое ≈ 9 мВ × код, разброс до двух раз
потребление 450 мкА плюс 1 мкА на делитель опоры
пуск 5 мкс делитель VREFINT — до 200 мкс

Входы задаются полями COMP_CSR:

Поле Код Источник
INPSEL («+», сигнал) 0 / 1 первый или второй вывод INP
INMSEL («−», порог) 0 / 1 / 2 / 3 ¼ / ½ / ¾ / 1 × VREFINT (1,212 В): 0,303 / 0,606 / 0,909 / 1,212 В
4 / 5 два канала ЦАП (у COMP1 — DAC3_CH1 и DAC1_CH1)
6 / 7 два вывода INM
SCALEN, BRGEN 1 буфер опоры и делитель на ¼ ½ ¾ — включать вместе с кодами 0…3
POLARITY 1 инвертировать выход
HYST 0…7 гистерезис
BLANKING 0…7 чей импульс гасит выход (например, TIM1 OC5)
LOCK 1 заморозить до сброса
VALUE — текущее состояние выхода (чтение)

Гистерезис — обязательная вещь для аналогового сигнала с шумом: без него выход дребезжит вблизи порога, а таймер в аварийном режиме ловит каждый дребезг. 20 мВ на входе компаратора при усилении ×16 и шунте 10 мОм — это 125 мА «мёртвой зоны» по току.

Гашение (blanking). В момент переключения силового ключа на шунте выброс — ёмкостный, не токовый. Компаратор его увидит. Гашение подаёт на компаратор импульс с канала таймера (TIM1 OC5, привязанный к моменту переключения), и на время импульса выход не меняется. Порог остаётся прежним, а ложные срабатывания исчезают.

ЦАП как порог. У G4 есть ЦАП без выводов — DAC3 и DAC4 — ровно для этого: их выход идёт только внутрь, на компараторы и ОУ. Порог защиты становится числом в регистре и меняется на ходу.


44.7 Куда идёт выход компаратора

Четыре адресата, любые одновременно:

Куда Как включить Зачем
на вывод альтернативная функция GPIO внешний драйвер, осциллограф
в EXTI (линии 21, 22, 29…33 у G4) EXTI_IMR1, фронт в RTSR1/FTSR1; линии 32 и 33 (COMP6, COMP7) — в EXTI_IMR2, RTSR2/FTSR2 прерывание; пробуждение из Stop (раздел 10.6) — компаратор работает без тактов
в аварийный вход TIM1/TIM8/TIM20 TIMx_AF1: бит BKCMPnE ШИМ выключается аппаратно, за десятки наносекунд, без ядра (раздел 13.5)
в гашение канала (OCREF_CLR) TIMx_AF2.OCRSEL = номер компаратора, SMCR.OCCS = 0, CCMRx.OCxCE = 1 канал гаснет до конца текущего периода и снова включится в следующем: ограничение тока «по циклам»

Разница между двумя последними: аварийный вход — это защёлка, выход таймера выключен до вмешательства программы; гашение канала — это ограничитель, который срабатывает в каждом периоде и не требует обработки вовсе.

Аварийный вход против гашения канала: при перегрузке выход с аварийным входом гаснет на первом пересечении порога 12 А и молчит до установки MOE, а выход с гашением канала обрезает каждый импульс в момент пересечения и в следующем периоде включается снова

/* Ограничение тока внутри периода: COMP1 гасит канал 1 TIM1 до следующего периода. */
static void tim1_ch1_clear_by_comp1(void)
{
    TIM1->AF2   = (TIM1->AF2 & ~TIM1_AF2_OCRSEL_Msk) | (0u << TIM1_AF2_OCRSEL_Pos);  /* 0 — COMP1 */
    TIM1->SMCR &= ~TIM_SMCR_OCCS;                   /* источник гашения — внутренний, не ETR */
    TIM1->CCMR1 |= TIM_CCMR1_OC1CE;                 /* разрешить гашение канала 1 */
}

Семь компараторов G474 делят три вектора прерываний: COMP1_2_3, COMP4_5_6, COMP7; в обработчике источник определяют по флагам линий EXTI.


44.8 🔧 Защита по току целиком внутри кристалла

Задача: ключ коммутирует нагрузку до 10 А, при 12 А ШИМ надо выключить быстрее, чем ключ успеет сгореть, а ток — измерять для регулирования.

Защита по току: шунт → ОУ → компаратор → таймер

Расчёт:

static void comp1_overcurrent(uint16_t dac_code)
{
    RCC->AHB2ENR |= RCC_AHB2ENR_DAC3EN | RCC_AHB2ENR_ADC12EN;
    RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_TIM1EN;

    DAC3->MCR     = (DAC_MODE_INTERNAL_NOBUF << DAC_MCR_MODE1_Pos)  /* выход только внутрь */
                  | DAC_MCR_HFSEL_1;                                /* AHB 170 МГц: режим «выше 160 МГц» */
    DAC3->DHR12R1 = dac_code;                       /* порог */
    DAC3->CR     |= DAC_CR_EN1;

    COMP1->CSR = (INM_DAC_A      << COMP_CSR_INMSEL_Pos)    /* «−» — порог из DAC3_CH1 */
               | (0u             << 8)                      /* «+» — первый вывод INP */
               | (HYST_20MV      << COMP_CSR_HYST_Pos)
               | (BLANK_TIM1_OC5 << COMP_CSR_BLANKING_Pos)
               | COMP_CSR_EN;

    /* Выход компаратора — на аварийный вход TIM1: ШИМ гаснет без участия ядра. */
    TIM1->AF1  |= TIM1_AF1_BKCMP1E;
    TIM1->BDTR |= TIM_BDTR_BKP | TIM_BDTR_BKE;    /* авария — единицей: компаратор выдаёт 1 при перегрузке */

    /* И на EXTI 21 — чтобы ядро узнало и записало событие. */
    EXTI->IMR1  |= EXTI_IMR1_IM21;
    EXTI->RTSR1 |= EXTI_RTSR1_RT21;
    NVIC_EnableIRQ(COMP1_2_3_IRQn);
}

/* Настройку защиты — заморозить до сброса. */
static void analog_lock(void)
{
    COMP1->CSR  |= COMP_CSR_LOCK;
    OPAMP1->CSR |= OPAMP_CSR_LOCK;
}

Полярность проверяют отдельно. После сброса BKP = 0: аварийный вход срабатывает на ноль, и выход компаратора приходит в него через эту же полярность (у каждого компаратора есть ещё свой бит инверсии BKCMPnP в AF1). А компаратор здесь в норме выдаёт ноль — без BKP = 1 авария стояла бы всё время, и ШИМ не запустился бы вовсе. Другой путь — инвертировать выход компаратора битом POLARITY или вход таймера битом BKCMP1P.

Порядок вызовов: усилитель (opamp1_pga16_to_adc), калибровка, порог и компаратор, потом LOCK. Сигнал с ОУ одновременно идёт на канал 13 ADC1 — регулятор читает ток обычным сканированием с DMA (раздел 14.6), а защита живёт отдельно и от программы не зависит.

Что здесь принципиально: между шунтом и выключенным ШИМ нет ни одной команды процессора. Компаратор — 17 нс, аварийный вход таймера — аппаратная защёлка. Прерывание нужно только для журнала.


44.9 Отличия L4 и F3

L476. Два ОУ и два компаратора, устроены проще:

static void opamp1_follower_l4(void)
{
    RCC->APB1ENR1 |= RCC_APB1ENR1_OPAMPEN;
    OPAMP1->CSR = (OPAMODE_FOLLOWER << OPAMP1_CSR_OPAMODE_Pos)
                | OPAMP1_CSR_OPARANGE                /* питание 3,3 В — «высокий» диапазон */
                | OPAMP1_CSR_OPAEN;
}

F303. ОУ — прямой предок G4: та же раскладка CSR, усиление только ×2…×16. Компаратор выбирает адресата выхода сам, полем OUTSEL в своём регистре; у G4 наоборот — таймер выбирает компаратор в AF1.


44.10 HAL

Функция Что делает
HAL_OPAMP_Init / DeInit режим, входы, усиление, скорость, подстройка — из структуры Init
HAL_OPAMP_Start / Stop OPAEN
HAL_OPAMP_SelfCalibrate, HAL_OPAMPEx_SelfCalibrateAll подстройка одного или всех ОУ (2 мс на шаг)
HAL_OPAMP_Lock LOCK
HAL_COMP_Init / DeInit входы, порог, гистерезис, полярность, гашение; у ряда семейств здесь же — фронт EXTI
HAL_COMP_Start / Stop (у части семейств — Start_IT) включение, при необходимости с прерыванием
HAL_COMP_GetOutputLevel текущее состояние выхода
HAL_COMP_TriggerCallback обратный вызов из обработчика EXTI
HAL_COMP_Lock LOCK

Связь компаратора с таймером HAL не настраивает — это делают в инициализации таймера (BreakInputSource, OCREF_CLR) либо напрямую в AF1/AF2.


44.11 Грабли

ОУ «не работает». Не включено тактирование: у G4 и F3 — SYSCFGEN, у L4 — OPAMPEN. Или вывод не переведён в аналоговый режим.

Усилитель ×64 «сглаживает» сигнал. Полоса 13 МГц / 64 = 200 кГц. Меньше усиление, больше шунт.

Показания уходят с нагревом. Заводская подстройка сделана при 25 °C, дрейф 10 мкВ/°C. Калибровать при рабочей температуре и повторять.

Выход «упирается» в 3,2 В. Насыщение за 100 мВ до шины: верх шкалы — VDDA − 0,1 В, планировать усиление под него.

ОУ нагружен на 1 кОм — напряжение просело. Нагрузочная способность 500 мкА: минимум ≈6,6 кОм, в PGA ≈12 кОм.

Первое измерение после включения — мусор. Пробуждение 3 мкс; ОУ включают заранее, не перед выборкой АЦП.

Компаратор дребезжит. Нет гистерезиса, либо шум больше него. Ставить HYST, при ШИМ-выбросах — гашение от таймера.

Порог от VREFINT «плавает» первые миллисекунды. Делитель опоры запускается до 200 мкс — включать SCALEN/BRGEN заранее и ждать.

Компаратор срабатывает, ШИМ не гаснет. Выход не привязан к таймеру: у G4 — бит BKCMPnE в AF1 и BKE в BDTR; у F3 — OUTSEL в самом компараторе.

ШИМ не запускается: авария сразу после включения. Полярность аварийного входа после сброса — ноль (BKP = 0), а компаратор в норме выдаёт ноль. Ставить BKP = 1 или инвертировать выход компаратора.

Настройка защиты изменилась сама. Нет LOCK; после него — только сброс.

Порог ЦАП на 170 МГц ведёт себя непредсказуемо. Не выставлен HFSEL в DAC_MCR: при частоте AHB выше 80 МГц он обязателен (01 — выше 80, 10 — выше 160 МГц) и даёт переносу кода в выход ЦАП лишние такты шины. HAL ставит его сам по частоте шины, код на регистрах — только если не забыть.

После Stop компаратор не будит. Не размаскирована линия EXTI компаратора (у G4 — 21…33), или не выбран фронт.

L4: усилитель работает странно. OPA_RANGE не соответствует VDDA.


44.12 Итоги

Дальше: раздел 45 «Сенсорный ввод: TSC» — ёмкостные кнопки и слайдеры без механики.

Открыть в интерактивном справочнике