Сравнение прерываний GPIO для трех популярных микроконтроллеров от TI, Microchip и STMicro
Сравним прерывания GPIO трех популярных микроконтроллеров: Texas Instruments CC2544, Microchip ATmega328P и STMicroelectronics STM32L151C6.
Данная статья является четвертой и последней частью серии про параллелизм и прерывания с прерываниями GPIO в качестве примера. Ранее мы обсудили основные понятия параллелизма и прерываний, прерываний GPIO и прерываний для периферийных устройств микроконтроллеров.
Здесь мы сравним прерывания трех микроконтроллеров:
- CC2544 от Texas Instruments, который используется в USB адаптере для беспроводной мыши Logitech M570. Технически это SoC (система на кристалле), но частью этой системы является микроконтроллер, на котором мы и сосредоточимся.
- ATmega328P от Microchip (компания Microchip приобрела компанию Atmel, которая раньше производила этот чип) использовался в Arduino Uno.
- STM32L151C6 от STMicroelectronics, который используется в Fitbit Charge.
Я выбрал вышеупомянутые микроконтроллеры, потому что я мог показать знакомые продукты, в которых они используются, и показать их реальную значимость.
Пожалуйста, помните, что все мои заявления о том, как микроконтроллеры работают в целом или как работает конкретный микроконтроллер, не являются неизменными фактами. Поэтому, когда я говорю, что конкретный микроконтроллер имеет 10 выводов GPIO, я имею в виду, что команда, разработавшая микроконтроллер, решила предоставить 10 выводов GPIO для текущей версии, на которую я ссылаюсь. В будущей версии может быть больше или меньше выводов GPIO.
Чтобы помочь закрепить некоторые идеи, которые я представил в этой серии, я покажу, как каждый из трех примеров микроконтроллеров реализует прерывания GPIO, и как активировать прерывание на определенном выводе для каждого из микроконтроллеров.
Texas Instruments CC2544
Первый микроконтроллер, на который мы посмотрим, - это SoC чип CC2544 от Texas Instruments.
Выводы GPIO с возможностью генерирования прерываний
CC2544 имеет 8 выводов GPIO, разделенных на два порта (PORT0 и PORT1) по четыре вывода на каждом. Все выводы имеют возможность генерирования прерываний, и каждый вывод имеет отдельный флаг прерывания.
Настройка прерываний
Все 8 выводов могут быть настроены независимо. Каждый вывод может быть настроен на обнаружение либо только нарастающего фронта (изменение с 0 на 1), либо только спадающего фронта (изменение с 1 на 0). Прерывание каждого вывода может быть отдельно включено или выключено. Флаг прерывания для вывода устанавливается всегда, когда происходит событие, для которого он настроен, независимо от того, включено ли прерывание или выключено.
Вектор прерывания, обработчик и приоритеты
Каждый порт имеет один вектор прерывания на порт (у PORT0 – это P0INT, а у PORT1 – это P1INT). Каждый вектор прерывания может быть отдельно включен или выключен. Каждый вектор также имеет флаг прерывания в контроллере прерываний, который устанавливается, когда прерывание разрешено. Из документации не ясно, устанавливаются ли флаги P0INT и P1INT, только если в GPIO разрешено прерывание по выводу. Я предполагаю, что это так. Однако флаги P0INT и P1INT в контроллере прерываний устанавливаются независимо от того, включены ли они внутри контроллера прерываний; CPU будет реагировать на прерывания только в том случае, если они включены.
Поскольку векторы прерываний есть только у портов, в обработчике прерывания вы должны проверить флаги выводов, чтобы выяснить, какой вывод из этого порта генерировал прерывание. В обработчике прерывания вы также должны очистить флаги выводов и флаг вектора прерывания. Флаги выводов должны быть очищены в первую очередь, до флага вектора прерывания.
Для CC2544 (в общем) каждый вектор прерывания не обязательно имеет отдельный приоритет, который может быть установлен напрямую. Каждый вектор прерывания является частью группы, содержащей не более двух других векторов прерывания. Приоритет назначается группе, и группе вы уже можете задать приоритет. Однако существует заранее установленный порядок обработки прерываний, если они имеют одинаковый приоритет. P0INT и P1INT принадлежат к разным приоритетным группам прерываний, поэтому, сосредоточившись только на этих двух прерываниях, вы можете контролировать порядок их обработки.
Обработчики прерываний в CC2544 могут быть прерваны прерываниями с более высоким приоритетом.
Microchip ATmega328P
Вторым в нашем списке идет 8-разрядный AVR микроконтроллер ATmega328P.
Выводы GPIO с возможностью генерирования прерываний
ATmega328P имеет 23 вывода GPIO, разделенных на три порта: PORTB (восемь выводов), PORTC (семь выводов) и PORTD (восемь выводов). Все выводы имеют возможность генерирования прерываний по изменению состояния на выводе. Однако отдельных флагов прерываний выводов нет, вместо этого флаг прерывания есть у каждого порта. Но два вывода на PORTD можно настроить как внешние прерывания, у них есть отдельные флаги прерывания.
Настройка прерываний
23 прерывания по изменению состояния на выводе предварительно настроены для обнаружения логического изменения значения на выводах (с 0 на 1 или с 1 на 0). Два внешних прерывания могут быть сконфигурированы для обнаружения только нарастающего фронта (изменение с 0 на 1), только спадающего фронта (изменение с 1 на 0) или постоянного значения 0. Прерывание по изменению состояния на выводе для каждого вывода может быть отдельно включено или выключено. Кроме того, может быть включено или выключено прерывание для каждого порта.
Флаг прерывания для порта или любого из выводов внешних прерываний устанавливается всегда, когда происходит событие, для которого он настроен, независимо от того, включено ли прерывание или выключено. Кроме того, флаг будет установлен независимо от того, настроен ли вывод как выход или как вход.
Вектор прерывания, обработчик и приоритеты
Каждый порт имеет один вектор прерывания (у PORTB – это PCINT0, у PORTC – это PCINT1, у PORTD – это PCINT2). Кроме того, каждый вывод внешнего прерывания имеет свой собственный отдельный вектор (вывод 2 в PORTD – INT0, а вывод 3 в PORTD – INT1). Каждый вектор прерывания может быть включен или отключен индивидуально, но это делается в периферийном устройстве GPIO, а не в контроллере прерываний (то есть контроллер прерываний не имеет возможности отдельного включения векторов прерываний, и все разрешения векторов прерываний выполняются в периферийных устройствах).
Поскольку векторы прерываний есть только у портов (для прерываний по изменению состояния на выводе), в обработчике прерывания необходимо выяснить, какой вывод и какое событие вызвало прерывание. Для этого потребуется прочитать маску прерываний для порта (чтобы узнать, прерывания каких выводов включены) и текущее значение вывода, чтобы выяснить, какое логическое изменение произошло. Однако для двух внешних прерываний вы уже будете знать, какой вывод вызвал прерывание, поскольку каждый вывод имеет отдельный вектор. Аппаратное обеспечение автоматически очищает флаги прерываний для внешних прерываний, хотя, ради безопасности, вы также можете очистить их в своем коде.
В ATmega328P приоритеты прерываний фиксированы и не могут быть изменены. После прерывания сброса прерывания выводов имеют самый высокий приоритет среди всех прерываний в следующем порядке: INT0, INT1, PCINT0, PCINT1, PCINT2.
Обработчики прерываний в ATmega328P могут быть прерваны прерываниями с более высоким приоритетом, но это не происходит автоматически. Когда запускается обработчик прерывания, CPU отключает все прерывания. Вы должны вручную включить прерывания в коде своего обработчика, чтобы разрешить вытеснение. Кроме того, существует регистр, называемый регистром состояния AVR, который является частью CPU, и значение которого CPU не сохраняет автоматически перед входом в прерывание и не восстанавливает после выхода из прерывания. Вы должны в своем обработчике прерывания сохранить и восстановить его значение. Причина, по которой вы должны это сделать, заключается в том, что CPU должен возобновить работу в том состоянии, в котором он находился до возникновения прерывания. Возможно, что действия, которые вы выполняете в своем обработчике, могут изменить этот регистр, поэтому, если вы не сохраните значение, которое он имел до начала ваших действий, и не восстановите его, CPU после вашего прерывания вернется в другое состояние, что может трудноуловимые ошибки в вашей системе.
STMicroelectronics STM32L151C6
Последний микроконтроллер в нашем списке – это 32-разрядный STM32L151C6.
Выводы GPIO с возможностью генерирования прерываний
STM32L151C6 имеет 37 выводов GPIO, но только 16 из них могут быть сконфигурированы для генерирования прерываний (так называемых внешних прерываний). Также есть некоторые ограничения на то, какие выводы могут быть сконфигурированы для одновременного генерирования прерываний.
37 выводов разделены на четыре порта:
- PA (16 выводов)
- PB (16 выводов)
- PC (3 вывода)
- PH (2 вывода)
В PA и PB выводы обозначены номерами от 0 до 15. PC имеет выводы 13–15, а PH имеет выводы 0 и 1. Все выводы с одинаковыми номерами (например, PA0, PB0 и PH0) совместно используют внешнюю линию прерывания (внешнее прерывание 0), поэтому только один из них может быть настроен на генерирование прерывания в любой момент времени.
В отличие от ATmege328P и CC2544, здесь есть отдельное внешнее устройство обработки прерываний, независимое от периферийного устройства GPIO, которое обрабатывает прерывания выводов. Это устройство также отличается от общего контроллера прерываний микроконтроллера. Каждое внешнее прерывание имеет свой собственный флаг.
Настройка прерываний
Каждая внешняя линия прерывания должна быть настроена на вывод GPIO, который генерирует прерывание на этой линии. Каждое внешнее прерывание может быть настроено на обнаружение изменения логического состояния (с 0 на 1 или с 1 на 0), только нарастающего фронта (изменение с 0 на 1) или только спадающего фронта (изменение с 1 на 0). Это связано с тем, что периферийное устройство разработано так, что вы можете независимо включать или выключать обнаружение нарастающего фронта и спадающего фронта. Каждое прерывание может быть отдельно включено и выключено. В отличие от CC2544 и ATmege328P, флаг прерывания для внешнего прерывания устанавливается, только если прерывание включено.
Вектор прерывания, обработчик и приоритеты
Внешние прерывания от 0 до 4 имеют свои собственные отдельные векторы прерываний. Внешние прерывания с 5 по 9 совместно используют один вектор прерываний, и прерывания с 10 по 15 также совместно используют еще один вектор прерываний. Это означает, что существует семь векторов прерываний, связанных с прерываниями GPIO. Каждый из этих векторов может быть отдельно включен или выключен. Каждый вектор также имеет свой собственный флаг в контроллере прерываний.
Обработчик прерывания должен сбросить флаг прерывания в модуле внешних прерываний (GPIO), а также в контроллере прерываний. Документация не проясняет порядок, в котором это должно быть сделано, но наиболее целесообразно следовать подходу CC2544, где сначала очищаются флаги GPIO, а затем флаги векторов прерываний.
Приоритеты в STML151C6 немного сложнее относительно того, как они настраиваются, и как они допускают вытеснение. Есть два способа настройки приоритетов. Самый простой способ – использовать уровни приоритета. Есть 16 различных уровней приоритета. Для определения возможности вытеснения используется только уровень приоритета, поэтому прерывание с более высоким уровнем приоритета может вытеснить прерывание, которое в данный момент обрабатывает процессор. Каждый вектор прерывания имеет уникальный номер прерывания. Если два прерывания с одинаковыми уровнями приоритета ожидают обработки, процессор выберет прерывание с меньшим номером прерывания. Однако прерывание с меньшим номером прерывания не может вытеснить другое прерывание с более высоким или таким же уровнем приоритета.
Второй подход к настройке прерываний заключается в использовании групповых приоритетов и подприоритетов. Количество различных групп и подприоритетов также настраивается. Независимо от конкретной конфигурации, групповой приоритет работает как уровень приоритета. Прерывания с более высоким приоритетом группы могут вытеснить прерывания с более низким приоритетом группы. Подприоритет и номер прерывания используются для определения того, какое прерывание запускается, если обработки ожидают два или более прерываний с одинаковым приоритетом группы. Сначала используется подприоритет. То прерывание, у которого более высокий подприоритет, обрабатывается перед тем прерыванием, у которого более низкий подприоритет. Если оба прерывания имеют один и тот же подприоритет, то сначала обрабатывается то, у которого номер прерывания меньше.
На этом мы завершаем серию о параллелизме и прерываниях GPIO. Если у вас есть какие-либо вопросы по поводу информации, представленной здесь, пожалуйста, сообщите нам об этом в комментариях ниже.