M41T56 это микросхема Real Time Clock, являющаяся аналогом популярной DS1307. И хотя даже цоколевка микросхем совпадает, у них есть существенные отличия, о которых я постараюсь рассказать.

Краткое описание


Я не буду останавливаться на работе шины IIC, отмечу только что обе микросхемы имеет адрес 0xd0. Для работы с временем микросхемы содержат семь регистров счета и регистр управления. Регистры счета содержат числа в двоично-десятичном формате, однако некоторые биты имеют особое значение.

Регистры
xxx — значение бита не определено.
функция индекс биты возможные значения
7 6 5 4 3 2 1 0
секунды 0x00 ST десятки секунд единицы секунд 0 — 59
минуты 0x01 xxx десятки минут единицы минут 0 — 59
часы 0x02 SEB SB десятки часов единицы часов 0 — 23
день 0x03 xxx xxx xxx xxx xxx день недели 1 — 7
день месяца 0x04 xxx xxx десятки дня единицы дня 1 — (28|29|30|31)
месяц 0x05 xxx xxx xxx дес единицы месяца 1 — 12
год 0x06 десятки года единицы года 0 — 99
регистр управления 0x07 OUT FT S величина коррекции -

Биты
x — после включения состояние бита может быть любым.
бит после сброса описание
ST x При записи 1 в этот бит генератор останавливается
CEB x Когда бит CEB (Century Enable Bit) установлен, то при достижении нового века бит CB (Century Bit) поменяет значение на противоположное.
CB x
OUT 1 Когда биты OUT (OUTput level) и FT (Frequency Test) равны нулю, вывод FT/OUT прижимается к земле. При FT=1 на выводе FT/OUT 512 Гц и бит OUT не имеет значения.
FT 0
S x Знак калибровки хода RTC.

Различия начинаются в назначении битов 7, 6 и 5 регистра часов. В M41T56 биты 7 и 6 используются для индикации перехода в новое столетие, а биты 5 и 4 используются для счета десятков часов. Причем счет часов возможен только в режиме 24, режим AM/PM недоступен. В DS1307 бит 7 не используется, ноль в бите 6 указывает, что используется режим счета 24 и этом случае биты 5 и 4 содержат десятки часов. Если в бите 6 единица, то бит 5 становится флагом AM/PM, а бит 4 содержит десятки часов.

Существенные отличия есть в регистре управления, которой содержит слово коррекции хода.

Коррекция хода


M41T56 позволяет компенсировать погрешность кварцевого резонатора в диапазоне от -62 до +124 ppm, что дает отклонение не более чем ±5 секунд за месяц. За компенсацию отвечают шесть младших битов управляющего регистра. Биты 4-0 содержат целое число без знака величины коррекции, а бит 5 задает направление коррекции. Если бит 5 содержит ноль, то ход замедляется с шагом 2.034 ppm, в противном случае RTC ускоряется с шагом 4.068 ppm. Это неудобно, поэтому я набросал пару простых функций для преобразования из ppm в слово коррекции и обратно.

/* Маска для получения только значения калибровки без знака. */
#define MASK_CALIBR             ((1 << 4) | (1 << 3) | (1 << 2) | (1 << 1) | (1 << 0))
/* Маска для получения только значения калибровки без знака. */
#define MASK_CALIBR_SIGN        (1 << 5)

/**
 * Получение значения коррекции хода.
 * @param caliber Калибровочное слово из RTC.
 * @return Коррекция хода в ppm.
 */
int8_t caliber_to_ppm(uint8_t caliber)
{
        int8_t result = caliber & MASK_CALIBR;

        result = (uint8_t) result * 2;
        if ((caliber & MASK_CALIBR_SIGN) != 0) {
                result = -result;
        } else {
                result = (uint8_t) result * 2;
        }

        return result;
}

/**
 * Получение калибровочного слова.
 * @param ppm Коррекция хода в ppm.
 * @return Калибровочное слово для RTC.
 */
uint8_t ppm_to_caliber(int8_t ppm)
{
        uint8_t result;

        if (ppm < 0) {
                result = (uint8_t) (-ppm + 1) / 2;
                result |= MASK_CALIBR_SIGN;
        } else {
                result = (uint8_t) (ppm + 2) / 4;
        }

        return result;
}

Детектирование сбоев


Ни DS1307, но M41T56 не умеют детектировать сбои генерации, но гарантируют, что при включении питания некоторые биты будут в определенном состоянии. M41T56 при включении в управляющем регистре будет 10xxxxxx. Для отслеживания сбоев в программе можно придерживаться следующего алгоритма. Если при включении микроконтроллера регистр управления RTC содержит 10xxxxxx, значит был сбой питания и в регистр нужно записать значение, старшие биты которого не равны 10. Самое простое — записать слово коррекции с битами 7 и 6 равными нулю.

Литература


  • Справочный листок M41T56
  • Справочный листок DS1307

Комментарии (14)


  1. FDA847
    27.06.2019 00:03

    Получается, что отличие от DS'ки только в наличии возможности подстройки хода? Есть ещё классая микросхема DS3231. Там встроенный калиброванный генератор! Но стоит она почти на порядок дороже DS1307.


    1. u_235 Автор
      27.06.2019 00:32

      Подстройка хода — это самое существенное отличие, ради которого и стоит применять M41T56.
      А у DS3231еще и температурная компенсация есть.


      1. assad77
        27.06.2019 13:07

        сейчас ds3231 использую только эту микросхему. ds1307 вообще никакая. за день на полминуты может уходить. а с этой микросхемой как?


        1. moviq
          27.06.2019 19:44

          Я использовал 1302, наверное это такая же только с другим интерфейсом. И припаивал 2 кондюка к выводам для подключения кварца. Один из них подстроечный. В итоге получалось также где-то «отклонение не более чем ±5 секунд за месяц». Но скорее всего тут ещё влияет температура и один раз скорректировав подстроечником уход может смениться


        1. u_235 Автор
          28.06.2019 00:16

          RTC с внешним кварцем чувствительны к разводке дорожек и к подключению земли, в мануалах этому уделено особое внимание. Мне попадались кварцы с уходом в пару минут за месяц, но ошибка в минуту за сутки — это слишком много и либо компоненты негодные, либо ошибки разводки.


          1. assad77
            28.06.2019 17:42

            так я ардуино модулям пользовался и DIY конструктором, когда сравнивал и выбирал для своей самоделки таймеры.
            DS3231 таких проблем не имел и уже в готовом решении я использовал DS3231.


  1. AntonSazonov
    27.06.2019 06:19

    Как вы ловко занимаетесь кастингом из uint8_t в int8_t и обратно.
    Долго думал в чём там смысл… Пришёл к выводу что его там нет.


    1. GarryC
      27.06.2019 14:08

      Ну некоторый смысл есть, просто его очень трудно уловить в коряво написанной программе.
      Автор упорно пляшет по граблям, несмотря на расставленные повсюду таблички. Попробуем привести этот фрагмент в приемлемый вид

      // для начала - битовые константы связаны и это надо подчеркнуть
      /* Маска для получения знака калибровки */
      #define MASK_CALIBR_SIGN        (1 << 5)
      /* Маска для получения значения калибровки без знака. */
      #define MASK_CALIBR          MASK_CALIBR_SIGN-1
      int8_t caliber_to_ppm(uint8_t caliber) { // если египет, то повсюду египет
              int8_t result = caliber & MASK_CALIBR;
              // здесь можно обойтись без преобразования типов, но лучше его оставить
              result = ((uint8_t) result) << 1; // мы делаем именно сдвиг 
              if (caliber & MASK_CALIBR_SIGN) {/* лучше избегать не равенства*/
                        result = ((uint8_t) result) << 1; // опять сдвиг
              } else {
                        result = 0 - result; //вычитание лучше унарного минуса
              }
              return result;
      }


      1. u_235 Автор
        27.06.2019 20:03

        Я согласен, что перемудрил с приведением типов, остальное дело вкуса. Кстати, ваш пример показывает, что даже мэтры делают глупые ошибки.


        1. GarryC
          28.06.2019 14:57

          На мой взгляд, нисколько не перемудрили, всегда лучше сдвигать без-знаковые типы:
          1) не будет неопределенного поведения и
          2) это часто быстрее на некоторых МК, я по этому поводу пост писал.
          А что за глупая ошибка?


          1. u_235 Автор
            28.06.2019 16:42
            -1

            Да, я читал эту статью о сдвигах и багах AVR-GCC и это было одной из причин, по которой я использовал умножение и деление вместо сдвигов. Вторая причина — КМК это в данном случае наглядней.
            Ошибка в раскрытии макроса MASK_CALIBR, в котором вы забыли круглые скобки.

            Теперь я совсем перестал понимать, в чем корявость программы.


            1. assad77
              28.06.2019 18:04

              Да нет корявости никакой.
              В таких по размеру программах вообще об этом бессмысленно говорить.
              Работает, понятно в общих чертах с первого взгляда и ладно.
              Ктото другой конечно бы написал по другому, но на это не стоит внимание обращать.
              По поводу размера: ну как кая разница больше ли прошивка на 6 байт или нет, если она помещается в память.
              Вот если не помещается, или например не хватает оперативки для переменных, или скорости не хватало бы или надо было энергию экономить, вот тогда и надо было бы чтото улучшать.
              Я б тоже по другому написал эту функцию, но это не делает Вашу программу корявой.

              int8_t caliber_to_ppm(uint8_t caliber) {
                  int8_t result = caliber & MASK_CALIBR;
                  return (caliber & MASK_CALIBR_SIGN) ? -(result*2):(result*4);
              }
              

              Просто потому, что так сразу видно:
              Если знак есть то умножаем на 2 (сдвигаем биты) и ставим знак минус, если нет то умножаем на 4 (сдвигаем биты).


            1. GarryC
              29.06.2019 01:04

              Простите, если обидел, я как раз имел в виду умножения вместо сдвига. Всегда следует ясно указывать, что мы делаем, а тут мы сдвигаем. Да и умножением не все так просто, лучше его здесь не использовать. Речь только об этом шла, не сердитесь.


  1. u_235 Автор
    28.06.2019 15:38

    del