Embedded HandbookПриложения
Все разделы › III. Периферия
STM32F103, STM32F407 · уровень средний · 32 мин чтения
Открыть в интерактивном справочнике

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.

Шина I²C: устройства только прижимают SCL и SDA к земле, поднимают линии резисторы 4,7 кОм — датчик 0x68 и EEPROM 24C08 висят на шине параллельно


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 — это заголовок, а настоящий адрес лежит в следующем байте.

Типичное чтение регистра датчика состоит из двух транзакций подряд:

  1. старт → адрес с битом записи → номер регистра;
  2. повторный старт → адрес с битом чтения → приём данных → стоп.

Повторный старт вместо «стоп плюс старт» важен: он не отпускает шину, и другой ведущий не может вклиниться между запросом и ответом.

Так чтение регистра 0x75 у устройства 0x68 выглядит на экране анализатора; метки над SDA показывают, кто передаёт каждый байт:

Чтение регистра по I²C на экране логического анализатора: адрес с записью, номер регистра, повторный старт, адрес с чтением, байт ответа


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 кОм проходят с запасом. Чем ниже сопротивление, тем круче фронты и лучше устойчивость к помехам, но больше ток при нуле; выбирают наименьшее, что пропускает нижняя граница.

Фронт SDA при ёмкости линии 400 пФ: 885 Ом дают время нарастания от 30 до 70 % ровно 300 нс, 2,95 кОм — 1000 нс, а 4,7 кОм — 1,6 мкс, дальше обоих пределов


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 Как искать неисправность

Порядок, экономящий часы:

  1. Осциллограф или логический анализатор. Без них отладка I²C — гадание. Видно сразу: поднимаются ли линии, есть ли подтверждение, какая реальная скорость.
  2. Сканирование шины. Программа перебирает все 127 адресов и смотрит, кто ответил подтверждением. Отвечает не тот адрес, что в документации, — вопрос со сдвигом решён. Не отвечает никто — проблема в питании, подтяжках или проводах.
  3. Снизить скорость до 100 кГц. Заработало — дело в подтяжках, длине линий или ёмкости.
  4. Проверить питание датчика. Модуль на 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» нет.

Чтение шести байт из датчика: на I²C 400 кГц посылка занимает 210 мкс, на I3C 12,5 МГц те же 84 бит-такта проходят за 6,72 мкс

Адреса раздаются на старте. Вместо зашитого адреса у каждого устройства есть 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 Итоги

Полные исходники

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».

Открыть в интерактивном справочнике