8-битные PIC: асинхронная и синхронная работа таймера 1

Семейство 8-битных PIC (я работаю с pic18f46k22) предлагает несколько таймеров (таймеры 1/3/5), которые могут работать как в асинхронном, так и в синхронном режимах при тактировании от внешнего источника.

Очевидные отличия:

  1. асинхронная работа дает возможность таймеру работать в спящем режиме
  2. Асинхронный источник может синхронизировать таймер быстрее, поскольку он не зависит от системных часов (таблица 27-12):временные характеристики

а что касается преимуществ синхронизации с внешним источником часов... ну я их не вижу. Одним из недостатков, о котором следует подумать, является возможное повреждение данных, если ЦП пытается прочитать счетчик во время его увеличения, но в таблице данных указано:

12.5.1 ЧТЕНИЕ И ЗАПИСЬ ТАЙМЕРА 1/3/5 В РЕЖИМЕ АСИНХРОННОГО СЧЕТЧИКА: Чтение TMRxH или TMRxL во время работы таймера от внешних асинхронных часов обеспечит правильное чтение (об этом заботится аппаратно).

Может кто-нибудь объяснить, почему они добавили возможность синхронизации внешнего источника часов с внутренними фазовыми часами? Я чувствую, что что-то упускаю. Большое спасибо

Ответы (3)

Некоторые операции с таймером не работают, когда он может измениться в середине цикла. Этот таймер также используется в сочетании с модулями CCP. Прочтите раздел описания модулей CCP, и вы, вероятно, найдете ограничения на то, когда он должен работать в синхронном режиме.

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

Это может многое объяснить: 14.1.2 РЕСУРС РЕЖИМА ТАЙМЕРА 1 16-битный ресурс таймера должен работать в режиме таймера или режиме синхронизированного счетчика, чтобы модуль CCP мог использовать функцию захвата. В режиме асинхронного счетчика операция захвата может не работать. Вероятно, это одна из причин добавления опции синхронизации.

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

Если у вас есть два асинхронных таймера, я бы посоветовал вам настроить один из них на непрерывную работу и ничего с ним не делать, кроме чтения его значения. Такие чтения должны выполняться путем чтения младшего байта, затем старшего байта, а затем снова младшего байта. Если младший байт изменился между двумя чтениями, повторите процесс. Другой таймер можно настроить для событий пробуждения, но с некоторыми оговорками:

  1. Запишите младший байт таймера, прежде чем делать что-либо еще, чтобы изменить его, а затем прочитайте его. Если младший байт изменился, предположите, что таймер мог быть произвольно поврежден, и начните снова с нуля.

  2. По крайней мере, в некоторых частях прерывание таймера происходит по фронту тактового сигнала после фронта тактового сигнала, который переводит таймер с 0xFFFE на 0xFFFF. Программирование таймера со значением 0xFFFF вызовет прерывание не на первом такте после такого действия, а на 65 537-м такте. Я не знаю, есть ли способ установить таймер для прерывания на следующем тике.

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

Привет, я ждал вашего ответа, когда читал ваш пост по аналогичной проблеме ... На самом деле у меня нет проблем с дизайном, и я только устанавливал таймер для работы в качестве счетчика краев. Но я как бы зациклился на опции синхронизации... Мой вопрос заключался в том, что я не могу понять, почему существует возможность синхронизации внешнего источника часов, если асинхронная работа явно более выгодна.
микроконтроллер также имеет функцию буферизации старшего байта при чтении младшего байта, и я не могу понять, почему я не должен использовать этот режим. Это должно решить проблему, на которую вы указали, и всегда возвращать хорошее чтение. то же самое верно для записи, так как буферизованное значение старшего байта записывается, когда записывается младший байт, и, следовательно, гарантирует хорошую запись
@fhlb: если таймер находится в асинхронном режиме, нужно дважды прочитать младший байт, даже если вам не нужен старший байт, и вам придется дважды прочитать старший байт, если вы никогда не смотрели на младший байт. Если кто-то читает байт именно в тот момент, когда он изменяется с 0x7F на 0x80 или с 0xFF на 0x00, он может сообщить любое значение, и защелка старшего байта ничего не делает, чтобы избежать этой проблемы. Если два чтения дают одно и то же значение и невозможно, чтобы счетчик увеличился кратно 256 раз между чтениями, значение гарантированно правильное, но определенно требуются два чтения.
Я понимаю, что чтение асинхронного счетчика может представлять риски, на которые вы указали, но в таблице данных четко указано, что действительное чтение всегда застраховано, и что проблема заключается в том, что таймер переполняется между чтением младшего байта и чтением старшего байт. Я не тот гуру электроники с часами, и я не могу сказать, как это возможно, но разве мы не должны доверять таблице данных?
12.5.1 ЧТЕНИЕ И ЗАПИСЬ ТАЙМЕРА 1/3/5 В РЕЖИМЕ АСИНХРОННОГО СЧЕТЧИКА: Чтение TMRxH или TMRxL во время работы таймера от внешних асинхронных часов обеспечит правильное чтение (об этом заботится аппаратно). Однако пользователь должен иметь в виду, что чтение 16-битного таймера в двух 8-битных значениях само по себе создает определенные проблемы, так как таймер может переполниться между чтениями.
@fhlb: производитель ЦП может попытаться сделать такие чтения надежными несколькими способами. Многие из них уменьшат вероятность отказа, но не устранят его. Учитывая ошибки, с которыми мне приходилось сталкиваться на протяжении многих лет, я не верю, что Microchip на самом деле правильно реализовала такие меры, особенно учитывая, что для этого требуется много дополнительных схем. Кроме того, код, использующий метод буфера старших байтов, может иметь проблемы, если есть какие-либо прерывания, которые могут потребоваться для чтения состояния таймера, поскольку это может привести к проблематичной последовательности событий:
1. Основной код считывает значение младшего байта FF и фиксирует старший байт; 2. Увеличение счетчика 3. Прерывание считывает младший байт и захватывает старший байт; 3. Код основной ветки считывает то, что, по его мнению, должно быть буферизованным старшим байтом. Если может произойти прерывание и прочитать таймер после того, как код основной линии прочитает младший байт, код основной линии должен защититься от этого; защититься от этой возможности, дважды прочитав младший байт таймера в коде основной строки, так же просто, как и использовать любые другие средства, поэтому я не вижу никаких причин не использовать этот подход, и в этом случае не имеет значения, читается ли на 100% надежны.
Между прочим, определение того, произошло ли какое-либо событие до определенного тактового цикла, является фундаментально сложной задачей, и нет жестких ограничений на то, сколько времени может занять такое определение. Лучшее, что можно сделать, это решить в следующем цикле, решила ли система, что событие произошло; логике обнаружения оригинального изобретения может потребоваться больше цикла, чтобы решить, что событие, которое произошло почти точно на границе тактового цикла, на самом деле произошло до часов, но маловероятно, чтобы прийти к такому выводу в точный момент прибытия следующих часов.
Ваша процедура чтения многобайтового таймера выполняется в обратном порядке. Вы читаете старший байт, младший байт, затем снова старший байт и сохраняете первые два, если второй старший байт совпадает с первым. Если нет, сделайте это снова. Не имеет значения, меняется ли младший байт между чтениями, важно только, чтобы между чтениями не было переноса от младшего к старшему байту.
@OlinLathrop: я не склонен доверять результату однократного чтения многобитового количества из асинхронного домена, если я не знаю что-либо об используемых механизмах синхронизации. Чтение низкий-высокий-низкий будет работать, даже если одно из чтений дает фиктивное значение, потому что младший байт увеличивался с 0x7F до 0x80. В этом случае чтение high-low-high не удастся.
@supe: Нет, это не подведет. Подумайте о каждом из возможных случаев, когда может произойти приращение и перенос. High-inc-low-high дает увеличенное значение. High-low-inc-high дает неинкрементное значение. High-carry-low-high — это конец. Так что высокий-низкий-носи-высокий. Покажите мне случай, когда это не работает.
@OlinLathrop: входящий тактовый импульс таймера достигает порога, на котором можно сообщить через текущее чтение, так что схема фиксации, которая должна указывать, должен ли этот тактовый импульс влиять на текущее чтение, становится метастабильной, в результате чего некоторые биты сообщают о новом значение часов и другие, чтобы сообщить старое значение часов.
@OlinLathrop: Возможно, Microchip удалось должным образом реализовать одно из аппаратных решений, чтобы избежать такого повреждения, но им требуется немало кремния, в котором нет необходимости, если код использует подход, который я описываю. Обратите внимание, что есть некоторые дешевые меры, которые делают «расщепление» считывания менее вероятным, чем если бы не применялись никакие меры для снижения этого риска, но дешевые элементы по-прежнему имеют нетривиальную вероятность отказа.

supercat упомянул о чтении ошибок микрочипов ... посмотрите на PIC18 (L) F26 / 46K22 Rev. A2 / A4 Silicon Errata и уточнение таблицы данных (этот микроконтроллер, который вы используете):

  1. Модуль: Таймер 1/3/5

Когда Таймер 1, Таймер 3 или Таймер 5 работают в режиме асинхронного внешнего ввода, может произойти непредвиденная генерация флага прерывания, если фронт внешнего тактового сигнала поступит слишком рано после записи прошивки в регистры TMRxH:TMRxL. Непредвиденное событие флага прерывания также может произойти при включении модуля или переключении из синхронного в асинхронный режим.

Обойти:

Эта проблема возникает только при работе таймера в асинхронном режиме. По возможности используйте модуль таймера в синхронном режиме, чтобы избежать ложных прерываний таймера.

Быстрый поиск в Google также показывает другие проблемы с режимом асинхронного таймера с другими микроконтроллерами (пример: pic18f4550 errata-сбой механизма буферизованного чтения и ошибки семейства pic18f97j60), поэтому, вероятно, это хороший момент, чтобы не слишком доверять асинхронному таймеру и добавьте дополнительные две строки кода, чтобы проверить любое чтение/запись. и не забудьте пример кода, представленный в errata, чтобы очистить генерацию флага неожиданного прерывания при записи таймера

Только что нашел это: microchip.com//wwwAppNotes/AppNotes.aspx?appnote=en573101