Периферия
Прежде чем перейти к следующей части, быстро посмотрим, что такое периферия.
Во встраиваемых системах периферия — это аппаратные компоненты, которые расширяют возможности микроконтроллера (MCU). Они позволяют микроконтроллеру взаимодействовать с внешним миром: обрабатывать входы и выходы, обмениваться данными, работать со временем и многое другое.
Пока ЦП отвечает за выполнение логики программы, периферия берёт на себя основную работу по взаимодействию с аппаратурой, часто разгружая ЦП. Это позволяет ЦП сосредоточиться на важных задачах, а периферийные блоки самостоятельно или почти без контроля выполняют специализированные функции.
Разгрузка
Разгрузка (offloading) — это практика, при которой определённые задачи передаются аппаратной периферии вместо того, чтобы выполнять их программно на ЦП. Это повышает производительность, снижает энергопотребление и позволяет выполнять операции параллельно. Например:
- Периферия UART может отправлять и принимать данные в фоновом режиме с помощью DMA (Direct Memory Access, прямой доступ к памяти), пока ЦП продолжает обрабатывать другую логику.
- Таймер можно настроить так, чтобы он генерировал точные задержки или периодические прерывания без участия ЦП.
- Контроллер ШИМ может управлять мотором непрерывно, без того, чтобы ЦП постоянно переключал выводы.
Разгрузка — ключевой приём проектирования во встраиваемых системах, позволяющий эффективно использовать ограниченную вычислительную мощность.
Распространённые типы периферии
Вот некоторые из самых распространённых видов периферии во встраиваемых системах:
| Периферия | Описание |
|---|---|
| GPIO (General Purpose Input/Output) | Цифровые выводы, которые можно настроить как входы или выходы для взаимодействия с внешним оборудованием, например кнопками, светодиодами и датчиками. |
| UART (Universal Asynchronous Receiver/Transmitter) | Интерфейс последовательной связи для отправки и приёма данных между устройствами, часто используется для отладки. |
| SPI (Serial Peripheral Interface) | Высокоскоростной синхронный протокол связи, который используется для подключения микроконтроллеров к периферии, например SD-картам, дисплеям и датчикам, по архитектуре «ведущий — ведомый». |
| I2C (Inter-Integrated Circuit) | Последовательный протокол связи по двум проводам, который используется для подключения низкоскоростной периферии, например датчиков и микросхем памяти, к микроконтроллеру. |
| ADC (Analog-to-Digital Converter) | Преобразует аналоговые сигналы от датчиков или других источников в цифровые значения, которые микроконтроллер может обработать. |
| PWM (Pulse Width Modulation) | Генерирует сигналы, которые управляют подачей мощности; часто используется для регулировки яркости светодиодов, управления скоростью моторов и работы сервоприводов. |
| Timer | Используется для генерации задержек, измерения интервалов времени, подсчёта событий или запуска действий в определённые моменты. |
| RTC (Real-Time Clock) | Отслеживает текущее время и дату даже при выключенной системе, обычно питается от батареи. |
Периферия в Rust
В embedded Rust к периферии обращаются по модели синглтона. Одна из основных целей Rust — безопасность, и она распространяется и на доступ к аппаратуре. Чтобы никакие две части программы не могли случайно управлять одной и той же периферией одновременно, Rust обеспечивает эксклюзивное владение через этот подход.
Паттерн «Синглтон»
Паттерн синглтон гарантирует, что в программе существует только один экземпляр каждой периферии. Это позволяет избежать распространённых ошибок, которые возникают, когда несколько фрагментов кода одновременно пытаются изменить один и тот же аппаратный ресурс.
В Embassy периферия тоже предоставляется по модели синглтона. Но мы не будем вызывать Peripherals::take() напрямую. Вместо этого используем функцию embassy_rp::init(Default::default()). Она берёт на себя базовую настройку системы и внутри вызывает Peripherals::take() за нас. Так мы получаем доступ ко всей периферии в безопасном и готовом к использованию виде.