Ещё раз про внешние прерывания в CH32V003

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

Я сейчас постараюсь устранить этот технический долг — описать как работать с внешними прерываниями.

Назначение системы внешних прерываний крайне простое — вызывать прерывание при изменении сигнала на ножке микроконтроллера. Прерывания можно на строить как на изменение сигнала с 1 на 0, так и с 0 на 1. Иногда говорят о фронте сигнала — нарастающий или спадающий. Можно запрограммировать оба изменения. В общем, что вам нужно, то и «заказывайте».

Внешние прерывания используют так называемые каналы (каналы прерываний). Что это значит?

Это означает, что, например, канал прерывания номер 2 будет обслуживать все изменения, которые приходят со 2-го бита (биты считаем с 0), независимо от какого порта они пришли. Другими словами, изменение сигнала на выводе 2-го бита порта GPIOA, а так же на выводе 2-го бита порта GPIOC и на выводе 2-го бита порта GPIOD — все попадут во 2-ой канал. Да, это накладывает определённые ограничения и иногда неудобства.

В микроконтроллерах CH32V003 три 8-разрядных порта: GPIOA, GPIOC, GPIOD. Порт GPIOB отсутствует.

Для обслуживания внешних прерываний создан специальный модуль — EXTI. В состав модуля входят несколько регистров. К счастью, номера битов регистров совпадают с номерами битов портов. Все регистры у модуля, вообще говоря, — 32-разрядные, но рабочими битами считаются биты с 0-го по 7-ой. Биты с 8-го по 31 — нерабочие, в них обычно записывают нули.

Рассмотрим состав регистров, их немного и они крайне простые.

Регистр INTERN — отвечает за включение прерывания от соответствующего канала (Ещё раз напомню — каналы соответствуют битам портов и имеют нумерацию с 0-го бита по 7-ой. И другие регистры имеют точно такую же конфигурацию.) Если вам нужно включит канал номер два, отвечающий за прерывание от 2-го бита какого-либо порта, запишите в этот регистр значение 0x04. (Не ступите! Не 0x02, а 0x04, поскольку 0x04 — это есть 0b00000100 в двоичном представлении.)

Регистр RTENR — отвечает за возникновение прерывания, если на выводе порта был обнаружен перепад с 0 на 1 (В разных коллективах это называют по разному — нарастающий фронт сигнала, передний фронт, …)

Регистр FTENR — отвечает за возникновение прерывания, если на выводе порта был обнаружен перепад с 1 на 0 (Опять же, в разных коллективах это называют — спадающий фронт сигнала, задний фронт, …)

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

Когда возникает прерывание в регистре INTFR в (соответствующем каналу) бите устанавливается флаг (бит переходит в единичное состояние), и в системе возникает прерывание. Этот флаг не снимается автоматически. В обработчике прерывания нужно сначала определить, от какого канала пришло прерывание — может это сразу несколько каналов сработало, а затем в ручную снять соответствующие флажки записью единицы (не нуля!) в регистр INTFR. Ну и, разумеется, нужно выполнить какие-то полезные действия — зачем-то ведь вам нужно было это прерывание.

Иногда бывает нужно выполнить какое-либо прерывание в ручную (то есть — программно). Для такого случая предназначен регистр SWIEVR. Запись в его какой-либо бит логической 1 приведёт к возникновению прерывания по соответствующему каналу. Это точно такое же прерывание, как от изменения в порту, только сэмулированно программным способом. Не забывайте, что и в этом случае тоже нужно точно так же снимать флаг прерывания.

Вот пример обработчика внешнего прерывания.

__attribute__((interrupt("WCH-Interrupt-fast")))
void EXTI7_0_IRQHandler(void)
{
if (((EXTI->INTFR & M2IN) != 0) && ((EXTI->INTENR & M2IN ) != 0))
{
EXTI->INTFR = M2IN; // Очищаю флаг прерывания

if ((GPIOD->INDR & M2IN) == M2IN)
led3_off();
else
led3_on();

}
}

ююю

Ну, всё!!! Задрало!

Писать и верстать статю я дальше уже не могу. WordPress считает, что он лучше меня знает, что мне надо. Ну, просто ещё одна Винда! Вместо работы у меня получается какая-то бестолковая борьба с этим wordpress-ом. Нафиг это нужно!

Статью полностью я разместил тут : https://aftershock.news/?q=node/1271561

Переходите по ссылке.

Оставьте комментарий