Встраиваемые системы
GPIO, UART, SPI, I2C
2016 год, проект SpaceX Falcon 9. Первый раз ракета садится обратно на платформу. За этим стоят сотни MCU: GPIO-пины управляют клапанами двигателей, UART гонит телеметрию на землю, SPI обновляет flash с параметрами ориентации, I2C читает 12 датчиков давления с двух проводов. Четыре протокола - один шедевр инженерии.
- **Метеостанция:** I2C-датчики температуры, давления, влажности на 2 проводах + SPI-дисплей для отображения + UART для отправки данных на ПК
- **Дрон:** SPI-гироскоп/акселерометр (6000 Гц выборка), I2C-барометр (высота), UART-GPS, GPIO-управление моторами через PWM
- **Промышленный контроллер:** RS-485 (UART) для связи на 1 км, SPI-Flash для логов, I2C-EEPROM для настроек
Philips, 1980: изобретение I2C
В 1980 году инженеры Philips Semiconductors столкнулись с проблемой: телевизионные чипсеты требовали десятки интерфейсных линий между микросхемами. Ответом стал I2C - Inter-Integrated Circuit. Два провода, адресация до 128 устройств. Патент истёк в 2006 году - и протокол стал бесплатным для всех. SPI появился чуть раньше в Motorola (1979). UART ещё старше - 1960-е, IBM. Все три протокола пережили несколько поколений техники и живут в каждом современном устройстве.
Предварительные знания
GPIO: цифровые пины
2003 год. Первый коммерческий Arduino-прото ещё не существует, но в Atmel уже понимают: MCU нужен выход во внешний мир. **GPIO** (General Purpose Input/Output) - самый примитивный способ. Каждый пин - либо **вход** (читаем 0 или 1 - кнопка нажата?), либо **выход** (устанавливаем 0 или 1 - включить LED). Ни протокола, ни пакетов - один бит, один провод.
**GPIO** - универсальные пины ввода/вывода. Режимы: **Input** (чтение: floating, pull-up, pull-down), **Output** (запись: push-pull, open-drain), **Alternate Function** (UART, SPI, I2C - пин управляется периферией), **Analog** (ADC/DAC). Состояние выхода: **0** = GND (0V), **1** = VCC (3.3V или 5V).
| Режим | Push-Pull | Open-Drain |
|---|---|---|
| Выход 1 | Подключает к VCC | Отключает (высокоимпедансный) |
| Выход 0 | Подключает к GND | Подключает к GND |
| Применение | LED, обычные выходы | I2C (SDA, SCL), шины с несколькими устройствами |
| Внешний pull-up | Не нужен | Обязателен |
**Скорость переключения** GPIO настраивается: Low (2 MHz), Medium (25 MHz), High (50 MHz), Very High (100 MHz). Высокая скорость = больше EMI и потребление тока. Для LED достаточно Low, для SPI-clock нужен High. Неправильная скорость - источник загадочных помех на осциллографе.
Кнопка подключена между пином PA0 и GND. Какой pull нужно настроить, чтобы без нажатия читать 1, а при нажатии - 0?
UART: последовательный порт
GPIO передаёт 1 бит на 1 провод. Для текста, чисел и команд нужен **протокол**. Самый простой - **UART** (Universal Asynchronous Receiver-Transmitter). Два провода: TX (передача) и RX (приём). Именно через UART отладочные printf() попадают в терминал на ПК. Каждый embedded-разработчик видел `/dev/ttyACM0` - это он.
**UART** - асинхронный последовательный протокол. Параметры: **Baud rate** (скорость, обычно 9600 или 115200 бод), **формат кадра** 8N1 = 8 бит данных + No parity + 1 stop бит. Нет тактового сигнала - передатчик и приёмник должны договориться о baud rate заранее. Линия в покое = 1 (idle), начало кадра = 0 (start bit).
| Параметр | Значение | Примечание |
|---|---|---|
| Проводов | 2 (TX + RX) + GND | Перекрёстное подключение: TX->RX, RX->TX |
| Скорость | 9600 - 3,000,000 бод | 115200 - стандарт для отладки |
| Дуплекс | Full-duplex | Одновременная передача и приём |
| Расстояние | До 15 м (RS-232) | С RS-485: до 1200 м |
| Устройства | Точка-точка (1:1) | Для 1:N нужен RS-485 |
**Главная ошибка новичков:** baud rate на передатчике и приёмнике ДОЛЖЕН совпадать. Если MCU настроен на 115200, а терминал на 9600 - в терминале будет мусор. UART асинхронный - нет тактового сигнала, который бы синхронизировал.
MCU отправляет данные по UART на 115200 бод, а ПК принимает на 9600 бод. Что увидит ПК?
SPI: быстрая синхронная шина
UART хорош для отладки, но дисплей на 240x320 пикселей - это 76800 байт на кадр. При 115200 бод - 5 секунд на один кадр. Катастрофа. Для быстрого обмена существует **SPI** (Serial Peripheral Interface) - синхронный протокол с отдельным тактовым сигналом. Скорости до **50+ MHz**. Один кадр дисплея - 12 миллисекунд.
**SPI** - синхронный, full-duplex протокол с 4 сигналами: **MOSI** (Master Out Slave In - данные от мастера), **MISO** (Master In Slave Out - данные от slave), **SCK/SCLK** (тактовый сигнал от мастера), **CS/SS** (Chip Select - выбор slave, active low). MCU = master, датчик/дисплей = slave.
| Параметр | SPI | UART |
|---|---|---|
| Синхронизация | Синхронный (SCK) | Асинхронный (baud rate) |
| Скорость | До 50+ MHz | До 3 Mbaud |
| Проводов | 4 (MOSI, MISO, SCK, CS) | 2 (TX, RX) |
| Дуплекс | Full-duplex | Full-duplex |
| Устройства | 1 master + N slaves (N линий CS) | Точка-точка |
| Применение | Flash, дисплеи, SD-карты | Отладка, GPS, Bluetooth |
**SPI Mode (CPOL/CPHA):** 4 комбинации определяют, по какому фронту SCK данные фиксируются. Mode 0 (CPOL=0, CPHA=0) - самый распространённый. Несовпадение Mode между master и slave = мусор. Всегда проверяйте datasheet устройства!
На SPI-шине подключены 3 slave-устройства. Сколько GPIO-пинов MCU нужно для CS?
I2C: мультиустройственная шина
Умные часы, 2013 год. Датчик пульса, акселерометр, барометр, гироскоп, магнитометр, EEPROM для настроек. SPI потребовал бы 6 линий CS + 3 общих = 9 дополнительных пинов только на периферию. **I2C** (Inter-Integrated Circuit) - два провода на всё: **SDA** и **SCL**. До 128 устройств. Уникальный 7-битный адрес на каждое.
**I2C** (произносится «ай-ту-си» или «ай-сквэрд-си») - синхронный, half-duplex протокол с адресацией. Два провода: **SDA** (Serial Data) и **SCL** (Serial Clock), оба с pull-up резисторами к VCC. Скорости: Standard (100 kHz), Fast (400 kHz), Fast Plus (1 MHz), High Speed (3.4 MHz). Master генерирует SCL, slave отвечает по адресу.
| Параметр | I2C | SPI | UART |
|---|---|---|---|
| Проводов | 2 (SDA, SCL) | 4 + N (CS) | 2 (TX, RX) |
| Скорость | 100 kHz - 3.4 MHz | 1 - 50+ MHz | 9600 - 3M бод |
| Дуплекс | Half-duplex | Full-duplex | Full-duplex |
| Адресация | 7-бит (до 128 устройств) | CS-линия на устройство | Нет (точка-точка) |
| Pull-up | Обязательны | Не нужны | Не нужны |
| Применение | Датчики, EEPROM, RTC | Flash, дисплей, SD | Отладка, GPS, BT |
**Когда что использовать?** I2C - для медленных датчиков (температура, давление, акселерометр), когда важна экономия пинов. SPI - для быстрых устройств (дисплей, Flash, SD-карта), когда скорость важнее числа проводов. UART - для связи с ПК, GPS-модулями, Bluetooth.
SPI быстрее, значит всегда лучше I2C. Нужно использовать SPI для всех задач
I2C использует 2 провода вместо 4+N, поддерживает до 128 устройств на одной шине и достаточно быстр для большинства датчиков (100-400 kHz). Для термометра, акселерометра, барометра I2C - оптимальный выбор
На реальной плате каждый провод - дорожка на PCB, место на разъёме и потенциальная точка отказа. 10 I2C-датчиков = 2 провода. 10 SPI-датчиков = 13 проводов + 10 GPIO пинов MCU под CS. Датчик температуры отдаёт данные раз в секунду - зачем ему 50 MHz SPI? I2C на 400 kHz более чем достаточно.
На I2C-шине подключены 5 датчиков. Сколько проводов (не считая GND и VCC) нужно от MCU?
Ключевые идеи
- **GPIO** - базовый ввод/вывод: push-pull/open-drain выходы, pull-up/pull-down входы, скорость до 100 MHz
- **UART** - асинхронный последовательный протокол (2 провода), до 3 Mbaud, отладка и связь точка-точка
- **SPI** - синхронный, full-duplex, до 50+ MHz, 4 провода + CS на каждый slave: Flash, дисплеи, SD-карты
- **I2C** - синхронный, 2 провода на 128 устройств, 100 kHz - 3.4 MHz, идеален для датчиков
Связанные темы
Интерфейсы - практическое применение знаний об архитектуре MCU:
- Архитектура микроконтроллеров — Memory-Mapped I/O - так MCU обращается к регистрам UART/SPI/I2C
- Таймеры и PWM — PWM через GPIO для управления моторами и яркостью LED
Вопросы для размышления
- Проектируется умные часы с датчиком пульса, акселерометром, дисплеем и Bluetooth-модулем. Какой интерфейс подходит для каждого компонента и почему?
- I2C использует open-drain с pull-up резисторами. Почему нельзя использовать push-pull для шины, к которой подключены несколько устройств?
- GPIO - как отдельный нерв (вкл/выкл), I2C - как адресная шина спинного мозга. Какая аналогия подходит для SPI и UART?
Связанные уроки
- emb-02 — Memory-Mapped I/O - основа обращения к регистрам UART/SPI/I2C
- emb-04 — PWM через GPIO для управления моторами и яркостью LED
- rob-03 — ROS 2 на роботах использует SPI/I2C для сенсоров и UART для GPS
- rts-01 — Real-time ограничения диктуют выбор протокола: SPI vs I2C
- par-01 — DMA-передача по SPI/UART - параллелизм на уровне железа
- emb-05 — ADC/DAC работают через те же GPIO Alternate Function пины
- net-01-intro