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

45. Сенсорный ввод: TSC

Кнопка без механики: площадка меди под пластиковой панелью, палец меняет её ёмкость на единицы пикофарад, и контроллер это замечает. Ни щелей в корпусе, ни контактов, которые изнашиваются, — устройство можно мыть и протирать. Контроллер сенсорных кнопок (TSC) — блок, который измеряет эти пикофарады аппаратно, методом переноса заряда; раздел объясняет, как он это делает, как подобрать обвязку и панель, как из числа получить «нажато» и что мешает.

Опорный камень — L476; те же регистры у F072 и F303. У F1, F4 и G4 блока нет.

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

Оригинал Перевод
touch sensing controller (TSC) контроллер сенсорных кнопок
surface charge transfer acquisition измерение переносом заряда
electrode, touchkey электрод, сенсорная кнопка
sampling capacitor (Cs) накопительный конденсатор
series resistor (Rs) последовательный резистор
overlay, front panel панель, накладка
sensitivity чувствительность
reference, delta опорное значение, разность
environment change system (ECS) слежение за средой: подстройка опоры
detection time-out (DTO) предел длительности нажатия
detection exclusion system (DXS) исключение одновременных нажатий
debounce подавление дребезга
active (driven) shield активный экран
spread spectrum расширение спектра
linear / rotary sensor слайдер / колесо
proximity приближение (обнаружение без касания)

45.1 У кого есть и что даёт

Семейство TSC Групп × выводов Каналов
F072 есть 8 × 4 до 24 (в каждой группе один вывод — под конденсатор)
F303 есть 8 × 4 до 24
L476 есть 8 × 4 до 24
F103, F407, G474 нет — —

Число выводов — по заголовкам семейств; в конкретном корпусе доступна часть. Группы измеряются параллельно, каналы внутри группы — по очереди: восемь кнопок на восьми группах измеряются за одно время, те же восемь кнопок в трёх группах (3 + 3 + 2) — за три: в каждой группе один вывод занят конденсатором, каналов остаётся три.

Без блока ту же идею можно повторить программно на любых выводах, но медленнее и шумнее; для одной-двух кнопок это работает, для панели — нет.


45.2 Принцип: перенос заряда

Перенос заряда

Электрод — это конденсатор Cx между медью и землёй, около 20 пФ; рядом на плате стоит накопительный конденсатор Cs в тысячи раз больше. Один цикл контроллера:

  1. вывод канала заряжает Cx от питания, вывод Cs отключён;
  2. оба вывода соединяются — заряд Cx перетекает в Cs; напряжение на Cs поднимается на малую долю;
  3. снова шаг 1 — пока напряжение на Cs не достигнет порога входа VIH.

Число циклов — результат. Каждый перенос поднимает напряжение на Cs в доле Cx / (Cx + Cs) от оставшегося пути до VDD, поэтому переносов нужно примерно (Cs / Cx) · ln(1 / (1 − 0,7)) при пороге 0,7·VDD. Палец добавляет к Cx единицы пикофарад — доля растёт, порог достигается раньше, счёт уменьшается:

Cs Cx Переносов +1 пФ +2 пФ +5 пФ Время при 1,6 мкс на перенос
47 нФ 20 пФ 2830 −134 −257 (9 %) −565 (20 %) 4,5 мс
10 нФ 20 пФ 603 −55 1 мс
100 нФ 20 пФ 6021 9,6 мс

Отсюда две вещи. Чувствительность растёт с Cs — больше переносов, больше разрешение, но дольше измерение. И сигнал — это разность (delta) между опорным счётом «никто не трогает» и текущим; абсолютное число зависит от платы, панели, температуры и само по себе ничего не значит.


45.3 Обвязка и панель

Элемент Значение Зачем
Cs 47 нФ (2,2…100); PPS, NPO, PET, PEN; не танталовый, X7R — только для простых кнопок стабильность: диэлектрическое поглощение и температурный ход Cs напрямую превращаются в ложные нажатия
Rs 10 кОм (1…10), ближе к выводу МК защита от ЭСР и помех; постоянная времени Rs·Cx — 200 нс (Cx 20 пФ), с пальцем 250 нс; фазу заряда берут не короче 3–5 таких постоянных: за 800 нс электрод заряжается на 96 %
диод Шоттки на электрод ёмкость ≤ 2 пФ дополнительная защита при жёсткой помехе
панель пластик до 2 мм, стекло лучше (выше ε); без воздушного зазора, клей без пузырей зазор в десятые доли миллиметра съедает чувствительность сильнее, чем миллиметр пластика
электрод ширина не меньше четырёх толщин панели (1,5 мм → 6 мм и больше); одинаковая форма у всех кнопок одинаковые Cx — общие пороги
зазор между кнопками от 2 мм, лучше 4–5 взаимное влияние
земля сетчатая заливка под дорожками к электродам, не сплошная сплошная земля добавляет Cx и убивает чувствительность
выводы только под TSC, не делить с другими функциями; дорожки короткие, подальше от стабилизатора и ШИМ наводки на электрод — это ложный палец
светодиод в кнопке шунтировать конденсатором 10 нФ иначе высокоомная цепь диода — антенна

45.4 Регистры и один цикл измерения

Регистр управления TSC_CR:

Поле Что задаёт
CTPH, CTPL длительность фазы заряда и фазы переноса: 1…16 тактов (код + 1)
PGPSC делитель тактов HCLK для генератора импульсов: 1…128 (2^код)
MCV предел счёта: 255…16383 (2^(8+код) − 1); при переполнении — флаг MCEF
SSE, SSD, SSPSC расширение спектра: включить, глубина (7 бит), делитель
IODEF незадействованные выводы групп: 0 — прижаты к земле, 1 — плавают
AM, SYNCPOL ждать внешнего синхроимпульса и его фронт
START, TSCE пуск, включение

Выводы описываются четырьмя регистрами по 32 бита (группа × 4 + номер вывода): IOCCR — какие выводы каналы, IOSCR — какие под Cs, IOHCR — гистерезис Шмитта на выводе (для выводов TSC выключить), IOASCR — аналоговый ключ (разряд). IOGCSR разрешает группы (биты 0…7) и сообщает, какие закончили (биты 16…23); результат — в IOGxCR, 14 бит.

/* HCLK 80 МГц / 32 = 2,5 МГц; заряд 2 такта + перенос 2 такта = 1,6 мкс
   на перенос, 625 кГц. Предел 8191 переносов — 13 мс: если электрод
   оборван или закорочен, измерение всё равно закончится (флаг MCEF). */
static void tsc_init(void)
{
    RCC->AHB1ENR |= RCC_AHB1ENR_TSCEN;
    TSC->CR = (CYCLES(2u)       << TSC_CR_CTPH_Pos)
            | (CYCLES(2u)       << TSC_CR_CTPL_Pos)
            | (PGPSC_CODE(32u)  << TSC_CR_PGPSC_Pos)
            | (MCV_CODE(8191u)  << TSC_CR_MCV_Pos)
            | TSC_CR_TSCE;                         /* IODEF = 0: свободные выводы — в низкий уровень */
    TSC->IOHCR  &= ~(TSC_IOHCR_G1_IO1 | TSC_IOHCR_G1_IO2);   /* Шмитт выключить на выводах TSC */
    TSC->IOSCR   =  TSC_IOSCR_G1_IO1;              /* IO1 — конденсатор Cs */
    TSC->IOCCR   =  TSC_IOCCR_G1_IO2;              /* IO2 — электрод (канал) */
    TSC->IOGCSR  =  TSC_IOGCSR_G1E;                /* группу 1 — считать */
}

/* Одно измерение: пауза разряда, пуск, ожидание конца, число переносов. 0 — переполнение. */
static uint32_t tsc_measure(void)
{
    delay_us(TSC_DISCHARGE_US);                    /* разряд Cs: выводы прижаты к земле (IODEF = 0) */
    TSC->ICR = TSC_ICR_EOAIC | TSC_ICR_MCEIC;
    TSC->CR |= TSC_CR_START;
    while ((TSC->ISR & TSC_ISR_EOAF) == 0u) { }
    if (TSC->ISR & TSC_ISR_MCEF)
        return 0u;
    return TSC->IOGXCR[0] & TSC_IOGXCR_CNT_Msk;
}

Пауза перед пуском нужна потому, что Cs разряжается только между измерениями, пока выводы прижаты к земле (IODEF = 0). Функция, вызванная сразу за предыдущей, даёт разряду считанные микросекунды, и остаток заряда сдвигает счёт на величину, зависящую от частоты вызовов. Паузу берут с запасом и одну и ту же перед каждым измерением: у вывода, прижатого к земле, десятки ом, и Cs 47 нФ через 50 Ом разряжается с постоянной времени 2,35 мкс — за десять таких, 24 мкс, остаётся меньше сотой доли процента заряда; TSC_DISCHARGE_US = 100 перекрывает это вчетверо. delay_us — любая пауза в микросекундах, хоть по таймеру (раздел 13).

Выводы группы переводятся в альтернативную функцию TSC (вывод Cs — с открытым стоком), а само измерение можно вести и по прерыванию EOAF, и по DMA — контроллер не требует внимания ядра, пока считает.

Несколько кнопок в одной группе — несколько «банков»: в каждом банке IOCCR включает по одному каналу на группу, банки измеряются по очереди. Три кнопки на группу — три измерения.


45.5 Из числа — в «нажато»

Сырой счёт превращается в событие четырьмя механизмами. Они не в блоке, а в программе, и без них кнопка не работает.

Опора и разность. Опорное значение — счёт при отпущенной кнопке; разность delta = ref − count. Нажатие только уменьшает счёт, поэтому отрицательную разность считают нулём.

Пороги с гистерезисом. Порог срабатывания — 55…65 % от разности при лёгком касании, порог отпускания — заметно ниже. Для отклика 257 (+2 пФ при Cs 47 нФ) это 154 и 90. Между ними кнопка сохраняет состояние — иначе дребезг на границе.

Слежение за средой (ECS). Температура, влажность, питание медленно уводят счёт; опора должна следовать за ними. Фильтр первого порядка: ref += K · (count − ref), K = 1/64 — опора догоняет уход на 30 отсчётов примерно за секунду (216 измерений по 4,5 мс), то есть заведомо медленнее любого нажатия. Пока кнопка нажата, слежение останавливают, иначе опора «съест» палец.

Дребезг и таймауты. Подтверждать состояние двумя-тремя измерениями подряд; ограничивать длительность нажатия (DTO: палец забыт на панели, или на неё легла книга — через заданное время перекалибровка); при нескольких кнопках разрешать только одну нажатую (DXS: ладонь накрыла три — считается самая сильная).

#define DETECT_IN    50u        /* порог срабатывания — 55…65 % от отклика на палец */
#define DETECT_OUT   30u        /* порог отпускания — ниже: гистерезис */
#define ECS_SHIFT    6u         /* K = 1/64 — постоянная времени фильтра ~64 измерения */

static uint32_t ref_x64;        /* опора × 64: целочисленный фильтр без дробей */
static int      pressed;

static int touch_update(uint32_t count)
{
    uint32_t ref = ref_x64 >> ECS_SHIFT;
    uint32_t delta = (ref > count) ? ref - count : 0u;    /* нажатие — только уменьшение */

    if (!pressed && delta > DETECT_IN)  pressed = 1;
    if ( pressed && delta < DETECT_OUT) pressed = 0;
    if (!pressed)                                            /* опора подстраивается лишь в покое */
        ref_x64 += count - ref;
    return pressed;
}

Пороги 50 и 30 в листинге — под синтетический прогон ниже (касания −80 и −40); для панели с откликом 257 ставят 154 и 90. Опору перед циклом задают первым измерением: ref_x64 = count << ECS_SHIFT. Если начать с нуля, опора догоняет счёт около секунды, и всё это время кнопка не срабатывает.

Состояния кнопки в готовой библиотеке богаче: отпущена, приближение (малая разность — рука рядом), нажата, ошибка (счёт вне разумного — обрыв или короткое). Приближение — это та же кнопка с меньшим порогом: подсветить панель, когда рука подносится.

Функция выше — без изменений — прогнана на синтетическом счёте (_verify/touch45/): 600 измерений, медленный уход опоры на −30, сильное касание на −80 и слабое на −40.

touch_update() на 600 измерениях: счёт и опора, разность с порогами 50 и 30, интервал нажатия


45.6 Помехи и что с ними делать

Слабое место метода — помеха на частоте переноса и её гармониках (сотни килогерц — десятки мегагерц): сетевые импульсные источники, ШИМ подсветки, радиопередатчики. Средства, от простых к сложным:

Требование к отклику панели — обычно не хуже 20 мс на измерение всех кнопок. Три канала одной группы меряются по очереди, и расширение прибавляется к каждому: 3 × (4,5 + 2,6) — 21 мс, уже больше нормы. Каналы в разных группах меряются одновременно: около 7 мс, с подтверждением двумя измерениями — 14 мс.


45.7 Слайдер, колесо, приближение

Слайдер — три и больше электродов в ряд, каждый на своём канале; палец над стыком меняет разность у двух соседей, и положение получают взвешиванием разностей: центр «тяжести» по каналам. Колесо — то же кольцом. Электроды слайдера делают зубчатыми, чтобы соседние перекрывались и разность менялась плавно. Для таких датчиков Cs — только стабильных диэлектриков (PPS, NPO, PET), потому что положение считается из абсолютных величин разностей, а не из порогов.

Приближение — кнопка с большим электродом и низким порогом: «рядом рука» за сантиметры до касания.


45.8 Библиотека и HAL

Готовая библиотека сенсорного ввода делится на три слоя: измерение (TSC), обработка (опора, разности, пороги, ECS, DTO, DXS, дребезг, положение слайдера) и приложение. Настройка — константы в одном заголовке: число каналов, кнопок, слайдеров, банков, пороги, коэффициенты K быстрый/медленный, задержки ECS, DTO, счётчики дребезга, режим свободных выводов. Пороги подбирают по логу разностей на готовой панели: разность при касании — базовая величина, от неё 60 % — срабатывание.

HAL описывает блок структурой TSC_InitTypeDef: CTPulseHighLength, CTPulseLowLength, SpreadSpectrum (+ Deviation, Prescaler), PulseGeneratorPrescaler, MaxCountValue, IODefaultMode, SynchroPinPolarity, AcquisitionMode, ChannelIOs, SamplingIOs, ShieldIOs. Цикл: HAL_TSC_IOConfig (банк), HAL_TSC_IODischarge, HAL_TSC_Start или HAL_TSC_Start_IT, HAL_TSC_PollForAcquisition, HAL_TSC_GroupGetStatus, HAL_TSC_GroupGetValue; обратный вызов — HAL_TSC_ConvCpltCallback.

Разряд перед измерением обязателен: остаточный заряд на Cs — это смещение счёта (пауза в tsc_measure, 45.4).


45.9 Батарейное питание

Блоку нужен HCLK, в режиме Stop он не считает. Схема для батарейного устройства: спать, просыпаться по таймеру (раздел 10.6) раз в 50–100 мс, измерить одну кнопку-«будильник» с большим электродом (приближение), уснуть. Полное сканирование — только когда она сработала. Cs при этом — только стабильных диэлектриков: между измерениями конденсатор долго стоит, и поглощение диэлектрика проявляется сильнее.


45.10 Грабли

Счёт всегда предельный (MCEF). Электрод оборван, вывод не в альтернативной функции, Cs не подключён или слишком велик для MCV: 220 нФ при 20 пФ — уже за 8191.

Счёт очень мал, кнопка «нажата» всегда. Cs мал или закорочен; сплошная земля под электродом; вывод Cs не с открытым стоком.

Кнопка срабатывает сама с прогревом. Опора не следит за средой (нет ECS) или Cs из X7R/тантала. Фильтр опоры и PPS/NPO.

Кнопка «залипает». Слежение за средой не остановлено во время нажатия и подтянуло опору к пальцу; нет порога отпускания ниже срабатывания.

Ложные нажатия от подсветки или зарядного. Помеха на частоте переноса: расширение спектра, синхронизация с ШИМ, больше Rs.

Работало на макете, не работает в корпусе. Воздушный зазор под панелью; толстая панель при маленьком электроде (нужно четыре толщины); клей с пузырями.

Соседняя кнопка тоже срабатывает. Малый зазор между электродами, общие дорожки, нет DXS.

Шмитт-триггер на выводе включён. IOHCR — для выводов TSC биты должны быть сброшены, иначе порог не тот и счёт скачет.

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


45.11 Итоги

Дальше: раздел 46 «Таймеры специального назначения: HRTIM и LPTIM» — пикосекунды для преобразователей и ШИМ, который работает во сне.

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