17. Шина I²C
Два провода, до сотни устройств, любые расстояния в пределах платы — и заслуженная репутация самой капризной периферии. Здесь больше всего случаев, когда всё сделано «по документации», а шина стоит колом.
Как это называется в документации
Оригинал Перевод master / slave ведущий / ведомый start / repeated start condition условие старта / повторного старта acknowledge ( ACK) / not acknowledge (NACK)подтверждение / отказ clock stretching растягивание такта ведомым arbitration lost потеря арбитража bus busy шина занята open-drain открытый сток rise time ( TRISE)время нарастания фронта address matched ( ADDR)адрес совпал EEPROM электрически стираемая постоянная память page write запись страницей write cycle time ( tWR)время цикла записи acknowledge polling опрос готовности по подтверждению SMBus, packet error checking (PEC) шина управления системой, контрольная сумма посылки
17.1 Как она устроена
Два провода: SCL — такт, SDA — данные. Оба выхода у всех устройств сделаны с открытым стоком: устройство умеет только прижать линию к земле, а поднимает её внешний резистор.
Отсюда сразу три следствия, определяющих всё остальное:
Подтягивающие резисторы обязательны. Без них линии никогда не поднимутся в единицу, и шина просто не заработает. Типовое значение — 4,7 кОм для 100 кГц, 2,2 кОм для 400 кГц. На готовых модулях датчиков они обычно уже стоят, но если на шине несколько модулей, их резисторы окажутся включены параллельно — суммарное сопротивление упадёт, и линию станет трудно прижимать.
Любое устройство может «придержать» такт. Медленный датчик прижимает SCL и заставляет ведущего ждать. Это штатный механизм, а не сбой.
Одно застрявшее устройство блокирует всех. Если ведомый сброшен посреди передачи и остался держать SDA, шина мертва для всех участников. Лечится приёмом из 17.6.
17.2 Адресация и транзакция
Адрес семибитный — то есть до 128 адресов, часть из которых зарезервирована. В регистр он кладётся сдвинутым влево на один бит, а младший бит указывает направление:
| Действие | Байт в линии |
|---|---|
запись в устройство 0x68 |
0xD0 |
чтение из устройства 0x68 |
0xD1 |
⚠️ Половина проблем «датчик не отвечает» — это путаница между семибитным адресом и уже сдвинутым восьмибитным. В документации на датчики встречаются оба варианта, и
0x68против0xD0описывают одно и то же устройство.
Вкладка «Адрес I²C» в калькуляторах приложения переводит адрес в байты линии в обе стороны и раскладывает десятибитный на два байта.
Десятибитный адрес. Семи бит хватает не всем, и в стандарте есть второй
вид адреса — десятибитный, то есть 1024 адреса. Отдельной линии под него нет:
адрес разложен на два байта, а признаком служит зарезервированная комбинация
старших бит 11110.
| Шаг | Байт в линии | Что в нём |
|---|---|---|
| старт | 0xF2 |
11110 + два старших бита адреса (01) + бит записи |
| второй байт | 0xA5 |
восемь младших бит адреса |
| повторный старт | 0xF3 |
те же старшие биты, но бит чтения |
В примере адрес 0x1A5. Прямого «чтения по десятибитному адресу» не бывает:
устройство обязано сначала услышать оба байта в режиме записи и запомнить, что
обращаются к нему, и только потом повторный старт с тем же заголовком
поворачивает передачу. Поэтому чтение стоит на 18 бит-тактов дороже
семибитного — на 400 кГц это лишние 45 мкс на каждую посылку.
Под заголовок ушли четыре семибитных адреса 0x78…0x7B — использовать их как
обычные нельзя ни одному устройству на той же шине.
В блоке это один бит. У I²C старого образца (F1, F4) бит ADDMODE в I2C_OAR1
делает десятибитным собственный адрес ведомого. Ведущий посылает десятибитный
адрес программно: заголовок в DR, флаг ADD10 в SR1, затем второй байт
и флаг ADDR. У блока нового
образца (F0, G0 и дальше) ведущему отведены два бита в CR2: ADD10 — адрес
десятибитный, и HEAD10R — передавать перед чтением только заголовок, без
второго байта, если устройство уже выбрано предыдущей посылкой.
⚠️ Десятибитных датчиков почти не бывает: массовая мелочь живёт в семи битах. Встретив
0xF2на экране анализатора, не ищите устройство с адресом0x79— это заголовок, а настоящий адрес лежит в следующем байте.
Типичное чтение регистра датчика состоит из двух транзакций подряд:
- старт → адрес с битом записи → номер регистра;
- повторный старт → адрес с битом чтения → приём данных → стоп.
Повторный старт вместо «стоп плюс старт» важен: он не отпускает шину, и другой ведущий не может вклиниться между запросом и ответом.
Так чтение регистра 0x75 у устройства 0x68 выглядит на экране анализатора; метки над SDA
показывают, кто передаёт каждый байт:
17.3 Настройка
void i2c1_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
/* PB6 (SCL) и PB7 (SDA): альтернативная функция, ОТКРЫТЫЙ СТОК. */
GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6 |
GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_CNF6; /* 11 -> AF open-drain */
GPIOB->CRL |= GPIO_CRL_MODE7 | GPIO_CRL_CNF7;
I2C1->CR1 &= ~I2C_CR1_PE; /* настраивать только выключенным */
I2C1->CR2 = APB1_MHZ; /* частота шины, НЕ скорость I2C */
I2C1->CCR = APB1_HZ / (2u * 100000u); /* делитель: 180 для 100 кГц */
I2C1->TRISE = APB1_MHZ + 1u; /* максимальное время фронта */
I2C1->CR1 |= I2C_CR1_PE;
}
⚠️ Выход обязан быть с открытым стоком. Настроите
push-pull— и микроконтроллер начнёт активно поднимать линию, борясь с датчиком, который её прижимает. Иногда это даже «работает» до первого конфликта, после чего выгорают выходные каскады.
Три числа, которые путают:
| Регистр | Что означает |
|---|---|
CR2.FREQ |
частота шины APB1 в мегагерцах (не скорость I²C) |
CCR |
делитель, задающий скорость шины |
TRISE |
максимально допустимое время нарастания фронта в тактах |
Расчёт делителя:
стандартный режим (100 кГц): CCR = Fpclk / (2 × Fscl) → 180 при 36 МГц
быстрый режим (400 кГц): CCR = I2C_CCR_FS | Fpclk / (3 × Fscl) → 30 при 36 МГц
В быстром режиме к делителю обязательно добавляют бит F/S (I2C_CCR_FS,
бит 15): при DUTY = 0 (бит 14) низкий уровень вдвое длиннее высокого —
отсюда тройка в формуле. Без F/S то же число 30 даёт стандартный режим с
равными полупериодами: 36 МГц / (2 × 30) = 600 кГц — вне любого стандарта.
TRISE считается из предельного времени фронта: 1000 нс для стандартного
режима даёт FREQ + 1, а 300 нс для быстрого — примерно втрое меньше.
Слишком большое значение сделает шину медленнее заявленного, слишком
малое — приведёт к сбоям на длинных линиях.
Подтяжка: между двумя границами
Резистор нельзя взять «любой»: он зажат снизу током, который выход способен утянуть, а сверху — ёмкостью линии, которую он должен зарядить за отведённое время фронта.
Снизу. Пока какое-то устройство держит линию в нуле, через резистор
течёт ток (VDD − VOL) / Rp, и он не должен превышать того, что тянет
самый слабый выход на шине. У вывода STM32F411 по даташиту VOL ≤ 0,4 В
при токе 8 мА, но датчик на той же шине может быть слабее — обычно
берут запас. Любое устройство стандартного и быстрого режима обязано утянуть
3 мА при 0,4 В, поэтому Rp ≥ (VDD − 0,4 В) / 3 мА: 0,97 кОм при 3,3 В
и 1,53 кОм при 5 В. Отсюда привычное «не ниже 1 кОм» на 3,3 В (ток 2,9 мА).
Сверху. Фронт формирует только резистор, разряжает же линию активно
выход; время нарастания между уровнями 30 и 70 % — t_r = Rp · Cb · ln(7/3)
≈ 0,85 · Rp · Cb. Даташит F411 задаёт предел: ёмкость линии до 400 пФ,
фронт не длиннее 1000 нс в стандартном режиме и 300 нс в быстром. Отсюда:
| Режим | Предел t_r |
Rp при 400 пФ, не больше |
|---|---|---|
| 100 кГц | 1000 нс | 2,95 кОм |
| 400 кГц | 300 нс | 885 Ом |
Обычные 4,7 кОм на длинной линии в 400 пФ дают фронт 1,6 мкс — на такой шине не укладывается ни быстрый режим, ни стандартный (предел 1000 нс), и это не ошибка настройки, а физика. Короткая шина на плате — это десятки пикофарад, и там 4,7 кОм проходят с запасом. Чем ниже сопротивление, тем круче фронты и лучше устойчивость к помехам, но больше ток при нуле; выбирают наименьшее, что пропускает нижняя граница.
17.4 🔧 Чтение регистра датчика
uint8_t i2c1_read_reg(uint8_t addr7, uint8_t reg, uint8_t *value)
{
/* 1. Старт. */
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)) { }
/* 2. Адрес в режиме записи. */
I2C1->DR = (uint8_t)(addr7 << 1);
while (!(I2C1->SR1 & I2C_SR1_ADDR)) { }
(void)I2C1->SR1; /* сброс ADDR: сначала SR1... */
(void)I2C1->SR2; /* ...затем SR2 */
/* 3. Номер регистра. */
while (!(I2C1->SR1 & I2C_SR1_TXE)) { }
I2C1->DR = reg;
while (!(I2C1->SR1 & I2C_SR1_BTF)) { }
/* 4. Повторный старт, адрес в режиме чтения. */
I2C1->CR1 |= I2C_CR1_START;
while (!(I2C1->SR1 & I2C_SR1_SB)) { }
I2C1->DR = (uint8_t)((addr7 << 1) | 1u);
while (!(I2C1->SR1 & I2C_SR1_ADDR)) { }
/* Единственный байт: снять подтверждение ДО сброса ADDR. */
I2C1->CR1 &= ~I2C_CR1_ACK;
(void)I2C1->SR1;
(void)I2C1->SR2;
I2C1->CR1 |= I2C_CR1_STOP;
while (!(I2C1->SR1 & I2C_SR1_RXNE)) { }
*value = (uint8_t)I2C1->DR;
I2C1->CR1 |= I2C_CR1_ACK;
return 0u;
}
Здесь спрятаны две неочевидности, каждая из которых вешает шину.
⚠️ Флаг
ADDRсбрасывается чтением двух регистров подряд — сначалаSR1, потомSR2. Прочитали только один — флаг остаётся, и шина стоит. Обозначение такого поведения в документации разбиралось в разделе 39.⚠️ При чтении одного байта подтверждение снимают заранее — до сброса
ADDR, а не после приёма. Иначе устройство отправит второй байт, которого вы не ждёте, и шина рассинхронизируется.
В рабочем коде обязательны таймауты. Все циклы while (!(флаг)) выше
показаны без них ради читаемости, но в изделии каждый такой цикл — потенциальное
вечное зависание: достаточно отвалиться одному проводу. В проверочном файле
к этому разделу таймауты есть, и функция возвращает номер шага, на котором
всё встало, — это сильно ускоряет поиск неисправности.
17.5 ⚠️ Известные ошибки самого блока
Отдельный случай, когда виноват не ваш код. У I²C в F1 перечень ошибок
кристалла описывает залипание признака занятости шины: после сбоя
на линии флаг BUSY остаётся взведённым, и любая попытка начать передачу
игнорируется. В перечне для F405/F407 (ES0182) такого пункта нет — там
у I²C свои ошибки (раздел 39б), — но то же состояние бывает у любой серии,
если ведомый застрял посреди байта и держит SDA (17.6).
Симптом узнаваемый: после случайной помехи или горячего подключения датчика шина перестаёт работать до перезагрузки, причём перезагрузка помогает не всегда.
Это ровно тот случай, ради которого стоит читать errata до отладки, а не после третьего часа поисков (раздел 39).
17.6 🔧 Как оживить залипшую шину
Приём, который стоит иметь в любом изделии с I²C.
Если ведомое устройство сброшено посреди передачи байта, оно может остаться
удерживающим SDA — ждёт продолжения тактов, которых не будет. Вывести его
из этого состояния можно, выдав девять тактов SCL вручную, обычным
GPIO: устройство досчитает свой байт и отпустит линию. Такты подают, пока SDA
не поднимется, и завершают ручным STOP — иначе ведомый останется внутри
транзакции до следующего START.
int i2c1_bus_recover(void)
{
I2C1->CR1 &= ~I2C_CR1_PE; /* отпустить линии контроллером */
/* PB6 (SCL) и PB7 (SDA) — обычные выходы с открытым стоком, обе в единице. */
GPIOB->BSRR = GPIO_BSRR_BS6 | GPIO_BSRR_BS7;
GPIOB->CRL &= ~(GPIO_CRL_MODE6 | GPIO_CRL_CNF6 | GPIO_CRL_MODE7 | GPIO_CRL_CNF7);
GPIOB->CRL |= GPIO_CRL_MODE6 | GPIO_CRL_CNF6_0 | GPIO_CRL_MODE7 | GPIO_CRL_CNF7_0;
for (int i = 0; i < 9 && !(GPIOB->IDR & GPIO_IDR_IDR7); i++) { /* пока SDA в нуле */
GPIOB->BSRR = GPIO_BSRR_BR6; /* SCL вниз */
for (volatile int d = 0; d < 100; d++) { }
GPIOB->BSRR = GPIO_BSRR_BS6; /* SCL вверх */
for (volatile int d = 0; d < 100; d++) { }
}
int stuck = !(GPIOB->IDR & GPIO_IDR_IDR7); /* SDA так и не отпустилась */
/* Ручной STOP: SDA в ноль при низком SCL, SCL вверх, затем SDA вверх. */
GPIOB->BSRR = GPIO_BSRR_BR6;
GPIOB->BSRR = GPIO_BSRR_BR7;
for (volatile int d = 0; d < 100; d++) { }
GPIOB->BSRR = GPIO_BSRR_BS6;
for (volatile int d = 0; d < 100; d++) { }
GPIOB->BSRR = GPIO_BSRR_BS7;
for (volatile int d = 0; d < 100; d++) { }
I2C1->CR1 |= I2C_CR1_SWRST; /* программный сброс блока */
I2C1->CR1 &= ~I2C_CR1_SWRST;
i2c1_init();
return stuck ? -1 : 0;
}
Девять, а не восемь: восемь тактов на биты данных плюс один на подтверждение.
Если и за девять тактов SDA не отпустилась, дело не в рассинхронизации:
ведомый завис, и поможет только снятие с него питания — функция вернёт −1.
Вызывать это стоит при обнаружении зависшей шины — например, когда функция чтения вернула ошибку по таймауту.
17.7 Как искать неисправность
Порядок, экономящий часы:
- Осциллограф или логический анализатор. Без них отладка I²C — гадание. Видно сразу: поднимаются ли линии, есть ли подтверждение, какая реальная скорость.
- Сканирование шины. Программа перебирает все 127 адресов и смотрит, кто ответил подтверждением. Отвечает не тот адрес, что в документации, — вопрос со сдвигом решён. Не отвечает никто — проблема в питании, подтяжках или проводах.
- Снизить скорость до 100 кГц. Заработало — дело в подтяжках, длине линий или ёмкости.
- Проверить питание датчика. Модуль на 5 В, подключённый к 3,3 В, может «почти работать»: отвечать через раз.
17.8 🔧 Внешняя EEPROM AT24C
Микросхема EEPROM серии 24C — самое простое место для настроек и счётчиков, когда встроенной Flash (11.5) пользоваться неудобно. Её пишут побайтно, без стирания страниц, и она выдерживает миллион циклов записи. Устроены эти микросхемы одинаково, но у каждой свои ловушки: адрес, страницы и время записи.
Адрес. Семибитный адрес устройства — это 1010 и три бита. У 24C04,
24C08 и 24C16 младшие из этих трёх битов — старшие биты адреса
ячейки, остальные — выводы A2…A0. Сам адрес ячейки восьмибитный. У
24C08 (1 КБ) два бита уходят на ячейку, и вывод остаётся один — A2:
| Ячейка 24C08 | Адрес устройства | Адрес ячейки на шине |
|---|---|---|
| 0x005 | 0x50 | 0x05 |
| 0x2F0 | 0x52 | 0xF0 |
| 0x3FF | 0x53 | 0xFF |
Двухбайтный адрес ячейки появляется только у старших моделей, от 24C32.
⚠️ 16-битный адрес для 24C04…24C16 — ошибка. Увидев, что «адрес устройства и адрес ячейки пересекаются», в HAL выбирают
I2C_MEMADD_SIZE_16BIT. Микросхема примет первый байт как адрес ячейки, а второй — как данные. На модели 24C08 запись «AB» в ячейку 5 легла в ячейки 0–2 как05,A,B, а сама ячейка 5 не изменилась. Для этих микросхем адрес ячейки —I2C_MEMADD_SIZE_8BIT, а старшие биты уходят в адрес устройства.
Страница. За одну посылку пишется не больше страницы — у 24C04 и 24C08 это 16 байт. Внутри страницы адрес растёт только младшими битами, и, дойдя до конца страницы, заворачивается на её начало. Двадцать байт, отправленные одной посылкой с адреса 0x0C, на модели легли так: - первые четыре байта в ячейках 0x0C–0x0F затёрлись последними четырьмя; - байты с пятого по шестнадцатый заняли ячейки 0x00–0x0B; - ячейки 0x10–0x1F остались пустыми.
Ошибки при этом никто не сообщил.
Цикл записи. После STOP микросхема до 5 мс записывает страницу и
не отвечает на свой адрес. Чтение сразу после записи на модели
получило отказ. Ждать вслепую все 5 мс не нужно: достаточно раз в
100 мкс спрашивать микросхему пустой посылкой, пока она не ответит.
/* Семибитный адрес: 1010 и три бита. У 24C04…24C16 младшие из них —
* старшие биты адреса ячейки, остальные — выводы A2…A0. */
static uint8_t dev7(const struct eeprom *e, uint32_t cell)
{
uint32_t blocks = (e->addr_bytes == 1 && e->size > 256u) ? (e->size >> 8) - 1u : 0u; /* 0, 1, 3 или 7 */
return (uint8_t)(0x50u | (e->pins & ~blocks & 7u) | ((cell >> 8) & blocks));
}
/* Пока идёт цикл записи (до 5 мс), микросхема не отвечает на свой адрес.
* Спрашиваем каждые 100 мкс — это быстрее, чем ждать наихудшие 5 мс
* вслепую. Вернёт число попыток или −1, если не ответила за 10 мс. */
int eeprom_wait(const struct eeprom *e, uint32_t cell)
{
for (int tries = 1; tries <= 100; tries++) {
if (i2c_write(dev7(e, cell), NULL, 0) == 0)
return tries;
delay_us(100);
}
return -1;
}
/* Записать n байт с адреса cell. Внутри страницы адрес «заворачивается» на
* её начало, поэтому кусок никогда не переходит границу страницы. */
int eeprom_write(const struct eeprom *e, uint32_t cell, const uint8_t *data, size_t n)
{
uint8_t buf[2 + 64];
if (e->page > 64u)
return -1; /* буфер — на страницу до 64 байт */
while (n) {
size_t room = e->page - (cell % e->page); /* до конца страницы */
size_t k = n < room ? n : room, h = 0;
if (e->addr_bytes == 2)
buf[h++] = (uint8_t)(cell >> 8);
buf[h++] = (uint8_t)cell;
for (size_t i = 0; i < k; i++)
buf[h + i] = data[i];
if (i2c_write(dev7(e, cell), buf, h + k) != 0 || eeprom_wait(e, cell) < 0)
return -1;
cell += k;
data += k;
n -= k;
}
return 0;
}
i2c_write и i2c_read — обёртка над кодом из 17.4 или над
HAL_I2C_Master_Transmit и HAL_I2C_Master_Receive. Пустая посылка —
только адрес без данных — и есть опрос готовности. Чтение подряд
(eeprom_read) сначала записывает адрес ячейки без данных, затем читает.
Внутренний счётчик сам идёт дальше, через границы страниц и даже через
конец памяти на её начало.
Опыт на модели AT24C08. Модель повторяет поведение микросхемы: 1 КБ, страницы по 16 байт с переносом, цикл записи 5 мс с молчанием, байт на шине 100 кГц — 90 мкс. Драйвер разбил те же 20 байт с адреса 0x0C на куски по 4 и 16 байт, и всё легло на место за 12 220 мкс. Это два цикла записи по 5 мс и время на шине. Опрос готовности находил микросхему за 26–27 попыток, то есть около 5 мс.
Время и износ. Записать 1 КБ побайтно — 5,12 с одних циклов записи, страницами — 0,32 с, в 16 раз быстрее. Ресурс в миллион циклов кажется огромным, пока не посчитать. Счётчик, который пишется раз в секунду, изнашивает ячейку за 11,6 суток, раз в минуту — за 1,9 года. Такие счётчики пишут реже или «размазывают» по разным страницам: у многих микросхем внутренний цикл переписывает страницу целиком, даже если меняется один байт, и миллион циклов считается на страницу, а не на байт. Соседние ячейки одной страницы тогда изнашиваются вместе. Как считает ресурс конкретная микросхема, сказано в строке ресурса её документации.
17.9 SMBus и I²C
SMBus — шина управления системой: батареи, источники питания, датчики на материнских платах. Она построена на I²C, и одно устройство часто работает на обеих шинах. Отличия:
| I²C | SMBus | |
|---|---|---|
| частота | 100 кГц в стандартном режиме, 400 кГц в быстром и выше; нижнего предела нет | от 10 до 100 кГц в SMBus 2.0; в 3.0 — ещё 400 кГц и 1 МГц |
удержание SCL в нуле |
не ограничено | не дольше 35 мс, потом устройство обязано отпустить шину |
| пороги уровней | от питания: 0,3 и 0,7 его величины | фиксированные: 0,8 и 2,1 В в SMBus 2.0; в 3.0 — 0,8 и 1,35 В, под питание от 1,8 В |
| контрольная сумма | нет | PEC — CRC-8 по всем байтам посылки |
Уровни SMBus 2.0 совпадают только при питании от 2,67 до 3,0 В: 0,3 × 2,67 = 0,8 В, а 0,7 × 3,0 = 2,1 В. За этими пределами совместимость проверяют по паспорту конкретного устройства.
Тайм-аут в 35 мс — главное практическое отличие. Ведомый SMBus не
может держать шину вечно, а ведущий, заметив долгий ноль на SCL,
сбрасывает обмен. Отсюда и нижний предел частоты — 10 кГц, которого у I²C
нет: ведущий, который медленно дёргает SCL вручную, для I²C законен, а
SMBus нарушает.
Против залипшей шины из 17.6 тайм-аут сам не сработает: там ведомый держит
SDA, а SCL свободна. Его вызывают нарочно: ведущий прижимает SCL на
35 мс и дольше — и каждый ведомый SMBus обязан сбросить обмен и отпустить
SDA. У обычных устройств I²C такого правила нет, им по-прежнему нужны
девять тактов.
PEC считается по всем байтам посылки, включая адреса:
/* PEC — контрольная сумма SMBus: CRC-8 с полиномом x^8 + x^2 + x + 1 (0x07),
* начальное 0; считается по всем байтам транзакции, включая адреса */
uint8_t smbus_pec(const uint8_t *p, size_t n)
{
uint8_t crc = 0;
while (n--) {
crc ^= *p++;
for (int i = 0; i < 8; i++)
crc = (crc & 0x80) ? (uint8_t)((crc << 1) ^ 0x07) : (uint8_t)(crc << 1);
}
return crc;
}
Для строки «123456789» результат — F4, как у эталона. Блок I²C у F1 и
F4 умеет режим SMBus (бит SMBUS в CR1) и считает PEC аппаратно (бит
ENPEC, результат — в SR2).
⚠️ PEC нельзя посылать обычному устройству I²C. Оно не знает, что это контрольная сумма. После записи регистра адрес внутри устройства растёт, и PEC ляжет в следующий регистр как данные.
17.10 F0 и G0: I²C нового образца
У F1 и F4 блок I²C один и тот же — старый, с SR1/SR2, DR и делителем
CCR. У F0 и G0 стоит другой блок, и он общий для всех новых серий
(F3, F7, L4, G4, H7): регистры по тем же смещениям у обеих серий —
TIMINGR на 0x10, ISR на 0x18, ICR на 0x1C, RXDR на 0x24,
TXDR на 0x28. Код с F1 на нём не собирается: no member named 'SR1',
то же для DR и CCR.
Скорость — одно число. Вместо CR2.FREQ, CCR и TRISE — регистр
TIMINGR из пяти полей. Такт блока делится на PRESC + 1, и в этих шагах
задаётся длина низкого (SCLL + 1) и высокого (SCLH + 1) уровня SCL;
SDADEL и SCLDEL — задержки данных относительно фронта. Для 100 кГц
удобен шаг 250 нс: низкий уровень 20 шагов — 5,0 мкс, высокий 16 — 4,0 мкс
(минимумы стандарта — 4,7 и 4,0), остальное добирают фронты и фильтры:
| F0 | G0 | |
|---|---|---|
| такт I2C1 после сброса | HSI 8 МГц (RCC_CFGR3_I2C1SW = 0) |
PCLK (RCC_CCIPR_I2C1SEL = 0): сразу после сброса 16 МГц, в опыте после PLL (раздел 6.7) — PCLK 64 МГц |
PRESC для шага 250 нс |
1 | 15 при 64 МГц (3 при 16 МГц) |
TIMINGR для 100 кГц |
0x10420F13 |
0xF0420F13 |
Меняется только PRESC — остальные четыре поля одинаковы:
#define T_STEP_NS ((PRESC + 1u) * 1000000u / (I2C_HZ / 1000u))
_Static_assert(T_STEP_NS == 250u, "шаг 250 нс");
_Static_assert((SCLL + 1u) * T_STEP_NS == 5000u && (SCLH + 1u) * T_STEP_NS == 4000u, "5,0 и 4,0 мкс");
I2C1->CR1 &= ~I2C_CR1_PE;
I2C1->TIMINGR = TIMING; /* одно число вместо FREQ, CCR и TRISE */
I2C1->CR1 |= I2C_CR1_PE;
Выводы SCL/SDA — по-прежнему открытый сток (OTYPER), альтернативная
функция у F0 — AF1, у G0 — AF6 (GPIO_AF1_I2C1, GPIO_AF6_I2C1 в заголовках
HAL); тактирование блока у G0 — в APBENR1.
Транзакция описывается заранее. У старого блока обмен вели по шагам:
старт, адрес, сброс ADDR двумя чтениями, снятие ACK перед последним
байтом. Здесь всё это сообщают блоку одной записью в CR2: адрес SADD,
направление RD_WRN, число байт NBYTES, AUTOEND — выдать STOP после
последнего байта самому, и START. Чтение регистра датчика из 17.4 —
две такие записи:
/* 1. Адрес, один байт на запись, без STOP — дальше повторный старт. */
I2C1->CR2 = ((uint32_t)addr7 << 1) | (1u << I2C_CR2_NBYTES_Pos) | I2C_CR2_START;
while (!(I2C1->ISR & (I2C_ISR_TXIS | I2C_ISR_NACKF))) {
}
if (I2C1->ISR & I2C_ISR_NACKF) { /* никто не ответил на адрес */
I2C1->ICR = I2C_ICR_NACKCF;
return 1u;
}
I2C1->TXDR = reg;
while (!(I2C1->ISR & I2C_ISR_TC)) { /* байт ушёл, STOP не выдан */
}
/* 2. Повторный старт, один байт на чтение; STOP блок выдаст сам — AUTOEND. */
I2C1->CR2 = ((uint32_t)addr7 << 1) | I2C_CR2_RD_WRN | (1u << I2C_CR2_NBYTES_Pos)
| I2C_CR2_AUTOEND | I2C_CR2_START;
while (!(I2C1->ISR & I2C_ISR_RXNE)) {
}
*value = (uint8_t)I2C1->RXDR;
while (!(I2C1->ISR & I2C_ISR_STOPF)) {
}
I2C1->ICR = I2C_ICR_STOPCF;
Ловушек старого блока здесь нет: ADDR сбрасывать нечем и незачем,
последний байт блок сам не подтверждает, флаги сбрасываются записью
единицы в ICR. Зато есть свои две. Если на адрес никто не ответил,
ждать TXIS бесполезно — придёт NACKF, и его надо проверять в том же
цикле, иначе программа зависает. И STOPF после AUTOEND нужно сбросить:
пока он стоит, блок занят. Сам обмен у G0 — слово в слово как у F0;
файлы отличаются только тактом, PRESC и номером альтернативной функции.
17.11 I3C: те же два провода, другой протокол
В картах регистров новых камней (например, H5 — приложение A8) есть блок с
именем I3C, а в дереве тактирования — бит I3C1EN. Это не опечатка и не
разновидность I²C: это отдельная шина, придуманная как замена связке «I²C для
настройки плюс отдельный провод прерывания». Провода те же два — SCL и SDA,
разводка и разъёмы те же, старые датчики с них снимать не нужно.
Что поменялось против I²C:
| I²C | I3C | |
|---|---|---|
| выход на линии | открытый сток, ток тянут подтяжки | на скорости — двухтактный; открытый сток остаётся только для старта и совместимости |
частота SCL |
100 кГц, 400 кГц, реже 1 МГц | до 12,5 МГц в обычном режиме |
| девятый бит | подтверждение ACK от ведомого |
бит перехода T — та же длина посылки, но линию не нужно отпускать |
| адрес | зашит в устройстве, совпадения решает паяльник | ведущий раздаёт адреса при старте шины |
| «данные готовы» | отдельный провод в GPIO и прерывание по фронту | устройство подаёт голос в самой шине |
| новое устройство на ходу | не предусмотрено | просит адрес само (горячее подключение) |
| общие команды | у каждого датчика свои регистры | набор общих команд, одинаковых у всех устройств |
| растягивание такта | ведомый может держать SCL |
запрещено — ведущий считает такты сам |
Скорость. Структура посылки осталась прежней: старт, байт адреса с битом направления, дальше байты данных, у каждого девятый бит. Чтение шести байт из регистра датчика — это 84 бит-такта и на I²C, и на I3C. Разница только в длине такта: на 400 кГц посылка занимает 210 мкс, на 12,5 МГц — 6,72 мкс, то есть в 31 раз меньше. Никакой другой магии в «скорости I3C» нет.
Адреса раздаются на старте. Вместо зашитого адреса у каждого устройства есть 64-битная визитка: 48-битный заводской номер плюс два байта с описанием того, что это за устройство и что оно умеет. Ведущий объявляет по шине процедуру раздачи адресов, устройства выкладывают свои визитки одновременно — и, поскольку линия с открытым стоком, побеждает тот, чей номер меньше: чужая единица гасится чужим нулём, проигравший видит расхождение и замолкает до следующего круга. Так за один проход ведущий обходит все устройства и каждому выдаёт семибитный адрес.
Отсюда следствие, ломающее привычку: адрес устройства больше не константа.
Если адреса раздаются процедурой ENTDAA, после перезапуска шины он может
оказаться другим, и «зашить 0x68 в драйвер» нельзя — устройство ищут
по заводскому номеру или по описанию из визитки. Если у устройства есть
статический адрес, ведущий может назначить его же динамическим (SETDASA,
для всех сразу — SETAASA), и адрес останется предсказуемым. Но это решает
ведущий, а не устройство.
Прерывание внутри шины. Когда датчику есть что сказать, он не дёргает
отдельный провод, а в паузе притягивает SDA к нулю и дальше передаёт свой
адрес — по тому же правилу «меньший номер побеждает», если заговорили двое.
Ведущий получает адрес и, если устройство так умеет, один-два байта пояснения:
что именно случилось. Экономится ножка микроконтроллера и весь код вокруг
внешнего прерывания (раздел 7), а задержка ответа перестаёт зависеть от периода
опроса: вместо «опрашиваем сто раз в секунду, в среднем узнаём через 5 мс» —
«узнаём по концу текущей посылки», то есть за единицы микросекунд.
Общие команды. Часть работы, которая у I²C всегда своя у каждого датчика, здесь описана стандартом: разрешить или запретить устройству подавать голос и подключаться на ходу, назначить новый адрес, сбросить раздачу адресов, сообщить предельную длину чтения и записи. Команды одинаковы у всех — драйвер шины занимается ими сам, до того как начнётся разговор с конкретным датчиком.
Как это выглядит в блоке STM32. У H5 регистров немного, и по их именам видно всё перечисленное:
| Регистр | Зачем |
|---|---|
CFGR |
кто мы на шине: ведущий или ведомое устройство (CRINIT) |
DEVR0 |
свой адрес и признак того, что адрес уже выдан (DAVAL) |
DEVR1…DEVR4 |
адреса устройств, которым ведущий их раздал, — до четырёх |
EPIDR |
собственный заводской номер, тот самый, которым устройство представляется |
BCR, DCR |
два байта визитки: что за устройство и что умеет |
IBIDR |
байты пояснения, пришедшие вместе с голосом устройства |
EVR |
флаги событий, среди них — «устройство подало голос» (IBIF) |
TIMINGR0…TIMINGR2 |
длительности: такт, паузы, времена перехода на двухтактный выход |
Старые I²C-устройства на той же шине живут: ведущий начинает разговор с
зарезервированного адреса 0x7E, на который они не отзываются, а если старых
устройств на шине нет, этот заголовок отключают битом NOARBH в CFGR — ради
тех самых девяти бит-тактов.
⚠️ Три ловушки при переходе. Первая: подтяжки. Двухтактный выход и килоомные резисторы — это лишний ток и заваленные фронты; на шине I3C резистор ставят один, слабый, и только ради открыто-стоковых участков. Вторая: растягивания такта нет — медленный ведомый, который у I²C просто держал
SCL, здесь молча теряет данные. Третья: адрес динамический, см. выше.Как это называется в документации
Оригинал Перевод controller / target ведущий / ведомое устройство dynamic address assignment ( ENTDAA)раздача адресов при старте шины provisioned ID ( EPIDR)заводской номер устройства bus / device characteristics register ( BCR,DCR)байты визитки: свойства шины и вид устройства in-band interrupt ( IBI)прерывание внутри шины hot-join подключение на ходу common command code ( CCC)общая команда, одинаковая у всех устройств arbitration header ( 0x7E)заголовок, отсекающий старые I²C-устройства push-pull / open-drain двухтактный выход / открытый сток transition bit ( T)девятый бит посылки вместо ACK
17.12 Грабли
Нет подтяжек. Шина не работает вовсе.
Выводы настроены как push-pull. Конфликт с ведомым.
Перепутан формат адреса. 0x68 против 0xD0.
ADDR сброшен не полностью. Прочитан только SR1.
Нет таймаутов. Отвалившийся провод вешает программу навсегда.
Слишком много устройств с собственными подтяжками. Параллельные резисторы дают слишком низкое суммарное сопротивление.
400 кГц не заводится на длинном шлейфе. При 400 пФ подтяжка обязана быть не выше 885 Ом, а стоят привычные 4,7 кОм — фронт 1,6 мкс вместо 300 нс. Переход на 100 кГц не спасает: и там предел 1000 нс, а 4,7 кОм дают 1,6 мкс. Либо ниже резистор (для 400 кГц не больше 885 Ом, для 100 кГц — не больше 2,95 кОм), либо короче провода.
Длинные провода. Ёмкость линии растягивает фронты, TRISE перестаёт
соответствовать действительности. Полметра на 400 кГц — уже много.
Общая земля забыта. Датчик на отдельной плате должен иметь общую землю с микроконтроллером, иначе уровни бессмысленны.
EEPROM теряет часть записанного. Запись перешла границу страницы, и адрес завернулся на начало страницы.
Чтение сразу после записи в EEPROM получает отказ. Идёт цикл записи до 5 мс. Нужно опрашивать готовность.
24C08 пишет не туда. Включён 16-битный адрес ячейки, и второй байт адреса стал данными.
Счётчик в EEPROM «умер» через две недели. Его писали раз в секунду, а ресурс — миллион циклов.
PEC испортил регистр датчика. Контрольную сумму SMBus послали обычному устройству I²C.
17.13 Итоги
- Оба вывода — с открытым стоком, подтягивающие резисторы обязательны: 4,7 кОм для 100 кГц, 2,2 кОм для 400 кГц.
CR2.FREQ— частота шины APB1, а не скорость I²C; скорость задаётCCR.- Адрес семибитный и кладётся сдвинутым влево; младший бит — направление.
- Флаг
ADDRсбрасывается чтениемSR1, затемSR2— иначе шина стоит. - При чтении одного байта подтверждение снимают до сброса
ADDR. - Все ожидания флагов в рабочем коде — только с таймаутами.
- У блока есть задокументированные дефекты, включая залипание признака занятости: читайте errata заранее.
- Залипшую шину оживляют девятью тактами
SCLвручную и программным сбросом блока. - EEPROM 24C пишут по страницам и после каждой опрашивают готовность: цикл записи до 5 мс. У 24C04…24C16 старшие биты адреса ячейки уходят в адрес устройства, а сам адрес ячейки восьмибитный. Ресурс — миллион циклов.
- SMBus 2.0 — это I²C с ограничениями: от 10 до 100 кГц,
SCLв нуле не дольше 35 мс, фиксированные уровни 0,8 и 2,1 В, контрольная сумма PEC — CRC-8; SMBus 3.0 добавил 400 кГц и 1 МГц и снизил верхний порог до 1,35 В.
Полные исходники
i2c_f0.c — I²C нового образца на STM32F072: чтение регистра датчика.
/* Раздел 17.10: I²C нового образца на STM32F072 — I2C1 на PB6/PB7 (AF1), такт HSI 8 МГц,
* 100 кГц через TIMINGR; чтение регистра датчика. */
#include <stddef.h>
#include "stm32f0xx.h"
_Static_assert(offsetof(I2C_TypeDef, TIMINGR) == 0x10u, "TIMINGR вместо CR2.FREQ, CCR и TRISE");
_Static_assert(offsetof(I2C_TypeDef, ISR) == 0x18u && offsetof(I2C_TypeDef, ICR) == 0x1Cu, "ISR/ICR вместо SR1/SR2");
_Static_assert(offsetof(I2C_TypeDef, RXDR) == 0x24u && offsetof(I2C_TypeDef, TXDR) == 0x28u, "два регистра данных");
/* Такт I2C1 у F0 после сброса — HSI 8 МГц (RCC_CFGR3_I2C1SW = 0).
* PRESC = 1: шаг 2 / 8 МГц = 250 нс; SCLL = 19 -> низкий уровень 20 шагов = 5,0 мкс,
* SCLH = 15 -> высокий 16 шагов = 4,0 мкс; SDADEL 2, SCLDEL 4 — задержки данных. */
#define I2C_HZ 8000000u
#define PRESC 1u
#define SCLL 19u
#define SCLH 15u
#define SDADEL 2u
#define SCLDEL 4u
#define T_STEP_NS ((PRESC + 1u) * 1000000u / (I2C_HZ / 1000u))
_Static_assert(T_STEP_NS == 250u, "шаг 250 нс");
_Static_assert((SCLL + 1u) * T_STEP_NS == 5000u && (SCLH + 1u) * T_STEP_NS == 4000u, "5,0 и 4,0 мкс");
#define TIMING ((PRESC << I2C_TIMINGR_PRESC_Pos) | (SCLDEL << I2C_TIMINGR_SCLDEL_Pos) \
| (SDADEL << I2C_TIMINGR_SDADEL_Pos) | (SCLH << I2C_TIMINGR_SCLH_Pos) | (SCLL << I2C_TIMINGR_SCLL_Pos))
_Static_assert(TIMING == 0x10420F13u, "TIMINGR для 100 кГц от 8 МГц");
void i2c1_init_f0(void)
{
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
GPIOB->OTYPER |= (1u << 6) | (1u << 7); /* открытый сток */
GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(0xFu << 24) & ~(0xFu << 28)) | (1u << 24) | (1u << 28); /* AF1 */
GPIOB->MODER = (GPIOB->MODER & ~(3u << 12) & ~(3u << 14)) | (2u << 12) | (2u << 14);
I2C1->CR1 &= ~I2C_CR1_PE;
I2C1->TIMINGR = TIMING; /* одно число вместо FREQ, CCR и TRISE */
I2C1->CR1 |= I2C_CR1_PE;
}
uint8_t i2c1_read_reg_f0(uint8_t addr7, uint8_t reg, uint8_t *value)
{
/* 1. Адрес, один байт на запись, без STOP — дальше повторный старт. */
I2C1->CR2 = ((uint32_t)addr7 << 1) | (1u << I2C_CR2_NBYTES_Pos) | I2C_CR2_START;
while (!(I2C1->ISR & (I2C_ISR_TXIS | I2C_ISR_NACKF))) {
}
if (I2C1->ISR & I2C_ISR_NACKF) { /* никто не ответил на адрес */
I2C1->ICR = I2C_ICR_NACKCF;
return 1u;
}
I2C1->TXDR = reg;
while (!(I2C1->ISR & I2C_ISR_TC)) { /* байт ушёл, STOP не выдан */
}
/* 2. Повторный старт, один байт на чтение; STOP блок выдаст сам — AUTOEND. */
I2C1->CR2 = ((uint32_t)addr7 << 1) | I2C_CR2_RD_WRN | (1u << I2C_CR2_NBYTES_Pos)
| I2C_CR2_AUTOEND | I2C_CR2_START;
while (!(I2C1->ISR & I2C_ISR_RXNE)) {
}
*value = (uint8_t)I2C1->RXDR;
while (!(I2C1->ISR & I2C_ISR_STOPF)) {
}
I2C1->ICR = I2C_ICR_STOPCF;
return 0u;
}
i2c_g0.c — тот же I²C на STM32G071.
/* Раздел 17.10: тот же I²C на STM32G071 — I2C1 на PB6/PB7 (AF6), такт PCLK 64 МГц. */
#include <stddef.h>
#include "stm32g0xx.h"
_Static_assert(offsetof(I2C_TypeDef, TIMINGR) == 0x10u && offsetof(I2C_TypeDef, TXDR) == 0x28u,
"блок тот же, что у F0");
/* Такт I2C1 у G0 после сброса — PCLK (RCC_CCIPR_I2C1SEL = 0), 64 МГц.
* Тот же шаг 250 нс: PRESC = 15 -> 16 / 64 МГц; остальные поля — как у F0. */
#define I2C_HZ 64000000u
#define PRESC 15u
#define SCLL 19u
#define SCLH 15u
#define SDADEL 2u
#define SCLDEL 4u
#define T_STEP_NS ((PRESC + 1u) * 1000000u / (I2C_HZ / 1000u))
_Static_assert(T_STEP_NS == 250u, "шаг 250 нс");
#define TIMING ((PRESC << I2C_TIMINGR_PRESC_Pos) | (SCLDEL << I2C_TIMINGR_SCLDEL_Pos) \
| (SDADEL << I2C_TIMINGR_SDADEL_Pos) | (SCLH << I2C_TIMINGR_SCLH_Pos) | (SCLL << I2C_TIMINGR_SCLL_Pos))
_Static_assert(TIMING == 0xF0420F13u, "TIMINGR для 100 кГц от 64 МГц");
void i2c1_init_g0(void)
{
RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
RCC->APBENR1 |= RCC_APBENR1_I2C1EN; /* у G0 — APBENR1 */
GPIOB->OTYPER |= (1u << 6) | (1u << 7);
GPIOB->AFR[0] = (GPIOB->AFR[0] & ~(0xFu << 24) & ~(0xFu << 28)) | (6u << 24) | (6u << 28); /* AF6 */
GPIOB->MODER = (GPIOB->MODER & ~(3u << 12) & ~(3u << 14)) | (2u << 12) | (2u << 14);
I2C1->CR1 &= ~I2C_CR1_PE;
I2C1->TIMINGR = TIMING;
I2C1->CR1 |= I2C_CR1_PE;
}
/* Обмен — слово в слово как у F0: тот же CR2, те же флаги. */
uint8_t i2c1_read_reg_g0(uint8_t addr7, uint8_t reg, uint8_t *value)
{
I2C1->CR2 = ((uint32_t)addr7 << 1) | (1u << I2C_CR2_NBYTES_Pos) | I2C_CR2_START;
while (!(I2C1->ISR & (I2C_ISR_TXIS | I2C_ISR_NACKF))) {
}
if (I2C1->ISR & I2C_ISR_NACKF) {
I2C1->ICR = I2C_ICR_NACKCF;
return 1u;
}
I2C1->TXDR = reg;
while (!(I2C1->ISR & I2C_ISR_TC)) {
}
I2C1->CR2 = ((uint32_t)addr7 << 1) | I2C_CR2_RD_WRN | (1u << I2C_CR2_NBYTES_Pos)
| I2C_CR2_AUTOEND | I2C_CR2_START;
while (!(I2C1->ISR & I2C_ISR_RXNE)) {
}
*value = (uint8_t)I2C1->RXDR;
while (!(I2C1->ISR & I2C_ISR_STOPF)) {
}
I2C1->ICR = I2C_ICR_STOPCF;
return 0u;
}
Дальше: раздел 17а «Микроконтроллер как ведомое устройство: I²C и SPI».