Top.Mail.Ru

Часть 20. I2C. Дополнение.

В статье "Часть 12. STM32 и C++. I2C в Cortex-M4" я описал, как работать с I2C на ядрах Cortex-M4. Продолжая работать с I2C на других чипах, я столкнулся с тем что данный способ общения с I2C корректен не для всех ядер. Описанный способ точно подходит для STM32F405xx и STM32F407xx, вполне возможно что подходит также и для STM32F415, STM32F417 и STM32F43x. Проверить это утверждение я не могу, так как нет необходимых МК. Что точно могу сказать, для серии STM32F411xx этот метод точно не походит, но к этому МК вернёмся чуть позже.

Сейчас рассмотрим STM32F030x4/x6/x8/xC и STM32F070x6/xB (про серию STM32F0x1/STM32F0x2/STM32F0x8 пока сказать ничего не могу, позже проверю и в комментариях отпишу). У него, да и у многих других МК, в регистре CR2 есть два интересных поля: NBYTES[7:0] - в который пишется количество байт/слов которое мы хотим передать и SADD[9:0] - в который пишется адрес устройства, к которому мы хотим обратиться. А так как не нужны пляски с бубном, как у F407, здесь код получается попроще. Я не буду приводить длиннющие куски кода, просто опишу алгоритм, а как это оформлено можно посмотреть в библиотеке.

Алгоритм чтения.

  1. Ждём флаг BUSY
  2. В регистре CR2:
    1. Сбрасываем:
      1. SADD
      2. NBYTES
      3. RELOAD
      4. AUTOEND
      5. RD_WRN
      6. START
      7. STOP
    2. Устанавливаем:
      1. SADD
      2. NBYTES
      3. AUTOEND или RELOAD
      4. READ
      5. START
  3. Ждём флаг RXNE
  4. В цикле из регистра RXDR считываем данные
  5. Ждём флаг STOP
  6. В регистре статуса ICR сбрасываем флаг STOPCF
  7. В регистре CR2 сбрасываем:
    1. SADD
    2. HEAD10R
    3. NBYTES
    4. RELOAD
    5. RD_WRN
  8. Выходим

Вроде всё просто, но есть нюансы.

Шаг 2 - я написал флаги и регистры по порядку, но не всё так просто. Есть МК, у которых эти команды можно выполнить пошагово, на F030CCx я столкнулся с тем, что необходимо считать регистр целиком, сбросить необходимые биты, установить необходимые биты и записать это всё обратно. Как только запишем получившуюся команду, I2C выплюнет на линию адрес с запросом на чтение и будет ждать ответа. Ещё один нюанс, на обычных I2C устройствах этот шаг не критичен, а при работе с микросхемами памяти - критичен. Если при работе с памятью мы не выполним это условие, то зависнем на третьем шаге.

Шаг 3 - интереса не представляет.

Шаг 4 - в шаге 2.2.3 указано два флага, а не один. Эти флаги влияют на количество принимаемых байт. Регистр NBYTES имеет длину 8 бит. Соответственно, мы можем передать только 255 байт/слов, а мы хотим принять 100500. Для приёма всей информации нам нужно разбить её на блоки по 255 байт. Мы записываем в NBYTES число 255, устанавливаем указатель на на