Этот проект посвящен созданию простого частотомера, способного измерять частоту до 100МГц с точностью 0.002%. За основу я взял ATtiny414, задействовав при этом его таймер/счетчик TCD0 и систему событий.

Недавно я задумал собрать частотомер с возможностью измерения до 100МГц, что позволило бы использовать его для проверки частоты процессора и кристаллов. В сети есть немало схем для сборки подобных девайсов на базе микроконтроллера, ведь в этом и состоит одно из назначений встроенных в МК таймеров/счетчиков. Однако большинство таких устройств не достигают уровня 100МГц, так как измерение внешней частоты ограничено половиной собственной тактовой частоты микроконтроллера.

Первая попытка


Я решил использовать внешние RTC (часы реального времени), тактируемые кристаллом 32.768кГц, для генерации прерываний с частотой 1Гц. Затем второй таймер/счетчик, тактируемый измеряемой частотой, будет отсчитывать количество циклов в этом односекундном интервале, в результате сообщая частоту в Гц.

Для первого прототипа я использовал таймер/счетчик TCB0, тактируемый через входной вывод, с захватом, который активировался от RTC подачей сигнала 1Гц. Как и предполагалось, измерить я смог только половину тактовой частоты, или 10МГц, поэтому потребовался четырехкаскадный делитель для деления входной частоты 100Мгц на 16, чтобы вписать ее в подходящий диапазон. В качестве делителя я попробовал задействовать CCL. Кстати, о подобной его реализации у меня даже есть отдельная статья Frequency Divider Using CCL.

Использование таймера/счетчика TCD0


Об использовании TCD0 я задумался просто между делом. Это 12-битное устройство, но, в отличие от большинства своих аналогов, работает оно асинхронно, то есть независимо от тактов процессора.

В первую очередь TCD0 предназначен для генерации сигналов, например при управлении электродвигателем, и я даже не знаком со многими из его возможностей. Однако мне показалось, что с его помощью вполне можно реализовать захват значения счетчика, работающего под управлением часов реального времени.

Опытным путем я выяснил, что TCD0 можно тактировать на частоте более 100МГц, что позволило бы собрать очень простой частотомер с нужным мне диапазоном действия без делителя.

Использование системы событий


Я мог использовать RTC для генерации прерывания каждую секунду, а затем захватывать значение счетчика из TCD0 через программу обработки прерываний. Тем не менее последние процессоры AVR предоставляют систему событий (Event System), позволяющую реализовать это более эффективно.

Можно сгенерировать внутренний сигнал с RTC и с помощью него непосредственно активировать захват. Преимущество здесь в том, что вызов службы прерываний не требует лишней обработки, в результате чего ответ возвращается практически мгновенно.

Выбор микроконтроллера


Компания Microchip предлагает три новых серии микроконтроллеров AVR:

  • ATtiny 0-, 1- и 2-;
  • ATmega 0;
  • AVR DA- и DB-.

С позиции периферии они одинаковы, поэтому я мог выбрать, к примеру, ATtiny414, ATmega4809 или AVR128DA28, все из которых снабжены TCD0 и способны использовать для тайминга внешний кварцевый резонатор 32.768КГц.

Первую версию схемы я протестировал с AVR128DA28, но для конечной все же выбрал ATtiny414, потому что он выполнен в более компактном корпусе, а дополнительные входы/выходы мне не требовались.

В итоге получилось так, что при использовании AVR128DA28 события работали, а после перехода на ATtiny414 перестали. Оказалось, что проблема в отличии терминологии для более ранних процессоров. Здесь я хочу поблагодарить пользователя AVR Freaks под ником kabasan за то, что помог разобраться. Если вы хотите побольше узнать о применении системы событий, то советую начать с серии AVR DA- или DB-, для которых используется более логичная терминология.

Примечание. Не стоит путать ATtiny 1 серии, ATtiny414, вышедшие в 2020, с более старыми ATtiny441, появившимися в 2014 в качестве расширенной версии еще более старого ATtiny44.

Измерение частоты кристалла


Я решил, что будет нелишним задействовать кварцевый резонатор, который позволит использовать частотомер для измерения частоты колебаний кристалла. В одном из вариантов схем подобного резонатора применяется небуферизованный КМОП-инвертор LVC1GU04 и ряд других компонентов1:


Здесь я задумался о возможности создания инвертора на базе ATtiny414 с применением системы событий таким образом:

  • Определить PA2 в качестве событийного выхода, EVOUT0. Это был единственный вариант, так как другой выход, EVOUT1, находится на том же выводе, что и TOSC2, используемый кварцевым резонатором RTC.
  • Определить PA1 в качестве асинхронного генератора событий на канале 0. Подойдет любой вывод на PORTA.
  • Настроить PA1 на инвертирование входа.

Далее выход инвертора, PA2, подключается ко входу частотомера, EXTCLK/PA3.

На моем прототипе эта схема отлично работала без каких-либо дополнительных компонентов с диапазоном частоты кристаллов от 2 до 25МГц. Однако для того, чтобы заставить кварц резонировать, может потребоваться дополнительное место на макетной плате. Так что, если вы проектируете для этой схемы печатную плату, то советую оставить место под пассивные компоненты на случай, если они понадобятся.

Схема


Вот схема частотомера 100МГц, компоновка которой соответствует схеме макетной платы:


Схема частотомера 100МГц на базе ATtiny414

В качестве дисплея используется модуль OLED 128x32 I2C с драйвером SSD1306. Для прототипа я взял дисплей Adafruit2, хотя вполне подойдет и любой аналог с AliExpress3. Резистор 33кОм и конденсатор 0.1мкФ обеспечивают корректный сброс дисплея при первой подаче питания, хотя они могут и не понадобиться.

В качестве резонатора служит кристалл 32.768кГц с точностью 20ppm и емкостной нагрузкой 12.5пФ 4. Для вычисления значений конденсатора я использовал формулу С = 2(СL – CS), где СL представляет емкостную нагрузку 12.5пФ, а CS паразитную емкость, которая на макетной плате достигает, вероятно, 5пФ, давая С = 15пФ. На печатной же плате ее значение, возможно, составит 2.5пФ.

В роли процессора выступил ATtiny414 в 14-контактном корпусе SOIC 5, который я установил на коммутационную плату – подходящий вариант есть у Adafruit6. Проект можно также реализовать на базе ATtiny814 или ATtiny1614 с бОльшим объемом памяти, но не на ATtiny404, поскольку в нем нет поддержки внешнего кристалла RTC.

Использование частотомера


Измерение частоты


Для измерения частоты сигнала нужно подключить устройство между In и GND. При питании 3.3В частотомер работал в диапазоне до 105МГц, а при повышении напряжения до 5В верхний порог сместился к 110МГц.

Измерение частоты кристалла


Для измерения частоты колебаний кристалла подключаемся между выводами Xtal и In:


Измерение частоты колебаний кристалла 16МГц

Программная часть


Код для ATtiny414


При написании кода для ATtiny414 и его обвязки мне пригодилась документация AVR1000b: Getting Started with Writing C-Code for AVR MCUs. Кроме того, при выборе символов для конкретных настроек регистра, будет нелишним почитать iotn414.h, который находится у вас на ПК в megaTinyCore.

OLED дисплей


В интерфейсн дисплея я задействовал те же функции, что и во многих прежних проектах, например Tiny Function Generator, где использовался такой же OLED дисплей I2C. Текст отрисовывается при помощи набора символом размером 6х8 пикселей, но при удвоенном масштабе для получения символов 12х16 пикселей используется функция сглаживания, описанная мной в Smooth Big Text.

Обратите внимание, что на ATtiny414 в megaTinyCore размер буфера I2C с целью экономии ОЗУ составляет всего 16 байт, поэтому мне пришлось изменить функции ClearDisplay и PlotChar() на отправку данных меньшими порциями.

Функцию Plotlnt() я подкорректировал на отображение запятых между каждой тройкой цифр, чтобы облегчить их чтение.

Часы реального времени


Настраивать RTC на использование внешнего кристалла сложнее, чем может показаться, поскольку контроллер часов защищен от случайного вмешательства со стороны протокола изменения конфигурации (CCP). По этой причине перед каждым внесением корректировок необходимо это действие активировать. Хорошо, что в приложении есть примечание, объясняющее, как это делать, и код я писал на примере из этого примечания7.

Таймер/счетчик TCD0


TCD0 настроен вести отсчет от 0 до 0xFFF и захватывать значение счетчика в регистр CAPTUREB при получении события B. Он генерирует прерывания при событии захвата, а также при переполнении счетчика, и тактируется от внешнего сигнала, поступающего через вывод EXTCLK/PA3:

void TCDSetup () { 
  TCD0.CTRLB = TCD_WGMODE_ONERAMP_gc;               // Установка режима счетчика 
  TCD0.CMPBCLR = 0xFFF;                             // Отсчет до максимума
  TCD0.INPUTCTRLB = TCD_INPUTMODE_EDGETRIG_gc;      // Захват и сброс счетчика
  TCD0.EVCTRLB = TCD_CFG_ASYNC_gc | TCD_ACTION_bm | TCD_TRIGEI_bm; // Активация события
  TCD0.INTCTRL = TCD_OVF_bm | TCD_TRIGB_bm;         // Активация прерываний

  // ожидание установки бита ENRDY
  while(!(TCD0.STATUS & TCD_ENRDY_bm));
  
  // Внешний тактовый сигнал, без делителя, активация таймера
  TCD0.CTRLA = TCD_CLKSEL_EXTCLK_gc | TCD_CNTPRES_DIV1_gc | TCD_ENABLE_bm;
}

Служба прерываний при переполнении инкрементирует счетчик MSByte для старшей части значения частоты:

ISR (TCD0_OVF_vect) {
  TCD0.INTFLAGS = TCD_OVF_bm;                       // Очистка флага прерывания по переполнению
  MSByte++;
}

Служба прерывания при захвате считывает регистр захвата и совмещает его значение с MSbyte, формируя значение Counter.
ISR (TCD0_TRIG_vect) {
  PORTA.IN = PIN4_bm;                               // Включение светодиода
  TCD0.INTFLAGS = TCD_TRIGB_bm;                     // Очистка флага прерывания по перехвату
  Counter = TCD0.CAPTUREB;
  Counter = (uint32_t)MSByte<<12 | Counter;
  MSByte = 0;
  Ready = true;
  PORTA.IN = PIN4_bm;                               // Отключение светодиода
  TCD0.INTFLAGS = TCD_OVF_bm;                       // Очистка флага прерывания по переполнению
}

Она также зажигает светодиод, сигнализируя о выполнении захвата. Если вам это не нужно, можете светодиод исключить.

События


Для того, чтобы задействовать события, нужно настроить переполнение RTC на генерацию события в канале 1, а TCD0 на использование этого события для выполнения захвата:

void EvsysSetup (void) {
  EVSYS.ASYNCCH1 = EVSYS_ASYNCCH1_RTC_OVF_gc;       // Событие, сгенерированное RTC OVF
  EVSYS.ASYNCUSER7 = EVSYS_ASYNCUSER7_ASYNCCH1_gc;  // Событие вызывает захват TCD0
  
  EVSYS.ASYNCCH0 = EVSYS_ASYNCCH0_PORTA_PIN1_gc;    // PA1 – это генератор событий
  EVSYS.ASYNCUSER8 = EVSYS_ASYNCUSER8_ASYNCCH0_gc;  // ASYNCUSER8 – это EVOUT0 (PA2)
  PORTMUX.CTRLA = PORTMUX_EVOUT0_bm;                // Активация EVOUT0
  PORTA.PIN1CTRL = PORT_INVEN_bm;                   // Инвертирование входа
}

Канал событий 0 служит для создания инвертора между PA1 и PA2, который, как говорилось выше, будет выступать в качестве кварцевого резонатора.

Основной цикл


Основной цикл ожидает установки глобальной переменной Ready, что укажет на выполнение захвата. Затем он копирует значение Counter в temp. При этом прерывания отключены, чтобы исключить возможное изменение этого значения службой прерываний в процессе его отображения:

void loop() {
  uint32_t temp;
  unsigned long start = millis();
  while (!Ready) {
    if (millis() - start > 1000) {
      Counter = 0;
      break;
    }
  }
  Ready = false;
  cli(); temp = Counter; sei();
  PlotInt(temp, 1, 0);
}

При отсутствии входного сигнала TCD0 не тактируется, и значение Counter не обновляется. Для проверки подобной ситуации присутствует односекундный таймаут, который сбрасывает Counter на ноль, если Ready не была установлена. Нулевое значение отображается функцией PlotInt() в виде трех прочерков.

Точность


Для проверки этого проекта мне нужно было найти способ генерировать точные сигналы с частотой до 100МГц, но такого генератора у меня нет. Точность моего предыдущего проекта, Programmable Signal Generator, составляет всего 1.1%, чего для данного случая будет явно недостаточно, к тому же его верхний предел всего 68МГц.

В связи с этим я купил коммутационную плату генератора тактовых импульсов Si5351A от Adafruit8, которую можно через I2C запрограммировать на генерацию сигналов от 8кГц до 160МГц (еще есть вариант аналогичной платы на Banggood9). Управление ей я реализовал через прекрасную библиотеку Si5351 Джейсона Миллдрама10, работающую на Arduino Uno.

Точность частотомера в первую очередь зависит от точности кристалла, используемого для генерации дискретизированного сигнала 1Гц. Я использовал цилиндрический кристалл с заявленной точностью 20ppm. Звучит неплохо, пока не вычислишь, что при входном сигнале 100МГц это эквивалентно ±2000Гц. На практике же его точность в целом оказалась раз в 5-10 выше заявленной.

Компиляция


Для компиляции используйте megaTinyCore Спенса Конде c GitHub. В меню Board под вкладкой megaTinyCore выберите опцию ATtiny1614/1604/814/804/441/404/241/204. Проверьте, чтобы следующие опции были установлены так (на остальные внимания не обращайте):

Chip: "ATtiny414"
Clock: "20 MHz Internal"
millis()/micros(): "TCA0 (default on 0-series)"

Затем с помощью программатора UPDI загрузите программу на ATtiny414. Теперь megaTinyCore поддерживает две возможности:

  • Создание программатора UPDI из Arduino Uno или другой платы на базе ATmega328P (инструкция на странице Make UPDI Programmer) и установку опции Programmer на jtag2updi.
  • Использование платы USB-Serial, такой как SparkFun FTDI Basic11, подключение TX к выводу UPDI через резистор 4.7кОм, подключение RX напрямую к выводу UPDI и установку опции Programmer на Serial port and 4.7k (pyupdi style).

Ошибку "Cannot locate flash and boot memories in description" можете проигнорировать.

Если же возникнет такая ошибка:

(.text+0x0): multiple definition of __vector_14

Это значит, что вы не установили опцию millis()/micros() как TCA0, о чем говорилось выше.

Вот вся программа для частотомера до 100МГц: 100MHz Frequency Meter Program.

Дополнительные возможности


Интерфейс


Эта схема подразумевает, что сигнал представляет собой меандр с амплитудой равной логическому уровню. В частотомере для рабочего применения лучше всего реализовать управление счетчиком через аналоговый интерфейс с защитой входа. Как вариант, можно взять модуль, основанный на высокоскоростном компараторе TLV3501.

Измерение периода


Используемая в этом частотомере техника подсчета импульсов наиболее точна на высоких частотах. Данный подход можно совместить с измерением интервалов для низких частот, о чем я писал в статье Frequency Probe.

Ссылки


1. Use of the CMOS Unbuffered Inverter in Oscillator Circuits на ti.com.
2. Monochrome 128x32 I2C OLED graphic display на Adafruit.
3. 0.91 inch 128x32 I2C IIC Serial OLED LCD Display Module на AliExpress.
4. AB38T-32.768kHz на Farnell.
5. AVR128DA28-I/SP на Mouser.co.uk
6. SMT Breakout PCB for SOIC-14 or TSSOP-14 на Adafruit.
7. TB3213 Getting Started with RTC на Microchip.
8. Adafruit Si5351A Clock Generator Breakout Board на Adafruit.
9. Si5351A Clock Generator Signal Generator на Banggood.
10. Si5351 Library for Arduino на GitHub.
11. SparkFun FTDI Basic Breakout — 5V на Sparkfun.

Комментарии (27)


  1. mphys
    16.08.2021 18:45

    А разность фаз двух одинаковых частот можно такой штукой (с модификациями) измерить?


    1. Ivanii
      16.08.2021 18:58

      Я никак не доделаю ATmega328(Ардуино нано) + EPM240, можно фазу отслеживать во времени с шагом 5 нс.


      1. belav
        16.08.2021 22:42

        А как шаг 5 нс будет гулять от температуры?


        1. Ivanii
          16.08.2021 23:58

          Как опорник OSC5A2B02 + джиттер умножителя +-0,4 нс.


          1. belav
            17.08.2021 00:23

            А джиттер от логики ПЛИС?


            1. Ivanii
              17.08.2021 09:33

              Он сильно меньше джиттера умножителя и влияния помех.

              А вот кратковременная нестабильность NEO-7N на 1 МГц оказалась порядка 20 нс, опорники меж собой не скачут.


  1. VT100
    16.08.2021 19:56

    Перевод, как всегда, - вырвиглазный.

    Жаль также, что автор не поискал (а переводчик не знал) чего-нибудь про более современные методы измерения частот. Что-то вроде reciprocal counting.


    1. dlinyj
      17.08.2021 11:20

      Можно чуть подробнее?



      1. VT100
        17.08.2021 20:41

        Если этого не было в библиографии у Л.И. (коментарий @Ivanii), то вот ещё:


        • New frequency counting principle improves resolution. Staffan Johansson, M.Sc. in Applied Physiscs.
        • Узлы профессионального частотомера. Баландин Н. И.

        Не найдутся — пишите в личку.


    1. igor_carenko
      17.08.2021 15:15
      +2

      А по-моему, хорошая реклама атмег новых :)

      я отсюда узнал, полез гуглить упомянутые тини/меги, нашёл, что ардуины новые на них есть...


      1. dlinyj
        17.08.2021 17:10

        Огласите весь список пожалуйста :)


      1. VT100
        17.08.2021 20:43

        Я о принципах, а не о реализации.
        А так — да.


  1. belav
    16.08.2021 22:40
    +5

    Точность 0.002%? Где-то тут статья была о необходимости высшего образования...


    1. N1X
      16.08.2021 23:54
      +4

      Ну написано "способного", видимо гипотетически он иногда способен попасть в эту цифру :)

      И нафиг все это термостатирование, рубидиевые стандарты и прочую попсу :D


      1. dlinyj
        17.08.2021 11:21

        Тут всё же говорится о любительском применении, о каком термостатировании может идти речь. Ну и потом, засовываем его в термокамеру, гоняем в цикле, вводим коэфициенты и получаем заданную точность.


        1. N1X
          17.08.2021 11:24
          +5

          Заданную в смысле "0.002%"? Увы... Сдается мне, что автор статьи просто спутал точность с дискретностью. Это частая ошибка между прочим. У тех людей, кто хоть как-то работал с измерительными приборами это вызывает некоторый зуд =)


  1. crustal
    17.08.2021 12:02

    Опытным путем я выяснил, что TCD0 можно тактировать на частоте более 100МГц, что позволило бы

    Зачем нужно тащить на хабр такое. Частота берется из даташита, опытным путем можно и на самокат 300 килограмм нагрузить, но нужно ли.


    1. dlinyj
      17.08.2021 23:07
      +1

      Как минимум потому, что недокументированные возможности это круто


      1. crustal
        18.08.2021 19:44
        -2

        Как минимум потому, что недокументированные возможности это круто

        20 лет назад этот 8-битный микроконтроллер уже не был крутым на фоне 16-битного MSP430. Сейчас 32-битные микроконтроллеры на 200 MHz стоят копейки. Зачем нужно тащить на хабр сильно устаревший МК — непонятно. Если уже обсуждать что-то по этой тематике, то хотя бы сравнение «continuously time-stamping frequency counting» с «reciprocal counting» и как это реализовать на stm32.

        После предыдущего коммента в этой теме моя карма упала еще на 2. Как бы всем понятно, что не за что, то есть типа наказывают за предыдущие комменты в других темах, причем не за последние, чтобы не было очевидно. Наверное за скромную попытку заступиться за хохлобратьев. И то правда, а оно мне надо?


        1. dlinyj
          19.08.2021 10:50

          20 лет назад этот 8-битный микроконтроллер уже не был крутым на фоне 16-битного MSP430. Сейчас 32-битные микроконтроллеры на 200 MHz стоят копейки. Зачем нужно тащить на хабр сильно устаревший МК — непонятно.

          Тут посты про zx spectrum бывают. Я использую контроллер в своей практике, он решает поставленные задачи.

          Потом, недокументированные возможности дают делать очень многое. И то что у вас отрицательная карма, явно говорит вам о том, что не вам судить что стоит делать на хабре, а что нет. Так как вы это регулярно не сюблюдаете.


          1. crustal
            21.08.2021 11:42

            И то что у вас отрицательная карма, явно говорит вам о том, что не вам судить что стоит делать на хабре, а что нет.

            А я и не судил что стоит делать на хабре, а что нет, просто спросил. Не вопрос, хотите использовать хабр в недокументированном режиме, — кто я такой, чтобы вам это запрещать? Просто спросил.


        1. nixtonixto
          26.08.2021 17:13

          Сейчас 32-битные микроконтроллеры на 200 MHz стоят копейки. Зачем нужно тащить на хабр сильно устаревший МК — непонятно.
          Как раз сейчас 32-битные контроллеры стоят от 10 долларов, STM32F030P4 за 500 рублей не желаете?

          И в статье не «сильно устаревший МК», а продакшн-модель 2020-го года. Простенькому частотомеру 100 DMIPS-числогрыз с потреблением пол-ампера совсем не нужен.


          1. crustal
            26.08.2021 19:58

            Как раз сейчас 32-битные контроллеры стоят от 10 долларов, STM32F030P4 за 500 рублей не желаете?

            Магазин не самых низких цен: www.chipdip.ru/product0/8001780701
            STM32L031K6T6 1232 шт. со склада г.Москва 210 руб.

            Что такое 210 руб, если вы работаете в ИТ и хотите инвестировать в проект сотни часов рабочего времени? Можете грамотно оценить выигрыш по времени разработки при переходе от 8-битной к 32-битной архитектуре и многократно больших разных ресурсах чипа?

            И в статье не «сильно устаревший МК», а продакшн-модель 2020-го года.

            Cильно устаревший МК, слегка подшаманенный, все еще находящийся в «продакшн» из-за очень низкой цены в очень крупных партиях.

            Простенькому частотомеру 100 DMIPS-числогрыз с потреблением пол-ампера совсем не нужен.

            Читайте, что пишите, на 100 MHz измерительное оборудование не бывает простеньким, точнее — можно слепить нечто воздушное из го*на и палок как в этой хабро-статье и претендовать на работу с 100 MHz сигналом, но к реальности это не будет иметь никакого отношения, можете поговорить с теми, кто имеет опыт работы с такими частотами.

            И «100 DMIPS-числогрыз с потреблением пол-ампера» — точно пол-ампера постоянно, вы ничего не путаете?


            1. Ivanii
              26.08.2021 22:04

              2,4 ГГц, https://aliexpress.ru/item/4000367868887.html оно работает и генератор термокомпенсированный.

              Я не люблю СТМ за противные АЦП, и больше потребление, я предпочитаю ATmega328p для мелких проектов, для шлюза UART - IP ESP8266, для батарейных проектов присмотрел nRF528**.


            1. dragonnur
              28.11.2021 03:01

              А если их вам нужно 50 штук? К тому же, НЯП «детали» это 10-20 % цены прибора.


  1. andand
    17.08.2021 15:16
    +2

    Прямо ностальгия на тему «Частотомер — цифровая шкала». Прескалер у PIC-ов тоже хорошо частоту держал.